aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/sunxi/clk-sunxi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/sunxi/clk-sunxi.c')
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c262
1 files changed, 222 insertions, 40 deletions
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 1818f404538d..379324eb5486 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -20,11 +20,221 @@
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#include <linux/spinlock.h>
23#include <linux/log2.h>
23 24
24#include "clk-factors.h" 25#include "clk-factors.h"
25 26
26static DEFINE_SPINLOCK(clk_lock); 27static DEFINE_SPINLOCK(clk_lock);
27 28
29/**
30 * sun6i_a31_ahb1_clk_setup() - Setup function for a31 ahb1 composite clk
31 */
32
33#define SUN6I_AHB1_MAX_PARENTS 4
34#define SUN6I_AHB1_MUX_PARENT_PLL6 3
35#define SUN6I_AHB1_MUX_SHIFT 12
36/* un-shifted mask is what mux_clk expects */
37#define SUN6I_AHB1_MUX_MASK 0x3
38#define SUN6I_AHB1_MUX_GET_PARENT(reg) ((reg >> SUN6I_AHB1_MUX_SHIFT) & \
39 SUN6I_AHB1_MUX_MASK)
40
41#define SUN6I_AHB1_DIV_SHIFT 4
42#define SUN6I_AHB1_DIV_MASK (0x3 << SUN6I_AHB1_DIV_SHIFT)
43#define SUN6I_AHB1_DIV_GET(reg) ((reg & SUN6I_AHB1_DIV_MASK) >> \
44 SUN6I_AHB1_DIV_SHIFT)
45#define SUN6I_AHB1_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_DIV_MASK) | \
46 (div << SUN6I_AHB1_DIV_SHIFT))
47#define SUN6I_AHB1_PLL6_DIV_SHIFT 6
48#define SUN6I_AHB1_PLL6_DIV_MASK (0x3 << SUN6I_AHB1_PLL6_DIV_SHIFT)
49#define SUN6I_AHB1_PLL6_DIV_GET(reg) ((reg & SUN6I_AHB1_PLL6_DIV_MASK) >> \
50 SUN6I_AHB1_PLL6_DIV_SHIFT)
51#define SUN6I_AHB1_PLL6_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_PLL6_DIV_MASK) | \
52 (div << SUN6I_AHB1_PLL6_DIV_SHIFT))
53
54struct sun6i_ahb1_clk {
55 struct clk_hw hw;
56 void __iomem *reg;
57};
58
59#define to_sun6i_ahb1_clk(_hw) container_of(_hw, struct sun6i_ahb1_clk, hw)
60
61static unsigned long sun6i_ahb1_clk_recalc_rate(struct clk_hw *hw,
62 unsigned long parent_rate)
63{
64 struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
65 unsigned long rate;
66 u32 reg;
67
68 /* Fetch the register value */
69 reg = readl(ahb1->reg);
70
71 /* apply pre-divider first if parent is pll6 */
72 if (SUN6I_AHB1_MUX_GET_PARENT(reg) == SUN6I_AHB1_MUX_PARENT_PLL6)
73 parent_rate /= SUN6I_AHB1_PLL6_DIV_GET(reg) + 1;
74
75 /* clk divider */
76 rate = parent_rate >> SUN6I_AHB1_DIV_GET(reg);
77
78 return rate;
79}
80
81static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
82 u8 parent, unsigned long parent_rate)
83{
84 u8 div, calcp, calcm = 1;
85
86 /*
87 * clock can only divide, so we will never be able to achieve
88 * frequencies higher than the parent frequency
89 */
90 if (parent_rate && rate > parent_rate)
91 rate = parent_rate;
92
93 div = DIV_ROUND_UP(parent_rate, rate);
94
95 /* calculate pre-divider if parent is pll6 */
96 if (parent == SUN6I_AHB1_MUX_PARENT_PLL6) {
97 if (div < 4)
98 calcp = 0;
99 else if (div / 2 < 4)
100 calcp = 1;
101 else if (div / 4 < 4)
102 calcp = 2;
103 else
104 calcp = 3;
105
106 calcm = DIV_ROUND_UP(div, 1 << calcp);
107 } else {
108 calcp = __roundup_pow_of_two(div);
109 calcp = calcp > 3 ? 3 : calcp;
110 }
111
112 /* we were asked to pass back divider values */
113 if (divp) {
114 *divp = calcp;
115 *pre_divp = calcm - 1;
116 }
117
118 return (parent_rate / calcm) >> calcp;
119}
120
121static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
122 unsigned long min_rate,
123 unsigned long max_rate,
124 unsigned long *best_parent_rate,
125 struct clk_hw **best_parent_clk)
126{
127 struct clk *clk = hw->clk, *parent, *best_parent = NULL;
128 int i, num_parents;
129 unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
130
131 /* find the parent that can help provide the fastest rate <= rate */
132 num_parents = __clk_get_num_parents(clk);
133 for (i = 0; i < num_parents; i++) {
134 parent = clk_get_parent_by_index(clk, i);
135 if (!parent)
136 continue;
137 if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
138 parent_rate = __clk_round_rate(parent, rate);
139 else
140 parent_rate = __clk_get_rate(parent);
141
142 child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i,
143 parent_rate);
144
145 if (child_rate <= rate && child_rate > best_child_rate) {
146 best_parent = parent;
147 best = parent_rate;
148 best_child_rate = child_rate;
149 }
150 }
151
152 if (best_parent)
153 *best_parent_clk = __clk_get_hw(best_parent);
154 *best_parent_rate = best;
155
156 return best_child_rate;
157}
158
159static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate,
160 unsigned long parent_rate)
161{
162 struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
163 unsigned long flags;
164 u8 div, pre_div, parent;
165 u32 reg;
166
167 spin_lock_irqsave(&clk_lock, flags);
168
169 reg = readl(ahb1->reg);
170
171 /* need to know which parent is used to apply pre-divider */
172 parent = SUN6I_AHB1_MUX_GET_PARENT(reg);
173 sun6i_ahb1_clk_round(rate, &div, &pre_div, parent, parent_rate);
174
175 reg = SUN6I_AHB1_DIV_SET(reg, div);
176 reg = SUN6I_AHB1_PLL6_DIV_SET(reg, pre_div);
177 writel(reg, ahb1->reg);
178
179 spin_unlock_irqrestore(&clk_lock, flags);
180
181 return 0;
182}
183
184static const struct clk_ops sun6i_ahb1_clk_ops = {
185 .determine_rate = sun6i_ahb1_clk_determine_rate,
186 .recalc_rate = sun6i_ahb1_clk_recalc_rate,
187 .set_rate = sun6i_ahb1_clk_set_rate,
188};
189
190static void __init sun6i_ahb1_clk_setup(struct device_node *node)
191{
192 struct clk *clk;
193 struct sun6i_ahb1_clk *ahb1;
194 struct clk_mux *mux;
195 const char *clk_name = node->name;
196 const char *parents[SUN6I_AHB1_MAX_PARENTS];
197 void __iomem *reg;
198 int i = 0;
199
200 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
201
202 /* we have a mux, we will have >1 parents */
203 while (i < SUN6I_AHB1_MAX_PARENTS &&
204 (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
205 i++;
206
207 of_property_read_string(node, "clock-output-names", &clk_name);
208
209 ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL);
210 if (!ahb1)
211 return;
212
213 mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
214 if (!mux) {
215 kfree(ahb1);
216 return;
217 }
218
219 /* set up clock properties */
220 mux->reg = reg;
221 mux->shift = SUN6I_AHB1_MUX_SHIFT;
222 mux->mask = SUN6I_AHB1_MUX_MASK;
223 mux->lock = &clk_lock;
224 ahb1->reg = reg;
225
226 clk = clk_register_composite(NULL, clk_name, parents, i,
227 &mux->hw, &clk_mux_ops,
228 &ahb1->hw, &sun6i_ahb1_clk_ops,
229 NULL, NULL, 0);
230
231 if (!IS_ERR(clk)) {
232 of_clk_add_provider(node, of_clk_src_simple_get, clk);
233 clk_register_clkdev(clk, clk_name, NULL);
234 }
235}
236CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-clk", sun6i_ahb1_clk_setup);
237
28/* Maximum number of parents our clocks have */ 238/* Maximum number of parents our clocks have */
29#define SUNXI_MAX_PARENTS 5 239#define SUNXI_MAX_PARENTS 5
30 240
@@ -355,43 +565,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
355} 565}
356 566
357/** 567/**
358 * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
359 */
360
361void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
362{
363 #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
364 #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
365
366 struct clk_hw *hw = __clk_get_hw(clk);
367 struct clk_composite *composite = to_clk_composite(hw);
368 struct clk_hw *rate_hw = composite->rate_hw;
369 struct clk_factors *factors = to_clk_factors(rate_hw);
370 unsigned long flags = 0;
371 u32 reg;
372
373 if (factors->lock)
374 spin_lock_irqsave(factors->lock, flags);
375
376 reg = readl(factors->reg);
377
378 /* set sample clock phase control */
379 reg &= ~(0x7 << 20);
380 reg |= ((sample & 0x7) << 20);
381
382 /* set output clock phase control */
383 reg &= ~(0x7 << 8);
384 reg |= ((output & 0x7) << 8);
385
386 writel(reg, factors->reg);
387
388 if (factors->lock)
389 spin_unlock_irqrestore(factors->lock, flags);
390}
391EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
392
393
394/**
395 * sunxi_factors_clk_setup() - Setup function for factor clocks 568 * sunxi_factors_clk_setup() - Setup function for factor clocks
396 */ 569 */
397 570
@@ -413,6 +586,7 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
413 .kwidth = 2, 586 .kwidth = 2,
414 .mshift = 0, 587 .mshift = 0,
415 .mwidth = 2, 588 .mwidth = 2,
589 .n_start = 1,
416}; 590};
417 591
418static struct clk_factors_config sun8i_a23_pll1_config = { 592static struct clk_factors_config sun8i_a23_pll1_config = {
@@ -520,7 +694,16 @@ static const struct factors_data sun7i_a20_out_data __initconst = {
520static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, 694static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
521 const struct factors_data *data) 695 const struct factors_data *data)
522{ 696{
523 return sunxi_factors_register(node, data, &clk_lock); 697 void __iomem *reg;
698
699 reg = of_iomap(node, 0);
700 if (!reg) {
701 pr_err("Could not get registers for factors-clk: %s\n",
702 node->name);
703 return NULL;
704 }
705
706 return sunxi_factors_register(node, data, &clk_lock, reg);
524} 707}
525 708
526 709
@@ -561,7 +744,7 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
561 of_property_read_string(node, "clock-output-names", &clk_name); 744 of_property_read_string(node, "clock-output-names", &clk_name);
562 745
563 clk = clk_register_mux(NULL, clk_name, parents, i, 746 clk = clk_register_mux(NULL, clk_name, parents, i,
564 CLK_SET_RATE_NO_REPARENT, reg, 747 CLK_SET_RATE_PARENT, reg,
565 data->shift, SUNXI_MUX_GATE_WIDTH, 748 data->shift, SUNXI_MUX_GATE_WIDTH,
566 0, &clk_lock); 749 0, &clk_lock);
567 750
@@ -1217,7 +1400,6 @@ CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
1217 1400
1218static const char *sun6i_critical_clocks[] __initdata = { 1401static const char *sun6i_critical_clocks[] __initdata = {
1219 "cpu", 1402 "cpu",
1220 "ahb1_sdram",
1221}; 1403};
1222 1404
1223static void __init sun6i_init_clocks(struct device_node *node) 1405static void __init sun6i_init_clocks(struct device_node *node)