diff options
-rw-r--r-- | arch/arm/mach-exynos/pm.c | 148 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos4.c | 172 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5250.c | 49 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5420.c | 49 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-exynos5440.c | 2 | ||||
-rw-r--r-- | drivers/clk/samsung/clk-s3c64xx.c | 79 | ||||
-rw-r--r-- | drivers/clk/samsung/clk.c | 71 | ||||
-rw-r--r-- | drivers/clk/samsung/clk.h | 14 |
8 files changed, 348 insertions, 236 deletions
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index e00025bbbe89..ba18214c9aca 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c | |||
@@ -35,56 +35,6 @@ | |||
35 | #include "common.h" | 35 | #include "common.h" |
36 | #include "regs-pmu.h" | 36 | #include "regs-pmu.h" |
37 | 37 | ||
38 | #define EXYNOS4_EPLL_LOCK (S5P_VA_CMU + 0x0C010) | ||
39 | #define EXYNOS4_VPLL_LOCK (S5P_VA_CMU + 0x0C020) | ||
40 | |||
41 | #define EXYNOS4_EPLL_CON0 (S5P_VA_CMU + 0x0C110) | ||
42 | #define EXYNOS4_EPLL_CON1 (S5P_VA_CMU + 0x0C114) | ||
43 | #define EXYNOS4_VPLL_CON0 (S5P_VA_CMU + 0x0C120) | ||
44 | #define EXYNOS4_VPLL_CON1 (S5P_VA_CMU + 0x0C124) | ||
45 | |||
46 | #define EXYNOS4_CLKSRC_MASK_TOP (S5P_VA_CMU + 0x0C310) | ||
47 | #define EXYNOS4_CLKSRC_MASK_CAM (S5P_VA_CMU + 0x0C320) | ||
48 | #define EXYNOS4_CLKSRC_MASK_TV (S5P_VA_CMU + 0x0C324) | ||
49 | #define EXYNOS4_CLKSRC_MASK_LCD0 (S5P_VA_CMU + 0x0C334) | ||
50 | #define EXYNOS4_CLKSRC_MASK_MAUDIO (S5P_VA_CMU + 0x0C33C) | ||
51 | #define EXYNOS4_CLKSRC_MASK_FSYS (S5P_VA_CMU + 0x0C340) | ||
52 | #define EXYNOS4_CLKSRC_MASK_PERIL0 (S5P_VA_CMU + 0x0C350) | ||
53 | #define EXYNOS4_CLKSRC_MASK_PERIL1 (S5P_VA_CMU + 0x0C354) | ||
54 | |||
55 | #define EXYNOS4_CLKSRC_MASK_DMC (S5P_VA_CMU + 0x10300) | ||
56 | |||
57 | #define EXYNOS4_EPLLCON0_LOCKED_SHIFT (29) | ||
58 | #define EXYNOS4_VPLLCON0_LOCKED_SHIFT (29) | ||
59 | |||
60 | #define EXYNOS4210_CLKSRC_MASK_LCD1 (S5P_VA_CMU + 0x0C338) | ||
61 | |||
62 | static const struct sleep_save exynos4_set_clksrc[] = { | ||
63 | { .reg = EXYNOS4_CLKSRC_MASK_TOP , .val = 0x00000001, }, | ||
64 | { .reg = EXYNOS4_CLKSRC_MASK_CAM , .val = 0x11111111, }, | ||
65 | { .reg = EXYNOS4_CLKSRC_MASK_TV , .val = 0x00000111, }, | ||
66 | { .reg = EXYNOS4_CLKSRC_MASK_LCD0 , .val = 0x00001111, }, | ||
67 | { .reg = EXYNOS4_CLKSRC_MASK_MAUDIO , .val = 0x00000001, }, | ||
68 | { .reg = EXYNOS4_CLKSRC_MASK_FSYS , .val = 0x01011111, }, | ||
69 | { .reg = EXYNOS4_CLKSRC_MASK_PERIL0 , .val = 0x01111111, }, | ||
70 | { .reg = EXYNOS4_CLKSRC_MASK_PERIL1 , .val = 0x01110111, }, | ||
71 | { .reg = EXYNOS4_CLKSRC_MASK_DMC , .val = 0x00010000, }, | ||
72 | }; | ||
73 | |||
74 | static const struct sleep_save exynos4210_set_clksrc[] = { | ||
75 | { .reg = EXYNOS4210_CLKSRC_MASK_LCD1 , .val = 0x00001111, }, | ||
76 | }; | ||
77 | |||
78 | static struct sleep_save exynos4_epll_save[] = { | ||
79 | SAVE_ITEM(EXYNOS4_EPLL_CON0), | ||
80 | SAVE_ITEM(EXYNOS4_EPLL_CON1), | ||
81 | }; | ||
82 | |||
83 | static struct sleep_save exynos4_vpll_save[] = { | ||
84 | SAVE_ITEM(EXYNOS4_VPLL_CON0), | ||
85 | SAVE_ITEM(EXYNOS4_VPLL_CON1), | ||
86 | }; | ||
87 | |||
88 | static struct sleep_save exynos5_sys_save[] = { | 38 | static struct sleep_save exynos5_sys_save[] = { |
89 | SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), | 39 | SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), |
90 | }; | 40 | }; |
@@ -124,10 +74,7 @@ static void exynos_pm_prepare(void) | |||
124 | 74 | ||
125 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | 75 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); |
126 | 76 | ||
127 | if (!soc_is_exynos5250()) { | 77 | if (soc_is_exynos5250()) { |
128 | s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save)); | ||
129 | s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save)); | ||
130 | } else { | ||
131 | s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); | 78 | s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); |
132 | /* Disable USE_RETENTION of JPEG_MEM_OPTION */ | 79 | /* Disable USE_RETENTION of JPEG_MEM_OPTION */ |
133 | tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION); | 80 | tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION); |
@@ -143,15 +90,6 @@ static void exynos_pm_prepare(void) | |||
143 | /* ensure at least INFORM0 has the resume address */ | 90 | /* ensure at least INFORM0 has the resume address */ |
144 | 91 | ||
145 | __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0); | 92 | __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0); |
146 | |||
147 | /* Before enter central sequence mode, clock src register have to set */ | ||
148 | |||
149 | if (!soc_is_exynos5250()) | ||
150 | s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc)); | ||
151 | |||
152 | if (soc_is_exynos4210()) | ||
153 | s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc)); | ||
154 | |||
155 | } | 93 | } |
156 | 94 | ||
157 | static int exynos_pm_add(struct device *dev, struct subsys_interface *sif) | 95 | static int exynos_pm_add(struct device *dev, struct subsys_interface *sif) |
@@ -162,73 +100,6 @@ static int exynos_pm_add(struct device *dev, struct subsys_interface *sif) | |||
162 | return 0; | 100 | return 0; |
163 | } | 101 | } |
164 | 102 | ||
165 | static unsigned long pll_base_rate; | ||
166 | |||
167 | static void exynos4_restore_pll(void) | ||
168 | { | ||
169 | unsigned long pll_con, locktime, lockcnt; | ||
170 | unsigned long pll_in_rate; | ||
171 | unsigned int p_div, epll_wait = 0, vpll_wait = 0; | ||
172 | |||
173 | if (pll_base_rate == 0) | ||
174 | return; | ||
175 | |||
176 | pll_in_rate = pll_base_rate; | ||
177 | |||
178 | /* EPLL */ | ||
179 | pll_con = exynos4_epll_save[0].val; | ||
180 | |||
181 | if (pll_con & (1 << 31)) { | ||
182 | pll_con &= (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT); | ||
183 | p_div = (pll_con >> PLL46XX_PDIV_SHIFT); | ||
184 | |||
185 | pll_in_rate /= 1000000; | ||
186 | |||
187 | locktime = (3000 / pll_in_rate) * p_div; | ||
188 | lockcnt = locktime * 10000 / (10000 / pll_in_rate); | ||
189 | |||
190 | __raw_writel(lockcnt, EXYNOS4_EPLL_LOCK); | ||
191 | |||
192 | s3c_pm_do_restore_core(exynos4_epll_save, | ||
193 | ARRAY_SIZE(exynos4_epll_save)); | ||
194 | epll_wait = 1; | ||
195 | } | ||
196 | |||
197 | pll_in_rate = pll_base_rate; | ||
198 | |||
199 | /* VPLL */ | ||
200 | pll_con = exynos4_vpll_save[0].val; | ||
201 | |||
202 | if (pll_con & (1 << 31)) { | ||
203 | pll_in_rate /= 1000000; | ||
204 | /* 750us */ | ||
205 | locktime = 750; | ||
206 | lockcnt = locktime * 10000 / (10000 / pll_in_rate); | ||
207 | |||
208 | __raw_writel(lockcnt, EXYNOS4_VPLL_LOCK); | ||
209 | |||
210 | s3c_pm_do_restore_core(exynos4_vpll_save, | ||
211 | ARRAY_SIZE(exynos4_vpll_save)); | ||
212 | vpll_wait = 1; | ||
213 | } | ||
214 | |||
215 | /* Wait PLL locking */ | ||
216 | |||
217 | do { | ||
218 | if (epll_wait) { | ||
219 | pll_con = __raw_readl(EXYNOS4_EPLL_CON0); | ||
220 | if (pll_con & (1 << EXYNOS4_EPLLCON0_LOCKED_SHIFT)) | ||
221 | epll_wait = 0; | ||
222 | } | ||
223 | |||
224 | if (vpll_wait) { | ||
225 | pll_con = __raw_readl(EXYNOS4_VPLL_CON0); | ||
226 | if (pll_con & (1 << EXYNOS4_VPLLCON0_LOCKED_SHIFT)) | ||
227 | vpll_wait = 0; | ||
228 | } | ||
229 | } while (epll_wait || vpll_wait); | ||
230 | } | ||
231 | |||
232 | static struct subsys_interface exynos_pm_interface = { | 103 | static struct subsys_interface exynos_pm_interface = { |
233 | .name = "exynos_pm", | 104 | .name = "exynos_pm", |
234 | .subsys = &exynos_subsys, | 105 | .subsys = &exynos_subsys, |
@@ -237,7 +108,6 @@ static struct subsys_interface exynos_pm_interface = { | |||
237 | 108 | ||
238 | static __init int exynos_pm_drvinit(void) | 109 | static __init int exynos_pm_drvinit(void) |
239 | { | 110 | { |
240 | struct clk *pll_base; | ||
241 | unsigned int tmp; | 111 | unsigned int tmp; |
242 | 112 | ||
243 | if (soc_is_exynos5440()) | 113 | if (soc_is_exynos5440()) |
@@ -251,15 +121,6 @@ static __init int exynos_pm_drvinit(void) | |||
251 | tmp |= ((0xFF << 8) | (0x1F << 1)); | 121 | tmp |= ((0xFF << 8) | (0x1F << 1)); |
252 | __raw_writel(tmp, S5P_WAKEUP_MASK); | 122 | __raw_writel(tmp, S5P_WAKEUP_MASK); |
253 | 123 | ||
254 | if (!soc_is_exynos5250()) { | ||
255 | pll_base = clk_get(NULL, "xtal"); | ||
256 | |||
257 | if (!IS_ERR(pll_base)) { | ||
258 | pll_base_rate = clk_get_rate(pll_base); | ||
259 | clk_put(pll_base); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | return subsys_interface_register(&exynos_pm_interface); | 124 | return subsys_interface_register(&exynos_pm_interface); |
264 | } | 125 | } |
265 | arch_initcall(exynos_pm_drvinit); | 126 | arch_initcall(exynos_pm_drvinit); |
@@ -343,13 +204,8 @@ static void exynos_pm_resume(void) | |||
343 | 204 | ||
344 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | 205 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); |
345 | 206 | ||
346 | if (!soc_is_exynos5250()) { | 207 | if (IS_ENABLED(CONFIG_SMP) && !soc_is_exynos5250()) |
347 | exynos4_restore_pll(); | ||
348 | |||
349 | #ifdef CONFIG_SMP | ||
350 | scu_enable(S5P_VA_SCU); | 208 | scu_enable(S5P_VA_SCU); |
351 | #endif | ||
352 | } | ||
353 | 209 | ||
354 | early_wakeup: | 210 | early_wakeup: |
355 | 211 | ||
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 010f071af883..b4f967210175 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/clk-provider.h> | 16 | #include <linux/clk-provider.h> |
17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/syscore_ops.h> | ||
19 | 20 | ||
20 | #include "clk.h" | 21 | #include "clk.h" |
21 | 22 | ||
@@ -130,6 +131,17 @@ enum exynos4_plls { | |||
130 | nr_plls /* number of PLLs */ | 131 | nr_plls /* number of PLLs */ |
131 | }; | 132 | }; |
132 | 133 | ||
134 | static void __iomem *reg_base; | ||
135 | static enum exynos4_soc exynos4_soc; | ||
136 | |||
137 | /* | ||
138 | * Support for CMU save/restore across system suspends | ||
139 | */ | ||
140 | #ifdef CONFIG_PM_SLEEP | ||
141 | static struct samsung_clk_reg_dump *exynos4_save_common; | ||
142 | static struct samsung_clk_reg_dump *exynos4_save_soc; | ||
143 | static struct samsung_clk_reg_dump *exynos4_save_pll; | ||
144 | |||
133 | /* | 145 | /* |
134 | * list of controller registers to be saved and restored during a | 146 | * list of controller registers to be saved and restored during a |
135 | * suspend/resume cycle. | 147 | * suspend/resume cycle. |
@@ -154,6 +166,17 @@ static unsigned long exynos4x12_clk_save[] __initdata = { | |||
154 | E4X12_MPLL_CON0, | 166 | E4X12_MPLL_CON0, |
155 | }; | 167 | }; |
156 | 168 | ||
169 | static unsigned long exynos4_clk_pll_regs[] __initdata = { | ||
170 | EPLL_LOCK, | ||
171 | VPLL_LOCK, | ||
172 | EPLL_CON0, | ||
173 | EPLL_CON1, | ||
174 | EPLL_CON2, | ||
175 | VPLL_CON0, | ||
176 | VPLL_CON1, | ||
177 | VPLL_CON2, | ||
178 | }; | ||
179 | |||
157 | static unsigned long exynos4_clk_regs[] __initdata = { | 180 | static unsigned long exynos4_clk_regs[] __initdata = { |
158 | SRC_LEFTBUS, | 181 | SRC_LEFTBUS, |
159 | DIV_LEFTBUS, | 182 | DIV_LEFTBUS, |
@@ -161,12 +184,6 @@ static unsigned long exynos4_clk_regs[] __initdata = { | |||
161 | SRC_RIGHTBUS, | 184 | SRC_RIGHTBUS, |
162 | DIV_RIGHTBUS, | 185 | DIV_RIGHTBUS, |
163 | GATE_IP_RIGHTBUS, | 186 | GATE_IP_RIGHTBUS, |
164 | EPLL_CON0, | ||
165 | EPLL_CON1, | ||
166 | EPLL_CON2, | ||
167 | VPLL_CON0, | ||
168 | VPLL_CON1, | ||
169 | VPLL_CON2, | ||
170 | SRC_TOP0, | 187 | SRC_TOP0, |
171 | SRC_TOP1, | 188 | SRC_TOP1, |
172 | SRC_CAM, | 189 | SRC_CAM, |
@@ -227,6 +244,124 @@ static unsigned long exynos4_clk_regs[] __initdata = { | |||
227 | GATE_IP_CPU, | 244 | GATE_IP_CPU, |
228 | }; | 245 | }; |
229 | 246 | ||
247 | static const struct samsung_clk_reg_dump src_mask_suspend[] = { | ||
248 | { .offset = SRC_MASK_TOP, .value = 0x00000001, }, | ||
249 | { .offset = SRC_MASK_CAM, .value = 0x11111111, }, | ||
250 | { .offset = SRC_MASK_TV, .value = 0x00000111, }, | ||
251 | { .offset = SRC_MASK_LCD0, .value = 0x00001111, }, | ||
252 | { .offset = SRC_MASK_MAUDIO, .value = 0x00000001, }, | ||
253 | { .offset = SRC_MASK_FSYS, .value = 0x01011111, }, | ||
254 | { .offset = SRC_MASK_PERIL0, .value = 0x01111111, }, | ||
255 | { .offset = SRC_MASK_PERIL1, .value = 0x01110111, }, | ||
256 | { .offset = SRC_MASK_DMC, .value = 0x00010000, }, | ||
257 | }; | ||
258 | |||
259 | static const struct samsung_clk_reg_dump src_mask_suspend_e4210[] = { | ||
260 | { .offset = E4210_SRC_MASK_LCD1, .value = 0x00001111, }, | ||
261 | }; | ||
262 | |||
263 | #define PLL_ENABLED (1 << 31) | ||
264 | #define PLL_LOCKED (1 << 29) | ||
265 | |||
266 | static void exynos4_clk_wait_for_pll(u32 reg) | ||
267 | { | ||
268 | u32 pll_con; | ||
269 | |||
270 | pll_con = readl(reg_base + reg); | ||
271 | if (!(pll_con & PLL_ENABLED)) | ||
272 | return; | ||
273 | |||
274 | while (!(pll_con & PLL_LOCKED)) { | ||
275 | cpu_relax(); | ||
276 | pll_con = readl(reg_base + reg); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | static int exynos4_clk_suspend(void) | ||
281 | { | ||
282 | samsung_clk_save(reg_base, exynos4_save_common, | ||
283 | ARRAY_SIZE(exynos4_clk_regs)); | ||
284 | samsung_clk_save(reg_base, exynos4_save_pll, | ||
285 | ARRAY_SIZE(exynos4_clk_pll_regs)); | ||
286 | |||
287 | if (exynos4_soc == EXYNOS4210) { | ||
288 | samsung_clk_save(reg_base, exynos4_save_soc, | ||
289 | ARRAY_SIZE(exynos4210_clk_save)); | ||
290 | samsung_clk_restore(reg_base, src_mask_suspend_e4210, | ||
291 | ARRAY_SIZE(src_mask_suspend_e4210)); | ||
292 | } else { | ||
293 | samsung_clk_save(reg_base, exynos4_save_soc, | ||
294 | ARRAY_SIZE(exynos4x12_clk_save)); | ||
295 | } | ||
296 | |||
297 | samsung_clk_restore(reg_base, src_mask_suspend, | ||
298 | ARRAY_SIZE(src_mask_suspend)); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static void exynos4_clk_resume(void) | ||
304 | { | ||
305 | samsung_clk_restore(reg_base, exynos4_save_pll, | ||
306 | ARRAY_SIZE(exynos4_clk_pll_regs)); | ||
307 | |||
308 | exynos4_clk_wait_for_pll(EPLL_CON0); | ||
309 | exynos4_clk_wait_for_pll(VPLL_CON0); | ||
310 | |||
311 | samsung_clk_restore(reg_base, exynos4_save_common, | ||
312 | ARRAY_SIZE(exynos4_clk_regs)); | ||
313 | |||
314 | if (exynos4_soc == EXYNOS4210) | ||
315 | samsung_clk_restore(reg_base, exynos4_save_soc, | ||
316 | ARRAY_SIZE(exynos4210_clk_save)); | ||
317 | else | ||
318 | samsung_clk_restore(reg_base, exynos4_save_soc, | ||
319 | ARRAY_SIZE(exynos4x12_clk_save)); | ||
320 | } | ||
321 | |||
322 | static struct syscore_ops exynos4_clk_syscore_ops = { | ||
323 | .suspend = exynos4_clk_suspend, | ||
324 | .resume = exynos4_clk_resume, | ||
325 | }; | ||
326 | |||
327 | static void exynos4_clk_sleep_init(void) | ||
328 | { | ||
329 | exynos4_save_common = samsung_clk_alloc_reg_dump(exynos4_clk_regs, | ||
330 | ARRAY_SIZE(exynos4_clk_regs)); | ||
331 | if (!exynos4_save_common) | ||
332 | goto err_warn; | ||
333 | |||
334 | if (exynos4_soc == EXYNOS4210) | ||
335 | exynos4_save_soc = samsung_clk_alloc_reg_dump( | ||
336 | exynos4210_clk_save, | ||
337 | ARRAY_SIZE(exynos4210_clk_save)); | ||
338 | else | ||
339 | exynos4_save_soc = samsung_clk_alloc_reg_dump( | ||
340 | exynos4x12_clk_save, | ||
341 | ARRAY_SIZE(exynos4x12_clk_save)); | ||
342 | if (!exynos4_save_soc) | ||
343 | goto err_common; | ||
344 | |||
345 | exynos4_save_pll = samsung_clk_alloc_reg_dump(exynos4_clk_pll_regs, | ||
346 | ARRAY_SIZE(exynos4_clk_pll_regs)); | ||
347 | if (!exynos4_save_pll) | ||
348 | goto err_soc; | ||
349 | |||
350 | register_syscore_ops(&exynos4_clk_syscore_ops); | ||
351 | return; | ||
352 | |||
353 | err_soc: | ||
354 | kfree(exynos4_save_soc); | ||
355 | err_common: | ||
356 | kfree(exynos4_save_common); | ||
357 | err_warn: | ||
358 | pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", | ||
359 | __func__); | ||
360 | } | ||
361 | #else | ||
362 | static void exynos4_clk_sleep_init(void) {} | ||
363 | #endif | ||
364 | |||
230 | /* list of all parent clock list */ | 365 | /* list of all parent clock list */ |
231 | PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; | 366 | PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; |
232 | PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", }; | 367 | PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", }; |
@@ -908,12 +1043,13 @@ static unsigned long exynos4_get_xom(void) | |||
908 | return xom; | 1043 | return xom; |
909 | } | 1044 | } |
910 | 1045 | ||
911 | static void __init exynos4_clk_register_finpll(unsigned long xom) | 1046 | static void __init exynos4_clk_register_finpll(void) |
912 | { | 1047 | { |
913 | struct samsung_fixed_rate_clock fclk; | 1048 | struct samsung_fixed_rate_clock fclk; |
914 | struct clk *clk; | 1049 | struct clk *clk; |
915 | unsigned long finpll_f = 24000000; | 1050 | unsigned long finpll_f = 24000000; |
916 | char *parent_name; | 1051 | char *parent_name; |
1052 | unsigned int xom = exynos4_get_xom(); | ||
917 | 1053 | ||
918 | parent_name = xom & 1 ? "xusbxti" : "xxti"; | 1054 | parent_name = xom & 1 ? "xusbxti" : "xxti"; |
919 | clk = clk_get(NULL, parent_name); | 1055 | clk = clk_get(NULL, parent_name); |
@@ -1038,27 +1174,21 @@ static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = { | |||
1038 | 1174 | ||
1039 | /* register exynos4 clocks */ | 1175 | /* register exynos4 clocks */ |
1040 | static void __init exynos4_clk_init(struct device_node *np, | 1176 | static void __init exynos4_clk_init(struct device_node *np, |
1041 | enum exynos4_soc exynos4_soc, | 1177 | enum exynos4_soc soc) |
1042 | void __iomem *reg_base, unsigned long xom) | ||
1043 | { | 1178 | { |
1179 | exynos4_soc = soc; | ||
1180 | |||
1044 | reg_base = of_iomap(np, 0); | 1181 | reg_base = of_iomap(np, 0); |
1045 | if (!reg_base) | 1182 | if (!reg_base) |
1046 | panic("%s: failed to map registers\n", __func__); | 1183 | panic("%s: failed to map registers\n", __func__); |
1047 | 1184 | ||
1048 | if (exynos4_soc == EXYNOS4210) | 1185 | samsung_clk_init(np, reg_base, CLK_NR_CLKS); |
1049 | samsung_clk_init(np, reg_base, CLK_NR_CLKS, | ||
1050 | exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs), | ||
1051 | exynos4210_clk_save, ARRAY_SIZE(exynos4210_clk_save)); | ||
1052 | else | ||
1053 | samsung_clk_init(np, reg_base, CLK_NR_CLKS, | ||
1054 | exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs), | ||
1055 | exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save)); | ||
1056 | 1186 | ||
1057 | samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks, | 1187 | samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks, |
1058 | ARRAY_SIZE(exynos4_fixed_rate_ext_clks), | 1188 | ARRAY_SIZE(exynos4_fixed_rate_ext_clks), |
1059 | ext_clk_match); | 1189 | ext_clk_match); |
1060 | 1190 | ||
1061 | exynos4_clk_register_finpll(xom); | 1191 | exynos4_clk_register_finpll(); |
1062 | 1192 | ||
1063 | if (exynos4_soc == EXYNOS4210) { | 1193 | if (exynos4_soc == EXYNOS4210) { |
1064 | samsung_clk_register_mux(exynos4210_mux_early, | 1194 | samsung_clk_register_mux(exynos4210_mux_early, |
@@ -1125,6 +1255,8 @@ static void __init exynos4_clk_init(struct device_node *np, | |||
1125 | samsung_clk_register_alias(exynos4_aliases, | 1255 | samsung_clk_register_alias(exynos4_aliases, |
1126 | ARRAY_SIZE(exynos4_aliases)); | 1256 | ARRAY_SIZE(exynos4_aliases)); |
1127 | 1257 | ||
1258 | exynos4_clk_sleep_init(); | ||
1259 | |||
1128 | pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n" | 1260 | pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n" |
1129 | "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n", | 1261 | "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n", |
1130 | exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", | 1262 | exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12", |
@@ -1136,12 +1268,12 @@ static void __init exynos4_clk_init(struct device_node *np, | |||
1136 | 1268 | ||
1137 | static void __init exynos4210_clk_init(struct device_node *np) | 1269 | static void __init exynos4210_clk_init(struct device_node *np) |
1138 | { | 1270 | { |
1139 | exynos4_clk_init(np, EXYNOS4210, NULL, exynos4_get_xom()); | 1271 | exynos4_clk_init(np, EXYNOS4210); |
1140 | } | 1272 | } |
1141 | CLK_OF_DECLARE(exynos4210_clk, "samsung,exynos4210-clock", exynos4210_clk_init); | 1273 | CLK_OF_DECLARE(exynos4210_clk, "samsung,exynos4210-clock", exynos4210_clk_init); |
1142 | 1274 | ||
1143 | static void __init exynos4412_clk_init(struct device_node *np) | 1275 | static void __init exynos4412_clk_init(struct device_node *np) |
1144 | { | 1276 | { |
1145 | exynos4_clk_init(np, EXYNOS4X12, NULL, exynos4_get_xom()); | 1277 | exynos4_clk_init(np, EXYNOS4X12); |
1146 | } | 1278 | } |
1147 | CLK_OF_DECLARE(exynos4412_clk, "samsung,exynos4412-clock", exynos4412_clk_init); | 1279 | CLK_OF_DECLARE(exynos4412_clk, "samsung,exynos4412-clock", exynos4412_clk_init); |
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index ff4beebe1f0b..e7ee4420da81 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/clk-provider.h> | 16 | #include <linux/clk-provider.h> |
17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/syscore_ops.h> | ||
19 | 20 | ||
20 | #include "clk.h" | 21 | #include "clk.h" |
21 | 22 | ||
@@ -85,6 +86,11 @@ enum exynos5250_plls { | |||
85 | nr_plls /* number of PLLs */ | 86 | nr_plls /* number of PLLs */ |
86 | }; | 87 | }; |
87 | 88 | ||
89 | static void __iomem *reg_base; | ||
90 | |||
91 | #ifdef CONFIG_PM_SLEEP | ||
92 | static struct samsung_clk_reg_dump *exynos5250_save; | ||
93 | |||
88 | /* | 94 | /* |
89 | * list of controller registers to be saved and restored during a | 95 | * list of controller registers to be saved and restored during a |
90 | * suspend/resume cycle. | 96 | * suspend/resume cycle. |
@@ -137,6 +143,41 @@ static unsigned long exynos5250_clk_regs[] __initdata = { | |||
137 | GATE_IP_ACP, | 143 | GATE_IP_ACP, |
138 | }; | 144 | }; |
139 | 145 | ||
146 | static int exynos5250_clk_suspend(void) | ||
147 | { | ||
148 | samsung_clk_save(reg_base, exynos5250_save, | ||
149 | ARRAY_SIZE(exynos5250_clk_regs)); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static void exynos5250_clk_resume(void) | ||
155 | { | ||
156 | samsung_clk_restore(reg_base, exynos5250_save, | ||
157 | ARRAY_SIZE(exynos5250_clk_regs)); | ||
158 | } | ||
159 | |||
160 | static struct syscore_ops exynos5250_clk_syscore_ops = { | ||
161 | .suspend = exynos5250_clk_suspend, | ||
162 | .resume = exynos5250_clk_resume, | ||
163 | }; | ||
164 | |||
165 | static void exynos5250_clk_sleep_init(void) | ||
166 | { | ||
167 | exynos5250_save = samsung_clk_alloc_reg_dump(exynos5250_clk_regs, | ||
168 | ARRAY_SIZE(exynos5250_clk_regs)); | ||
169 | if (!exynos5250_save) { | ||
170 | pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", | ||
171 | __func__); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | register_syscore_ops(&exynos5250_clk_syscore_ops); | ||
176 | } | ||
177 | #else | ||
178 | static void exynos5250_clk_sleep_init(void) {} | ||
179 | #endif | ||
180 | |||
140 | /* list of all parent clock list */ | 181 | /* list of all parent clock list */ |
141 | PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; | 182 | PNAME(mout_apll_p) = { "fin_pll", "fout_apll", }; |
142 | PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", }; | 183 | PNAME(mout_cpu_p) = { "mout_apll", "mout_mpll", }; |
@@ -645,8 +686,6 @@ static struct of_device_id ext_clk_match[] __initdata = { | |||
645 | /* register exynox5250 clocks */ | 686 | /* register exynox5250 clocks */ |
646 | static void __init exynos5250_clk_init(struct device_node *np) | 687 | static void __init exynos5250_clk_init(struct device_node *np) |
647 | { | 688 | { |
648 | void __iomem *reg_base; | ||
649 | |||
650 | if (np) { | 689 | if (np) { |
651 | reg_base = of_iomap(np, 0); | 690 | reg_base = of_iomap(np, 0); |
652 | if (!reg_base) | 691 | if (!reg_base) |
@@ -655,9 +694,7 @@ static void __init exynos5250_clk_init(struct device_node *np) | |||
655 | panic("%s: unable to determine soc\n", __func__); | 694 | panic("%s: unable to determine soc\n", __func__); |
656 | } | 695 | } |
657 | 696 | ||
658 | samsung_clk_init(np, reg_base, CLK_NR_CLKS, | 697 | samsung_clk_init(np, reg_base, CLK_NR_CLKS); |
659 | exynos5250_clk_regs, ARRAY_SIZE(exynos5250_clk_regs), | ||
660 | NULL, 0); | ||
661 | samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, | 698 | samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks, |
662 | ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), | 699 | ARRAY_SIZE(exynos5250_fixed_rate_ext_clks), |
663 | ext_clk_match); | 700 | ext_clk_match); |
@@ -685,6 +722,8 @@ static void __init exynos5250_clk_init(struct device_node *np) | |||
685 | samsung_clk_register_gate(exynos5250_gate_clks, | 722 | samsung_clk_register_gate(exynos5250_gate_clks, |
686 | ARRAY_SIZE(exynos5250_gate_clks)); | 723 | ARRAY_SIZE(exynos5250_gate_clks)); |
687 | 724 | ||
725 | exynos5250_clk_sleep_init(); | ||
726 | |||
688 | pr_info("Exynos5250: clock setup completed, armclk=%ld\n", | 727 | pr_info("Exynos5250: clock setup completed, armclk=%ld\n", |
689 | _get_rate("div_arm2")); | 728 | _get_rate("div_arm2")); |
690 | } | 729 | } |
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index ab4f2f7d88ef..60b26819bed5 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/clk-provider.h> | 16 | #include <linux/clk-provider.h> |
17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/syscore_ops.h> | ||
19 | 20 | ||
20 | #include "clk.h" | 21 | #include "clk.h" |
21 | 22 | ||
@@ -108,6 +109,11 @@ enum exynos5420_plls { | |||
108 | nr_plls /* number of PLLs */ | 109 | nr_plls /* number of PLLs */ |
109 | }; | 110 | }; |
110 | 111 | ||
112 | static void __iomem *reg_base; | ||
113 | |||
114 | #ifdef CONFIG_PM_SLEEP | ||
115 | static struct samsung_clk_reg_dump *exynos5420_save; | ||
116 | |||
111 | /* | 117 | /* |
112 | * list of controller registers to be saved and restored during a | 118 | * list of controller registers to be saved and restored during a |
113 | * suspend/resume cycle. | 119 | * suspend/resume cycle. |
@@ -174,6 +180,41 @@ static unsigned long exynos5420_clk_regs[] __initdata = { | |||
174 | DIV_KFC0, | 180 | DIV_KFC0, |
175 | }; | 181 | }; |
176 | 182 | ||
183 | static int exynos5420_clk_suspend(void) | ||
184 | { | ||
185 | samsung_clk_save(reg_base, exynos5420_save, | ||
186 | ARRAY_SIZE(exynos5420_clk_regs)); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static void exynos5420_clk_resume(void) | ||
192 | { | ||
193 | samsung_clk_restore(reg_base, exynos5420_save, | ||
194 | ARRAY_SIZE(exynos5420_clk_regs)); | ||
195 | } | ||
196 | |||
197 | static struct syscore_ops exynos5420_clk_syscore_ops = { | ||
198 | .suspend = exynos5420_clk_suspend, | ||
199 | .resume = exynos5420_clk_resume, | ||
200 | }; | ||
201 | |||
202 | static void exynos5420_clk_sleep_init(void) | ||
203 | { | ||
204 | exynos5420_save = samsung_clk_alloc_reg_dump(exynos5420_clk_regs, | ||
205 | ARRAY_SIZE(exynos5420_clk_regs)); | ||
206 | if (!exynos5420_save) { | ||
207 | pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", | ||
208 | __func__); | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | register_syscore_ops(&exynos5420_clk_syscore_ops); | ||
213 | } | ||
214 | #else | ||
215 | static void exynos5420_clk_sleep_init(void) {} | ||
216 | #endif | ||
217 | |||
177 | /* list of all parent clocks */ | 218 | /* list of all parent clocks */ |
178 | PNAME(mspll_cpu_p) = { "sclk_cpll", "sclk_dpll", | 219 | PNAME(mspll_cpu_p) = { "sclk_cpll", "sclk_dpll", |
179 | "sclk_mpll", "sclk_spll" }; | 220 | "sclk_mpll", "sclk_spll" }; |
@@ -737,8 +778,6 @@ static struct of_device_id ext_clk_match[] __initdata = { | |||
737 | /* register exynos5420 clocks */ | 778 | /* register exynos5420 clocks */ |
738 | static void __init exynos5420_clk_init(struct device_node *np) | 779 | static void __init exynos5420_clk_init(struct device_node *np) |
739 | { | 780 | { |
740 | void __iomem *reg_base; | ||
741 | |||
742 | if (np) { | 781 | if (np) { |
743 | reg_base = of_iomap(np, 0); | 782 | reg_base = of_iomap(np, 0); |
744 | if (!reg_base) | 783 | if (!reg_base) |
@@ -747,9 +786,7 @@ static void __init exynos5420_clk_init(struct device_node *np) | |||
747 | panic("%s: unable to determine soc\n", __func__); | 786 | panic("%s: unable to determine soc\n", __func__); |
748 | } | 787 | } |
749 | 788 | ||
750 | samsung_clk_init(np, reg_base, CLK_NR_CLKS, | 789 | samsung_clk_init(np, reg_base, CLK_NR_CLKS); |
751 | exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs), | ||
752 | NULL, 0); | ||
753 | samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks, | 790 | samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks, |
754 | ARRAY_SIZE(exynos5420_fixed_rate_ext_clks), | 791 | ARRAY_SIZE(exynos5420_fixed_rate_ext_clks), |
755 | ext_clk_match); | 792 | ext_clk_match); |
@@ -765,5 +802,7 @@ static void __init exynos5420_clk_init(struct device_node *np) | |||
765 | ARRAY_SIZE(exynos5420_div_clks)); | 802 | ARRAY_SIZE(exynos5420_div_clks)); |
766 | samsung_clk_register_gate(exynos5420_gate_clks, | 803 | samsung_clk_register_gate(exynos5420_gate_clks, |
767 | ARRAY_SIZE(exynos5420_gate_clks)); | 804 | ARRAY_SIZE(exynos5420_gate_clks)); |
805 | |||
806 | exynos5420_clk_sleep_init(); | ||
768 | } | 807 | } |
769 | CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init); | 808 | CLK_OF_DECLARE(exynos5420_clk, "samsung,exynos5420-clock", exynos5420_clk_init); |
diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c index cbc15b56891d..2bfad5a993d0 100644 --- a/drivers/clk/samsung/clk-exynos5440.c +++ b/drivers/clk/samsung/clk-exynos5440.c | |||
@@ -101,7 +101,7 @@ static void __init exynos5440_clk_init(struct device_node *np) | |||
101 | return; | 101 | return; |
102 | } | 102 | } |
103 | 103 | ||
104 | samsung_clk_init(np, reg_base, CLK_NR_CLKS, NULL, 0, NULL, 0); | 104 | samsung_clk_init(np, reg_base, CLK_NR_CLKS); |
105 | samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks, | 105 | samsung_clk_of_register_fixed_ext(exynos5440_fixed_rate_ext_clks, |
106 | ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match); | 106 | ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match); |
107 | 107 | ||
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index 8e27aee6887e..8bda658137a8 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/clk-provider.h> | 13 | #include <linux/clk-provider.h> |
14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
16 | #include <linux/syscore_ops.h> | ||
16 | 17 | ||
17 | #include <dt-bindings/clock/samsung,s3c64xx-clock.h> | 18 | #include <dt-bindings/clock/samsung,s3c64xx-clock.h> |
18 | 19 | ||
@@ -61,6 +62,13 @@ enum s3c64xx_plls { | |||
61 | apll, mpll, epll, | 62 | apll, mpll, epll, |
62 | }; | 63 | }; |
63 | 64 | ||
65 | static void __iomem *reg_base; | ||
66 | static bool is_s3c6400; | ||
67 | |||
68 | #ifdef CONFIG_PM_SLEEP | ||
69 | static struct samsung_clk_reg_dump *s3c64xx_save_common; | ||
70 | static struct samsung_clk_reg_dump *s3c64xx_save_soc; | ||
71 | |||
64 | /* | 72 | /* |
65 | * List of controller registers to be saved and restored during | 73 | * List of controller registers to be saved and restored during |
66 | * a suspend/resume cycle. | 74 | * a suspend/resume cycle. |
@@ -87,6 +95,60 @@ static unsigned long s3c6410_clk_regs[] __initdata = { | |||
87 | MEM0_GATE, | 95 | MEM0_GATE, |
88 | }; | 96 | }; |
89 | 97 | ||
98 | static int s3c64xx_clk_suspend(void) | ||
99 | { | ||
100 | samsung_clk_save(reg_base, s3c64xx_save_common, | ||
101 | ARRAY_SIZE(s3c64xx_clk_regs)); | ||
102 | |||
103 | if (!is_s3c6400) | ||
104 | samsung_clk_save(reg_base, s3c64xx_save_soc, | ||
105 | ARRAY_SIZE(s3c6410_clk_regs)); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static void s3c64xx_clk_resume(void) | ||
111 | { | ||
112 | samsung_clk_restore(reg_base, s3c64xx_save_common, | ||
113 | ARRAY_SIZE(s3c64xx_clk_regs)); | ||
114 | |||
115 | if (!is_s3c6400) | ||
116 | samsung_clk_restore(reg_base, s3c64xx_save_soc, | ||
117 | ARRAY_SIZE(s3c6410_clk_regs)); | ||
118 | } | ||
119 | |||
120 | static struct syscore_ops s3c64xx_clk_syscore_ops = { | ||
121 | .suspend = s3c64xx_clk_suspend, | ||
122 | .resume = s3c64xx_clk_resume, | ||
123 | }; | ||
124 | |||
125 | static void s3c64xx_clk_sleep_init(void) | ||
126 | { | ||
127 | s3c64xx_save_common = samsung_clk_alloc_reg_dump(s3c64xx_clk_regs, | ||
128 | ARRAY_SIZE(s3c64xx_clk_regs)); | ||
129 | if (!s3c64xx_save_common) | ||
130 | goto err_warn; | ||
131 | |||
132 | if (!is_s3c6400) { | ||
133 | s3c64xx_save_soc = samsung_clk_alloc_reg_dump(s3c6410_clk_regs, | ||
134 | ARRAY_SIZE(s3c6410_clk_regs)); | ||
135 | if (!s3c64xx_save_soc) | ||
136 | goto err_soc; | ||
137 | } | ||
138 | |||
139 | register_syscore_ops(&s3c64xx_clk_syscore_ops); | ||
140 | return; | ||
141 | |||
142 | err_soc: | ||
143 | kfree(s3c64xx_save_common); | ||
144 | err_warn: | ||
145 | pr_warn("%s: failed to allocate sleep save data, no sleep support!\n", | ||
146 | __func__); | ||
147 | } | ||
148 | #else | ||
149 | static void s3c64xx_clk_sleep_init(void) {} | ||
150 | #endif | ||
151 | |||
90 | /* List of parent clocks common for all S3C64xx SoCs. */ | 152 | /* List of parent clocks common for all S3C64xx SoCs. */ |
91 | PNAME(spi_mmc_p) = { "mout_epll", "dout_mpll", "fin_pll", "clk27m" }; | 153 | PNAME(spi_mmc_p) = { "mout_epll", "dout_mpll", "fin_pll", "clk27m" }; |
92 | PNAME(uart_p) = { "mout_epll", "dout_mpll" }; | 154 | PNAME(uart_p) = { "mout_epll", "dout_mpll" }; |
@@ -391,11 +453,11 @@ static void __init s3c64xx_clk_register_fixed_ext(unsigned long fin_pll_f, | |||
391 | 453 | ||
392 | /* Register s3c64xx clocks. */ | 454 | /* Register s3c64xx clocks. */ |
393 | void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, | 455 | void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, |
394 | unsigned long xusbxti_f, bool is_s3c6400, | 456 | unsigned long xusbxti_f, bool s3c6400, |
395 | void __iomem *reg_base) | 457 | void __iomem *base) |
396 | { | 458 | { |
397 | unsigned long *soc_regs = NULL; | 459 | reg_base = base; |
398 | unsigned long nr_soc_regs = 0; | 460 | is_s3c6400 = s3c6400; |
399 | 461 | ||
400 | if (np) { | 462 | if (np) { |
401 | reg_base = of_iomap(np, 0); | 463 | reg_base = of_iomap(np, 0); |
@@ -403,13 +465,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, | |||
403 | panic("%s: failed to map registers\n", __func__); | 465 | panic("%s: failed to map registers\n", __func__); |
404 | } | 466 | } |
405 | 467 | ||
406 | if (!is_s3c6400) { | 468 | samsung_clk_init(np, reg_base, NR_CLKS); |
407 | soc_regs = s3c6410_clk_regs; | ||
408 | nr_soc_regs = ARRAY_SIZE(s3c6410_clk_regs); | ||
409 | } | ||
410 | |||
411 | samsung_clk_init(np, reg_base, NR_CLKS, s3c64xx_clk_regs, | ||
412 | ARRAY_SIZE(s3c64xx_clk_regs), soc_regs, nr_soc_regs); | ||
413 | 469 | ||
414 | /* Register external clocks. */ | 470 | /* Register external clocks. */ |
415 | if (!np) | 471 | if (!np) |
@@ -452,6 +508,7 @@ void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f, | |||
452 | 508 | ||
453 | samsung_clk_register_alias(s3c64xx_clock_aliases, | 509 | samsung_clk_register_alias(s3c64xx_clock_aliases, |
454 | ARRAY_SIZE(s3c64xx_clock_aliases)); | 510 | ARRAY_SIZE(s3c64xx_clock_aliases)); |
511 | s3c64xx_clk_sleep_init(); | ||
455 | 512 | ||
456 | pr_info("%s clocks: apll = %lu, mpll = %lu\n" | 513 | pr_info("%s clocks: apll = %lu, mpll = %lu\n" |
457 | "\tepll = %lu, arm_clk = %lu\n", | 514 | "\tepll = %lu, arm_clk = %lu\n", |
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index f503f32e2f80..91bec3ebdc8f 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c | |||
@@ -21,64 +21,45 @@ static void __iomem *reg_base; | |||
21 | static struct clk_onecell_data clk_data; | 21 | static struct clk_onecell_data clk_data; |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | #ifdef CONFIG_PM_SLEEP | 24 | void samsung_clk_save(void __iomem *base, |
25 | static struct samsung_clk_reg_dump *reg_dump; | 25 | struct samsung_clk_reg_dump *rd, |
26 | static unsigned long nr_reg_dump; | 26 | unsigned int num_regs) |
27 | |||
28 | static int samsung_clk_suspend(void) | ||
29 | { | 27 | { |
30 | struct samsung_clk_reg_dump *rd = reg_dump; | 28 | for (; num_regs > 0; --num_regs, ++rd) |
31 | unsigned long i; | 29 | rd->value = readl(base + rd->offset); |
32 | 30 | } | |
33 | for (i = 0; i < nr_reg_dump; i++, rd++) | ||
34 | rd->value = __raw_readl(reg_base + rd->offset); | ||
35 | 31 | ||
36 | return 0; | 32 | void samsung_clk_restore(void __iomem *base, |
33 | const struct samsung_clk_reg_dump *rd, | ||
34 | unsigned int num_regs) | ||
35 | { | ||
36 | for (; num_regs > 0; --num_regs, ++rd) | ||
37 | writel(rd->value, base + rd->offset); | ||
37 | } | 38 | } |
38 | 39 | ||
39 | static void samsung_clk_resume(void) | 40 | struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( |
41 | const unsigned long *rdump, | ||
42 | unsigned long nr_rdump) | ||
40 | { | 43 | { |
41 | struct samsung_clk_reg_dump *rd = reg_dump; | 44 | struct samsung_clk_reg_dump *rd; |
42 | unsigned long i; | 45 | unsigned int i; |
43 | 46 | ||
44 | for (i = 0; i < nr_reg_dump; i++, rd++) | 47 | rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL); |
45 | __raw_writel(rd->value, reg_base + rd->offset); | 48 | if (!rd) |
46 | } | 49 | return NULL; |
50 | |||
51 | for (i = 0; i < nr_rdump; ++i) | ||
52 | rd[i].offset = rdump[i]; | ||
47 | 53 | ||
48 | static struct syscore_ops samsung_clk_syscore_ops = { | 54 | return rd; |
49 | .suspend = samsung_clk_suspend, | 55 | } |
50 | .resume = samsung_clk_resume, | ||
51 | }; | ||
52 | #endif /* CONFIG_PM_SLEEP */ | ||
53 | 56 | ||
54 | /* setup the essentials required to support clock lookup using ccf */ | 57 | /* setup the essentials required to support clock lookup using ccf */ |
55 | void __init samsung_clk_init(struct device_node *np, void __iomem *base, | 58 | void __init samsung_clk_init(struct device_node *np, void __iomem *base, |
56 | unsigned long nr_clks, unsigned long *rdump, | 59 | unsigned long nr_clks) |
57 | unsigned long nr_rdump, unsigned long *soc_rdump, | ||
58 | unsigned long nr_soc_rdump) | ||
59 | { | 60 | { |
60 | reg_base = base; | 61 | reg_base = base; |
61 | 62 | ||
62 | #ifdef CONFIG_PM_SLEEP | ||
63 | if (rdump && nr_rdump) { | ||
64 | unsigned int idx; | ||
65 | reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump) | ||
66 | * (nr_rdump + nr_soc_rdump), GFP_KERNEL); | ||
67 | if (!reg_dump) { | ||
68 | pr_err("%s: memory alloc for register dump failed\n", | ||
69 | __func__); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | for (idx = 0; idx < nr_rdump; idx++) | ||
74 | reg_dump[idx].offset = rdump[idx]; | ||
75 | for (idx = 0; idx < nr_soc_rdump; idx++) | ||
76 | reg_dump[nr_rdump + idx].offset = soc_rdump[idx]; | ||
77 | nr_reg_dump = nr_rdump + nr_soc_rdump; | ||
78 | register_syscore_ops(&samsung_clk_syscore_ops); | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); | 63 | clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); |
83 | if (!clk_table) | 64 | if (!clk_table) |
84 | panic("could not allocate clock lookup table\n"); | 65 | panic("could not allocate clock lookup table\n"); |
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index 31b4174e7a5b..c7141ba826e0 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h | |||
@@ -313,9 +313,7 @@ struct samsung_pll_clock { | |||
313 | _lock, _con, _rtable, _alias) | 313 | _lock, _con, _rtable, _alias) |
314 | 314 | ||
315 | extern void __init samsung_clk_init(struct device_node *np, void __iomem *base, | 315 | extern void __init samsung_clk_init(struct device_node *np, void __iomem *base, |
316 | unsigned long nr_clks, unsigned long *rdump, | 316 | unsigned long nr_clks); |
317 | unsigned long nr_rdump, unsigned long *soc_rdump, | ||
318 | unsigned long nr_soc_rdump); | ||
319 | extern void __init samsung_clk_of_register_fixed_ext( | 317 | extern void __init samsung_clk_of_register_fixed_ext( |
320 | struct samsung_fixed_rate_clock *fixed_rate_clk, | 318 | struct samsung_fixed_rate_clock *fixed_rate_clk, |
321 | unsigned int nr_fixed_rate_clk, | 319 | unsigned int nr_fixed_rate_clk, |
@@ -340,4 +338,14 @@ extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list, | |||
340 | 338 | ||
341 | extern unsigned long _get_rate(const char *clk_name); | 339 | extern unsigned long _get_rate(const char *clk_name); |
342 | 340 | ||
341 | extern void samsung_clk_save(void __iomem *base, | ||
342 | struct samsung_clk_reg_dump *rd, | ||
343 | unsigned int num_regs); | ||
344 | extern void samsung_clk_restore(void __iomem *base, | ||
345 | const struct samsung_clk_reg_dump *rd, | ||
346 | unsigned int num_regs); | ||
347 | extern struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump( | ||
348 | const unsigned long *rdump, | ||
349 | unsigned long nr_rdump); | ||
350 | |||
343 | #endif /* __SAMSUNG_CLK_H */ | 351 | #endif /* __SAMSUNG_CLK_H */ |