···11+* Clock bindings for Axis ARTPEC-6 chip22+33+The bindings are based on the clock provider binding in44+Documentation/devicetree/bindings/clock/clock-bindings.txt55+66+External clocks:77+----------------88+99+There are two external inputs to the main clock controller which should be1010+provided using the common clock bindings.1111+- "sys_refclk": External 50 Mhz oscillator (required)1212+- "i2s_refclk": Alternate audio reference clock (optional).1313+1414+Main clock controller1515+---------------------1616+1717+Required properties:1818+- #clock-cells: Should be <1>1919+ See dt-bindings/clock/axis,artpec6-clkctrl.h for the list of valid identifiers.2020+- compatible: Should be "axis,artpec6-clkctrl"2121+- reg: Must contain the base address and length of the system controller2222+- clocks: Must contain a phandle entry for each clock in clock-names2323+- clock-names: Must include the external oscillator ("sys_refclk"). Optional2424+ ones are the audio reference clock ("i2s_refclk") and the audio fractional2525+ dividers ("frac_clk0" and "frac_clk1").2626+2727+Examples:2828+2929+ext_clk: ext_clk {3030+ #clock-cells = <0>;3131+ compatible = "fixed-clock";3232+ clock-frequency = <50000000>;3333+};3434+3535+clkctrl: clkctrl@f8000000 {3636+ #clock-cells = <1>;3737+ compatible = "axis,artpec6-clkctrl";3838+ reg = <0xf8000000 0x48>;3939+ clocks = <&ext_clk>;4040+ clock-names = "sys_refclk";4141+};
+1-1
MAINTAINERS
···973973L: linux-arm-kernel@axis.com974974F: arch/arm/mach-artpec975975F: arch/arm/boot/dts/artpec6*976976-F: drivers/clk/clk-artpec6.c976976+F: drivers/clk/axis977977978978ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT979979M: Nicolas Ferre <nicolas.ferre@atmel.com>
···11+/*22+ * ARTPEC-6 clock initialization33+ *44+ * Copyright 2015-2016 Axis Comunications AB.55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License version 2 as88+ * published by the Free Software Foundation.99+ */1010+1111+#include <linux/clk-provider.h>1212+#include <linux/device.h>1313+#include <linux/io.h>1414+#include <linux/of.h>1515+#include <linux/of_address.h>1616+#include <linux/platform_device.h>1717+#include <linux/slab.h>1818+#include <dt-bindings/clock/axis,artpec6-clkctrl.h>1919+2020+#define NUM_I2S_CLOCKS 22121+2222+struct artpec6_clkctrl_drvdata {2323+ struct clk *clk_table[ARTPEC6_CLK_NUMCLOCKS];2424+ void __iomem *syscon_base;2525+ struct clk_onecell_data clk_data;2626+ spinlock_t i2scfg_lock;2727+};2828+2929+static struct artpec6_clkctrl_drvdata *clkdata;3030+3131+static const char *const i2s_clk_names[NUM_I2S_CLOCKS] = {3232+ "i2s0",3333+ "i2s1",3434+};3535+3636+static const int i2s_clk_indexes[NUM_I2S_CLOCKS] = {3737+ ARTPEC6_CLK_I2S0_CLK,3838+ ARTPEC6_CLK_I2S1_CLK,3939+};4040+4141+static void of_artpec6_clkctrl_setup(struct device_node *np)4242+{4343+ int i;4444+ const char *sys_refclk_name;4545+ u32 pll_mode, pll_m, pll_n;4646+ struct clk **clks;4747+4848+ /* Mandatory parent clock. */4949+ i = of_property_match_string(np, "clock-names", "sys_refclk");5050+ if (i < 0)5151+ return;5252+5353+ sys_refclk_name = of_clk_get_parent_name(np, i);5454+5555+ clkdata = kzalloc(sizeof(*clkdata), GFP_KERNEL);5656+ if (!clkdata)5757+ return;5858+5959+ clks = clkdata->clk_table;6060+6161+ for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i)6262+ clks[i] = ERR_PTR(-EPROBE_DEFER);6363+6464+ clkdata->syscon_base = of_iomap(np, 0);6565+ BUG_ON(clkdata->syscon_base == NULL);6666+6767+ /* Read PLL1 factors configured by boot strap pins. */6868+ pll_mode = (readl(clkdata->syscon_base) >> 6) & 3;6969+ switch (pll_mode) {7070+ case 0: /* DDR3-2133 mode */7171+ pll_m = 4;7272+ pll_n = 85;7373+ break;7474+ case 1: /* DDR3-1866 mode */7575+ pll_m = 6;7676+ pll_n = 112;7777+ break;7878+ case 2: /* DDR3-1600 mode */7979+ pll_m = 4;8080+ pll_n = 64;8181+ break;8282+ case 3: /* DDR3-1333 mode */8383+ pll_m = 8;8484+ pll_n = 106;8585+ break;8686+ }8787+8888+ clks[ARTPEC6_CLK_CPU] =8989+ clk_register_fixed_factor(NULL, "cpu", sys_refclk_name, 0, pll_n,9090+ pll_m);9191+ clks[ARTPEC6_CLK_CPU_PERIPH] =9292+ clk_register_fixed_factor(NULL, "cpu_periph", "cpu", 0, 1, 2);9393+9494+ /* EPROBE_DEFER on the apb_clock is not handled in amba devices. */9595+ clks[ARTPEC6_CLK_UART_PCLK] =9696+ clk_register_fixed_factor(NULL, "uart_pclk", "cpu", 0, 1, 8);9797+ clks[ARTPEC6_CLK_UART_REFCLK] =9898+ clk_register_fixed_rate(NULL, "uart_ref", sys_refclk_name, 0,9999+ 50000000);100100+101101+ clks[ARTPEC6_CLK_SPI_PCLK] =102102+ clk_register_fixed_factor(NULL, "spi_pclk", "cpu", 0, 1, 8);103103+ clks[ARTPEC6_CLK_SPI_SSPCLK] =104104+ clk_register_fixed_rate(NULL, "spi_sspclk", sys_refclk_name, 0,105105+ 50000000);106106+107107+ clks[ARTPEC6_CLK_DBG_PCLK] =108108+ clk_register_fixed_factor(NULL, "dbg_pclk", "cpu", 0, 1, 8);109109+110110+ clkdata->clk_data.clks = clkdata->clk_table;111111+ clkdata->clk_data.clk_num = ARTPEC6_CLK_NUMCLOCKS;112112+113113+ of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data);114114+}115115+116116+CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl",117117+ of_artpec6_clkctrl_setup);118118+119119+static int artpec6_clkctrl_probe(struct platform_device *pdev)120120+{121121+ int propidx;122122+ struct device_node *np = pdev->dev.of_node;123123+ struct device *dev = &pdev->dev;124124+ struct clk **clks = clkdata->clk_table;125125+ const char *sys_refclk_name;126126+ const char *i2s_refclk_name = NULL;127127+ const char *frac_clk_name[2] = { NULL, NULL };128128+ const char *i2s_mux_parents[2];129129+ u32 muxreg;130130+ int i;131131+ int err = 0;132132+133133+ /* Mandatory parent clock. */134134+ propidx = of_property_match_string(np, "clock-names", "sys_refclk");135135+ if (propidx < 0)136136+ return -EINVAL;137137+138138+ sys_refclk_name = of_clk_get_parent_name(np, propidx);139139+140140+ /* Find clock names of optional parent clocks. */141141+ propidx = of_property_match_string(np, "clock-names", "i2s_refclk");142142+ if (propidx >= 0)143143+ i2s_refclk_name = of_clk_get_parent_name(np, propidx);144144+145145+ propidx = of_property_match_string(np, "clock-names", "frac_clk0");146146+ if (propidx >= 0)147147+ frac_clk_name[0] = of_clk_get_parent_name(np, propidx);148148+ propidx = of_property_match_string(np, "clock-names", "frac_clk1");149149+ if (propidx >= 0)150150+ frac_clk_name[1] = of_clk_get_parent_name(np, propidx);151151+152152+ spin_lock_init(&clkdata->i2scfg_lock);153153+154154+ clks[ARTPEC6_CLK_NAND_CLKA] =155155+ clk_register_fixed_factor(dev, "nand_clka", "cpu", 0, 1, 8);156156+ clks[ARTPEC6_CLK_NAND_CLKB] =157157+ clk_register_fixed_rate(dev, "nand_clkb", sys_refclk_name, 0,158158+ 100000000);159159+ clks[ARTPEC6_CLK_ETH_ACLK] =160160+ clk_register_fixed_factor(dev, "eth_aclk", "cpu", 0, 1, 4);161161+ clks[ARTPEC6_CLK_DMA_ACLK] =162162+ clk_register_fixed_factor(dev, "dma_aclk", "cpu", 0, 1, 4);163163+ clks[ARTPEC6_CLK_PTP_REF] =164164+ clk_register_fixed_rate(dev, "ptp_ref", sys_refclk_name, 0,165165+ 100000000);166166+ clks[ARTPEC6_CLK_SD_PCLK] =167167+ clk_register_fixed_rate(dev, "sd_pclk", sys_refclk_name, 0,168168+ 100000000);169169+ clks[ARTPEC6_CLK_SD_IMCLK] =170170+ clk_register_fixed_rate(dev, "sd_imclk", sys_refclk_name, 0,171171+ 100000000);172172+ clks[ARTPEC6_CLK_I2S_HST] =173173+ clk_register_fixed_factor(dev, "i2s_hst", "cpu", 0, 1, 8);174174+175175+ for (i = 0; i < NUM_I2S_CLOCKS; ++i) {176176+ if (i2s_refclk_name && frac_clk_name[i]) {177177+ i2s_mux_parents[0] = frac_clk_name[i];178178+ i2s_mux_parents[1] = i2s_refclk_name;179179+180180+ clks[i2s_clk_indexes[i]] =181181+ clk_register_mux(dev, i2s_clk_names[i],182182+ i2s_mux_parents, 2,183183+ CLK_SET_RATE_NO_REPARENT |184184+ CLK_SET_RATE_PARENT,185185+ clkdata->syscon_base + 0x14, i, 1,186186+ 0, &clkdata->i2scfg_lock);187187+ } else if (frac_clk_name[i]) {188188+ /* Lock the mux for internal clock reference. */189189+ muxreg = readl(clkdata->syscon_base + 0x14);190190+ muxreg &= ~BIT(i);191191+ writel(muxreg, clkdata->syscon_base + 0x14);192192+ clks[i2s_clk_indexes[i]] =193193+ clk_register_fixed_factor(dev, i2s_clk_names[i],194194+ frac_clk_name[i], 0, 1,195195+ 1);196196+ } else if (i2s_refclk_name) {197197+ /* Lock the mux for external clock reference. */198198+ muxreg = readl(clkdata->syscon_base + 0x14);199199+ muxreg |= BIT(i);200200+ writel(muxreg, clkdata->syscon_base + 0x14);201201+ clks[i2s_clk_indexes[i]] =202202+ clk_register_fixed_factor(dev, i2s_clk_names[i],203203+ i2s_refclk_name, 0, 1, 1);204204+ }205205+ }206206+207207+ clks[ARTPEC6_CLK_I2C] =208208+ clk_register_fixed_rate(dev, "i2c", sys_refclk_name, 0, 100000000);209209+210210+ clks[ARTPEC6_CLK_SYS_TIMER] =211211+ clk_register_fixed_rate(dev, "timer", sys_refclk_name, 0,212212+ 100000000);213213+ clks[ARTPEC6_CLK_FRACDIV_IN] =214214+ clk_register_fixed_rate(dev, "fracdiv_in", sys_refclk_name, 0,215215+ 600000000);216216+217217+ for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i) {218218+ if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -EPROBE_DEFER) {219219+ dev_err(dev,220220+ "Failed to register clock at index %d err=%ld\n",221221+ i, PTR_ERR(clks[i]));222222+ err = PTR_ERR(clks[i]);223223+ }224224+ }225225+226226+ return err;227227+}228228+229229+static const struct of_device_id artpec_clkctrl_of_match[] = {230230+ { .compatible = "axis,artpec6-clkctrl" },231231+ {}232232+};233233+234234+static struct platform_driver artpec6_clkctrl_driver = {235235+ .probe = artpec6_clkctrl_probe,236236+ .driver = {237237+ .name = "artpec6_clkctrl",238238+ .of_match_table = artpec_clkctrl_of_match,239239+ },240240+};241241+242242+builtin_platform_driver(artpec6_clkctrl_driver);
+38
include/dt-bindings/clock/axis,artpec6-clkctrl.h
···11+/*22+ * ARTPEC-6 clock controller indexes33+ *44+ * Copyright 2016 Axis Comunications AB.55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License version 2 as88+ * published by the Free Software Foundation.99+ */1010+1111+#ifndef DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H1212+#define DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H1313+1414+#define ARTPEC6_CLK_CPU 01515+#define ARTPEC6_CLK_CPU_PERIPH 11616+#define ARTPEC6_CLK_NAND_CLKA 21717+#define ARTPEC6_CLK_NAND_CLKB 31818+#define ARTPEC6_CLK_ETH_ACLK 41919+#define ARTPEC6_CLK_DMA_ACLK 52020+#define ARTPEC6_CLK_PTP_REF 62121+#define ARTPEC6_CLK_SD_PCLK 72222+#define ARTPEC6_CLK_SD_IMCLK 82323+#define ARTPEC6_CLK_I2S_HST 92424+#define ARTPEC6_CLK_I2S0_CLK 102525+#define ARTPEC6_CLK_I2S1_CLK 112626+#define ARTPEC6_CLK_UART_PCLK 122727+#define ARTPEC6_CLK_UART_REFCLK 132828+#define ARTPEC6_CLK_I2C 142929+#define ARTPEC6_CLK_SPI_PCLK 153030+#define ARTPEC6_CLK_SPI_SSPCLK 163131+#define ARTPEC6_CLK_SYS_TIMER 173232+#define ARTPEC6_CLK_FRACDIV_IN 183333+#define ARTPEC6_CLK_DBG_PCLK 193434+3535+/* This must be the highest clock index plus one. */3636+#define ARTPEC6_CLK_NUMCLOCKS 203737+3838+#endif