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

clk: samsung: add clock controller driver for s3c2412

This driver can handle the clock controller in the s3c2412 soc.

The clock structure is built according to the manuals of the included
SoCs and might include changes in comparison to the previous clock
structure.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Tomasz Figa <t.figa@samsung.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>

authored by

Heiko Stuebner and committed by
Kukjin Kim
ca2e90ac 7d03fed8

+343
+1
drivers/clk/samsung/Makefile
··· 8 8 obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o 9 9 obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o 10 10 obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-audss.o 11 + obj-$(CONFIG_S3C2412_COMMON_CLK)+= clk-s3c2412.o 11 12 obj-$(CONFIG_S3C2443_COMMON_CLK)+= clk-s3c2443.o 12 13 obj-$(CONFIG_ARCH_S3C64XX) += clk-s3c64xx.o
+269
drivers/clk/samsung/clk-s3c2412.c
··· 1 + /* 2 + * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * Common Clock Framework support for S3C2412 and S3C2413. 9 + */ 10 + 11 + #include <linux/clk.h> 12 + #include <linux/clkdev.h> 13 + #include <linux/clk-provider.h> 14 + #include <linux/of.h> 15 + #include <linux/of_address.h> 16 + #include <linux/syscore_ops.h> 17 + 18 + #include <dt-bindings/clock/s3c2412.h> 19 + 20 + #include "clk.h" 21 + #include "clk-pll.h" 22 + 23 + #define LOCKTIME 0x00 24 + #define MPLLCON 0x04 25 + #define UPLLCON 0x08 26 + #define CLKCON 0x0c 27 + #define CLKDIVN 0x14 28 + #define CLKSRC 0x1c 29 + 30 + /* list of PLLs to be registered */ 31 + enum s3c2412_plls { 32 + mpll, upll, 33 + }; 34 + 35 + static void __iomem *reg_base; 36 + 37 + #ifdef CONFIG_PM_SLEEP 38 + static struct samsung_clk_reg_dump *s3c2412_save; 39 + 40 + /* 41 + * list of controller registers to be saved and restored during a 42 + * suspend/resume cycle. 43 + */ 44 + static unsigned long s3c2412_clk_regs[] __initdata = { 45 + LOCKTIME, 46 + MPLLCON, 47 + UPLLCON, 48 + CLKCON, 49 + CLKDIVN, 50 + CLKSRC, 51 + }; 52 + 53 + static int s3c2412_clk_suspend(void) 54 + { 55 + samsung_clk_save(reg_base, s3c2412_save, 56 + ARRAY_SIZE(s3c2412_clk_regs)); 57 + 58 + return 0; 59 + } 60 + 61 + static void s3c2412_clk_resume(void) 62 + { 63 + samsung_clk_restore(reg_base, s3c2412_save, 64 + ARRAY_SIZE(s3c2412_clk_regs)); 65 + } 66 + 67 + static struct syscore_ops s3c2412_clk_syscore_ops = { 68 + .suspend = s3c2412_clk_suspend, 69 + .resume = s3c2412_clk_resume, 70 + }; 71 + 72 + static void s3c2412_clk_sleep_init(void) 73 + { 74 + s3c2412_save = samsung_clk_alloc_reg_dump(s3c2412_clk_regs, 75 + ARRAY_SIZE(s3c2412_clk_regs)); 76 + if (!s3c2412_save) { 77 + pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", 78 + __func__); 79 + return; 80 + } 81 + 82 + register_syscore_ops(&s3c2412_clk_syscore_ops); 83 + return; 84 + } 85 + #else 86 + static void s3c2412_clk_sleep_init(void) {} 87 + #endif 88 + 89 + static struct clk_div_table divxti_d[] = { 90 + { .val = 0, .div = 1 }, 91 + { .val = 1, .div = 2 }, 92 + { .val = 2, .div = 4 }, 93 + { .val = 3, .div = 6 }, 94 + { .val = 4, .div = 8 }, 95 + { .val = 5, .div = 10 }, 96 + { .val = 6, .div = 12 }, 97 + { .val = 7, .div = 14 }, 98 + { /* sentinel */ }, 99 + }; 100 + 101 + struct samsung_div_clock s3c2412_dividers[] __initdata = { 102 + DIV_T(0, "div_xti", "xti", CLKSRC, 0, 3, divxti_d), 103 + DIV(0, "div_cam", "mux_cam", CLKDIVN, 16, 4), 104 + DIV(0, "div_i2s", "mux_i2s", CLKDIVN, 12, 4), 105 + DIV(0, "div_uart", "mux_uart", CLKDIVN, 8, 4), 106 + DIV(0, "div_usb", "mux_usb", CLKDIVN, 6, 1), 107 + DIV(0, "div_hclk_half", "hclk", CLKDIVN, 5, 1), 108 + DIV(ARMDIV, "armdiv", "msysclk", CLKDIVN, 3, 1), 109 + DIV(PCLK, "pclk", "hclk", CLKDIVN, 2, 1), 110 + DIV(HCLK, "hclk", "armdiv", CLKDIVN, 0, 2), 111 + }; 112 + 113 + struct samsung_fixed_factor_clock s3c2412_ffactor[] __initdata = { 114 + FFACTOR(0, "ff_hclk", "hclk", 2, 1, CLK_SET_RATE_PARENT), 115 + }; 116 + 117 + /* 118 + * The first two use the OM[4] setting, which is not readable from 119 + * software, so assume it is set to xti. 120 + */ 121 + PNAME(erefclk_p) = { "xti", "xti", "xti", "ext" }; 122 + PNAME(urefclk_p) = { "xti", "xti", "xti", "ext" }; 123 + 124 + PNAME(camclk_p) = { "usysclk", "hclk" }; 125 + PNAME(usbclk_p) = { "usysclk", "hclk" }; 126 + PNAME(i2sclk_p) = { "erefclk", "mpll" }; 127 + PNAME(uartclk_p) = { "erefclk", "mpll" }; 128 + PNAME(usysclk_p) = { "urefclk", "upll" }; 129 + PNAME(msysclk_p) = { "mdivclk", "mpll" }; 130 + PNAME(mdivclk_p) = { "xti", "div_xti" }; 131 + PNAME(armclk_p) = { "armdiv", "hclk" }; 132 + 133 + struct samsung_mux_clock s3c2412_muxes[] __initdata = { 134 + MUX(0, "erefclk", erefclk_p, CLKSRC, 14, 2), 135 + MUX(0, "urefclk", urefclk_p, CLKSRC, 12, 2), 136 + MUX(0, "mux_cam", camclk_p, CLKSRC, 11, 1), 137 + MUX(0, "mux_usb", usbclk_p, CLKSRC, 10, 1), 138 + MUX(0, "mux_i2s", i2sclk_p, CLKSRC, 9, 1), 139 + MUX(0, "mux_uart", uartclk_p, CLKSRC, 8, 1), 140 + MUX(USYSCLK, "usysclk", usysclk_p, CLKSRC, 5, 1), 141 + MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1), 142 + MUX(MDIVCLK, "mdivclk", mdivclk_p, CLKSRC, 3, 1), 143 + MUX(ARMCLK, "armclk", armclk_p, CLKDIVN, 4, 1), 144 + }; 145 + 146 + static struct samsung_pll_clock s3c2412_plls[] __initdata = { 147 + [mpll] = PLL(pll_s3c2440_mpll, MPLL, "mpll", "xti", 148 + LOCKTIME, MPLLCON, NULL), 149 + [upll] = PLL(pll_s3c2410_upll, UPLL, "upll", "urefclk", 150 + LOCKTIME, UPLLCON, NULL), 151 + }; 152 + 153 + struct samsung_gate_clock s3c2412_gates[] __initdata = { 154 + GATE(PCLK_WDT, "wdt", "pclk", CLKCON, 28, 0, 0), 155 + GATE(PCLK_SPI, "spi", "pclk", CLKCON, 27, 0, 0), 156 + GATE(PCLK_I2S, "i2s", "pclk", CLKCON, 26, 0, 0), 157 + GATE(PCLK_I2C, "i2c", "pclk", CLKCON, 25, 0, 0), 158 + GATE(PCLK_ADC, "adc", "pclk", CLKCON, 24, 0, 0), 159 + GATE(PCLK_RTC, "rtc", "pclk", CLKCON, 23, 0, 0), 160 + GATE(PCLK_GPIO, "gpio", "pclk", CLKCON, 22, CLK_IGNORE_UNUSED, 0), 161 + GATE(PCLK_UART2, "uart2", "pclk", CLKCON, 21, 0, 0), 162 + GATE(PCLK_UART1, "uart1", "pclk", CLKCON, 20, 0, 0), 163 + GATE(PCLK_UART0, "uart0", "pclk", CLKCON, 19, 0, 0), 164 + GATE(PCLK_SDI, "sdi", "pclk", CLKCON, 18, 0, 0), 165 + GATE(PCLK_PWM, "pwm", "pclk", CLKCON, 17, 0, 0), 166 + GATE(PCLK_USBD, "usb-device", "pclk", CLKCON, 16, 0, 0), 167 + GATE(SCLK_CAM, "sclk_cam", "div_cam", CLKCON, 15, 0, 0), 168 + GATE(SCLK_UART, "sclk_uart", "div_uart", CLKCON, 14, 0, 0), 169 + GATE(SCLK_I2S, "sclk_i2s", "div_i2s", CLKCON, 13, 0, 0), 170 + GATE(SCLK_USBH, "sclk_usbh", "div_usb", CLKCON, 12, 0, 0), 171 + GATE(SCLK_USBD, "sclk_usbd", "div_usb", CLKCON, 11, 0, 0), 172 + GATE(HCLK_HALF, "hclk_half", "div_hclk_half", CLKCON, 10, CLK_IGNORE_UNUSED, 0), 173 + GATE(HCLK_X2, "hclkx2", "ff_hclk", CLKCON, 9, CLK_IGNORE_UNUSED, 0), 174 + GATE(HCLK_SDRAM, "sdram", "hclk", CLKCON, 8, CLK_IGNORE_UNUSED, 0), 175 + GATE(HCLK_USBH, "usb-host", "hclk", CLKCON, 6, 0, 0), 176 + GATE(HCLK_LCD, "lcd", "hclk", CLKCON, 5, 0, 0), 177 + GATE(HCLK_NAND, "nand", "hclk", CLKCON, 4, 0, 0), 178 + GATE(HCLK_DMA3, "dma3", "hclk", CLKCON, 3, CLK_IGNORE_UNUSED, 0), 179 + GATE(HCLK_DMA2, "dma2", "hclk", CLKCON, 2, CLK_IGNORE_UNUSED, 0), 180 + GATE(HCLK_DMA1, "dma1", "hclk", CLKCON, 1, CLK_IGNORE_UNUSED, 0), 181 + GATE(HCLK_DMA0, "dma0", "hclk", CLKCON, 0, CLK_IGNORE_UNUSED, 0), 182 + }; 183 + 184 + struct samsung_clock_alias s3c2412_aliases[] __initdata = { 185 + ALIAS(PCLK_UART0, "s3c2412-uart.0", "uart"), 186 + ALIAS(PCLK_UART1, "s3c2412-uart.1", "uart"), 187 + ALIAS(PCLK_UART2, "s3c2412-uart.2", "uart"), 188 + ALIAS(PCLK_UART0, "s3c2412-uart.0", "clk_uart_baud2"), 189 + ALIAS(PCLK_UART1, "s3c2412-uart.1", "clk_uart_baud2"), 190 + ALIAS(PCLK_UART2, "s3c2412-uart.2", "clk_uart_baud2"), 191 + ALIAS(SCLK_UART, NULL, "clk_uart_baud3"), 192 + ALIAS(PCLK_I2C, "s3c2410-i2c.0", "i2c"), 193 + ALIAS(PCLK_ADC, NULL, "adc"), 194 + ALIAS(PCLK_RTC, NULL, "rtc"), 195 + ALIAS(PCLK_PWM, NULL, "timers"), 196 + ALIAS(HCLK_LCD, NULL, "lcd"), 197 + ALIAS(PCLK_USBD, NULL, "usb-device"), 198 + ALIAS(SCLK_USBD, NULL, "usb-bus-gadget"), 199 + ALIAS(HCLK_USBH, NULL, "usb-host"), 200 + ALIAS(SCLK_USBH, NULL, "usb-bus-host"), 201 + ALIAS(ARMCLK, NULL, "armclk"), 202 + ALIAS(HCLK, NULL, "hclk"), 203 + ALIAS(MPLL, NULL, "mpll"), 204 + ALIAS(MSYSCLK, NULL, "fclk"), 205 + }; 206 + 207 + /* 208 + * fixed rate clocks generated outside the soc 209 + * Only necessary until the devicetree-move is complete 210 + */ 211 + #define XTI 1 212 + struct samsung_fixed_rate_clock s3c2412_common_frate_clks[] __initdata = { 213 + FRATE(XTI, "xti", NULL, CLK_IS_ROOT, 0), 214 + FRATE(0, "ext", NULL, CLK_IS_ROOT, 0), 215 + }; 216 + 217 + static void __init s3c2412_common_clk_register_fixed_ext(unsigned long xti_f, 218 + unsigned long ext_f) 219 + { 220 + /* xtal alias is necessary for the current cpufreq driver */ 221 + struct samsung_clock_alias xti_alias = ALIAS(XTI, NULL, "xtal"); 222 + 223 + s3c2412_common_frate_clks[0].fixed_rate = xti_f; 224 + s3c2412_common_frate_clks[1].fixed_rate = ext_f; 225 + samsung_clk_register_fixed_rate(s3c2412_common_frate_clks, 226 + ARRAY_SIZE(s3c2412_common_frate_clks)); 227 + 228 + samsung_clk_register_alias(&xti_alias, 1); 229 + } 230 + 231 + void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, 232 + unsigned long ext_f, void __iomem *base) 233 + { 234 + reg_base = base; 235 + 236 + if (np) { 237 + reg_base = of_iomap(np, 0); 238 + if (!reg_base) 239 + panic("%s: failed to map registers\n", __func__); 240 + } 241 + 242 + samsung_clk_init(np, reg_base, NR_CLKS); 243 + 244 + /* Register external clocks only in non-dt cases */ 245 + if (!np) 246 + s3c2412_common_clk_register_fixed_ext(xti_f, ext_f); 247 + 248 + /* Register PLLs. */ 249 + samsung_clk_register_pll(s3c2412_plls, ARRAY_SIZE(s3c2412_plls), 250 + reg_base); 251 + 252 + /* Register common internal clocks. */ 253 + samsung_clk_register_mux(s3c2412_muxes, ARRAY_SIZE(s3c2412_muxes)); 254 + samsung_clk_register_div(s3c2412_dividers, 255 + ARRAY_SIZE(s3c2412_dividers)); 256 + samsung_clk_register_gate(s3c2412_gates, ARRAY_SIZE(s3c2412_gates)); 257 + samsung_clk_register_fixed_factor(s3c2412_ffactor, 258 + ARRAY_SIZE(s3c2412_ffactor)); 259 + samsung_clk_register_alias(s3c2412_aliases, 260 + ARRAY_SIZE(s3c2412_aliases)); 261 + 262 + s3c2412_clk_sleep_init(); 263 + } 264 + 265 + static void __init s3c2412_clk_init(struct device_node *np) 266 + { 267 + s3c2412_common_clk_init(np, 0, 0, 0); 268 + } 269 + CLK_OF_DECLARE(s3c2412_clk, "samsung,s3c2412-clock", s3c2412_clk_init);
+73
include/dt-bindings/clock/s3c2412.h
··· 1 + /* 2 + * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * Device Tree binding constants clock controllers of Samsung S3C2412. 9 + */ 10 + 11 + #ifndef _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H 12 + #define _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H 13 + 14 + /* 15 + * Let each exported clock get a unique index, which is used on DT-enabled 16 + * platforms to lookup the clock from a clock specifier. These indices are 17 + * therefore considered an ABI and so must not be changed. This implies 18 + * that new clocks should be added either in free spaces between clock groups 19 + * or at the end. 20 + */ 21 + 22 + /* Core clocks. */ 23 + 24 + /* id 1 is reserved */ 25 + #define MPLL 2 26 + #define UPLL 3 27 + #define MDIVCLK 4 28 + #define MSYSCLK 5 29 + #define USYSCLK 6 30 + #define HCLK 7 31 + #define PCLK 8 32 + #define ARMDIV 9 33 + #define ARMCLK 10 34 + 35 + 36 + /* Special clocks */ 37 + #define SCLK_CAM 16 38 + #define SCLK_UART 17 39 + #define SCLK_I2S 18 40 + #define SCLK_USBD 19 41 + #define SCLK_USBH 20 42 + 43 + /* pclk-gates */ 44 + #define PCLK_WDT 32 45 + #define PCLK_SPI 33 46 + #define PCLK_I2S 34 47 + #define PCLK_I2C 35 48 + #define PCLK_ADC 36 49 + #define PCLK_RTC 37 50 + #define PCLK_GPIO 38 51 + #define PCLK_UART2 39 52 + #define PCLK_UART1 40 53 + #define PCLK_UART0 41 54 + #define PCLK_SDI 42 55 + #define PCLK_PWM 43 56 + #define PCLK_USBD 44 57 + 58 + /* hclk-gates */ 59 + #define HCLK_HALF 48 60 + #define HCLK_X2 49 61 + #define HCLK_SDRAM 50 62 + #define HCLK_USBH 51 63 + #define HCLK_LCD 52 64 + #define HCLK_NAND 53 65 + #define HCLK_DMA3 54 66 + #define HCLK_DMA2 55 67 + #define HCLK_DMA1 56 68 + #define HCLK_DMA0 57 69 + 70 + /* Total number of clocks. */ 71 + #define NR_CLKS (HCLK_DMA0 + 1) 72 + 73 + #endif /* _DT_BINDINGS_CLOCK_SAMSUNG_S3C2412_CLOCK_H */