aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/sunxi
diff options
context:
space:
mode:
authorMike Turquette <mturquette@linaro.org>2014-09-27 15:52:33 -0400
committerMike Turquette <mturquette@linaro.org>2014-09-27 15:52:33 -0400
commit4dc7ed32f398fa76b9e1d243a852420b1dad0150 (patch)
treea040f8c006ea7a7a3c962f135c8efd8b72cbc4b4 /drivers/clk/sunxi
parent5ad67d3e5e0a5059945a7726a407763a23f80d9e (diff)
parent9c8176bfb67f98ed9a521b624dcb6ab7fa254aa7 (diff)
Merge tag 'sunxi-clocks-for-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into clk-next
Allwinner Clocks Additions for 3.18 The most important part of this serie is the addition of the phase API to handle the MMC clocks in the Allwinner SoCs. Apart from that, the A23 gained a new mbus driver, and there's a fix for a incorrect divider table on the APB0 clock.
Diffstat (limited to 'drivers/clk/sunxi')
-rw-r--r--drivers/clk/sunxi/Makefile2
-rw-r--r--drivers/clk/sunxi/clk-factors.c101
-rw-r--r--drivers/clk/sunxi/clk-factors.h16
-rw-r--r--drivers/clk/sunxi/clk-mod0.c283
-rw-r--r--drivers/clk/sunxi/clk-sun8i-mbus.c78
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c161
6 files changed, 485 insertions, 156 deletions
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 6850cba35871..7ddc2b553846 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -5,6 +5,8 @@
5obj-y += clk-sunxi.o clk-factors.o 5obj-y += clk-sunxi.o clk-factors.o
6obj-y += clk-a10-hosc.o 6obj-y += clk-a10-hosc.o
7obj-y += clk-a20-gmac.o 7obj-y += clk-a20-gmac.o
8obj-y += clk-mod0.o
9obj-y += clk-sun8i-mbus.o
8 10
9obj-$(CONFIG_MFD_SUN6I_PRCM) += \ 11obj-$(CONFIG_MFD_SUN6I_PRCM) += \
10 clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ 12 clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 2057c8ac648f..f83ba097126c 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -9,18 +9,18 @@
9 */ 9 */
10 10
11#include <linux/clk-provider.h> 11#include <linux/clk-provider.h>
12#include <linux/delay.h>
13#include <linux/err.h>
14#include <linux/io.h>
12#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/of_address.h>
13#include <linux/slab.h> 17#include <linux/slab.h>
14#include <linux/io.h>
15#include <linux/err.h>
16#include <linux/string.h> 18#include <linux/string.h>
17 19
18#include <linux/delay.h>
19
20#include "clk-factors.h" 20#include "clk-factors.h"
21 21
22/* 22/*
23 * DOC: basic adjustable factor-based clock that cannot gate 23 * DOC: basic adjustable factor-based clock
24 * 24 *
25 * Traits of this clock: 25 * Traits of this clock:
26 * prepare - clk_prepare only ensures that parents are prepared 26 * prepare - clk_prepare only ensures that parents are prepared
@@ -32,6 +32,8 @@
32 32
33#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw) 33#define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
34 34
35#define FACTORS_MAX_PARENTS 5
36
35#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos)) 37#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos))
36#define CLRMASK(len, pos) (~(SETMASK(len, pos))) 38#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
37#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit)) 39#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
@@ -147,9 +149,96 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
147 return 0; 149 return 0;
148} 150}
149 151
150const struct clk_ops clk_factors_ops = { 152static const struct clk_ops clk_factors_ops = {
151 .determine_rate = clk_factors_determine_rate, 153 .determine_rate = clk_factors_determine_rate,
152 .recalc_rate = clk_factors_recalc_rate, 154 .recalc_rate = clk_factors_recalc_rate,
153 .round_rate = clk_factors_round_rate, 155 .round_rate = clk_factors_round_rate,
154 .set_rate = clk_factors_set_rate, 156 .set_rate = clk_factors_set_rate,
155}; 157};
158
159struct clk * __init sunxi_factors_register(struct device_node *node,
160 const struct factors_data *data,
161 spinlock_t *lock)
162{
163 struct clk *clk;
164 struct clk_factors *factors;
165 struct clk_gate *gate = NULL;
166 struct clk_mux *mux = NULL;
167 struct clk_hw *gate_hw = NULL;
168 struct clk_hw *mux_hw = NULL;
169 const char *clk_name = node->name;
170 const char *parents[FACTORS_MAX_PARENTS];
171 void __iomem *reg;
172 int i = 0;
173
174 reg = of_iomap(node, 0);
175
176 /* if we have a mux, we will have >1 parents */
177 while (i < FACTORS_MAX_PARENTS &&
178 (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
179 i++;
180
181 /*
182 * some factor clocks, such as pll5 and pll6, may have multiple
183 * outputs, and have their name designated in factors_data
184 */
185 if (data->name)
186 clk_name = data->name;
187 else
188 of_property_read_string(node, "clock-output-names", &clk_name);
189
190 factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
191 if (!factors)
192 return NULL;
193
194 /* set up factors properties */
195 factors->reg = reg;
196 factors->config = data->table;
197 factors->get_factors = data->getter;
198 factors->lock = lock;
199
200 /* Add a gate if this factor clock can be gated */
201 if (data->enable) {
202 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
203 if (!gate) {
204 kfree(factors);
205 return NULL;
206 }
207
208 /* set up gate properties */
209 gate->reg = reg;
210 gate->bit_idx = data->enable;
211 gate->lock = factors->lock;
212 gate_hw = &gate->hw;
213 }
214
215 /* Add a mux if this factor clock can be muxed */
216 if (data->mux) {
217 mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
218 if (!mux) {
219 kfree(factors);
220 kfree(gate);
221 return NULL;
222 }
223
224 /* set up gate properties */
225 mux->reg = reg;
226 mux->shift = data->mux;
227 mux->mask = SUNXI_FACTORS_MUX_MASK;
228 mux->lock = factors->lock;
229 mux_hw = &mux->hw;
230 }
231
232 clk = clk_register_composite(NULL, clk_name,
233 parents, i,
234 mux_hw, &clk_mux_ops,
235 &factors->hw, &clk_factors_ops,
236 gate_hw, &clk_gate_ops, 0);
237
238 if (!IS_ERR(clk)) {
239 of_clk_add_provider(node, of_clk_src_simple_get, clk);
240 clk_register_clkdev(clk, clk_name, NULL);
241 }
242
243 return clk;
244}
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index d2d0efa39379..9913840018d3 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -3,9 +3,12 @@
3 3
4#include <linux/clk-provider.h> 4#include <linux/clk-provider.h>
5#include <linux/clkdev.h> 5#include <linux/clkdev.h>
6#include <linux/spinlock.h>
6 7
7#define SUNXI_FACTORS_NOT_APPLICABLE (0) 8#define SUNXI_FACTORS_NOT_APPLICABLE (0)
8 9
10#define SUNXI_FACTORS_MUX_MASK 0x3
11
9struct clk_factors_config { 12struct clk_factors_config {
10 u8 nshift; 13 u8 nshift;
11 u8 nwidth; 14 u8 nwidth;
@@ -18,6 +21,14 @@ struct clk_factors_config {
18 u8 n_start; 21 u8 n_start;
19}; 22};
20 23
24struct factors_data {
25 int enable;
26 int mux;
27 struct clk_factors_config *table;
28 void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
29 const char *name;
30};
31
21struct clk_factors { 32struct clk_factors {
22 struct clk_hw hw; 33 struct clk_hw hw;
23 void __iomem *reg; 34 void __iomem *reg;
@@ -26,5 +37,8 @@ struct clk_factors {
26 spinlock_t *lock; 37 spinlock_t *lock;
27}; 38};
28 39
29extern const struct clk_ops clk_factors_ops; 40struct clk * __init sunxi_factors_register(struct device_node *node,
41 const struct factors_data *data,
42 spinlock_t *lock);
43
30#endif 44#endif
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
new file mode 100644
index 000000000000..4a563850ee6e
--- /dev/null
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -0,0 +1,283 @@
1/*
2 * Copyright 2013 Emilio López
3 *
4 * Emilio López <emilio@elopez.com.ar>
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; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/clk-provider.h>
18#include <linux/clkdev.h>
19#include <linux/of_address.h>
20
21#include "clk-factors.h"
22
23/**
24 * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks
25 * MOD0 rate is calculated as follows
26 * rate = (parent_rate >> p) / (m + 1);
27 */
28
29static void sun4i_a10_get_mod0_factors(u32 *freq, u32 parent_rate,
30 u8 *n, u8 *k, u8 *m, u8 *p)
31{
32 u8 div, calcm, calcp;
33
34 /* These clocks can only divide, so we will never be able to achieve
35 * frequencies higher than the parent frequency */
36 if (*freq > parent_rate)
37 *freq = parent_rate;
38
39 div = DIV_ROUND_UP(parent_rate, *freq);
40
41 if (div < 16)
42 calcp = 0;
43 else if (div / 2 < 16)
44 calcp = 1;
45 else if (div / 4 < 16)
46 calcp = 2;
47 else
48 calcp = 3;
49
50 calcm = DIV_ROUND_UP(div, 1 << calcp);
51
52 *freq = (parent_rate >> calcp) / calcm;
53
54 /* we were called to round the frequency, we can now return */
55 if (n == NULL)
56 return;
57
58 *m = calcm - 1;
59 *p = calcp;
60}
61
62/* user manual says "n" but it's really "p" */
63static struct clk_factors_config sun4i_a10_mod0_config = {
64 .mshift = 0,
65 .mwidth = 4,
66 .pshift = 16,
67 .pwidth = 2,
68};
69
70static const struct factors_data sun4i_a10_mod0_data __initconst = {
71 .enable = 31,
72 .mux = 24,
73 .table = &sun4i_a10_mod0_config,
74 .getter = sun4i_a10_get_mod0_factors,
75};
76
77static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
78
79static void __init sun4i_a10_mod0_setup(struct device_node *node)
80{
81 sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock);
82}
83CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
84
85static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
86
87static void __init sun5i_a13_mbus_setup(struct device_node *node)
88{
89 struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock);
90
91 /* The MBUS clocks needs to be always enabled */
92 __clk_get(mbus);
93 clk_prepare_enable(mbus);
94}
95CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
96
97struct mmc_phase_data {
98 u8 offset;
99};
100
101struct mmc_phase {
102 struct clk_hw hw;
103 void __iomem *reg;
104 struct mmc_phase_data *data;
105 spinlock_t *lock;
106};
107
108#define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
109
110static int mmc_get_phase(struct clk_hw *hw)
111{
112 struct clk *mmc, *mmc_parent, *clk = hw->clk;
113 struct mmc_phase *phase = to_mmc_phase(hw);
114 unsigned int mmc_rate, mmc_parent_rate;
115 u16 step, mmc_div;
116 u32 value;
117 u8 delay;
118
119 value = readl(phase->reg);
120 delay = (value >> phase->data->offset) & 0x3;
121
122 if (!delay)
123 return 180;
124
125 /* Get the main MMC clock */
126 mmc = clk_get_parent(clk);
127 if (!mmc)
128 return -EINVAL;
129
130 /* And its rate */
131 mmc_rate = clk_get_rate(mmc);
132 if (!mmc_rate)
133 return -EINVAL;
134
135 /* Now, get the MMC parent (most likely some PLL) */
136 mmc_parent = clk_get_parent(mmc);
137 if (!mmc_parent)
138 return -EINVAL;
139
140 /* And its rate */
141 mmc_parent_rate = clk_get_rate(mmc_parent);
142 if (!mmc_parent_rate)
143 return -EINVAL;
144
145 /* Get MMC clock divider */
146 mmc_div = mmc_parent_rate / mmc_rate;
147
148 step = DIV_ROUND_CLOSEST(360, mmc_div);
149 return delay * step;
150}
151
152static int mmc_set_phase(struct clk_hw *hw, int degrees)
153{
154 struct clk *mmc, *mmc_parent, *clk = hw->clk;
155 struct mmc_phase *phase = to_mmc_phase(hw);
156 unsigned int mmc_rate, mmc_parent_rate;
157 unsigned long flags;
158 u32 value;
159 u8 delay;
160
161 /* Get the main MMC clock */
162 mmc = clk_get_parent(clk);
163 if (!mmc)
164 return -EINVAL;
165
166 /* And its rate */
167 mmc_rate = clk_get_rate(mmc);
168 if (!mmc_rate)
169 return -EINVAL;
170
171 /* Now, get the MMC parent (most likely some PLL) */
172 mmc_parent = clk_get_parent(mmc);
173 if (!mmc_parent)
174 return -EINVAL;
175
176 /* And its rate */
177 mmc_parent_rate = clk_get_rate(mmc_parent);
178 if (!mmc_parent_rate)
179 return -EINVAL;
180
181 if (degrees != 180) {
182 u16 step, mmc_div;
183
184 /* Get MMC clock divider */
185 mmc_div = mmc_parent_rate / mmc_rate;
186
187 /*
188 * We can only outphase the clocks by multiple of the
189 * PLL's period.
190 *
191 * Since the MMC clock in only a divider, and the
192 * formula to get the outphasing in degrees is deg =
193 * 360 * delta / period
194 *
195 * If we simplify this formula, we can see that the
196 * only thing that we're concerned about is the number
197 * of period we want to outphase our clock from, and
198 * the divider set by the MMC clock.
199 */
200 step = DIV_ROUND_CLOSEST(360, mmc_div);
201 delay = DIV_ROUND_CLOSEST(degrees, step);
202 } else {
203 delay = 0;
204 }
205
206 spin_lock_irqsave(phase->lock, flags);
207 value = readl(phase->reg);
208 value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
209 value |= delay << phase->data->offset;
210 writel(value, phase->reg);
211 spin_unlock_irqrestore(phase->lock, flags);
212
213 return 0;
214}
215
216static const struct clk_ops mmc_clk_ops = {
217 .get_phase = mmc_get_phase,
218 .set_phase = mmc_set_phase,
219};
220
221static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
222 struct mmc_phase_data *data)
223{
224 const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
225 struct clk_init_data init = {
226 .num_parents = 1,
227 .parent_names = parent_names,
228 .ops = &mmc_clk_ops,
229 };
230
231 struct mmc_phase *phase;
232 struct clk *clk;
233
234 phase = kmalloc(sizeof(*phase), GFP_KERNEL);
235 if (!phase)
236 return;
237
238 phase->hw.init = &init;
239
240 phase->reg = of_iomap(node, 0);
241 if (!phase->reg)
242 goto err_free;
243
244 phase->data = data;
245 phase->lock = &sun4i_a10_mod0_lock;
246
247 if (of_property_read_string(node, "clock-output-names", &init.name))
248 init.name = node->name;
249
250 clk = clk_register(NULL, &phase->hw);
251 if (IS_ERR(clk))
252 goto err_unmap;
253
254 of_clk_add_provider(node, of_clk_src_simple_get, clk);
255
256 return;
257
258err_unmap:
259 iounmap(phase->reg);
260err_free:
261 kfree(phase);
262}
263
264
265static struct mmc_phase_data mmc_output_clk = {
266 .offset = 8,
267};
268
269static struct mmc_phase_data mmc_sample_clk = {
270 .offset = 20,
271};
272
273static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
274{
275 sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
276}
277CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
278
279static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
280{
281 sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
282}
283CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c
new file mode 100644
index 000000000000..8e49b44cee41
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun8i-mbus.c
@@ -0,0 +1,78 @@
1/*
2 * Copyright 2014 Chen-Yu Tsai
3 *
4 * Chen-Yu Tsai <wens@csie.org>
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; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/clk-provider.h>
18#include <linux/clkdev.h>
19#include <linux/of_address.h>
20
21#include "clk-factors.h"
22
23/**
24 * sun8i_a23_get_mbus_factors() - calculates m factor for MBUS clocks
25 * MBUS rate is calculated as follows
26 * rate = parent_rate / (m + 1);
27 */
28
29static void sun8i_a23_get_mbus_factors(u32 *freq, u32 parent_rate,
30 u8 *n, u8 *k, u8 *m, u8 *p)
31{
32 u8 div;
33
34 /*
35 * These clocks can only divide, so we will never be able to
36 * achieve frequencies higher than the parent frequency
37 */
38 if (*freq > parent_rate)
39 *freq = parent_rate;
40
41 div = DIV_ROUND_UP(parent_rate, *freq);
42
43 if (div > 8)
44 div = 8;
45
46 *freq = parent_rate / div;
47
48 /* we were called to round the frequency, we can now return */
49 if (m == NULL)
50 return;
51
52 *m = div - 1;
53}
54
55static struct clk_factors_config sun8i_a23_mbus_config = {
56 .mshift = 0,
57 .mwidth = 3,
58};
59
60static const struct factors_data sun8i_a23_mbus_data __initconst = {
61 .enable = 31,
62 .mux = 24,
63 .table = &sun8i_a23_mbus_config,
64 .getter = sun8i_a23_get_mbus_factors,
65};
66
67static DEFINE_SPINLOCK(sun8i_a23_mbus_lock);
68
69static void __init sun8i_a23_mbus_setup(struct device_node *node)
70{
71 struct clk *mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
72 &sun8i_a23_mbus_lock);
73
74 /* The MBUS clocks needs to be always enabled */
75 __clk_get(mbus);
76 clk_prepare_enable(mbus);
77}
78CLK_OF_DECLARE(sun8i_a23_mbus, "allwinner,sun8i-a23-mbus-clk", sun8i_a23_mbus_setup);
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index b654b7b1d137..d5dc951264ca 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -19,6 +19,7 @@
19#include <linux/of.h> 19#include <linux/of.h>
20#include <linux/of_address.h> 20#include <linux/of_address.h>
21#include <linux/reset-controller.h> 21#include <linux/reset-controller.h>
22#include <linux/spinlock.h>
22 23
23#include "clk-factors.h" 24#include "clk-factors.h"
24 25
@@ -319,46 +320,6 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate,
319 320
320 321
321 322
322/**
323 * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks
324 * MOD0 rate is calculated as follows
325 * rate = (parent_rate >> p) / (m + 1);
326 */
327
328static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate,
329 u8 *n, u8 *k, u8 *m, u8 *p)
330{
331 u8 div, calcm, calcp;
332
333 /* These clocks can only divide, so we will never be able to achieve
334 * frequencies higher than the parent frequency */
335 if (*freq > parent_rate)
336 *freq = parent_rate;
337
338 div = DIV_ROUND_UP(parent_rate, *freq);
339
340 if (div < 16)
341 calcp = 0;
342 else if (div / 2 < 16)
343 calcp = 1;
344 else if (div / 4 < 16)
345 calcp = 2;
346 else
347 calcp = 3;
348
349 calcm = DIV_ROUND_UP(div, 1 << calcp);
350
351 *freq = (parent_rate >> calcp) / calcm;
352
353 /* we were called to round the frequency, we can now return */
354 if (n == NULL)
355 return;
356
357 *m = calcm - 1;
358 *p = calcp;
359}
360
361
362 323
363/** 324/**
364 * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B 325 * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B
@@ -440,16 +401,6 @@ EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
440 * sunxi_factors_clk_setup() - Setup function for factor clocks 401 * sunxi_factors_clk_setup() - Setup function for factor clocks
441 */ 402 */
442 403
443#define SUNXI_FACTORS_MUX_MASK 0x3
444
445struct factors_data {
446 int enable;
447 int mux;
448 struct clk_factors_config *table;
449 void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
450 const char *name;
451};
452
453static struct clk_factors_config sun4i_pll1_config = { 404static struct clk_factors_config sun4i_pll1_config = {
454 .nshift = 8, 405 .nshift = 8,
455 .nwidth = 5, 406 .nwidth = 5,
@@ -504,14 +455,6 @@ static struct clk_factors_config sun4i_apb1_config = {
504}; 455};
505 456
506/* user manual says "n" but it's really "p" */ 457/* user manual says "n" but it's really "p" */
507static struct clk_factors_config sun4i_mod0_config = {
508 .mshift = 0,
509 .mwidth = 4,
510 .pshift = 16,
511 .pwidth = 2,
512};
513
514/* user manual says "n" but it's really "p" */
515static struct clk_factors_config sun7i_a20_out_config = { 458static struct clk_factors_config sun7i_a20_out_config = {
516 .mshift = 8, 459 .mshift = 8,
517 .mwidth = 5, 460 .mwidth = 5,
@@ -568,13 +511,6 @@ static const struct factors_data sun4i_apb1_data __initconst = {
568 .getter = sun4i_get_apb1_factors, 511 .getter = sun4i_get_apb1_factors,
569}; 512};
570 513
571static const struct factors_data sun4i_mod0_data __initconst = {
572 .enable = 31,
573 .mux = 24,
574 .table = &sun4i_mod0_config,
575 .getter = sun4i_get_mod0_factors,
576};
577
578static const struct factors_data sun7i_a20_out_data __initconst = { 514static const struct factors_data sun7i_a20_out_data __initconst = {
579 .enable = 31, 515 .enable = 31,
580 .mux = 24, 516 .mux = 24,
@@ -583,89 +519,9 @@ static const struct factors_data sun7i_a20_out_data __initconst = {
583}; 519};
584 520
585static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, 521static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
586 const struct factors_data *data) 522 const struct factors_data *data)
587{ 523{
588 struct clk *clk; 524 return sunxi_factors_register(node, data, &clk_lock);
589 struct clk_factors *factors;
590 struct clk_gate *gate = NULL;
591 struct clk_mux *mux = NULL;
592 struct clk_hw *gate_hw = NULL;
593 struct clk_hw *mux_hw = NULL;
594 const char *clk_name = node->name;
595 const char *parents[SUNXI_MAX_PARENTS];
596 void __iomem *reg;
597 int i = 0;
598
599 reg = of_iomap(node, 0);
600
601 /* if we have a mux, we will have >1 parents */
602 while (i < SUNXI_MAX_PARENTS &&
603 (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
604 i++;
605
606 /*
607 * some factor clocks, such as pll5 and pll6, may have multiple
608 * outputs, and have their name designated in factors_data
609 */
610 if (data->name)
611 clk_name = data->name;
612 else
613 of_property_read_string(node, "clock-output-names", &clk_name);
614
615 factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
616 if (!factors)
617 return NULL;
618
619 /* Add a gate if this factor clock can be gated */
620 if (data->enable) {
621 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
622 if (!gate) {
623 kfree(factors);
624 return NULL;
625 }
626
627 /* set up gate properties */
628 gate->reg = reg;
629 gate->bit_idx = data->enable;
630 gate->lock = &clk_lock;
631 gate_hw = &gate->hw;
632 }
633
634 /* Add a mux if this factor clock can be muxed */
635 if (data->mux) {
636 mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
637 if (!mux) {
638 kfree(factors);
639 kfree(gate);
640 return NULL;
641 }
642
643 /* set up gate properties */
644 mux->reg = reg;
645 mux->shift = data->mux;
646 mux->mask = SUNXI_FACTORS_MUX_MASK;
647 mux->lock = &clk_lock;
648 mux_hw = &mux->hw;
649 }
650
651 /* set up factors properties */
652 factors->reg = reg;
653 factors->config = data->table;
654 factors->get_factors = data->getter;
655 factors->lock = &clk_lock;
656
657 clk = clk_register_composite(NULL, clk_name,
658 parents, i,
659 mux_hw, &clk_mux_ops,
660 &factors->hw, &clk_factors_ops,
661 gate_hw, &clk_gate_ops, 0);
662
663 if (!IS_ERR(clk)) {
664 of_clk_add_provider(node, of_clk_src_simple_get, clk);
665 clk_register_clkdev(clk, clk_name, NULL);
666 }
667
668 return clk;
669} 525}
670 526
671 527
@@ -762,10 +618,19 @@ static const struct div_data sun4i_ahb_data __initconst = {
762 .width = 2, 618 .width = 2,
763}; 619};
764 620
621static const struct clk_div_table sun4i_apb0_table[] __initconst = {
622 { .val = 0, .div = 2 },
623 { .val = 1, .div = 2 },
624 { .val = 2, .div = 4 },
625 { .val = 3, .div = 8 },
626 { } /* sentinel */
627};
628
765static const struct div_data sun4i_apb0_data __initconst = { 629static const struct div_data sun4i_apb0_data __initconst = {
766 .shift = 8, 630 .shift = 8,
767 .pow = 1, 631 .pow = 1,
768 .width = 2, 632 .width = 2,
633 .table = sun4i_apb0_table,
769}; 634};
770 635
771static const struct div_data sun6i_a31_apb2_div_data __initconst = { 636static const struct div_data sun6i_a31_apb2_div_data __initconst = {
@@ -1199,7 +1064,6 @@ static const struct of_device_id clk_factors_match[] __initconst = {
1199 {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, 1064 {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
1200 {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, 1065 {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
1201 {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, 1066 {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
1202 {.compatible = "allwinner,sun4i-a10-mod0-clk", .data = &sun4i_mod0_data,},
1203 {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, 1067 {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
1204 {} 1068 {}
1205}; 1069};
@@ -1311,7 +1175,6 @@ static void __init sun4i_a10_init_clocks(struct device_node *node)
1311CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); 1175CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks);
1312 1176
1313static const char *sun5i_critical_clocks[] __initdata = { 1177static const char *sun5i_critical_clocks[] __initdata = {
1314 "mbus",
1315 "pll5_ddr", 1178 "pll5_ddr",
1316 "ahb_sdram", 1179 "ahb_sdram",
1317}; 1180};