diff options
Diffstat (limited to 'drivers/clk/sunxi/clk-sun9i-core.c')
-rw-r--r-- | drivers/clk/sunxi/clk-sun9i-core.c | 119 |
1 files changed, 85 insertions, 34 deletions
diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c index 3cb9036d91bb..d8da77d72861 100644 --- a/drivers/clk/sunxi/clk-sun9i-core.c +++ b/drivers/clk/sunxi/clk-sun9i-core.c | |||
@@ -24,50 +24,51 @@ | |||
24 | 24 | ||
25 | 25 | ||
26 | /** | 26 | /** |
27 | * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1 | 27 | * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4 |
28 | * PLL4 rate is calculated as follows | 28 | * PLL4 rate is calculated as follows |
29 | * rate = (parent_rate * n >> p) / (m + 1); | 29 | * rate = (parent_rate * n >> p) / (m + 1); |
30 | * parent_rate is always 24Mhz | 30 | * parent_rate is always 24MHz |
31 | * | 31 | * |
32 | * p and m are named div1 and div2 in Allwinner's SDK | 32 | * p and m are named div1 and div2 in Allwinner's SDK |
33 | */ | 33 | */ |
34 | 34 | ||
35 | static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, | 35 | static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, |
36 | u8 *n, u8 *k, u8 *m, u8 *p) | 36 | u8 *n_ret, u8 *k, u8 *m_ret, u8 *p_ret) |
37 | { | 37 | { |
38 | int div; | 38 | int n; |
39 | int m = 1; | ||
40 | int p = 1; | ||
39 | 41 | ||
40 | /* Normalize value to a 6M multiple */ | 42 | /* Normalize value to a 6 MHz multiple (24 MHz / 4) */ |
41 | div = DIV_ROUND_UP(*freq, 6000000); | 43 | n = DIV_ROUND_UP(*freq, 6000000); |
42 | 44 | ||
43 | /* divs above 256 cannot be odd */ | 45 | /* If n is too large switch to steps of 12 MHz */ |
44 | if (div > 256) | 46 | if (n > 255) { |
45 | div = round_up(div, 2); | 47 | m = 0; |
48 | n = (n + 1) / 2; | ||
49 | } | ||
50 | |||
51 | /* If n is still too large switch to steps of 24 MHz */ | ||
52 | if (n > 255) { | ||
53 | p = 0; | ||
54 | n = (n + 1) / 2; | ||
55 | } | ||
46 | 56 | ||
47 | /* divs above 512 must be a multiple of 4 */ | 57 | /* n must be between 12 and 255 */ |
48 | if (div > 512) | 58 | if (n > 255) |
49 | div = round_up(div, 4); | 59 | n = 255; |
60 | else if (n < 12) | ||
61 | n = 12; | ||
50 | 62 | ||
51 | *freq = 6000000 * div; | 63 | *freq = ((24000000 * n) >> p) / (m + 1); |
52 | 64 | ||
53 | /* we were called to round the frequency, we can now return */ | 65 | /* we were called to round the frequency, we can now return */ |
54 | if (n == NULL) | 66 | if (n_ret == NULL) |
55 | return; | 67 | return; |
56 | 68 | ||
57 | /* p will be 1 for divs under 512 */ | 69 | *n_ret = n; |
58 | if (div < 512) | 70 | *m_ret = m; |
59 | *p = 1; | 71 | *p_ret = p; |
60 | else | ||
61 | *p = 0; | ||
62 | |||
63 | /* m will be 1 if div is odd */ | ||
64 | if (div & 1) | ||
65 | *m = 1; | ||
66 | else | ||
67 | *m = 0; | ||
68 | |||
69 | /* calculate a suitable n based on m and p */ | ||
70 | *n = div / (*p + 1) / (*m + 1); | ||
71 | } | 72 | } |
72 | 73 | ||
73 | static struct clk_factors_config sun9i_a80_pll4_config = { | 74 | static struct clk_factors_config sun9i_a80_pll4_config = { |
@@ -89,7 +90,17 @@ static DEFINE_SPINLOCK(sun9i_a80_pll4_lock); | |||
89 | 90 | ||
90 | static void __init sun9i_a80_pll4_setup(struct device_node *node) | 91 | static void __init sun9i_a80_pll4_setup(struct device_node *node) |
91 | { | 92 | { |
92 | sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock); | 93 | void __iomem *reg; |
94 | |||
95 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); | ||
96 | if (!reg) { | ||
97 | pr_err("Could not get registers for a80-pll4-clk: %s\n", | ||
98 | node->name); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | sunxi_factors_register(node, &sun9i_a80_pll4_data, | ||
103 | &sun9i_a80_pll4_lock, reg); | ||
93 | } | 104 | } |
94 | CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); | 105 | CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); |
95 | 106 | ||
@@ -139,8 +150,18 @@ static DEFINE_SPINLOCK(sun9i_a80_gt_lock); | |||
139 | 150 | ||
140 | static void __init sun9i_a80_gt_setup(struct device_node *node) | 151 | static void __init sun9i_a80_gt_setup(struct device_node *node) |
141 | { | 152 | { |
142 | struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data, | 153 | void __iomem *reg; |
143 | &sun9i_a80_gt_lock); | 154 | struct clk *gt; |
155 | |||
156 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); | ||
157 | if (!reg) { | ||
158 | pr_err("Could not get registers for a80-gt-clk: %s\n", | ||
159 | node->name); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | gt = sunxi_factors_register(node, &sun9i_a80_gt_data, | ||
164 | &sun9i_a80_gt_lock, reg); | ||
144 | 165 | ||
145 | /* The GT bus clock needs to be always enabled */ | 166 | /* The GT bus clock needs to be always enabled */ |
146 | __clk_get(gt); | 167 | __clk_get(gt); |
@@ -194,7 +215,17 @@ static DEFINE_SPINLOCK(sun9i_a80_ahb_lock); | |||
194 | 215 | ||
195 | static void __init sun9i_a80_ahb_setup(struct device_node *node) | 216 | static void __init sun9i_a80_ahb_setup(struct device_node *node) |
196 | { | 217 | { |
197 | sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock); | 218 | void __iomem *reg; |
219 | |||
220 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); | ||
221 | if (!reg) { | ||
222 | pr_err("Could not get registers for a80-ahb-clk: %s\n", | ||
223 | node->name); | ||
224 | return; | ||
225 | } | ||
226 | |||
227 | sunxi_factors_register(node, &sun9i_a80_ahb_data, | ||
228 | &sun9i_a80_ahb_lock, reg); | ||
198 | } | 229 | } |
199 | CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup); | 230 | CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup); |
200 | 231 | ||
@@ -210,7 +241,17 @@ static DEFINE_SPINLOCK(sun9i_a80_apb0_lock); | |||
210 | 241 | ||
211 | static void __init sun9i_a80_apb0_setup(struct device_node *node) | 242 | static void __init sun9i_a80_apb0_setup(struct device_node *node) |
212 | { | 243 | { |
213 | sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock); | 244 | void __iomem *reg; |
245 | |||
246 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); | ||
247 | if (!reg) { | ||
248 | pr_err("Could not get registers for a80-apb0-clk: %s\n", | ||
249 | node->name); | ||
250 | return; | ||
251 | } | ||
252 | |||
253 | sunxi_factors_register(node, &sun9i_a80_apb0_data, | ||
254 | &sun9i_a80_apb0_lock, reg); | ||
214 | } | 255 | } |
215 | CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); | 256 | CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); |
216 | 257 | ||
@@ -266,6 +307,16 @@ static DEFINE_SPINLOCK(sun9i_a80_apb1_lock); | |||
266 | 307 | ||
267 | static void __init sun9i_a80_apb1_setup(struct device_node *node) | 308 | static void __init sun9i_a80_apb1_setup(struct device_node *node) |
268 | { | 309 | { |
269 | sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock); | 310 | void __iomem *reg; |
311 | |||
312 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); | ||
313 | if (!reg) { | ||
314 | pr_err("Could not get registers for a80-apb1-clk: %s\n", | ||
315 | node->name); | ||
316 | return; | ||
317 | } | ||
318 | |||
319 | sunxi_factors_register(node, &sun9i_a80_apb1_data, | ||
320 | &sun9i_a80_apb1_lock, reg); | ||
270 | } | 321 | } |
271 | CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); | 322 | CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); |