diff options
Diffstat (limited to 'drivers/clk/sunxi')
-rw-r--r-- | drivers/clk/sunxi/Makefile | 4 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-a20-gmac.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-factors.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-factors.h | 1 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 76 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sun6i-apb0.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sun6i-ar100.c | 4 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sun8i-apb0.c | 68 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 129 |
9 files changed, 236 insertions, 52 deletions
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 762fd64dbd1f..6850cba35871 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile | |||
@@ -6,4 +6,6 @@ obj-y += clk-sunxi.o clk-factors.o | |||
6 | obj-y += clk-a10-hosc.o | 6 | obj-y += clk-a10-hosc.o |
7 | obj-y += clk-a20-gmac.o | 7 | obj-y += clk-a20-gmac.o |
8 | 8 | ||
9 | obj-$(CONFIG_MFD_SUN6I_PRCM) += clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o | 9 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ |
10 | clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ | ||
11 | clk-sun8i-apb0.o | ||
diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c index 633ddc4389ef..5296fd6dd7b3 100644 --- a/drivers/clk/sunxi/clk-a20-gmac.c +++ b/drivers/clk/sunxi/clk-a20-gmac.c | |||
@@ -60,7 +60,7 @@ static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) | |||
60 | struct clk_gate *gate; | 60 | struct clk_gate *gate; |
61 | const char *clk_name = node->name; | 61 | const char *clk_name = node->name; |
62 | const char *parents[SUN7I_A20_GMAC_PARENTS]; | 62 | const char *parents[SUN7I_A20_GMAC_PARENTS]; |
63 | void *reg; | 63 | void __iomem *reg; |
64 | 64 | ||
65 | if (of_property_read_string(node, "clock-output-names", &clk_name)) | 65 | if (of_property_read_string(node, "clock-output-names", &clk_name)) |
66 | return; | 66 | return; |
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index 3806d97e529b..2057c8ac648f 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c | |||
@@ -62,7 +62,7 @@ static unsigned long clk_factors_recalc_rate(struct clk_hw *hw, | |||
62 | p = FACTOR_GET(config->pshift, config->pwidth, reg); | 62 | p = FACTOR_GET(config->pshift, config->pwidth, reg); |
63 | 63 | ||
64 | /* Calculate the rate */ | 64 | /* Calculate the rate */ |
65 | rate = (parent_rate * n * (k + 1) >> p) / (m + 1); | 65 | rate = (parent_rate * (n + config->n_start) * (k + 1) >> p) / (m + 1); |
66 | 66 | ||
67 | return rate; | 67 | return rate; |
68 | } | 68 | } |
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h index 02e1a43ebac7..d2d0efa39379 100644 --- a/drivers/clk/sunxi/clk-factors.h +++ b/drivers/clk/sunxi/clk-factors.h | |||
@@ -15,6 +15,7 @@ struct clk_factors_config { | |||
15 | u8 mwidth; | 15 | u8 mwidth; |
16 | u8 pshift; | 16 | u8 pshift; |
17 | u8 pwidth; | 17 | u8 pwidth; |
18 | u8 n_start; | ||
18 | }; | 19 | }; |
19 | 20 | ||
20 | struct clk_factors { | 21 | struct clk_factors { |
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c index 670f90d629d7..e10d0521ec76 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c | |||
@@ -9,23 +9,53 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/clk-provider.h> | 11 | #include <linux/clk-provider.h> |
12 | #include <linux/clkdev.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_device.h> | ||
14 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
15 | 17 | ||
16 | #define SUN6I_APB0_GATES_MAX_SIZE 32 | 18 | #define SUN6I_APB0_GATES_MAX_SIZE 32 |
17 | 19 | ||
20 | struct gates_data { | ||
21 | DECLARE_BITMAP(mask, SUN6I_APB0_GATES_MAX_SIZE); | ||
22 | }; | ||
23 | |||
24 | static const struct gates_data sun6i_a31_apb0_gates __initconst = { | ||
25 | .mask = {0x7F}, | ||
26 | }; | ||
27 | |||
28 | static const struct gates_data sun8i_a23_apb0_gates __initconst = { | ||
29 | .mask = {0x5D}, | ||
30 | }; | ||
31 | |||
32 | static const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = { | ||
33 | { .compatible = "allwinner,sun6i-a31-apb0-gates-clk", .data = &sun6i_a31_apb0_gates }, | ||
34 | { .compatible = "allwinner,sun8i-a23-apb0-gates-clk", .data = &sun8i_a23_apb0_gates }, | ||
35 | { /* sentinel */ } | ||
36 | }; | ||
37 | |||
18 | static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) | 38 | static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) |
19 | { | 39 | { |
20 | struct device_node *np = pdev->dev.of_node; | 40 | struct device_node *np = pdev->dev.of_node; |
21 | struct clk_onecell_data *clk_data; | 41 | struct clk_onecell_data *clk_data; |
42 | const struct of_device_id *device; | ||
43 | const struct gates_data *data; | ||
22 | const char *clk_parent; | 44 | const char *clk_parent; |
23 | const char *clk_name; | 45 | const char *clk_name; |
24 | struct resource *r; | 46 | struct resource *r; |
25 | void __iomem *reg; | 47 | void __iomem *reg; |
26 | int gate_id; | ||
27 | int ngates; | 48 | int ngates; |
28 | int i; | 49 | int i; |
50 | int j = 0; | ||
51 | |||
52 | if (!np) | ||
53 | return -ENODEV; | ||
54 | |||
55 | device = of_match_device(sun6i_a31_apb0_gates_clk_dt_ids, &pdev->dev); | ||
56 | if (!device) | ||
57 | return -ENODEV; | ||
58 | data = device->data; | ||
29 | 59 | ||
30 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 60 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
31 | reg = devm_ioremap_resource(&pdev->dev, r); | 61 | reg = devm_ioremap_resource(&pdev->dev, r); |
@@ -36,54 +66,36 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) | |||
36 | if (!clk_parent) | 66 | if (!clk_parent) |
37 | return -EINVAL; | 67 | return -EINVAL; |
38 | 68 | ||
39 | ngates = of_property_count_strings(np, "clock-output-names"); | ||
40 | if (ngates < 0) | ||
41 | return ngates; | ||
42 | |||
43 | if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE) | ||
44 | return -EINVAL; | ||
45 | |||
46 | clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), | 69 | clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), |
47 | GFP_KERNEL); | 70 | GFP_KERNEL); |
48 | if (!clk_data) | 71 | if (!clk_data) |
49 | return -ENOMEM; | 72 | return -ENOMEM; |
50 | 73 | ||
51 | clk_data->clks = devm_kzalloc(&pdev->dev, | 74 | /* Worst-case size approximation and memory allocation */ |
52 | SUN6I_APB0_GATES_MAX_SIZE * | 75 | ngates = find_last_bit(data->mask, SUN6I_APB0_GATES_MAX_SIZE); |
53 | sizeof(struct clk *), | 76 | clk_data->clks = devm_kcalloc(&pdev->dev, (ngates + 1), |
54 | GFP_KERNEL); | 77 | sizeof(struct clk *), GFP_KERNEL); |
55 | if (!clk_data->clks) | 78 | if (!clk_data->clks) |
56 | return -ENOMEM; | 79 | return -ENOMEM; |
57 | 80 | ||
58 | for (i = 0; i < ngates; i++) { | 81 | for_each_set_bit(i, data->mask, SUN6I_APB0_GATES_MAX_SIZE) { |
59 | of_property_read_string_index(np, "clock-output-names", | 82 | of_property_read_string_index(np, "clock-output-names", |
60 | i, &clk_name); | 83 | j, &clk_name); |
61 | 84 | ||
62 | gate_id = i; | 85 | clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name, |
63 | of_property_read_u32_index(np, "clock-indices", i, &gate_id); | 86 | clk_parent, 0, reg, i, |
87 | 0, NULL); | ||
88 | WARN_ON(IS_ERR(clk_data->clks[i])); | ||
89 | clk_register_clkdev(clk_data->clks[i], clk_name, NULL); | ||
64 | 90 | ||
65 | WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE); | 91 | j++; |
66 | if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE) | ||
67 | continue; | ||
68 | |||
69 | clk_data->clks[gate_id] = clk_register_gate(&pdev->dev, | ||
70 | clk_name, | ||
71 | clk_parent, 0, | ||
72 | reg, gate_id, | ||
73 | 0, NULL); | ||
74 | WARN_ON(IS_ERR(clk_data->clks[gate_id])); | ||
75 | } | 92 | } |
76 | 93 | ||
77 | clk_data->clk_num = ngates; | 94 | clk_data->clk_num = ngates + 1; |
78 | 95 | ||
79 | return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | 96 | return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); |
80 | } | 97 | } |
81 | 98 | ||
82 | const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = { | ||
83 | { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" }, | ||
84 | { /* sentinel */ } | ||
85 | }; | ||
86 | |||
87 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { | 99 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { |
88 | .driver = { | 100 | .driver = { |
89 | .name = "sun6i-a31-apb0-gates-clk", | 101 | .name = "sun6i-a31-apb0-gates-clk", |
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c index 11f17c34c2ae..1fa23371c8c6 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0.c | |||
@@ -57,7 +57,7 @@ static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev) | |||
57 | return of_clk_add_provider(np, of_clk_src_simple_get, clk); | 57 | return of_clk_add_provider(np, of_clk_src_simple_get, clk); |
58 | } | 58 | } |
59 | 59 | ||
60 | const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = { | 60 | static const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = { |
61 | { .compatible = "allwinner,sun6i-a31-apb0-clk" }, | 61 | { .compatible = "allwinner,sun6i-a31-apb0-clk" }, |
62 | { /* sentinel */ } | 62 | { /* sentinel */ } |
63 | }; | 63 | }; |
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c index f73cc051f0dd..eca8ca025b6a 100644 --- a/drivers/clk/sunxi/clk-sun6i-ar100.c +++ b/drivers/clk/sunxi/clk-sun6i-ar100.c | |||
@@ -160,7 +160,7 @@ static int ar100_set_rate(struct clk_hw *hw, unsigned long rate, | |||
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
162 | 162 | ||
163 | struct clk_ops ar100_ops = { | 163 | static struct clk_ops ar100_ops = { |
164 | .recalc_rate = ar100_recalc_rate, | 164 | .recalc_rate = ar100_recalc_rate, |
165 | .determine_rate = ar100_determine_rate, | 165 | .determine_rate = ar100_determine_rate, |
166 | .set_parent = ar100_set_parent, | 166 | .set_parent = ar100_set_parent, |
@@ -213,7 +213,7 @@ static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev) | |||
213 | return of_clk_add_provider(np, of_clk_src_simple_get, clk); | 213 | return of_clk_add_provider(np, of_clk_src_simple_get, clk); |
214 | } | 214 | } |
215 | 215 | ||
216 | const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = { | 216 | static const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = { |
217 | { .compatible = "allwinner,sun6i-a31-ar100-clk" }, | 217 | { .compatible = "allwinner,sun6i-a31-ar100-clk" }, |
218 | { /* sentinel */ } | 218 | { /* sentinel */ } |
219 | }; | 219 | }; |
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c new file mode 100644 index 000000000000..1f5ba9b4b8cd --- /dev/null +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Chen-Yu Tsai | ||
3 | * Author: Chen-Yu Tsai <wens@csie.org> | ||
4 | * | ||
5 | * Allwinner A23 APB0 clock driver | ||
6 | * | ||
7 | * License Terms: GNU General Public License v2 | ||
8 | * | ||
9 | * Based on clk-sun6i-apb0.c | ||
10 | * Allwinner A31 APB0 clock driver | ||
11 | * | ||
12 | * Copyright (C) 2014 Free Electrons | ||
13 | * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/clk-provider.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) | ||
23 | { | ||
24 | struct device_node *np = pdev->dev.of_node; | ||
25 | const char *clk_name = np->name; | ||
26 | const char *clk_parent; | ||
27 | struct resource *r; | ||
28 | void __iomem *reg; | ||
29 | struct clk *clk; | ||
30 | |||
31 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
32 | reg = devm_ioremap_resource(&pdev->dev, r); | ||
33 | if (IS_ERR(reg)) | ||
34 | return PTR_ERR(reg); | ||
35 | |||
36 | clk_parent = of_clk_get_parent_name(np, 0); | ||
37 | if (!clk_parent) | ||
38 | return -EINVAL; | ||
39 | |||
40 | of_property_read_string(np, "clock-output-names", &clk_name); | ||
41 | |||
42 | /* The A23 APB0 clock is a standard 2 bit wide divider clock */ | ||
43 | clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg, | ||
44 | 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); | ||
45 | if (IS_ERR(clk)) | ||
46 | return PTR_ERR(clk); | ||
47 | |||
48 | return of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
49 | } | ||
50 | |||
51 | static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { | ||
52 | { .compatible = "allwinner,sun8i-a23-apb0-clk" }, | ||
53 | { /* sentinel */ } | ||
54 | }; | ||
55 | |||
56 | static struct platform_driver sun8i_a23_apb0_clk_driver = { | ||
57 | .driver = { | ||
58 | .name = "sun8i-a23-apb0-clk", | ||
59 | .owner = THIS_MODULE, | ||
60 | .of_match_table = sun8i_a23_apb0_clk_dt_ids, | ||
61 | }, | ||
62 | .probe = sun8i_a23_apb0_clk_probe, | ||
63 | }; | ||
64 | module_platform_driver(sun8i_a23_apb0_clk_driver); | ||
65 | |||
66 | MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); | ||
67 | MODULE_DESCRIPTION("Allwinner A23 APB0 clock Driver"); | ||
68 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index fb2ce8440f0e..b654b7b1d137 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -164,6 +164,54 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate, | |||
164 | } | 164 | } |
165 | 165 | ||
166 | /** | 166 | /** |
167 | * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1 | ||
168 | * PLL1 rate is calculated as follows | ||
169 | * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1); | ||
170 | * parent_rate is always 24Mhz | ||
171 | */ | ||
172 | |||
173 | static void sun8i_a23_get_pll1_factors(u32 *freq, u32 parent_rate, | ||
174 | u8 *n, u8 *k, u8 *m, u8 *p) | ||
175 | { | ||
176 | u8 div; | ||
177 | |||
178 | /* Normalize value to a 6M multiple */ | ||
179 | div = *freq / 6000000; | ||
180 | *freq = 6000000 * div; | ||
181 | |||
182 | /* we were called to round the frequency, we can now return */ | ||
183 | if (n == NULL) | ||
184 | return; | ||
185 | |||
186 | /* m is always zero for pll1 */ | ||
187 | *m = 0; | ||
188 | |||
189 | /* k is 1 only on these cases */ | ||
190 | if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000) | ||
191 | *k = 1; | ||
192 | else | ||
193 | *k = 0; | ||
194 | |||
195 | /* p will be 2 for divs under 20 and odd divs under 32 */ | ||
196 | if (div < 20 || (div < 32 && (div & 1))) | ||
197 | *p = 2; | ||
198 | |||
199 | /* p will be 1 for even divs under 32, divs under 40 and odd pairs | ||
200 | * of divs between 40-62 */ | ||
201 | else if (div < 40 || (div < 64 && (div & 2))) | ||
202 | *p = 1; | ||
203 | |||
204 | /* any other entries have p = 0 */ | ||
205 | else | ||
206 | *p = 0; | ||
207 | |||
208 | /* calculate a suitable n based on k and p */ | ||
209 | div <<= *p; | ||
210 | div /= (*k + 1); | ||
211 | *n = div / 4 - 1; | ||
212 | } | ||
213 | |||
214 | /** | ||
167 | * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 | 215 | * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 |
168 | * PLL5 rate is calculated as follows | 216 | * PLL5 rate is calculated as follows |
169 | * rate = parent_rate * n * (k + 1) | 217 | * rate = parent_rate * n * (k + 1) |
@@ -422,6 +470,18 @@ static struct clk_factors_config sun6i_a31_pll1_config = { | |||
422 | .mwidth = 2, | 470 | .mwidth = 2, |
423 | }; | 471 | }; |
424 | 472 | ||
473 | static struct clk_factors_config sun8i_a23_pll1_config = { | ||
474 | .nshift = 8, | ||
475 | .nwidth = 5, | ||
476 | .kshift = 4, | ||
477 | .kwidth = 2, | ||
478 | .mshift = 0, | ||
479 | .mwidth = 2, | ||
480 | .pshift = 16, | ||
481 | .pwidth = 2, | ||
482 | .n_start = 1, | ||
483 | }; | ||
484 | |||
425 | static struct clk_factors_config sun4i_pll5_config = { | 485 | static struct clk_factors_config sun4i_pll5_config = { |
426 | .nshift = 8, | 486 | .nshift = 8, |
427 | .nwidth = 5, | 487 | .nwidth = 5, |
@@ -471,6 +531,12 @@ static const struct factors_data sun6i_a31_pll1_data __initconst = { | |||
471 | .getter = sun6i_a31_get_pll1_factors, | 531 | .getter = sun6i_a31_get_pll1_factors, |
472 | }; | 532 | }; |
473 | 533 | ||
534 | static const struct factors_data sun8i_a23_pll1_data __initconst = { | ||
535 | .enable = 31, | ||
536 | .table = &sun8i_a23_pll1_config, | ||
537 | .getter = sun8i_a23_get_pll1_factors, | ||
538 | }; | ||
539 | |||
474 | static const struct factors_data sun7i_a20_pll4_data __initconst = { | 540 | static const struct factors_data sun7i_a20_pll4_data __initconst = { |
475 | .enable = 31, | 541 | .enable = 31, |
476 | .table = &sun4i_pll5_config, | 542 | .table = &sun4i_pll5_config, |
@@ -527,7 +593,7 @@ static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, | |||
527 | struct clk_hw *mux_hw = NULL; | 593 | struct clk_hw *mux_hw = NULL; |
528 | const char *clk_name = node->name; | 594 | const char *clk_name = node->name; |
529 | const char *parents[SUNXI_MAX_PARENTS]; | 595 | const char *parents[SUNXI_MAX_PARENTS]; |
530 | void *reg; | 596 | void __iomem *reg; |
531 | int i = 0; | 597 | int i = 0; |
532 | 598 | ||
533 | reg = of_iomap(node, 0); | 599 | reg = of_iomap(node, 0); |
@@ -632,7 +698,7 @@ static void __init sunxi_mux_clk_setup(struct device_node *node, | |||
632 | struct clk *clk; | 698 | struct clk *clk; |
633 | const char *clk_name = node->name; | 699 | const char *clk_name = node->name; |
634 | const char *parents[SUNXI_MAX_PARENTS]; | 700 | const char *parents[SUNXI_MAX_PARENTS]; |
635 | void *reg; | 701 | void __iomem *reg; |
636 | int i = 0; | 702 | int i = 0; |
637 | 703 | ||
638 | reg = of_iomap(node, 0); | 704 | reg = of_iomap(node, 0); |
@@ -664,6 +730,7 @@ struct div_data { | |||
664 | u8 shift; | 730 | u8 shift; |
665 | u8 pow; | 731 | u8 pow; |
666 | u8 width; | 732 | u8 width; |
733 | const struct clk_div_table *table; | ||
667 | }; | 734 | }; |
668 | 735 | ||
669 | static const struct div_data sun4i_axi_data __initconst = { | 736 | static const struct div_data sun4i_axi_data __initconst = { |
@@ -672,6 +739,23 @@ static const struct div_data sun4i_axi_data __initconst = { | |||
672 | .width = 2, | 739 | .width = 2, |
673 | }; | 740 | }; |
674 | 741 | ||
742 | static const struct clk_div_table sun8i_a23_axi_table[] __initconst = { | ||
743 | { .val = 0, .div = 1 }, | ||
744 | { .val = 1, .div = 2 }, | ||
745 | { .val = 2, .div = 3 }, | ||
746 | { .val = 3, .div = 4 }, | ||
747 | { .val = 4, .div = 4 }, | ||
748 | { .val = 5, .div = 4 }, | ||
749 | { .val = 6, .div = 4 }, | ||
750 | { .val = 7, .div = 4 }, | ||
751 | { } /* sentinel */ | ||
752 | }; | ||
753 | |||
754 | static const struct div_data sun8i_a23_axi_data __initconst = { | ||
755 | .width = 3, | ||
756 | .table = sun8i_a23_axi_table, | ||
757 | }; | ||
758 | |||
675 | static const struct div_data sun4i_ahb_data __initconst = { | 759 | static const struct div_data sun4i_ahb_data __initconst = { |
676 | .shift = 4, | 760 | .shift = 4, |
677 | .pow = 1, | 761 | .pow = 1, |
@@ -696,7 +780,7 @@ static void __init sunxi_divider_clk_setup(struct device_node *node, | |||
696 | struct clk *clk; | 780 | struct clk *clk; |
697 | const char *clk_name = node->name; | 781 | const char *clk_name = node->name; |
698 | const char *clk_parent; | 782 | const char *clk_parent; |
699 | void *reg; | 783 | void __iomem *reg; |
700 | 784 | ||
701 | reg = of_iomap(node, 0); | 785 | reg = of_iomap(node, 0); |
702 | 786 | ||
@@ -704,10 +788,10 @@ static void __init sunxi_divider_clk_setup(struct device_node *node, | |||
704 | 788 | ||
705 | of_property_read_string(node, "clock-output-names", &clk_name); | 789 | of_property_read_string(node, "clock-output-names", &clk_name); |
706 | 790 | ||
707 | clk = clk_register_divider(NULL, clk_name, clk_parent, 0, | 791 | clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0, |
708 | reg, data->shift, data->width, | 792 | reg, data->shift, data->width, |
709 | data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0, | 793 | data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0, |
710 | &clk_lock); | 794 | data->table, &clk_lock); |
711 | if (clk) { | 795 | if (clk) { |
712 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 796 | of_clk_add_provider(node, of_clk_src_simple_get, clk); |
713 | clk_register_clkdev(clk, clk_name, NULL); | 797 | clk_register_clkdev(clk, clk_name, NULL); |
@@ -804,6 +888,10 @@ static const struct gates_data sun7i_a20_ahb_gates_data __initconst = { | |||
804 | .mask = { 0x12f77fff, 0x16ff3f }, | 888 | .mask = { 0x12f77fff, 0x16ff3f }, |
805 | }; | 889 | }; |
806 | 890 | ||
891 | static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = { | ||
892 | .mask = {0x25386742, 0x2505111}, | ||
893 | }; | ||
894 | |||
807 | static const struct gates_data sun4i_apb0_gates_data __initconst = { | 895 | static const struct gates_data sun4i_apb0_gates_data __initconst = { |
808 | .mask = {0x4EF}, | 896 | .mask = {0x4EF}, |
809 | }; | 897 | }; |
@@ -836,6 +924,10 @@ static const struct gates_data sun6i_a31_apb1_gates_data __initconst = { | |||
836 | .mask = {0x3031}, | 924 | .mask = {0x3031}, |
837 | }; | 925 | }; |
838 | 926 | ||
927 | static const struct gates_data sun8i_a23_apb1_gates_data __initconst = { | ||
928 | .mask = {0x3021}, | ||
929 | }; | ||
930 | |||
839 | static const struct gates_data sun6i_a31_apb2_gates_data __initconst = { | 931 | static const struct gates_data sun6i_a31_apb2_gates_data __initconst = { |
840 | .mask = {0x3F000F}, | 932 | .mask = {0x3F000F}, |
841 | }; | 933 | }; |
@@ -844,6 +936,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = { | |||
844 | .mask = { 0xff80ff }, | 936 | .mask = { 0xff80ff }, |
845 | }; | 937 | }; |
846 | 938 | ||
939 | static const struct gates_data sun8i_a23_apb2_gates_data __initconst = { | ||
940 | .mask = {0x1F0007}, | ||
941 | }; | ||
942 | |||
847 | static const struct gates_data sun4i_a10_usb_gates_data __initconst = { | 943 | static const struct gates_data sun4i_a10_usb_gates_data __initconst = { |
848 | .mask = {0x1C0}, | 944 | .mask = {0x1C0}, |
849 | .reset_mask = 0x07, | 945 | .reset_mask = 0x07, |
@@ -866,11 +962,10 @@ static void __init sunxi_gates_clk_setup(struct device_node *node, | |||
866 | struct gates_reset_data *reset_data; | 962 | struct gates_reset_data *reset_data; |
867 | const char *clk_parent; | 963 | const char *clk_parent; |
868 | const char *clk_name; | 964 | const char *clk_name; |
869 | void *reg; | 965 | void __iomem *reg; |
870 | int qty; | 966 | int qty; |
871 | int i = 0; | 967 | int i = 0; |
872 | int j = 0; | 968 | int j = 0; |
873 | int ignore; | ||
874 | 969 | ||
875 | reg = of_iomap(node, 0); | 970 | reg = of_iomap(node, 0); |
876 | 971 | ||
@@ -891,14 +986,12 @@ static void __init sunxi_gates_clk_setup(struct device_node *node, | |||
891 | of_property_read_string_index(node, "clock-output-names", | 986 | of_property_read_string_index(node, "clock-output-names", |
892 | j, &clk_name); | 987 | j, &clk_name); |
893 | 988 | ||
894 | /* No driver claims this clock, but it should remain gated */ | ||
895 | ignore = !strcmp("ahb_sdram", clk_name) ? CLK_IGNORE_UNUSED : 0; | ||
896 | |||
897 | clk_data->clks[i] = clk_register_gate(NULL, clk_name, | 989 | clk_data->clks[i] = clk_register_gate(NULL, clk_name, |
898 | clk_parent, ignore, | 990 | clk_parent, 0, |
899 | reg + 4 * (i/32), i % 32, | 991 | reg + 4 * (i/32), i % 32, |
900 | 0, &clk_lock); | 992 | 0, &clk_lock); |
901 | WARN_ON(IS_ERR(clk_data->clks[i])); | 993 | WARN_ON(IS_ERR(clk_data->clks[i])); |
994 | clk_register_clkdev(clk_data->clks[i], clk_name, NULL); | ||
902 | 995 | ||
903 | j++; | 996 | j++; |
904 | } | 997 | } |
@@ -991,7 +1084,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node, | |||
991 | struct clk_gate *gate = NULL; | 1084 | struct clk_gate *gate = NULL; |
992 | struct clk_fixed_factor *fix_factor; | 1085 | struct clk_fixed_factor *fix_factor; |
993 | struct clk_divider *divider; | 1086 | struct clk_divider *divider; |
994 | void *reg; | 1087 | void __iomem *reg; |
995 | int i = 0; | 1088 | int i = 0; |
996 | int flags, clkflags; | 1089 | int flags, clkflags; |
997 | 1090 | ||
@@ -1102,6 +1195,7 @@ free_clkdata: | |||
1102 | static const struct of_device_id clk_factors_match[] __initconst = { | 1195 | static const struct of_device_id clk_factors_match[] __initconst = { |
1103 | {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,}, | 1196 | {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,}, |
1104 | {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, | 1197 | {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, |
1198 | {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,}, | ||
1105 | {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, | 1199 | {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, |
1106 | {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, | 1200 | {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, |
1107 | {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, | 1201 | {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, |
@@ -1113,6 +1207,7 @@ static const struct of_device_id clk_factors_match[] __initconst = { | |||
1113 | /* Matches for divider clocks */ | 1207 | /* Matches for divider clocks */ |
1114 | static const struct of_device_id clk_div_match[] __initconst = { | 1208 | static const struct of_device_id clk_div_match[] __initconst = { |
1115 | {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,}, | 1209 | {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,}, |
1210 | {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,}, | ||
1116 | {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,}, | 1211 | {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,}, |
1117 | {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,}, | 1212 | {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,}, |
1118 | {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,}, | 1213 | {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,}, |
@@ -1142,6 +1237,7 @@ static const struct of_device_id clk_gates_match[] __initconst = { | |||
1142 | {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, | 1237 | {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, |
1143 | {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, | 1238 | {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, |
1144 | {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, | 1239 | {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, |
1240 | {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,}, | ||
1145 | {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, | 1241 | {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, |
1146 | {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, | 1242 | {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, |
1147 | {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, | 1243 | {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, |
@@ -1151,7 +1247,9 @@ static const struct of_device_id clk_gates_match[] __initconst = { | |||
1151 | {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, | 1247 | {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, |
1152 | {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,}, | 1248 | {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,}, |
1153 | {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,}, | 1249 | {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,}, |
1250 | {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,}, | ||
1154 | {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, | 1251 | {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, |
1252 | {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,}, | ||
1155 | {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, | 1253 | {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, |
1156 | {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,}, | 1254 | {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,}, |
1157 | {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,}, | 1255 | {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,}, |
@@ -1202,6 +1300,7 @@ static void __init sunxi_init_clocks(const char *clocks[], int nclocks) | |||
1202 | 1300 | ||
1203 | static const char *sun4i_a10_critical_clocks[] __initdata = { | 1301 | static const char *sun4i_a10_critical_clocks[] __initdata = { |
1204 | "pll5_ddr", | 1302 | "pll5_ddr", |
1303 | "ahb_sdram", | ||
1205 | }; | 1304 | }; |
1206 | 1305 | ||
1207 | static void __init sun4i_a10_init_clocks(struct device_node *node) | 1306 | static void __init sun4i_a10_init_clocks(struct device_node *node) |
@@ -1214,6 +1313,7 @@ CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks) | |||
1214 | static const char *sun5i_critical_clocks[] __initdata = { | 1313 | static const char *sun5i_critical_clocks[] __initdata = { |
1215 | "mbus", | 1314 | "mbus", |
1216 | "pll5_ddr", | 1315 | "pll5_ddr", |
1316 | "ahb_sdram", | ||
1217 | }; | 1317 | }; |
1218 | 1318 | ||
1219 | static void __init sun5i_init_clocks(struct device_node *node) | 1319 | static void __init sun5i_init_clocks(struct device_node *node) |
@@ -1236,3 +1336,4 @@ static void __init sun6i_init_clocks(struct device_node *node) | |||
1236 | ARRAY_SIZE(sun6i_critical_clocks)); | 1336 | ARRAY_SIZE(sun6i_critical_clocks)); |
1237 | } | 1337 | } |
1238 | CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); | 1338 | CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); |
1339 | CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks); | ||