diff options
author | Michael Turquette <mturquette@baylibre.com> | 2015-12-15 22:13:39 -0500 |
---|---|---|
committer | Michael Turquette <mturquette@baylibre.com> | 2015-12-22 14:57:32 -0500 |
commit | d90e149666258bc84e14c1c31c2064a345220cd7 (patch) | |
tree | 6b645071c83096c20b5f638723402440d5f42cc7 | |
parent | 3837bd277abd08395588139759cbd56f00f14cb4 (diff) | |
parent | c5dae0df298120e0a331d749d77fd472c253b5b3 (diff) |
Merge branch 'clk-shmobile-for-v4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into clk-next
-rw-r--r-- | Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt | 4 | ||||
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/shmobile/Makefile | 24 | ||||
-rw-r--r-- | drivers/clk/shmobile/clk-div6.c | 137 | ||||
-rw-r--r-- | drivers/clk/shmobile/clk-div6.h | 7 | ||||
-rw-r--r-- | drivers/clk/shmobile/r8a7795-cpg-mssr.c | 382 | ||||
-rw-r--r-- | drivers/clk/shmobile/renesas-cpg-mssr.c | 596 | ||||
-rw-r--r-- | drivers/clk/shmobile/renesas-cpg-mssr.h | 132 |
8 files changed, 1220 insertions, 63 deletions
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt index 38dcf0370143..ae36ab842919 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt | |||
@@ -20,6 +20,10 @@ Required Properties: | |||
20 | clocks must be specified. For clocks with multiple parents, invalid | 20 | clocks must be specified. For clocks with multiple parents, invalid |
21 | settings must be specified as "<0>". | 21 | settings must be specified as "<0>". |
22 | - #clock-cells: Must be 0 | 22 | - #clock-cells: Must be 0 |
23 | |||
24 | |||
25 | Optional Properties: | ||
26 | |||
23 | - clock-output-names: The name of the clock as a free-form string | 27 | - clock-output-names: The name of the clock as a free-form string |
24 | 28 | ||
25 | 29 | ||
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 0ecccf30cd28..0e0fdac2a599 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -71,6 +71,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ | |||
71 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 71 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
72 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ | 72 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ |
73 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ | 73 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ |
74 | obj-$(CONFIG_ARCH_RENESAS) += shmobile/ | ||
74 | obj-$(CONFIG_ARCH_SIRF) += sirf/ | 75 | obj-$(CONFIG_ARCH_SIRF) += sirf/ |
75 | obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ | 76 | obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ |
76 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | 77 | obj-$(CONFIG_PLAT_SPEAR) += spear/ |
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index 97c71c885e4f..7e2579b30326 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile | |||
@@ -1,13 +1,13 @@ | |||
1 | obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o | 1 | obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o |
2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o | 2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o clk-mstp.o |
3 | obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o | 3 | obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-mstp.o clk-div6.o |
4 | obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o | 4 | obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-mstp.o clk-div6.o |
5 | obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o | 5 | obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o clk-mstp.o |
6 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o | 6 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o clk-mstp.o |
7 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o | 7 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-mstp.o clk-div6.o |
8 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o | 8 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-mstp.o clk-div6.o |
9 | obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o | 9 | obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-mstp.o clk-div6.o |
10 | obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o | 10 | obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-mstp.o clk-div6.o |
11 | obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o | 11 | obj-$(CONFIG_ARCH_R8A7795) += renesas-cpg-mssr.o \ |
12 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o | 12 | r8a7795-cpg-mssr.o clk-div6.o |
13 | obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o | 13 | obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-mstp.o clk-div6.o |
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c index b4c8d6746f68..999994769450 100644 --- a/drivers/clk/shmobile/clk-div6.c +++ b/drivers/clk/shmobile/clk-div6.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | 20 | ||
21 | #include "clk-div6.h" | ||
22 | |||
21 | #define CPG_DIV6_CKSTP BIT(8) | 23 | #define CPG_DIV6_CKSTP BIT(8) |
22 | #define CPG_DIV6_DIV(d) ((d) & 0x3f) | 24 | #define CPG_DIV6_DIV(d) ((d) & 0x3f) |
23 | #define CPG_DIV6_DIV_MASK 0x3f | 25 | #define CPG_DIV6_DIV_MASK 0x3f |
@@ -172,67 +174,44 @@ static const struct clk_ops cpg_div6_clock_ops = { | |||
172 | .set_rate = cpg_div6_clock_set_rate, | 174 | .set_rate = cpg_div6_clock_set_rate, |
173 | }; | 175 | }; |
174 | 176 | ||
175 | static void __init cpg_div6_clock_init(struct device_node *np) | 177 | |
178 | /** | ||
179 | * cpg_div6_register - Register a DIV6 clock | ||
180 | * @name: Name of the DIV6 clock | ||
181 | * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8) | ||
182 | * @parent_names: Array containing the names of the parent clocks | ||
183 | * @reg: Mapped register used to control the DIV6 clock | ||
184 | */ | ||
185 | struct clk * __init cpg_div6_register(const char *name, | ||
186 | unsigned int num_parents, | ||
187 | const char **parent_names, | ||
188 | void __iomem *reg) | ||
176 | { | 189 | { |
177 | unsigned int num_parents, valid_parents; | 190 | unsigned int valid_parents; |
178 | const char **parent_names; | ||
179 | struct clk_init_data init; | 191 | struct clk_init_data init; |
180 | struct div6_clock *clock; | 192 | struct div6_clock *clock; |
181 | const char *name; | ||
182 | struct clk *clk; | 193 | struct clk *clk; |
183 | unsigned int i; | 194 | unsigned int i; |
184 | int ret; | ||
185 | 195 | ||
186 | clock = kzalloc(sizeof(*clock), GFP_KERNEL); | 196 | clock = kzalloc(sizeof(*clock), GFP_KERNEL); |
187 | if (!clock) | 197 | if (!clock) |
188 | return; | 198 | return ERR_PTR(-ENOMEM); |
189 | 199 | ||
190 | num_parents = of_clk_get_parent_count(np); | 200 | clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents), |
191 | if (num_parents < 1) { | 201 | GFP_KERNEL); |
192 | pr_err("%s: no parent found for %s DIV6 clock\n", | 202 | if (!clock->parents) { |
193 | __func__, np->name); | 203 | clk = ERR_PTR(-ENOMEM); |
194 | return; | 204 | goto free_clock; |
195 | } | 205 | } |
196 | 206 | ||
197 | clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents), | 207 | clock->reg = reg; |
198 | GFP_KERNEL); | ||
199 | parent_names = kmalloc_array(num_parents, sizeof(*parent_names), | ||
200 | GFP_KERNEL); | ||
201 | if (!parent_names) | ||
202 | return; | ||
203 | 208 | ||
204 | /* Remap the clock register and read the divisor. Disabling the | 209 | /* |
205 | * clock overwrites the divisor, so we need to cache its value for the | 210 | * Read the divisor. Disabling the clock overwrites the divisor, so we |
206 | * enable operation. | 211 | * need to cache its value for the enable operation. |
207 | */ | 212 | */ |
208 | clock->reg = of_iomap(np, 0); | ||
209 | if (clock->reg == NULL) { | ||
210 | pr_err("%s: failed to map %s DIV6 clock register\n", | ||
211 | __func__, np->name); | ||
212 | goto error; | ||
213 | } | ||
214 | |||
215 | clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1; | 213 | clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1; |
216 | 214 | ||
217 | /* Parse the DT properties. */ | ||
218 | ret = of_property_read_string(np, "clock-output-names", &name); | ||
219 | if (ret < 0) { | ||
220 | pr_err("%s: failed to get %s DIV6 clock output name\n", | ||
221 | __func__, np->name); | ||
222 | goto error; | ||
223 | } | ||
224 | |||
225 | |||
226 | for (i = 0, valid_parents = 0; i < num_parents; i++) { | ||
227 | const char *name = of_clk_get_parent_name(np, i); | ||
228 | |||
229 | if (name) { | ||
230 | parent_names[valid_parents] = name; | ||
231 | clock->parents[valid_parents] = i; | ||
232 | valid_parents++; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | switch (num_parents) { | 215 | switch (num_parents) { |
237 | case 1: | 216 | case 1: |
238 | /* fixed parent clock */ | 217 | /* fixed parent clock */ |
@@ -250,8 +229,18 @@ static void __init cpg_div6_clock_init(struct device_node *np) | |||
250 | break; | 229 | break; |
251 | default: | 230 | default: |
252 | pr_err("%s: invalid number of parents for DIV6 clock %s\n", | 231 | pr_err("%s: invalid number of parents for DIV6 clock %s\n", |
253 | __func__, np->name); | 232 | __func__, name); |
254 | goto error; | 233 | clk = ERR_PTR(-EINVAL); |
234 | goto free_parents; | ||
235 | } | ||
236 | |||
237 | /* Filter out invalid parents */ | ||
238 | for (i = 0, valid_parents = 0; i < num_parents; i++) { | ||
239 | if (parent_names[i]) { | ||
240 | parent_names[valid_parents] = parent_names[i]; | ||
241 | clock->parents[valid_parents] = i; | ||
242 | valid_parents++; | ||
243 | } | ||
255 | } | 244 | } |
256 | 245 | ||
257 | /* Register the clock. */ | 246 | /* Register the clock. */ |
@@ -264,6 +253,53 @@ static void __init cpg_div6_clock_init(struct device_node *np) | |||
264 | clock->hw.init = &init; | 253 | clock->hw.init = &init; |
265 | 254 | ||
266 | clk = clk_register(NULL, &clock->hw); | 255 | clk = clk_register(NULL, &clock->hw); |
256 | if (IS_ERR(clk)) | ||
257 | goto free_parents; | ||
258 | |||
259 | return clk; | ||
260 | |||
261 | free_parents: | ||
262 | kfree(clock->parents); | ||
263 | free_clock: | ||
264 | kfree(clock); | ||
265 | return clk; | ||
266 | } | ||
267 | |||
268 | static void __init cpg_div6_clock_init(struct device_node *np) | ||
269 | { | ||
270 | unsigned int num_parents; | ||
271 | const char **parent_names; | ||
272 | const char *clk_name = np->name; | ||
273 | void __iomem *reg; | ||
274 | struct clk *clk; | ||
275 | unsigned int i; | ||
276 | |||
277 | num_parents = of_clk_get_parent_count(np); | ||
278 | if (num_parents < 1) { | ||
279 | pr_err("%s: no parent found for %s DIV6 clock\n", | ||
280 | __func__, np->name); | ||
281 | return; | ||
282 | } | ||
283 | |||
284 | parent_names = kmalloc_array(num_parents, sizeof(*parent_names), | ||
285 | GFP_KERNEL); | ||
286 | if (!parent_names) | ||
287 | return; | ||
288 | |||
289 | reg = of_iomap(np, 0); | ||
290 | if (reg == NULL) { | ||
291 | pr_err("%s: failed to map %s DIV6 clock register\n", | ||
292 | __func__, np->name); | ||
293 | goto error; | ||
294 | } | ||
295 | |||
296 | /* Parse the DT properties. */ | ||
297 | of_property_read_string(np, "clock-output-names", &clk_name); | ||
298 | |||
299 | for (i = 0; i < num_parents; i++) | ||
300 | parent_names[i] = of_clk_get_parent_name(np, i); | ||
301 | |||
302 | clk = cpg_div6_register(clk_name, num_parents, parent_names, reg); | ||
267 | if (IS_ERR(clk)) { | 303 | if (IS_ERR(clk)) { |
268 | pr_err("%s: failed to register %s DIV6 clock (%ld)\n", | 304 | pr_err("%s: failed to register %s DIV6 clock (%ld)\n", |
269 | __func__, np->name, PTR_ERR(clk)); | 305 | __func__, np->name, PTR_ERR(clk)); |
@@ -276,9 +312,8 @@ static void __init cpg_div6_clock_init(struct device_node *np) | |||
276 | return; | 312 | return; |
277 | 313 | ||
278 | error: | 314 | error: |
279 | if (clock->reg) | 315 | if (reg) |
280 | iounmap(clock->reg); | 316 | iounmap(reg); |
281 | kfree(parent_names); | 317 | kfree(parent_names); |
282 | kfree(clock); | ||
283 | } | 318 | } |
284 | CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init); | 319 | CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init); |
diff --git a/drivers/clk/shmobile/clk-div6.h b/drivers/clk/shmobile/clk-div6.h new file mode 100644 index 000000000000..9a85a95188da --- /dev/null +++ b/drivers/clk/shmobile/clk-div6.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef __SHMOBILE_CLK_DIV6_H__ | ||
2 | #define __SHMOBILE_CLK_DIV6_H__ | ||
3 | |||
4 | struct clk *cpg_div6_register(const char *name, unsigned int num_parents, | ||
5 | const char **parent_names, void __iomem *reg); | ||
6 | |||
7 | #endif | ||
diff --git a/drivers/clk/shmobile/r8a7795-cpg-mssr.c b/drivers/clk/shmobile/r8a7795-cpg-mssr.c new file mode 100644 index 000000000000..57c413635d1a --- /dev/null +++ b/drivers/clk/shmobile/r8a7795-cpg-mssr.c | |||
@@ -0,0 +1,382 @@ | |||
1 | /* | ||
2 | * r8a7795 Clock Pulse Generator / Module Standby and Software Reset | ||
3 | * | ||
4 | * Copyright (C) 2015 Glider bvba | ||
5 | * | ||
6 | * Based on clk-rcar-gen3.c | ||
7 | * | ||
8 | * Copyright (C) 2015 Renesas Electronics Corp. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
13 | */ | ||
14 | |||
15 | #include <linux/bug.h> | ||
16 | #include <linux/clk-provider.h> | ||
17 | #include <linux/device.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/of.h> | ||
23 | |||
24 | #include <dt-bindings/clock/r8a7795-cpg-mssr.h> | ||
25 | |||
26 | #include "renesas-cpg-mssr.h" | ||
27 | |||
28 | |||
29 | enum clk_ids { | ||
30 | /* Core Clock Outputs exported to DT */ | ||
31 | LAST_DT_CORE_CLK = R8A7795_CLK_OSC, | ||
32 | |||
33 | /* External Input Clocks */ | ||
34 | CLK_EXTAL, | ||
35 | CLK_EXTALR, | ||
36 | |||
37 | /* Internal Core Clocks */ | ||
38 | CLK_MAIN, | ||
39 | CLK_PLL0, | ||
40 | CLK_PLL1, | ||
41 | CLK_PLL2, | ||
42 | CLK_PLL3, | ||
43 | CLK_PLL4, | ||
44 | CLK_PLL1_DIV2, | ||
45 | CLK_PLL1_DIV4, | ||
46 | CLK_S0, | ||
47 | CLK_S1, | ||
48 | CLK_S2, | ||
49 | CLK_S3, | ||
50 | CLK_SDSRC, | ||
51 | CLK_SSPSRC, | ||
52 | |||
53 | /* Module Clocks */ | ||
54 | MOD_CLK_BASE | ||
55 | }; | ||
56 | |||
57 | enum r8a7795_clk_types { | ||
58 | CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM, | ||
59 | CLK_TYPE_GEN3_PLL0, | ||
60 | CLK_TYPE_GEN3_PLL1, | ||
61 | CLK_TYPE_GEN3_PLL2, | ||
62 | CLK_TYPE_GEN3_PLL3, | ||
63 | CLK_TYPE_GEN3_PLL4, | ||
64 | }; | ||
65 | |||
66 | static const struct cpg_core_clk r8a7795_core_clks[] __initconst = { | ||
67 | /* External Clock Inputs */ | ||
68 | DEF_INPUT("extal", CLK_EXTAL), | ||
69 | DEF_INPUT("extalr", CLK_EXTALR), | ||
70 | |||
71 | /* Internal Core Clocks */ | ||
72 | DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL), | ||
73 | DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN), | ||
74 | DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN), | ||
75 | DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN), | ||
76 | DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN), | ||
77 | DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN), | ||
78 | |||
79 | DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), | ||
80 | DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1), | ||
81 | DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1), | ||
82 | DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1), | ||
83 | DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), | ||
84 | DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), | ||
85 | |||
86 | /* Core Clock Outputs */ | ||
87 | DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), | ||
88 | DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), | ||
89 | DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1), | ||
90 | DEF_FIXED("zx", R8A7795_CLK_ZX, CLK_PLL1_DIV2, 2, 1), | ||
91 | DEF_FIXED("s0d1", R8A7795_CLK_S0D1, CLK_S0, 1, 1), | ||
92 | DEF_FIXED("s0d4", R8A7795_CLK_S0D4, CLK_S0, 4, 1), | ||
93 | DEF_FIXED("s1d1", R8A7795_CLK_S1D1, CLK_S1, 1, 1), | ||
94 | DEF_FIXED("s1d2", R8A7795_CLK_S1D2, CLK_S1, 2, 1), | ||
95 | DEF_FIXED("s1d4", R8A7795_CLK_S1D4, CLK_S1, 4, 1), | ||
96 | DEF_FIXED("s2d1", R8A7795_CLK_S2D1, CLK_S2, 1, 1), | ||
97 | DEF_FIXED("s2d2", R8A7795_CLK_S2D2, CLK_S2, 2, 1), | ||
98 | DEF_FIXED("s2d4", R8A7795_CLK_S2D4, CLK_S2, 4, 1), | ||
99 | DEF_FIXED("s3d1", R8A7795_CLK_S3D1, CLK_S3, 1, 1), | ||
100 | DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1), | ||
101 | DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1), | ||
102 | DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1), | ||
103 | DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1), | ||
104 | |||
105 | DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014), | ||
106 | DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250), | ||
107 | }; | ||
108 | |||
109 | static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = { | ||
110 | DEF_MOD("scif5", 202, R8A7795_CLK_S3D4), | ||
111 | DEF_MOD("scif4", 203, R8A7795_CLK_S3D4), | ||
112 | DEF_MOD("scif3", 204, R8A7795_CLK_S3D4), | ||
113 | DEF_MOD("scif1", 206, R8A7795_CLK_S3D4), | ||
114 | DEF_MOD("scif0", 207, R8A7795_CLK_S3D4), | ||
115 | DEF_MOD("msiof3", 208, R8A7795_CLK_MSO), | ||
116 | DEF_MOD("msiof2", 209, R8A7795_CLK_MSO), | ||
117 | DEF_MOD("msiof1", 210, R8A7795_CLK_MSO), | ||
118 | DEF_MOD("msiof0", 211, R8A7795_CLK_MSO), | ||
119 | DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S3D1), | ||
120 | DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1), | ||
121 | DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S3D1), | ||
122 | DEF_MOD("scif2", 310, R8A7795_CLK_S3D4), | ||
123 | DEF_MOD("pcie1", 318, R8A7795_CLK_S3D1), | ||
124 | DEF_MOD("pcie0", 319, R8A7795_CLK_S3D1), | ||
125 | DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1), | ||
126 | DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4), | ||
127 | DEF_MOD("audmac1", 501, R8A7795_CLK_S3D4), | ||
128 | DEF_MOD("hscif4", 516, R8A7795_CLK_S3D1), | ||
129 | DEF_MOD("hscif3", 517, R8A7795_CLK_S3D1), | ||
130 | DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1), | ||
131 | DEF_MOD("hscif1", 519, R8A7795_CLK_S3D1), | ||
132 | DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1), | ||
133 | DEF_MOD("vspd3", 620, R8A7795_CLK_S2D1), | ||
134 | DEF_MOD("vspd2", 621, R8A7795_CLK_S2D1), | ||
135 | DEF_MOD("vspd1", 622, R8A7795_CLK_S2D1), | ||
136 | DEF_MOD("vspd0", 623, R8A7795_CLK_S2D1), | ||
137 | DEF_MOD("vspbc", 624, R8A7795_CLK_S2D1), | ||
138 | DEF_MOD("vspbd", 626, R8A7795_CLK_S2D1), | ||
139 | DEF_MOD("vspi2", 629, R8A7795_CLK_S2D1), | ||
140 | DEF_MOD("vspi1", 630, R8A7795_CLK_S2D1), | ||
141 | DEF_MOD("vspi0", 631, R8A7795_CLK_S2D1), | ||
142 | DEF_MOD("ehci2", 701, R8A7795_CLK_S3D4), | ||
143 | DEF_MOD("ehci1", 702, R8A7795_CLK_S3D4), | ||
144 | DEF_MOD("ehci0", 703, R8A7795_CLK_S3D4), | ||
145 | DEF_MOD("hsusb", 704, R8A7795_CLK_S3D4), | ||
146 | DEF_MOD("du3", 721, R8A7795_CLK_S2D1), | ||
147 | DEF_MOD("du2", 722, R8A7795_CLK_S2D1), | ||
148 | DEF_MOD("du1", 723, R8A7795_CLK_S2D1), | ||
149 | DEF_MOD("du0", 724, R8A7795_CLK_S2D1), | ||
150 | DEF_MOD("hdmi1", 728, R8A7795_CLK_HDMI), | ||
151 | DEF_MOD("hdmi0", 729, R8A7795_CLK_HDMI), | ||
152 | DEF_MOD("etheravb", 812, R8A7795_CLK_S3D2), | ||
153 | DEF_MOD("gpio7", 905, R8A7795_CLK_CP), | ||
154 | DEF_MOD("gpio6", 906, R8A7795_CLK_CP), | ||
155 | DEF_MOD("gpio5", 907, R8A7795_CLK_CP), | ||
156 | DEF_MOD("gpio4", 908, R8A7795_CLK_CP), | ||
157 | DEF_MOD("gpio3", 909, R8A7795_CLK_CP), | ||
158 | DEF_MOD("gpio2", 910, R8A7795_CLK_CP), | ||
159 | DEF_MOD("gpio1", 911, R8A7795_CLK_CP), | ||
160 | DEF_MOD("gpio0", 912, R8A7795_CLK_CP), | ||
161 | DEF_MOD("i2c6", 918, R8A7795_CLK_S3D2), | ||
162 | DEF_MOD("i2c5", 919, R8A7795_CLK_S3D2), | ||
163 | DEF_MOD("i2c4", 927, R8A7795_CLK_S3D2), | ||
164 | DEF_MOD("i2c3", 928, R8A7795_CLK_S3D2), | ||
165 | DEF_MOD("i2c2", 929, R8A7795_CLK_S3D2), | ||
166 | DEF_MOD("i2c1", 930, R8A7795_CLK_S3D2), | ||
167 | DEF_MOD("i2c0", 931, R8A7795_CLK_S3D2), | ||
168 | DEF_MOD("ssi-all", 1005, R8A7795_CLK_S3D4), | ||
169 | DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)), | ||
170 | DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)), | ||
171 | DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)), | ||
172 | DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)), | ||
173 | DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)), | ||
174 | DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)), | ||
175 | DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)), | ||
176 | DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)), | ||
177 | DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)), | ||
178 | DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)), | ||
179 | DEF_MOD("scu-all", 1017, R8A7795_CLK_S3D4), | ||
180 | DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)), | ||
181 | DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)), | ||
182 | DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)), | ||
183 | DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)), | ||
184 | DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)), | ||
185 | DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)), | ||
186 | DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)), | ||
187 | DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)), | ||
188 | DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)), | ||
189 | DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)), | ||
190 | DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)), | ||
191 | DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)), | ||
192 | DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)), | ||
193 | DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)), | ||
194 | }; | ||
195 | |||
196 | static const unsigned int r8a7795_crit_mod_clks[] __initconst = { | ||
197 | MOD_CLK_ID(408), /* INTC-AP (GIC) */ | ||
198 | }; | ||
199 | |||
200 | |||
201 | #define CPG_PLL0CR 0x00d8 | ||
202 | #define CPG_PLL2CR 0x002c | ||
203 | #define CPG_PLL4CR 0x01f4 | ||
204 | |||
205 | /* | ||
206 | * CPG Clock Data | ||
207 | */ | ||
208 | |||
209 | /* | ||
210 | * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4 | ||
211 | * 14 13 19 17 (MHz) | ||
212 | *------------------------------------------------------------------- | ||
213 | * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144 | ||
214 | * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144 | ||
215 | * 0 0 1 0 Prohibited setting | ||
216 | * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144 | ||
217 | * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120 | ||
218 | * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120 | ||
219 | * 0 1 1 0 Prohibited setting | ||
220 | * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120 | ||
221 | * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96 | ||
222 | * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96 | ||
223 | * 1 0 1 0 Prohibited setting | ||
224 | * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96 | ||
225 | * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144 | ||
226 | * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144 | ||
227 | * 1 1 1 0 Prohibited setting | ||
228 | * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144 | ||
229 | */ | ||
230 | #define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \ | ||
231 | (((md) & BIT(13)) >> 11) | \ | ||
232 | (((md) & BIT(19)) >> 18) | \ | ||
233 | (((md) & BIT(17)) >> 17)) | ||
234 | |||
235 | struct cpg_pll_config { | ||
236 | unsigned int extal_div; | ||
237 | unsigned int pll1_mult; | ||
238 | unsigned int pll3_mult; | ||
239 | }; | ||
240 | |||
241 | static const struct cpg_pll_config cpg_pll_configs[16] __initconst = { | ||
242 | /* EXTAL div PLL1 mult PLL3 mult */ | ||
243 | { 1, 192, 192, }, | ||
244 | { 1, 192, 128, }, | ||
245 | { 0, /* Prohibited setting */ }, | ||
246 | { 1, 192, 192, }, | ||
247 | { 1, 160, 160, }, | ||
248 | { 1, 160, 106, }, | ||
249 | { 0, /* Prohibited setting */ }, | ||
250 | { 1, 160, 160, }, | ||
251 | { 1, 128, 128, }, | ||
252 | { 1, 128, 84, }, | ||
253 | { 0, /* Prohibited setting */ }, | ||
254 | { 1, 128, 128, }, | ||
255 | { 2, 192, 192, }, | ||
256 | { 2, 192, 128, }, | ||
257 | { 0, /* Prohibited setting */ }, | ||
258 | { 2, 192, 192, }, | ||
259 | }; | ||
260 | |||
261 | static const struct cpg_pll_config *cpg_pll_config __initdata; | ||
262 | |||
263 | static | ||
264 | struct clk * __init r8a7795_cpg_clk_register(struct device *dev, | ||
265 | const struct cpg_core_clk *core, | ||
266 | const struct cpg_mssr_info *info, | ||
267 | struct clk **clks, | ||
268 | void __iomem *base) | ||
269 | { | ||
270 | const struct clk *parent; | ||
271 | unsigned int mult = 1; | ||
272 | unsigned int div = 1; | ||
273 | u32 value; | ||
274 | |||
275 | parent = clks[core->parent]; | ||
276 | if (IS_ERR(parent)) | ||
277 | return ERR_CAST(parent); | ||
278 | |||
279 | switch (core->type) { | ||
280 | case CLK_TYPE_GEN3_MAIN: | ||
281 | div = cpg_pll_config->extal_div; | ||
282 | break; | ||
283 | |||
284 | case CLK_TYPE_GEN3_PLL0: | ||
285 | /* | ||
286 | * PLL0 is a configurable multiplier clock. Register it as a | ||
287 | * fixed factor clock for now as there's no generic multiplier | ||
288 | * clock implementation and we currently have no need to change | ||
289 | * the multiplier value. | ||
290 | */ | ||
291 | value = readl(base + CPG_PLL0CR); | ||
292 | mult = (((value >> 24) & 0x7f) + 1) * 2; | ||
293 | break; | ||
294 | |||
295 | case CLK_TYPE_GEN3_PLL1: | ||
296 | mult = cpg_pll_config->pll1_mult; | ||
297 | break; | ||
298 | |||
299 | case CLK_TYPE_GEN3_PLL2: | ||
300 | /* | ||
301 | * PLL2 is a configurable multiplier clock. Register it as a | ||
302 | * fixed factor clock for now as there's no generic multiplier | ||
303 | * clock implementation and we currently have no need to change | ||
304 | * the multiplier value. | ||
305 | */ | ||
306 | value = readl(base + CPG_PLL2CR); | ||
307 | mult = (((value >> 24) & 0x7f) + 1) * 2; | ||
308 | break; | ||
309 | |||
310 | case CLK_TYPE_GEN3_PLL3: | ||
311 | mult = cpg_pll_config->pll3_mult; | ||
312 | break; | ||
313 | |||
314 | case CLK_TYPE_GEN3_PLL4: | ||
315 | /* | ||
316 | * PLL4 is a configurable multiplier clock. Register it as a | ||
317 | * fixed factor clock for now as there's no generic multiplier | ||
318 | * clock implementation and we currently have no need to change | ||
319 | * the multiplier value. | ||
320 | */ | ||
321 | value = readl(base + CPG_PLL4CR); | ||
322 | mult = (((value >> 24) & 0x7f) + 1) * 2; | ||
323 | break; | ||
324 | |||
325 | default: | ||
326 | return ERR_PTR(-EINVAL); | ||
327 | } | ||
328 | |||
329 | return clk_register_fixed_factor(NULL, core->name, | ||
330 | __clk_get_name(parent), 0, mult, div); | ||
331 | } | ||
332 | |||
333 | /* | ||
334 | * Reset register definitions. | ||
335 | */ | ||
336 | #define MODEMR 0xe6160060 | ||
337 | |||
338 | static u32 rcar_gen3_read_mode_pins(void) | ||
339 | { | ||
340 | void __iomem *modemr = ioremap_nocache(MODEMR, 4); | ||
341 | u32 mode; | ||
342 | |||
343 | BUG_ON(!modemr); | ||
344 | mode = ioread32(modemr); | ||
345 | iounmap(modemr); | ||
346 | |||
347 | return mode; | ||
348 | } | ||
349 | |||
350 | static int __init r8a7795_cpg_mssr_init(struct device *dev) | ||
351 | { | ||
352 | u32 cpg_mode = rcar_gen3_read_mode_pins(); | ||
353 | |||
354 | cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; | ||
355 | if (!cpg_pll_config->extal_div) { | ||
356 | dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode); | ||
357 | return -EINVAL; | ||
358 | } | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = { | ||
364 | /* Core Clocks */ | ||
365 | .core_clks = r8a7795_core_clks, | ||
366 | .num_core_clks = ARRAY_SIZE(r8a7795_core_clks), | ||
367 | .last_dt_core_clk = LAST_DT_CORE_CLK, | ||
368 | .num_total_core_clks = MOD_CLK_BASE, | ||
369 | |||
370 | /* Module Clocks */ | ||
371 | .mod_clks = r8a7795_mod_clks, | ||
372 | .num_mod_clks = ARRAY_SIZE(r8a7795_mod_clks), | ||
373 | .num_hw_mod_clks = 12 * 32, | ||
374 | |||
375 | /* Critical Module Clocks */ | ||
376 | .crit_mod_clks = r8a7795_crit_mod_clks, | ||
377 | .num_crit_mod_clks = ARRAY_SIZE(r8a7795_crit_mod_clks), | ||
378 | |||
379 | /* Callbacks */ | ||
380 | .init = r8a7795_cpg_mssr_init, | ||
381 | .cpg_clk_register = r8a7795_cpg_clk_register, | ||
382 | }; | ||
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.c b/drivers/clk/shmobile/renesas-cpg-mssr.c new file mode 100644 index 000000000000..9a4d888164bb --- /dev/null +++ b/drivers/clk/shmobile/renesas-cpg-mssr.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | * Renesas Clock Pulse Generator / Module Standby and Software Reset | ||
3 | * | ||
4 | * Copyright (C) 2015 Glider bvba | ||
5 | * | ||
6 | * Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c | ||
7 | * | ||
8 | * Copyright (C) 2013 Ideas On Board SPRL | ||
9 | * Copyright (C) 2015 Renesas Electronics Corp. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/clk-provider.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/mod_devicetable.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of_address.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/pm_clock.h> | ||
26 | #include <linux/pm_domain.h> | ||
27 | #include <linux/slab.h> | ||
28 | |||
29 | #include <dt-bindings/clock/renesas-cpg-mssr.h> | ||
30 | |||
31 | #include "renesas-cpg-mssr.h" | ||
32 | #include "clk-div6.h" | ||
33 | |||
34 | #ifdef DEBUG | ||
35 | #define WARN_DEBUG(x) do { } while (0) | ||
36 | #else | ||
37 | #define WARN_DEBUG(x) WARN_ON(x) | ||
38 | #endif | ||
39 | |||
40 | |||
41 | /* | ||
42 | * Module Standby and Software Reset register offets. | ||
43 | * | ||
44 | * If the registers exist, these are valid for SH-Mobile, R-Mobile, | ||
45 | * R-Car Gen 2, and R-Car Gen 3. | ||
46 | * These are NOT valid for R-Car Gen1 and RZ/A1! | ||
47 | */ | ||
48 | |||
49 | /* | ||
50 | * Module Stop Status Register offsets | ||
51 | */ | ||
52 | |||
53 | static const u16 mstpsr[] = { | ||
54 | 0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4, | ||
55 | 0x9A0, 0x9A4, 0x9A8, 0x9AC, | ||
56 | }; | ||
57 | |||
58 | #define MSTPSR(i) mstpsr[i] | ||
59 | |||
60 | |||
61 | /* | ||
62 | * System Module Stop Control Register offsets | ||
63 | */ | ||
64 | |||
65 | static const u16 smstpcr[] = { | ||
66 | 0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C, | ||
67 | 0x990, 0x994, 0x998, 0x99C, | ||
68 | }; | ||
69 | |||
70 | #define SMSTPCR(i) smstpcr[i] | ||
71 | |||
72 | |||
73 | /* | ||
74 | * Software Reset Register offsets | ||
75 | */ | ||
76 | |||
77 | static const u16 srcr[] = { | ||
78 | 0x0A0, 0x0A8, 0x0B0, 0x0B8, 0x0BC, 0x0C4, 0x1C8, 0x1CC, | ||
79 | 0x920, 0x924, 0x928, 0x92C, | ||
80 | }; | ||
81 | |||
82 | #define SRCR(i) srcr[i] | ||
83 | |||
84 | |||
85 | /* Realtime Module Stop Control Register offsets */ | ||
86 | #define RMSTPCR(i) (smstpcr[i] - 0x20) | ||
87 | |||
88 | /* Modem Module Stop Control Register offsets (r8a73a4) */ | ||
89 | #define MMSTPCR(i) (smstpcr[i] + 0x20) | ||
90 | |||
91 | /* Software Reset Clearing Register offsets */ | ||
92 | #define SRSTCLR(i) (0x940 + (i) * 4) | ||
93 | |||
94 | |||
95 | /** | ||
96 | * Clock Pulse Generator / Module Standby and Software Reset Private Data | ||
97 | * | ||
98 | * @dev: CPG/MSSR device | ||
99 | * @base: CPG/MSSR register block base address | ||
100 | * @mstp_lock: protects writes to SMSTPCR | ||
101 | * @clks: Array containing all Core and Module Clocks | ||
102 | * @num_core_clks: Number of Core Clocks in clks[] | ||
103 | * @num_mod_clks: Number of Module Clocks in clks[] | ||
104 | * @last_dt_core_clk: ID of the last Core Clock exported to DT | ||
105 | */ | ||
106 | struct cpg_mssr_priv { | ||
107 | struct device *dev; | ||
108 | void __iomem *base; | ||
109 | spinlock_t mstp_lock; | ||
110 | |||
111 | struct clk **clks; | ||
112 | unsigned int num_core_clks; | ||
113 | unsigned int num_mod_clks; | ||
114 | unsigned int last_dt_core_clk; | ||
115 | }; | ||
116 | |||
117 | |||
118 | /** | ||
119 | * struct mstp_clock - MSTP gating clock | ||
120 | * @hw: handle between common and hardware-specific interfaces | ||
121 | * @index: MSTP clock number | ||
122 | * @priv: CPG/MSSR private data | ||
123 | */ | ||
124 | struct mstp_clock { | ||
125 | struct clk_hw hw; | ||
126 | u32 index; | ||
127 | struct cpg_mssr_priv *priv; | ||
128 | }; | ||
129 | |||
130 | #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) | ||
131 | |||
132 | static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) | ||
133 | { | ||
134 | struct mstp_clock *clock = to_mstp_clock(hw); | ||
135 | struct cpg_mssr_priv *priv = clock->priv; | ||
136 | unsigned int reg = clock->index / 32; | ||
137 | unsigned int bit = clock->index % 32; | ||
138 | struct device *dev = priv->dev; | ||
139 | u32 bitmask = BIT(bit); | ||
140 | unsigned long flags; | ||
141 | unsigned int i; | ||
142 | u32 value; | ||
143 | |||
144 | dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk, | ||
145 | enable ? "ON" : "OFF"); | ||
146 | spin_lock_irqsave(&priv->mstp_lock, flags); | ||
147 | |||
148 | value = clk_readl(priv->base + SMSTPCR(reg)); | ||
149 | if (enable) | ||
150 | value &= ~bitmask; | ||
151 | else | ||
152 | value |= bitmask; | ||
153 | clk_writel(value, priv->base + SMSTPCR(reg)); | ||
154 | |||
155 | spin_unlock_irqrestore(&priv->mstp_lock, flags); | ||
156 | |||
157 | if (!enable) | ||
158 | return 0; | ||
159 | |||
160 | for (i = 1000; i > 0; --i) { | ||
161 | if (!(clk_readl(priv->base + MSTPSR(reg)) & | ||
162 | bitmask)) | ||
163 | break; | ||
164 | cpu_relax(); | ||
165 | } | ||
166 | |||
167 | if (!i) { | ||
168 | dev_err(dev, "Failed to enable SMSTP %p[%d]\n", | ||
169 | priv->base + SMSTPCR(reg), bit); | ||
170 | return -ETIMEDOUT; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int cpg_mstp_clock_enable(struct clk_hw *hw) | ||
177 | { | ||
178 | return cpg_mstp_clock_endisable(hw, true); | ||
179 | } | ||
180 | |||
181 | static void cpg_mstp_clock_disable(struct clk_hw *hw) | ||
182 | { | ||
183 | cpg_mstp_clock_endisable(hw, false); | ||
184 | } | ||
185 | |||
186 | static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) | ||
187 | { | ||
188 | struct mstp_clock *clock = to_mstp_clock(hw); | ||
189 | struct cpg_mssr_priv *priv = clock->priv; | ||
190 | u32 value; | ||
191 | |||
192 | value = clk_readl(priv->base + MSTPSR(clock->index / 32)); | ||
193 | |||
194 | return !(value & BIT(clock->index % 32)); | ||
195 | } | ||
196 | |||
197 | static const struct clk_ops cpg_mstp_clock_ops = { | ||
198 | .enable = cpg_mstp_clock_enable, | ||
199 | .disable = cpg_mstp_clock_disable, | ||
200 | .is_enabled = cpg_mstp_clock_is_enabled, | ||
201 | }; | ||
202 | |||
203 | static | ||
204 | struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec, | ||
205 | void *data) | ||
206 | { | ||
207 | unsigned int clkidx = clkspec->args[1]; | ||
208 | struct cpg_mssr_priv *priv = data; | ||
209 | struct device *dev = priv->dev; | ||
210 | unsigned int idx; | ||
211 | const char *type; | ||
212 | struct clk *clk; | ||
213 | |||
214 | switch (clkspec->args[0]) { | ||
215 | case CPG_CORE: | ||
216 | type = "core"; | ||
217 | if (clkidx > priv->last_dt_core_clk) { | ||
218 | dev_err(dev, "Invalid %s clock index %u\n", type, | ||
219 | clkidx); | ||
220 | return ERR_PTR(-EINVAL); | ||
221 | } | ||
222 | clk = priv->clks[clkidx]; | ||
223 | break; | ||
224 | |||
225 | case CPG_MOD: | ||
226 | type = "module"; | ||
227 | idx = MOD_CLK_PACK(clkidx); | ||
228 | if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) { | ||
229 | dev_err(dev, "Invalid %s clock index %u\n", type, | ||
230 | clkidx); | ||
231 | return ERR_PTR(-EINVAL); | ||
232 | } | ||
233 | clk = priv->clks[priv->num_core_clks + idx]; | ||
234 | break; | ||
235 | |||
236 | default: | ||
237 | dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]); | ||
238 | return ERR_PTR(-EINVAL); | ||
239 | } | ||
240 | |||
241 | if (IS_ERR(clk)) | ||
242 | dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx, | ||
243 | PTR_ERR(clk)); | ||
244 | else | ||
245 | dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n", | ||
246 | clkspec->args[0], clkspec->args[1], clk, clk); | ||
247 | return clk; | ||
248 | } | ||
249 | |||
250 | static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, | ||
251 | const struct cpg_mssr_info *info, | ||
252 | struct cpg_mssr_priv *priv) | ||
253 | { | ||
254 | struct clk *clk = NULL, *parent; | ||
255 | struct device *dev = priv->dev; | ||
256 | unsigned int id = core->id; | ||
257 | const char *parent_name; | ||
258 | |||
259 | WARN_DEBUG(id >= priv->num_core_clks); | ||
260 | WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); | ||
261 | |||
262 | switch (core->type) { | ||
263 | case CLK_TYPE_IN: | ||
264 | clk = of_clk_get_by_name(priv->dev->of_node, core->name); | ||
265 | break; | ||
266 | |||
267 | case CLK_TYPE_FF: | ||
268 | case CLK_TYPE_DIV6P1: | ||
269 | WARN_DEBUG(core->parent >= priv->num_core_clks); | ||
270 | parent = priv->clks[core->parent]; | ||
271 | if (IS_ERR(parent)) { | ||
272 | clk = parent; | ||
273 | goto fail; | ||
274 | } | ||
275 | |||
276 | parent_name = __clk_get_name(parent); | ||
277 | if (core->type == CLK_TYPE_FF) { | ||
278 | clk = clk_register_fixed_factor(NULL, core->name, | ||
279 | parent_name, 0, | ||
280 | core->mult, core->div); | ||
281 | } else { | ||
282 | clk = cpg_div6_register(core->name, 1, &parent_name, | ||
283 | priv->base + core->offset); | ||
284 | } | ||
285 | break; | ||
286 | |||
287 | default: | ||
288 | if (info->cpg_clk_register) | ||
289 | clk = info->cpg_clk_register(dev, core, info, | ||
290 | priv->clks, priv->base); | ||
291 | else | ||
292 | dev_err(dev, "%s has unsupported core clock type %u\n", | ||
293 | core->name, core->type); | ||
294 | break; | ||
295 | } | ||
296 | |||
297 | if (IS_ERR_OR_NULL(clk)) | ||
298 | goto fail; | ||
299 | |||
300 | dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk); | ||
301 | priv->clks[id] = clk; | ||
302 | return; | ||
303 | |||
304 | fail: | ||
305 | dev_err(dev, "Failed to register %s clock %s: %ld\n", "core,", | ||
306 | core->name, PTR_ERR(clk)); | ||
307 | } | ||
308 | |||
309 | static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod, | ||
310 | const struct cpg_mssr_info *info, | ||
311 | struct cpg_mssr_priv *priv) | ||
312 | { | ||
313 | struct mstp_clock *clock = NULL; | ||
314 | struct device *dev = priv->dev; | ||
315 | unsigned int id = mod->id; | ||
316 | struct clk_init_data init; | ||
317 | struct clk *parent, *clk; | ||
318 | const char *parent_name; | ||
319 | unsigned int i; | ||
320 | |||
321 | WARN_DEBUG(id < priv->num_core_clks); | ||
322 | WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks); | ||
323 | WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks); | ||
324 | WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); | ||
325 | |||
326 | parent = priv->clks[mod->parent]; | ||
327 | if (IS_ERR(parent)) { | ||
328 | clk = parent; | ||
329 | goto fail; | ||
330 | } | ||
331 | |||
332 | clock = kzalloc(sizeof(*clock), GFP_KERNEL); | ||
333 | if (!clock) { | ||
334 | clk = ERR_PTR(-ENOMEM); | ||
335 | goto fail; | ||
336 | } | ||
337 | |||
338 | init.name = mod->name; | ||
339 | init.ops = &cpg_mstp_clock_ops; | ||
340 | init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; | ||
341 | for (i = 0; i < info->num_crit_mod_clks; i++) | ||
342 | if (id == info->crit_mod_clks[i]) { | ||
343 | #ifdef CLK_ENABLE_HAND_OFF | ||
344 | dev_dbg(dev, "MSTP %s setting CLK_ENABLE_HAND_OFF\n", | ||
345 | mod->name); | ||
346 | init.flags |= CLK_ENABLE_HAND_OFF; | ||
347 | break; | ||
348 | #else | ||
349 | dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n", | ||
350 | mod->name); | ||
351 | return; | ||
352 | #endif | ||
353 | } | ||
354 | |||
355 | parent_name = __clk_get_name(parent); | ||
356 | init.parent_names = &parent_name; | ||
357 | init.num_parents = 1; | ||
358 | |||
359 | clock->index = id - priv->num_core_clks; | ||
360 | clock->priv = priv; | ||
361 | clock->hw.init = &init; | ||
362 | |||
363 | clk = clk_register(NULL, &clock->hw); | ||
364 | if (IS_ERR(clk)) | ||
365 | goto fail; | ||
366 | |||
367 | dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk); | ||
368 | priv->clks[id] = clk; | ||
369 | return; | ||
370 | |||
371 | fail: | ||
372 | dev_err(dev, "Failed to register %s clock %s: %ld\n", "module,", | ||
373 | mod->name, PTR_ERR(clk)); | ||
374 | kfree(clock); | ||
375 | } | ||
376 | |||
377 | |||
378 | #ifdef CONFIG_PM_GENERIC_DOMAINS_OF | ||
379 | struct cpg_mssr_clk_domain { | ||
380 | struct generic_pm_domain genpd; | ||
381 | struct device_node *np; | ||
382 | unsigned int num_core_pm_clks; | ||
383 | unsigned int core_pm_clks[0]; | ||
384 | }; | ||
385 | |||
386 | static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec, | ||
387 | struct cpg_mssr_clk_domain *pd) | ||
388 | { | ||
389 | unsigned int i; | ||
390 | |||
391 | if (clkspec->np != pd->np || clkspec->args_count != 2) | ||
392 | return false; | ||
393 | |||
394 | switch (clkspec->args[0]) { | ||
395 | case CPG_CORE: | ||
396 | for (i = 0; i < pd->num_core_pm_clks; i++) | ||
397 | if (clkspec->args[1] == pd->core_pm_clks[i]) | ||
398 | return true; | ||
399 | return false; | ||
400 | |||
401 | case CPG_MOD: | ||
402 | return true; | ||
403 | |||
404 | default: | ||
405 | return false; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd, | ||
410 | struct device *dev) | ||
411 | { | ||
412 | struct cpg_mssr_clk_domain *pd = | ||
413 | container_of(genpd, struct cpg_mssr_clk_domain, genpd); | ||
414 | struct device_node *np = dev->of_node; | ||
415 | struct of_phandle_args clkspec; | ||
416 | struct clk *clk; | ||
417 | int i = 0; | ||
418 | int error; | ||
419 | |||
420 | while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, | ||
421 | &clkspec)) { | ||
422 | if (cpg_mssr_is_pm_clk(&clkspec, pd)) | ||
423 | goto found; | ||
424 | |||
425 | of_node_put(clkspec.np); | ||
426 | i++; | ||
427 | } | ||
428 | |||
429 | return 0; | ||
430 | |||
431 | found: | ||
432 | clk = of_clk_get_from_provider(&clkspec); | ||
433 | of_node_put(clkspec.np); | ||
434 | |||
435 | if (IS_ERR(clk)) | ||
436 | return PTR_ERR(clk); | ||
437 | |||
438 | error = pm_clk_create(dev); | ||
439 | if (error) { | ||
440 | dev_err(dev, "pm_clk_create failed %d\n", error); | ||
441 | goto fail_put; | ||
442 | } | ||
443 | |||
444 | error = pm_clk_add_clk(dev, clk); | ||
445 | if (error) { | ||
446 | dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error); | ||
447 | goto fail_destroy; | ||
448 | } | ||
449 | |||
450 | return 0; | ||
451 | |||
452 | fail_destroy: | ||
453 | pm_clk_destroy(dev); | ||
454 | fail_put: | ||
455 | clk_put(clk); | ||
456 | return error; | ||
457 | } | ||
458 | |||
459 | static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd, | ||
460 | struct device *dev) | ||
461 | { | ||
462 | if (!list_empty(&dev->power.subsys_data->clock_list)) | ||
463 | pm_clk_destroy(dev); | ||
464 | } | ||
465 | |||
466 | static int __init cpg_mssr_add_clk_domain(struct device *dev, | ||
467 | const unsigned int *core_pm_clks, | ||
468 | unsigned int num_core_pm_clks) | ||
469 | { | ||
470 | struct device_node *np = dev->of_node; | ||
471 | struct generic_pm_domain *genpd; | ||
472 | struct cpg_mssr_clk_domain *pd; | ||
473 | size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]); | ||
474 | |||
475 | pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL); | ||
476 | if (!pd) | ||
477 | return -ENOMEM; | ||
478 | |||
479 | pd->np = np; | ||
480 | pd->num_core_pm_clks = num_core_pm_clks; | ||
481 | memcpy(pd->core_pm_clks, core_pm_clks, pm_size); | ||
482 | |||
483 | genpd = &pd->genpd; | ||
484 | genpd->name = np->name; | ||
485 | genpd->flags = GENPD_FLAG_PM_CLK; | ||
486 | pm_genpd_init(genpd, &simple_qos_governor, false); | ||
487 | genpd->attach_dev = cpg_mssr_attach_dev; | ||
488 | genpd->detach_dev = cpg_mssr_detach_dev; | ||
489 | |||
490 | of_genpd_add_provider_simple(np, genpd); | ||
491 | return 0; | ||
492 | } | ||
493 | #else | ||
494 | static inline int cpg_mssr_add_clk_domain(struct device *dev, | ||
495 | const unsigned int *core_pm_clks, | ||
496 | unsigned int num_core_pm_clks) | ||
497 | { | ||
498 | return 0; | ||
499 | } | ||
500 | #endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */ | ||
501 | |||
502 | |||
503 | static const struct of_device_id cpg_mssr_match[] = { | ||
504 | #ifdef CONFIG_ARCH_R8A7795 | ||
505 | { | ||
506 | .compatible = "renesas,r8a7795-cpg-mssr", | ||
507 | .data = &r8a7795_cpg_mssr_info, | ||
508 | }, | ||
509 | #endif | ||
510 | { /* sentinel */ } | ||
511 | }; | ||
512 | |||
513 | static void cpg_mssr_del_clk_provider(void *data) | ||
514 | { | ||
515 | of_clk_del_provider(data); | ||
516 | } | ||
517 | |||
518 | static int __init cpg_mssr_probe(struct platform_device *pdev) | ||
519 | { | ||
520 | struct device *dev = &pdev->dev; | ||
521 | struct device_node *np = dev->of_node; | ||
522 | const struct cpg_mssr_info *info; | ||
523 | struct cpg_mssr_priv *priv; | ||
524 | unsigned int nclks, i; | ||
525 | struct resource *res; | ||
526 | struct clk **clks; | ||
527 | int error; | ||
528 | |||
529 | info = of_match_node(cpg_mssr_match, np)->data; | ||
530 | if (info->init) { | ||
531 | error = info->init(dev); | ||
532 | if (error) | ||
533 | return error; | ||
534 | } | ||
535 | |||
536 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
537 | if (!priv) | ||
538 | return -ENOMEM; | ||
539 | |||
540 | priv->dev = dev; | ||
541 | spin_lock_init(&priv->mstp_lock); | ||
542 | |||
543 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
544 | priv->base = devm_ioremap_resource(dev, res); | ||
545 | if (IS_ERR(priv->base)) | ||
546 | return PTR_ERR(priv->base); | ||
547 | |||
548 | nclks = info->num_total_core_clks + info->num_hw_mod_clks; | ||
549 | clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL); | ||
550 | if (!clks) | ||
551 | return -ENOMEM; | ||
552 | |||
553 | priv->clks = clks; | ||
554 | priv->num_core_clks = info->num_total_core_clks; | ||
555 | priv->num_mod_clks = info->num_hw_mod_clks; | ||
556 | priv->last_dt_core_clk = info->last_dt_core_clk; | ||
557 | |||
558 | for (i = 0; i < nclks; i++) | ||
559 | clks[i] = ERR_PTR(-ENOENT); | ||
560 | |||
561 | for (i = 0; i < info->num_core_clks; i++) | ||
562 | cpg_mssr_register_core_clk(&info->core_clks[i], info, priv); | ||
563 | |||
564 | for (i = 0; i < info->num_mod_clks; i++) | ||
565 | cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv); | ||
566 | |||
567 | error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv); | ||
568 | if (error) | ||
569 | return error; | ||
570 | |||
571 | devm_add_action(dev, cpg_mssr_del_clk_provider, np); | ||
572 | |||
573 | error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks, | ||
574 | info->num_core_pm_clks); | ||
575 | if (error) | ||
576 | return error; | ||
577 | |||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static struct platform_driver cpg_mssr_driver = { | ||
582 | .driver = { | ||
583 | .name = "renesas-cpg-mssr", | ||
584 | .of_match_table = cpg_mssr_match, | ||
585 | }, | ||
586 | }; | ||
587 | |||
588 | static int __init cpg_mssr_init(void) | ||
589 | { | ||
590 | return platform_driver_probe(&cpg_mssr_driver, cpg_mssr_probe); | ||
591 | } | ||
592 | |||
593 | subsys_initcall(cpg_mssr_init); | ||
594 | |||
595 | MODULE_DESCRIPTION("Renesas CPG/MSSR Driver"); | ||
596 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/clk/shmobile/renesas-cpg-mssr.h b/drivers/clk/shmobile/renesas-cpg-mssr.h new file mode 100644 index 000000000000..e09f03cbf086 --- /dev/null +++ b/drivers/clk/shmobile/renesas-cpg-mssr.h | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * Renesas Clock Pulse Generator / Module Standby and Software Reset | ||
3 | * | ||
4 | * Copyright (C) 2015 Glider bvba | ||
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 as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | */ | ||
10 | |||
11 | #ifndef __CLK_RENESAS_CPG_MSSR_H__ | ||
12 | #define __CLK_RENESAS_CPG_MSSR_H__ | ||
13 | |||
14 | /* | ||
15 | * Definitions of CPG Core Clocks | ||
16 | * | ||
17 | * These include: | ||
18 | * - Clock outputs exported to DT | ||
19 | * - External input clocks | ||
20 | * - Internal CPG clocks | ||
21 | */ | ||
22 | |||
23 | struct cpg_core_clk { | ||
24 | /* Common */ | ||
25 | const char *name; | ||
26 | unsigned int id; | ||
27 | unsigned int type; | ||
28 | /* Depending on type */ | ||
29 | unsigned int parent; /* Core Clocks only */ | ||
30 | unsigned int div; | ||
31 | unsigned int mult; | ||
32 | unsigned int offset; | ||
33 | }; | ||
34 | |||
35 | enum clk_types { | ||
36 | /* Generic */ | ||
37 | CLK_TYPE_IN, /* External Clock Input */ | ||
38 | CLK_TYPE_FF, /* Fixed Factor Clock */ | ||
39 | CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */ | ||
40 | |||
41 | /* Custom definitions start here */ | ||
42 | CLK_TYPE_CUSTOM, | ||
43 | }; | ||
44 | |||
45 | #define DEF_TYPE(_name, _id, _type...) \ | ||
46 | { .name = _name, .id = _id, .type = _type } | ||
47 | #define DEF_BASE(_name, _id, _type, _parent...) \ | ||
48 | DEF_TYPE(_name, _id, _type, .parent = _parent) | ||
49 | |||
50 | #define DEF_INPUT(_name, _id) \ | ||
51 | DEF_TYPE(_name, _id, CLK_TYPE_IN) | ||
52 | #define DEF_FIXED(_name, _id, _parent, _div, _mult) \ | ||
53 | DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult) | ||
54 | #define DEF_DIV6P1(_name, _id, _parent, _offset) \ | ||
55 | DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset) | ||
56 | |||
57 | |||
58 | /* | ||
59 | * Definitions of Module Clocks | ||
60 | */ | ||
61 | |||
62 | struct mssr_mod_clk { | ||
63 | const char *name; | ||
64 | unsigned int id; | ||
65 | unsigned int parent; /* Add MOD_CLK_BASE for Module Clocks */ | ||
66 | }; | ||
67 | |||
68 | /* Convert from sparse base-100 to packed index space */ | ||
69 | #define MOD_CLK_PACK(x) ((x) - ((x) / 100) * (100 - 32)) | ||
70 | |||
71 | #define MOD_CLK_ID(x) (MOD_CLK_BASE + MOD_CLK_PACK(x)) | ||
72 | |||
73 | #define DEF_MOD(_name, _mod, _parent...) \ | ||
74 | { .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent } | ||
75 | |||
76 | |||
77 | struct device_node; | ||
78 | |||
79 | /** | ||
80 | * SoC-specific CPG/MSSR Description | ||
81 | * | ||
82 | * @core_clks: Array of Core Clock definitions | ||
83 | * @num_core_clks: Number of entries in core_clks[] | ||
84 | * @last_dt_core_clk: ID of the last Core Clock exported to DT | ||
85 | * @num_total_core_clks: Total number of Core Clocks (exported + internal) | ||
86 | * | ||
87 | * @mod_clks: Array of Module Clock definitions | ||
88 | * @num_mod_clks: Number of entries in mod_clks[] | ||
89 | * @num_hw_mod_clks: Number of Module Clocks supported by the hardware | ||
90 | * | ||
91 | * @crit_mod_clks: Array with Module Clock IDs of critical clocks that | ||
92 | * should not be disabled without a knowledgeable driver | ||
93 | * @num_crit_mod_clks: Number of entries in crit_mod_clks[] | ||
94 | * | ||
95 | * @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power | ||
96 | * Management, in addition to Module Clocks | ||
97 | * @num_core_pm_clks: Number of entries in core_pm_clks[] | ||
98 | * | ||
99 | * @init: Optional callback to perform SoC-specific initialization | ||
100 | * @cpg_clk_register: Optional callback to handle special Core Clock types | ||
101 | */ | ||
102 | |||
103 | struct cpg_mssr_info { | ||
104 | /* Core Clocks */ | ||
105 | const struct cpg_core_clk *core_clks; | ||
106 | unsigned int num_core_clks; | ||
107 | unsigned int last_dt_core_clk; | ||
108 | unsigned int num_total_core_clks; | ||
109 | |||
110 | /* Module Clocks */ | ||
111 | const struct mssr_mod_clk *mod_clks; | ||
112 | unsigned int num_mod_clks; | ||
113 | unsigned int num_hw_mod_clks; | ||
114 | |||
115 | /* Critical Module Clocks that should not be disabled */ | ||
116 | const unsigned int *crit_mod_clks; | ||
117 | unsigned int num_crit_mod_clks; | ||
118 | |||
119 | /* Core Clocks suitable for PM, in addition to the Module Clocks */ | ||
120 | const unsigned int *core_pm_clks; | ||
121 | unsigned int num_core_pm_clks; | ||
122 | |||
123 | /* Callbacks */ | ||
124 | int (*init)(struct device *dev); | ||
125 | struct clk *(*cpg_clk_register)(struct device *dev, | ||
126 | const struct cpg_core_clk *core, | ||
127 | const struct cpg_mssr_info *info, | ||
128 | struct clk **clks, void __iomem *base); | ||
129 | }; | ||
130 | |||
131 | extern const struct cpg_mssr_info r8a7795_cpg_mssr_info; | ||
132 | #endif | ||