Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'clk-artpec6' into clk-next

* clk-artpec6:
clk: add artpec-6 clock controller
clk: add device tree binding for Artpec-6 clock controller

+324 -1
+41
Documentation/devicetree/bindings/clock/artpec6.txt
··· 1 + * Clock bindings for Axis ARTPEC-6 chip 2 + 3 + The bindings are based on the clock provider binding in 4 + Documentation/devicetree/bindings/clock/clock-bindings.txt 5 + 6 + External clocks: 7 + ---------------- 8 + 9 + There are two external inputs to the main clock controller which should be 10 + provided using the common clock bindings. 11 + - "sys_refclk": External 50 Mhz oscillator (required) 12 + - "i2s_refclk": Alternate audio reference clock (optional). 13 + 14 + Main clock controller 15 + --------------------- 16 + 17 + Required properties: 18 + - #clock-cells: Should be <1> 19 + See dt-bindings/clock/axis,artpec6-clkctrl.h for the list of valid identifiers. 20 + - compatible: Should be "axis,artpec6-clkctrl" 21 + - reg: Must contain the base address and length of the system controller 22 + - clocks: Must contain a phandle entry for each clock in clock-names 23 + - clock-names: Must include the external oscillator ("sys_refclk"). Optional 24 + ones are the audio reference clock ("i2s_refclk") and the audio fractional 25 + dividers ("frac_clk0" and "frac_clk1"). 26 + 27 + Examples: 28 + 29 + ext_clk: ext_clk { 30 + #clock-cells = <0>; 31 + compatible = "fixed-clock"; 32 + clock-frequency = <50000000>; 33 + }; 34 + 35 + clkctrl: clkctrl@f8000000 { 36 + #clock-cells = <1>; 37 + compatible = "axis,artpec6-clkctrl"; 38 + reg = <0xf8000000 0x48>; 39 + clocks = <&ext_clk>; 40 + clock-names = "sys_refclk"; 41 + };
+1 -1
MAINTAINERS
··· 973 973 L: linux-arm-kernel@axis.com 974 974 F: arch/arm/mach-artpec 975 975 F: arch/arm/boot/dts/artpec6* 976 - F: drivers/clk/clk-artpec6.c 976 + F: drivers/clk/axis 977 977 978 978 ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT 979 979 M: Nicolas Ferre <nicolas.ferre@atmel.com>
+1
drivers/clk/Makefile
··· 51 51 obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o 52 52 obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o 53 53 obj-$(CONFIG_COMMON_CLK_AT91) += at91/ 54 + obj-$(CONFIG_ARCH_ARTPEC) += axis/ 54 55 obj-y += bcm/ 55 56 obj-$(CONFIG_ARCH_BERLIN) += berlin/ 56 57 obj-$(CONFIG_ARCH_HISI) += hisilicon/
+1
drivers/clk/axis/Makefile
··· 1 + obj-$(CONFIG_MACH_ARTPEC6) += clk-artpec6.o
+242
drivers/clk/axis/clk-artpec6.c
··· 1 + /* 2 + * ARTPEC-6 clock initialization 3 + * 4 + * Copyright 2015-2016 Axis Comunications AB. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/clk-provider.h> 12 + #include <linux/device.h> 13 + #include <linux/io.h> 14 + #include <linux/of.h> 15 + #include <linux/of_address.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/slab.h> 18 + #include <dt-bindings/clock/axis,artpec6-clkctrl.h> 19 + 20 + #define NUM_I2S_CLOCKS 2 21 + 22 + struct artpec6_clkctrl_drvdata { 23 + struct clk *clk_table[ARTPEC6_CLK_NUMCLOCKS]; 24 + void __iomem *syscon_base; 25 + struct clk_onecell_data clk_data; 26 + spinlock_t i2scfg_lock; 27 + }; 28 + 29 + static struct artpec6_clkctrl_drvdata *clkdata; 30 + 31 + static const char *const i2s_clk_names[NUM_I2S_CLOCKS] = { 32 + "i2s0", 33 + "i2s1", 34 + }; 35 + 36 + static const int i2s_clk_indexes[NUM_I2S_CLOCKS] = { 37 + ARTPEC6_CLK_I2S0_CLK, 38 + ARTPEC6_CLK_I2S1_CLK, 39 + }; 40 + 41 + static void of_artpec6_clkctrl_setup(struct device_node *np) 42 + { 43 + int i; 44 + const char *sys_refclk_name; 45 + u32 pll_mode, pll_m, pll_n; 46 + struct clk **clks; 47 + 48 + /* Mandatory parent clock. */ 49 + i = of_property_match_string(np, "clock-names", "sys_refclk"); 50 + if (i < 0) 51 + return; 52 + 53 + sys_refclk_name = of_clk_get_parent_name(np, i); 54 + 55 + clkdata = kzalloc(sizeof(*clkdata), GFP_KERNEL); 56 + if (!clkdata) 57 + return; 58 + 59 + clks = clkdata->clk_table; 60 + 61 + for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i) 62 + clks[i] = ERR_PTR(-EPROBE_DEFER); 63 + 64 + clkdata->syscon_base = of_iomap(np, 0); 65 + BUG_ON(clkdata->syscon_base == NULL); 66 + 67 + /* Read PLL1 factors configured by boot strap pins. */ 68 + pll_mode = (readl(clkdata->syscon_base) >> 6) & 3; 69 + switch (pll_mode) { 70 + case 0: /* DDR3-2133 mode */ 71 + pll_m = 4; 72 + pll_n = 85; 73 + break; 74 + case 1: /* DDR3-1866 mode */ 75 + pll_m = 6; 76 + pll_n = 112; 77 + break; 78 + case 2: /* DDR3-1600 mode */ 79 + pll_m = 4; 80 + pll_n = 64; 81 + break; 82 + case 3: /* DDR3-1333 mode */ 83 + pll_m = 8; 84 + pll_n = 106; 85 + break; 86 + } 87 + 88 + clks[ARTPEC6_CLK_CPU] = 89 + clk_register_fixed_factor(NULL, "cpu", sys_refclk_name, 0, pll_n, 90 + pll_m); 91 + clks[ARTPEC6_CLK_CPU_PERIPH] = 92 + clk_register_fixed_factor(NULL, "cpu_periph", "cpu", 0, 1, 2); 93 + 94 + /* EPROBE_DEFER on the apb_clock is not handled in amba devices. */ 95 + clks[ARTPEC6_CLK_UART_PCLK] = 96 + clk_register_fixed_factor(NULL, "uart_pclk", "cpu", 0, 1, 8); 97 + clks[ARTPEC6_CLK_UART_REFCLK] = 98 + clk_register_fixed_rate(NULL, "uart_ref", sys_refclk_name, 0, 99 + 50000000); 100 + 101 + clks[ARTPEC6_CLK_SPI_PCLK] = 102 + clk_register_fixed_factor(NULL, "spi_pclk", "cpu", 0, 1, 8); 103 + clks[ARTPEC6_CLK_SPI_SSPCLK] = 104 + clk_register_fixed_rate(NULL, "spi_sspclk", sys_refclk_name, 0, 105 + 50000000); 106 + 107 + clks[ARTPEC6_CLK_DBG_PCLK] = 108 + clk_register_fixed_factor(NULL, "dbg_pclk", "cpu", 0, 1, 8); 109 + 110 + clkdata->clk_data.clks = clkdata->clk_table; 111 + clkdata->clk_data.clk_num = ARTPEC6_CLK_NUMCLOCKS; 112 + 113 + of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data); 114 + } 115 + 116 + CLK_OF_DECLARE(artpec6_clkctrl, "axis,artpec6-clkctrl", 117 + of_artpec6_clkctrl_setup); 118 + 119 + static int artpec6_clkctrl_probe(struct platform_device *pdev) 120 + { 121 + int propidx; 122 + struct device_node *np = pdev->dev.of_node; 123 + struct device *dev = &pdev->dev; 124 + struct clk **clks = clkdata->clk_table; 125 + const char *sys_refclk_name; 126 + const char *i2s_refclk_name = NULL; 127 + const char *frac_clk_name[2] = { NULL, NULL }; 128 + const char *i2s_mux_parents[2]; 129 + u32 muxreg; 130 + int i; 131 + int err = 0; 132 + 133 + /* Mandatory parent clock. */ 134 + propidx = of_property_match_string(np, "clock-names", "sys_refclk"); 135 + if (propidx < 0) 136 + return -EINVAL; 137 + 138 + sys_refclk_name = of_clk_get_parent_name(np, propidx); 139 + 140 + /* Find clock names of optional parent clocks. */ 141 + propidx = of_property_match_string(np, "clock-names", "i2s_refclk"); 142 + if (propidx >= 0) 143 + i2s_refclk_name = of_clk_get_parent_name(np, propidx); 144 + 145 + propidx = of_property_match_string(np, "clock-names", "frac_clk0"); 146 + if (propidx >= 0) 147 + frac_clk_name[0] = of_clk_get_parent_name(np, propidx); 148 + propidx = of_property_match_string(np, "clock-names", "frac_clk1"); 149 + if (propidx >= 0) 150 + frac_clk_name[1] = of_clk_get_parent_name(np, propidx); 151 + 152 + spin_lock_init(&clkdata->i2scfg_lock); 153 + 154 + clks[ARTPEC6_CLK_NAND_CLKA] = 155 + clk_register_fixed_factor(dev, "nand_clka", "cpu", 0, 1, 8); 156 + clks[ARTPEC6_CLK_NAND_CLKB] = 157 + clk_register_fixed_rate(dev, "nand_clkb", sys_refclk_name, 0, 158 + 100000000); 159 + clks[ARTPEC6_CLK_ETH_ACLK] = 160 + clk_register_fixed_factor(dev, "eth_aclk", "cpu", 0, 1, 4); 161 + clks[ARTPEC6_CLK_DMA_ACLK] = 162 + clk_register_fixed_factor(dev, "dma_aclk", "cpu", 0, 1, 4); 163 + clks[ARTPEC6_CLK_PTP_REF] = 164 + clk_register_fixed_rate(dev, "ptp_ref", sys_refclk_name, 0, 165 + 100000000); 166 + clks[ARTPEC6_CLK_SD_PCLK] = 167 + clk_register_fixed_rate(dev, "sd_pclk", sys_refclk_name, 0, 168 + 100000000); 169 + clks[ARTPEC6_CLK_SD_IMCLK] = 170 + clk_register_fixed_rate(dev, "sd_imclk", sys_refclk_name, 0, 171 + 100000000); 172 + clks[ARTPEC6_CLK_I2S_HST] = 173 + clk_register_fixed_factor(dev, "i2s_hst", "cpu", 0, 1, 8); 174 + 175 + for (i = 0; i < NUM_I2S_CLOCKS; ++i) { 176 + if (i2s_refclk_name && frac_clk_name[i]) { 177 + i2s_mux_parents[0] = frac_clk_name[i]; 178 + i2s_mux_parents[1] = i2s_refclk_name; 179 + 180 + clks[i2s_clk_indexes[i]] = 181 + clk_register_mux(dev, i2s_clk_names[i], 182 + i2s_mux_parents, 2, 183 + CLK_SET_RATE_NO_REPARENT | 184 + CLK_SET_RATE_PARENT, 185 + clkdata->syscon_base + 0x14, i, 1, 186 + 0, &clkdata->i2scfg_lock); 187 + } else if (frac_clk_name[i]) { 188 + /* Lock the mux for internal clock reference. */ 189 + muxreg = readl(clkdata->syscon_base + 0x14); 190 + muxreg &= ~BIT(i); 191 + writel(muxreg, clkdata->syscon_base + 0x14); 192 + clks[i2s_clk_indexes[i]] = 193 + clk_register_fixed_factor(dev, i2s_clk_names[i], 194 + frac_clk_name[i], 0, 1, 195 + 1); 196 + } else if (i2s_refclk_name) { 197 + /* Lock the mux for external clock reference. */ 198 + muxreg = readl(clkdata->syscon_base + 0x14); 199 + muxreg |= BIT(i); 200 + writel(muxreg, clkdata->syscon_base + 0x14); 201 + clks[i2s_clk_indexes[i]] = 202 + clk_register_fixed_factor(dev, i2s_clk_names[i], 203 + i2s_refclk_name, 0, 1, 1); 204 + } 205 + } 206 + 207 + clks[ARTPEC6_CLK_I2C] = 208 + clk_register_fixed_rate(dev, "i2c", sys_refclk_name, 0, 100000000); 209 + 210 + clks[ARTPEC6_CLK_SYS_TIMER] = 211 + clk_register_fixed_rate(dev, "timer", sys_refclk_name, 0, 212 + 100000000); 213 + clks[ARTPEC6_CLK_FRACDIV_IN] = 214 + clk_register_fixed_rate(dev, "fracdiv_in", sys_refclk_name, 0, 215 + 600000000); 216 + 217 + for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i) { 218 + if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -EPROBE_DEFER) { 219 + dev_err(dev, 220 + "Failed to register clock at index %d err=%ld\n", 221 + i, PTR_ERR(clks[i])); 222 + err = PTR_ERR(clks[i]); 223 + } 224 + } 225 + 226 + return err; 227 + } 228 + 229 + static const struct of_device_id artpec_clkctrl_of_match[] = { 230 + { .compatible = "axis,artpec6-clkctrl" }, 231 + {} 232 + }; 233 + 234 + static struct platform_driver artpec6_clkctrl_driver = { 235 + .probe = artpec6_clkctrl_probe, 236 + .driver = { 237 + .name = "artpec6_clkctrl", 238 + .of_match_table = artpec_clkctrl_of_match, 239 + }, 240 + }; 241 + 242 + builtin_platform_driver(artpec6_clkctrl_driver);
+38
include/dt-bindings/clock/axis,artpec6-clkctrl.h
··· 1 + /* 2 + * ARTPEC-6 clock controller indexes 3 + * 4 + * Copyright 2016 Axis Comunications AB. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #ifndef DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H 12 + #define DT_BINDINGS_CLK_ARTPEC6_CLKCTRL_H 13 + 14 + #define ARTPEC6_CLK_CPU 0 15 + #define ARTPEC6_CLK_CPU_PERIPH 1 16 + #define ARTPEC6_CLK_NAND_CLKA 2 17 + #define ARTPEC6_CLK_NAND_CLKB 3 18 + #define ARTPEC6_CLK_ETH_ACLK 4 19 + #define ARTPEC6_CLK_DMA_ACLK 5 20 + #define ARTPEC6_CLK_PTP_REF 6 21 + #define ARTPEC6_CLK_SD_PCLK 7 22 + #define ARTPEC6_CLK_SD_IMCLK 8 23 + #define ARTPEC6_CLK_I2S_HST 9 24 + #define ARTPEC6_CLK_I2S0_CLK 10 25 + #define ARTPEC6_CLK_I2S1_CLK 11 26 + #define ARTPEC6_CLK_UART_PCLK 12 27 + #define ARTPEC6_CLK_UART_REFCLK 13 28 + #define ARTPEC6_CLK_I2C 14 29 + #define ARTPEC6_CLK_SPI_PCLK 15 30 + #define ARTPEC6_CLK_SPI_SSPCLK 16 31 + #define ARTPEC6_CLK_SYS_TIMER 17 32 + #define ARTPEC6_CLK_FRACDIV_IN 18 33 + #define ARTPEC6_CLK_DBG_PCLK 19 34 + 35 + /* This must be the highest clock index plus one. */ 36 + #define ARTPEC6_CLK_NUMCLOCKS 20 37 + 38 + #endif