aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/sunxi/clk-sun9i-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/sunxi/clk-sun9i-core.c')
-rw-r--r--drivers/clk/sunxi/clk-sun9i-core.c119
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
35static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate, 35static 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
73static struct clk_factors_config sun9i_a80_pll4_config = { 74static struct clk_factors_config sun9i_a80_pll4_config = {
@@ -89,7 +90,17 @@ static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
89 90
90static void __init sun9i_a80_pll4_setup(struct device_node *node) 91static 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}
94CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup); 105CLK_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
140static void __init sun9i_a80_gt_setup(struct device_node *node) 151static 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
195static void __init sun9i_a80_ahb_setup(struct device_node *node) 216static 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}
199CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup); 230CLK_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
211static void __init sun9i_a80_apb0_setup(struct device_node *node) 242static 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}
215CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup); 256CLK_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
267static void __init sun9i_a80_apb1_setup(struct device_node *node) 308static 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}
271CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup); 322CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);