2 * Copyright (c) 2013 Heiko Stuebner <heiko@sntech.de>
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.
8 * Common Clock Framework support for S3C2443 and following SoCs.
11 #include <linux/clk-provider.h>
13 #include <linux/of_address.h>
14 #include <linux/reboot.h>
16 #include <dt-bindings/clock/s3c2443.h>
21 /* S3C2416 clock controller register offsets */
26 #define EPLLCON_K 0x1C
43 static void __iomem
*reg_base
;
46 * list of controller registers to be saved and restored during a
47 * suspend/resume cycle.
49 static unsigned long s3c2443_clk_regs
[] __initdata
= {
64 PNAME(epllref_p
) = { "mpllref", "mpllref", "xti", "ext" };
65 PNAME(esysclk_p
) = { "epllref", "epll" };
66 PNAME(mpllref_p
) = { "xti", "mdivclk" };
67 PNAME(msysclk_p
) = { "mpllref", "mpll" };
68 PNAME(armclk_p
) = { "armdiv" , "hclk" };
69 PNAME(i2s0_p
) = { "div_i2s0", "ext_i2s", "epllref", "epllref" };
71 static struct samsung_mux_clock s3c2443_common_muxes
[] __initdata
= {
72 MUX(0, "epllref", epllref_p
, CLKSRC
, 7, 2),
73 MUX(ESYSCLK
, "esysclk", esysclk_p
, CLKSRC
, 6, 1),
74 MUX(0, "mpllref", mpllref_p
, CLKSRC
, 3, 1),
75 MUX(MSYSCLK
, "msysclk", msysclk_p
, CLKSRC
, 4, 1),
76 MUX(ARMCLK
, "armclk", armclk_p
, CLKDIV0
, 13, 1),
77 MUX(0, "mux_i2s0", i2s0_p
, CLKSRC
, 14, 2),
80 static struct clk_div_table hclk_d
[] = {
81 { .val
= 0, .div
= 1 },
82 { .val
= 1, .div
= 2 },
83 { .val
= 3, .div
= 4 },
87 static struct clk_div_table mdivclk_d
[] = {
88 { .val
= 0, .div
= 1 },
89 { .val
= 1, .div
= 3 },
90 { .val
= 2, .div
= 5 },
91 { .val
= 3, .div
= 7 },
92 { .val
= 4, .div
= 9 },
93 { .val
= 5, .div
= 11 },
94 { .val
= 6, .div
= 13 },
95 { .val
= 7, .div
= 15 },
99 static struct samsung_div_clock s3c2443_common_dividers
[] __initdata
= {
100 DIV_T(0, "mdivclk", "xti", CLKDIV0
, 6, 3, mdivclk_d
),
101 DIV(0, "prediv", "msysclk", CLKDIV0
, 4, 2),
102 DIV_T(HCLK
, "hclk", "prediv", CLKDIV0
, 0, 2, hclk_d
),
103 DIV(PCLK
, "pclk", "hclk", CLKDIV0
, 2, 1),
104 DIV(0, "div_hsspi0_epll", "esysclk", CLKDIV1
, 24, 2),
105 DIV(0, "div_fimd", "esysclk", CLKDIV1
, 16, 8),
106 DIV(0, "div_i2s0", "esysclk", CLKDIV1
, 12, 4),
107 DIV(0, "div_uart", "esysclk", CLKDIV1
, 8, 4),
108 DIV(0, "div_hsmmc1", "esysclk", CLKDIV1
, 6, 2),
109 DIV(0, "div_usbhost", "esysclk", CLKDIV1
, 4, 2),
112 static struct samsung_gate_clock s3c2443_common_gates
[] __initdata
= {
113 GATE(SCLK_HSMMC_EXT
, "sclk_hsmmcext", "ext", SCLKCON
, 13, 0, 0),
114 GATE(SCLK_HSMMC1
, "sclk_hsmmc1", "div_hsmmc1", SCLKCON
, 12, 0, 0),
115 GATE(SCLK_FIMD
, "sclk_fimd", "div_fimd", SCLKCON
, 10, 0, 0),
116 GATE(SCLK_I2S0
, "sclk_i2s0", "mux_i2s0", SCLKCON
, 9, 0, 0),
117 GATE(SCLK_UART
, "sclk_uart", "div_uart", SCLKCON
, 8, 0, 0),
118 GATE(SCLK_USBH
, "sclk_usbhost", "div_usbhost", SCLKCON
, 1, 0, 0),
119 GATE(HCLK_DRAM
, "dram", "hclk", HCLKCON
, 19, CLK_IGNORE_UNUSED
, 0),
120 GATE(HCLK_SSMC
, "ssmc", "hclk", HCLKCON
, 18, CLK_IGNORE_UNUSED
, 0),
121 GATE(HCLK_HSMMC1
, "hsmmc1", "hclk", HCLKCON
, 16, 0, 0),
122 GATE(HCLK_USBD
, "usb-device", "hclk", HCLKCON
, 12, 0, 0),
123 GATE(HCLK_USBH
, "usb-host", "hclk", HCLKCON
, 11, 0, 0),
124 GATE(HCLK_LCD
, "lcd", "hclk", HCLKCON
, 9, 0, 0),
125 GATE(HCLK_DMA5
, "dma5", "hclk", HCLKCON
, 5, CLK_IGNORE_UNUSED
, 0),
126 GATE(HCLK_DMA4
, "dma4", "hclk", HCLKCON
, 4, CLK_IGNORE_UNUSED
, 0),
127 GATE(HCLK_DMA3
, "dma3", "hclk", HCLKCON
, 3, CLK_IGNORE_UNUSED
, 0),
128 GATE(HCLK_DMA2
, "dma2", "hclk", HCLKCON
, 2, CLK_IGNORE_UNUSED
, 0),
129 GATE(HCLK_DMA1
, "dma1", "hclk", HCLKCON
, 1, CLK_IGNORE_UNUSED
, 0),
130 GATE(HCLK_DMA0
, "dma0", "hclk", HCLKCON
, 0, CLK_IGNORE_UNUSED
, 0),
131 GATE(PCLK_GPIO
, "gpio", "pclk", PCLKCON
, 13, CLK_IGNORE_UNUSED
, 0),
132 GATE(PCLK_RTC
, "rtc", "pclk", PCLKCON
, 12, 0, 0),
133 GATE(PCLK_WDT
, "wdt", "pclk", PCLKCON
, 11, 0, 0),
134 GATE(PCLK_PWM
, "pwm", "pclk", PCLKCON
, 10, 0, 0),
135 GATE(PCLK_I2S0
, "i2s0", "pclk", PCLKCON
, 9, 0, 0),
136 GATE(PCLK_AC97
, "ac97", "pclk", PCLKCON
, 8, 0, 0),
137 GATE(PCLK_ADC
, "adc", "pclk", PCLKCON
, 7, 0, 0),
138 GATE(PCLK_SPI0
, "spi0", "pclk", PCLKCON
, 6, 0, 0),
139 GATE(PCLK_I2C0
, "i2c0", "pclk", PCLKCON
, 4, 0, 0),
140 GATE(PCLK_UART3
, "uart3", "pclk", PCLKCON
, 3, 0, 0),
141 GATE(PCLK_UART2
, "uart2", "pclk", PCLKCON
, 2, 0, 0),
142 GATE(PCLK_UART1
, "uart1", "pclk", PCLKCON
, 1, 0, 0),
143 GATE(PCLK_UART0
, "uart0", "pclk", PCLKCON
, 0, 0, 0),
146 static struct samsung_clock_alias s3c2443_common_aliases
[] __initdata
= {
147 ALIAS(MSYSCLK
, NULL
, "msysclk"),
148 ALIAS(ARMCLK
, NULL
, "armclk"),
149 ALIAS(MPLL
, NULL
, "mpll"),
150 ALIAS(EPLL
, NULL
, "epll"),
151 ALIAS(HCLK
, NULL
, "hclk"),
152 ALIAS(HCLK_SSMC
, NULL
, "nand"),
153 ALIAS(PCLK_UART0
, "s3c2440-uart.0", "uart"),
154 ALIAS(PCLK_UART1
, "s3c2440-uart.1", "uart"),
155 ALIAS(PCLK_UART2
, "s3c2440-uart.2", "uart"),
156 ALIAS(PCLK_UART3
, "s3c2440-uart.3", "uart"),
157 ALIAS(PCLK_UART0
, "s3c2440-uart.0", "clk_uart_baud2"),
158 ALIAS(PCLK_UART1
, "s3c2440-uart.1", "clk_uart_baud2"),
159 ALIAS(PCLK_UART2
, "s3c2440-uart.2", "clk_uart_baud2"),
160 ALIAS(PCLK_UART3
, "s3c2440-uart.3", "clk_uart_baud2"),
161 ALIAS(SCLK_UART
, NULL
, "clk_uart_baud3"),
162 ALIAS(PCLK_PWM
, NULL
, "timers"),
163 ALIAS(PCLK_RTC
, NULL
, "rtc"),
164 ALIAS(PCLK_WDT
, NULL
, "watchdog"),
165 ALIAS(PCLK_ADC
, NULL
, "adc"),
166 ALIAS(PCLK_I2C0
, "s3c2410-i2c.0", "i2c"),
167 ALIAS(HCLK_USBD
, NULL
, "usb-device"),
168 ALIAS(HCLK_USBH
, NULL
, "usb-host"),
169 ALIAS(SCLK_USBH
, NULL
, "usb-bus-host"),
170 ALIAS(PCLK_SPI0
, "s3c2443-spi.0", "spi"),
171 ALIAS(PCLK_SPI0
, "s3c2443-spi.0", "spi_busclk0"),
172 ALIAS(HCLK_HSMMC1
, "s3c-sdhci.1", "hsmmc"),
173 ALIAS(HCLK_HSMMC1
, "s3c-sdhci.1", "mmc_busclk.0"),
174 ALIAS(PCLK_I2S0
, "samsung-i2s.0", "iis"),
175 ALIAS(SCLK_I2S0
, NULL
, "i2s-if"),
176 ALIAS(HCLK_LCD
, NULL
, "lcd"),
177 ALIAS(SCLK_FIMD
, NULL
, "sclk_fimd"),
180 /* S3C2416 specific clocks */
182 static struct samsung_pll_clock s3c2416_pll_clks
[] __initdata
= {
183 PLL(pll_6552_s3c2416
, MPLL
, "mpll", "mpllref", LOCKCON0
, MPLLCON
, NULL
),
184 PLL(pll_6553
, EPLL
, "epll", "epllref", LOCKCON1
, EPLLCON
, NULL
),
187 PNAME(s3c2416_hsmmc0_p
) = { "sclk_hsmmc0", "sclk_hsmmcext" };
188 PNAME(s3c2416_hsmmc1_p
) = { "sclk_hsmmc1", "sclk_hsmmcext" };
189 PNAME(s3c2416_hsspi0_p
) = { "hsspi0_epll", "hsspi0_mpll" };
191 static struct clk_div_table armdiv_s3c2416_d
[] = {
192 { .val
= 0, .div
= 1 },
193 { .val
= 1, .div
= 2 },
194 { .val
= 2, .div
= 3 },
195 { .val
= 3, .div
= 4 },
196 { .val
= 5, .div
= 6 },
197 { .val
= 7, .div
= 8 },
201 static struct samsung_div_clock s3c2416_dividers
[] __initdata
= {
202 DIV_T(ARMDIV
, "armdiv", "msysclk", CLKDIV0
, 9, 3, armdiv_s3c2416_d
),
203 DIV(0, "div_hsspi0_mpll", "msysclk", CLKDIV2
, 0, 4),
204 DIV(0, "div_hsmmc0", "esysclk", CLKDIV2
, 6, 2),
207 static struct samsung_mux_clock s3c2416_muxes
[] __initdata
= {
208 MUX(MUX_HSMMC0
, "mux_hsmmc0", s3c2416_hsmmc0_p
, CLKSRC
, 16, 1),
209 MUX(MUX_HSMMC1
, "mux_hsmmc1", s3c2416_hsmmc1_p
, CLKSRC
, 17, 1),
210 MUX(MUX_HSSPI0
, "mux_hsspi0", s3c2416_hsspi0_p
, CLKSRC
, 18, 1),
213 static struct samsung_gate_clock s3c2416_gates
[] __initdata
= {
214 GATE(0, "hsspi0_mpll", "div_hsspi0_mpll", SCLKCON
, 19, 0, 0),
215 GATE(0, "hsspi0_epll", "div_hsspi0_epll", SCLKCON
, 14, 0, 0),
216 GATE(0, "sclk_hsmmc0", "div_hsmmc0", SCLKCON
, 6, 0, 0),
217 GATE(HCLK_2D
, "2d", "hclk", HCLKCON
, 20, 0, 0),
218 GATE(HCLK_HSMMC0
, "hsmmc0", "hclk", HCLKCON
, 15, 0, 0),
219 GATE(HCLK_IROM
, "irom", "hclk", HCLKCON
, 13, CLK_IGNORE_UNUSED
, 0),
220 GATE(PCLK_PCM
, "pcm", "pclk", PCLKCON
, 19, 0, 0),
223 static struct samsung_clock_alias s3c2416_aliases
[] __initdata
= {
224 ALIAS(HCLK_HSMMC0
, "s3c-sdhci.0", "hsmmc"),
225 ALIAS(HCLK_HSMMC0
, "s3c-sdhci.0", "mmc_busclk.0"),
226 ALIAS(MUX_HSMMC0
, "s3c-sdhci.0", "mmc_busclk.2"),
227 ALIAS(MUX_HSMMC1
, "s3c-sdhci.1", "mmc_busclk.2"),
228 ALIAS(MUX_HSSPI0
, "s3c2443-spi.0", "spi_busclk2"),
229 ALIAS(ARMDIV
, NULL
, "armdiv"),
232 /* S3C2443 specific clocks */
234 static struct samsung_pll_clock s3c2443_pll_clks
[] __initdata
= {
235 PLL(pll_3000
, MPLL
, "mpll", "mpllref", LOCKCON0
, MPLLCON
, NULL
),
236 PLL(pll_2126
, EPLL
, "epll", "epllref", LOCKCON1
, EPLLCON
, NULL
),
239 static struct clk_div_table armdiv_s3c2443_d
[] = {
240 { .val
= 0, .div
= 1 },
241 { .val
= 8, .div
= 2 },
242 { .val
= 2, .div
= 3 },
243 { .val
= 9, .div
= 4 },
244 { .val
= 10, .div
= 6 },
245 { .val
= 11, .div
= 8 },
246 { .val
= 13, .div
= 12 },
247 { .val
= 15, .div
= 16 },
251 static struct samsung_div_clock s3c2443_dividers
[] __initdata
= {
252 DIV_T(ARMDIV
, "armdiv", "msysclk", CLKDIV0
, 9, 4, armdiv_s3c2443_d
),
253 DIV(0, "div_cam", "esysclk", CLKDIV1
, 26, 4),
256 static struct samsung_gate_clock s3c2443_gates
[] __initdata
= {
257 GATE(SCLK_HSSPI0
, "sclk_hsspi0", "div_hsspi0_epll", SCLKCON
, 14, 0, 0),
258 GATE(SCLK_CAM
, "sclk_cam", "div_cam", SCLKCON
, 11, 0, 0),
259 GATE(HCLK_CFC
, "cfc", "hclk", HCLKCON
, 17, CLK_IGNORE_UNUSED
, 0),
260 GATE(HCLK_CAM
, "cam", "hclk", HCLKCON
, 8, 0, 0),
261 GATE(PCLK_SPI1
, "spi1", "pclk", PCLKCON
, 15, 0, 0),
262 GATE(PCLK_SDI
, "sdi", "pclk", PCLKCON
, 5, 0, 0),
265 static struct samsung_clock_alias s3c2443_aliases
[] __initdata
= {
266 ALIAS(SCLK_HSSPI0
, "s3c2443-spi.0", "spi_busclk2"),
267 ALIAS(SCLK_HSMMC1
, "s3c-sdhci.1", "mmc_busclk.2"),
268 ALIAS(SCLK_CAM
, NULL
, "camif-upll"),
269 ALIAS(PCLK_SPI1
, "s3c2410-spi.0", "spi"),
270 ALIAS(PCLK_SDI
, NULL
, "sdi"),
271 ALIAS(HCLK_CFC
, NULL
, "cfc"),
272 ALIAS(ARMDIV
, NULL
, "armdiv"),
275 /* S3C2450 specific clocks */
277 PNAME(s3c2450_cam_p
) = { "div_cam", "hclk" };
278 PNAME(s3c2450_hsspi1_p
) = { "hsspi1_epll", "hsspi1_mpll" };
279 PNAME(i2s1_p
) = { "div_i2s1", "ext_i2s", "epllref", "epllref" };
281 static struct samsung_div_clock s3c2450_dividers
[] __initdata
= {
282 DIV(0, "div_cam", "esysclk", CLKDIV1
, 26, 4),
283 DIV(0, "div_hsspi1_epll", "esysclk", CLKDIV2
, 24, 2),
284 DIV(0, "div_hsspi1_mpll", "msysclk", CLKDIV2
, 16, 4),
285 DIV(0, "div_i2s1", "esysclk", CLKDIV2
, 12, 4),
288 static struct samsung_mux_clock s3c2450_muxes
[] __initdata
= {
289 MUX(0, "mux_cam", s3c2450_cam_p
, CLKSRC
, 20, 1),
290 MUX(MUX_HSSPI1
, "mux_hsspi1", s3c2450_hsspi1_p
, CLKSRC
, 19, 1),
291 MUX(0, "mux_i2s1", i2s1_p
, CLKSRC
, 12, 2),
294 static struct samsung_gate_clock s3c2450_gates
[] __initdata
= {
295 GATE(SCLK_I2S1
, "sclk_i2s1", "div_i2s1", SCLKCON
, 5, 0, 0),
296 GATE(HCLK_CFC
, "cfc", "hclk", HCLKCON
, 17, 0, 0),
297 GATE(HCLK_CAM
, "cam", "hclk", HCLKCON
, 8, 0, 0),
298 GATE(HCLK_DMA7
, "dma7", "hclk", HCLKCON
, 7, CLK_IGNORE_UNUSED
, 0),
299 GATE(HCLK_DMA6
, "dma6", "hclk", HCLKCON
, 6, CLK_IGNORE_UNUSED
, 0),
300 GATE(PCLK_I2S1
, "i2s1", "pclk", PCLKCON
, 17, 0, 0),
301 GATE(PCLK_I2C1
, "i2c1", "pclk", PCLKCON
, 16, 0, 0),
302 GATE(PCLK_SPI1
, "spi1", "pclk", PCLKCON
, 14, 0, 0),
305 static struct samsung_clock_alias s3c2450_aliases
[] __initdata
= {
306 ALIAS(PCLK_SPI1
, "s3c2443-spi.1", "spi"),
307 ALIAS(PCLK_SPI1
, "s3c2443-spi.1", "spi_busclk0"),
308 ALIAS(MUX_HSSPI1
, "s3c2443-spi.1", "spi_busclk2"),
309 ALIAS(PCLK_I2C1
, "s3c2410-i2c.1", "i2c"),
312 static int s3c2443_restart(struct notifier_block
*this,
313 unsigned long mode
, void *cmd
)
315 __raw_writel(0x533c2443, reg_base
+ SWRST
);
319 static struct notifier_block s3c2443_restart_handler
= {
320 .notifier_call
= s3c2443_restart
,
325 * fixed rate clocks generated outside the soc
326 * Only necessary until the devicetree-move is complete
328 static struct samsung_fixed_rate_clock s3c2443_common_frate_clks
[] __initdata
= {
329 FRATE(0, "xti", NULL
, 0, 0),
330 FRATE(0, "ext", NULL
, 0, 0),
331 FRATE(0, "ext_i2s", NULL
, 0, 0),
332 FRATE(0, "ext_uart", NULL
, 0, 0),
335 static void __init
s3c2443_common_clk_register_fixed_ext(
336 struct samsung_clk_provider
*ctx
, unsigned long xti_f
)
338 s3c2443_common_frate_clks
[0].fixed_rate
= xti_f
;
339 samsung_clk_register_fixed_rate(ctx
, s3c2443_common_frate_clks
,
340 ARRAY_SIZE(s3c2443_common_frate_clks
));
343 void __init
s3c2443_common_clk_init(struct device_node
*np
, unsigned long xti_f
,
347 struct samsung_clk_provider
*ctx
;
352 reg_base
= of_iomap(np
, 0);
354 panic("%s: failed to map registers\n", __func__
);
357 ctx
= samsung_clk_init(np
, reg_base
, NR_CLKS
);
359 /* Register external clocks only in non-dt cases */
361 s3c2443_common_clk_register_fixed_ext(ctx
, xti_f
);
364 if (current_soc
== S3C2416
|| current_soc
== S3C2450
)
365 samsung_clk_register_pll(ctx
, s3c2416_pll_clks
,
366 ARRAY_SIZE(s3c2416_pll_clks
), reg_base
);
368 samsung_clk_register_pll(ctx
, s3c2443_pll_clks
,
369 ARRAY_SIZE(s3c2443_pll_clks
), reg_base
);
371 /* Register common internal clocks. */
372 samsung_clk_register_mux(ctx
, s3c2443_common_muxes
,
373 ARRAY_SIZE(s3c2443_common_muxes
));
374 samsung_clk_register_div(ctx
, s3c2443_common_dividers
,
375 ARRAY_SIZE(s3c2443_common_dividers
));
376 samsung_clk_register_gate(ctx
, s3c2443_common_gates
,
377 ARRAY_SIZE(s3c2443_common_gates
));
378 samsung_clk_register_alias(ctx
, s3c2443_common_aliases
,
379 ARRAY_SIZE(s3c2443_common_aliases
));
381 /* Register SoC-specific clocks. */
382 switch (current_soc
) {
384 samsung_clk_register_div(ctx
, s3c2450_dividers
,
385 ARRAY_SIZE(s3c2450_dividers
));
386 samsung_clk_register_mux(ctx
, s3c2450_muxes
,
387 ARRAY_SIZE(s3c2450_muxes
));
388 samsung_clk_register_gate(ctx
, s3c2450_gates
,
389 ARRAY_SIZE(s3c2450_gates
));
390 samsung_clk_register_alias(ctx
, s3c2450_aliases
,
391 ARRAY_SIZE(s3c2450_aliases
));
392 /* fall through, as s3c2450 extends the s3c2416 clocks */
394 samsung_clk_register_div(ctx
, s3c2416_dividers
,
395 ARRAY_SIZE(s3c2416_dividers
));
396 samsung_clk_register_mux(ctx
, s3c2416_muxes
,
397 ARRAY_SIZE(s3c2416_muxes
));
398 samsung_clk_register_gate(ctx
, s3c2416_gates
,
399 ARRAY_SIZE(s3c2416_gates
));
400 samsung_clk_register_alias(ctx
, s3c2416_aliases
,
401 ARRAY_SIZE(s3c2416_aliases
));
404 samsung_clk_register_div(ctx
, s3c2443_dividers
,
405 ARRAY_SIZE(s3c2443_dividers
));
406 samsung_clk_register_gate(ctx
, s3c2443_gates
,
407 ARRAY_SIZE(s3c2443_gates
));
408 samsung_clk_register_alias(ctx
, s3c2443_aliases
,
409 ARRAY_SIZE(s3c2443_aliases
));
413 samsung_clk_sleep_init(reg_base
, s3c2443_clk_regs
,
414 ARRAY_SIZE(s3c2443_clk_regs
));
416 samsung_clk_of_add_provider(np
, ctx
);
418 ret
= register_restart_handler(&s3c2443_restart_handler
);
420 pr_warn("cannot register restart handler, %d\n", ret
);
423 static void __init
s3c2416_clk_init(struct device_node
*np
)
425 s3c2443_common_clk_init(np
, 0, S3C2416
, NULL
);
427 CLK_OF_DECLARE(s3c2416_clk
, "samsung,s3c2416-clock", s3c2416_clk_init
);
429 static void __init
s3c2443_clk_init(struct device_node
*np
)
431 s3c2443_common_clk_init(np
, 0, S3C2443
, NULL
);
433 CLK_OF_DECLARE(s3c2443_clk
, "samsung,s3c2443-clock", s3c2443_clk_init
);
435 static void __init
s3c2450_clk_init(struct device_node
*np
)
437 s3c2443_common_clk_init(np
, 0, S3C2450
, NULL
);
439 CLK_OF_DECLARE(s3c2450_clk
, "samsung,s3c2450-clock", s3c2450_clk_init
);