Merge tag 'renesas-soc-fixes2-for-v3.19' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / drivers / clk / sunxi / clk-mod0.c
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
29 static 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" */
63 static struct clk_factors_config sun4i_a10_mod0_config = {
64         .mshift = 0,
65         .mwidth = 4,
66         .pshift = 16,
67         .pwidth = 2,
68 };
69
70 static const struct factors_data sun4i_a10_mod0_data __initconst = {
71         .enable = 31,
72         .mux = 24,
73         .muxmask = BIT(1) | BIT(0),
74         .table = &sun4i_a10_mod0_config,
75         .getter = sun4i_a10_get_mod0_factors,
76 };
77
78 static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
79
80 static void __init sun4i_a10_mod0_setup(struct device_node *node)
81 {
82         sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock);
83 }
84 CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
85
86 static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
87
88 static void __init sun5i_a13_mbus_setup(struct device_node *node)
89 {
90         struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock);
91
92         /* The MBUS clocks needs to be always enabled */
93         __clk_get(mbus);
94         clk_prepare_enable(mbus);
95 }
96 CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
97
98 struct mmc_phase_data {
99         u8      offset;
100 };
101
102 struct mmc_phase {
103         struct clk_hw           hw;
104         void __iomem            *reg;
105         struct mmc_phase_data   *data;
106         spinlock_t              *lock;
107 };
108
109 #define to_mmc_phase(_hw) container_of(_hw, struct mmc_phase, hw)
110
111 static int mmc_get_phase(struct clk_hw *hw)
112 {
113         struct clk *mmc, *mmc_parent, *clk = hw->clk;
114         struct mmc_phase *phase = to_mmc_phase(hw);
115         unsigned int mmc_rate, mmc_parent_rate;
116         u16 step, mmc_div;
117         u32 value;
118         u8 delay;
119
120         value = readl(phase->reg);
121         delay = (value >> phase->data->offset) & 0x3;
122
123         if (!delay)
124                 return 180;
125
126         /* Get the main MMC clock */
127         mmc = clk_get_parent(clk);
128         if (!mmc)
129                 return -EINVAL;
130
131         /* And its rate */
132         mmc_rate = clk_get_rate(mmc);
133         if (!mmc_rate)
134                 return -EINVAL;
135
136         /* Now, get the MMC parent (most likely some PLL) */
137         mmc_parent = clk_get_parent(mmc);
138         if (!mmc_parent)
139                 return -EINVAL;
140
141         /* And its rate */
142         mmc_parent_rate = clk_get_rate(mmc_parent);
143         if (!mmc_parent_rate)
144                 return -EINVAL;
145
146         /* Get MMC clock divider */
147         mmc_div = mmc_parent_rate / mmc_rate;
148
149         step = DIV_ROUND_CLOSEST(360, mmc_div);
150         return delay * step;
151 }
152
153 static int mmc_set_phase(struct clk_hw *hw, int degrees)
154 {
155         struct clk *mmc, *mmc_parent, *clk = hw->clk;
156         struct mmc_phase *phase = to_mmc_phase(hw);
157         unsigned int mmc_rate, mmc_parent_rate;
158         unsigned long flags;
159         u32 value;
160         u8 delay;
161
162         /* Get the main MMC clock */
163         mmc = clk_get_parent(clk);
164         if (!mmc)
165                 return -EINVAL;
166
167         /* And its rate */
168         mmc_rate = clk_get_rate(mmc);
169         if (!mmc_rate)
170                 return -EINVAL;
171
172         /* Now, get the MMC parent (most likely some PLL) */
173         mmc_parent = clk_get_parent(mmc);
174         if (!mmc_parent)
175                 return -EINVAL;
176
177         /* And its rate */
178         mmc_parent_rate = clk_get_rate(mmc_parent);
179         if (!mmc_parent_rate)
180                 return -EINVAL;
181
182         if (degrees != 180) {
183                 u16 step, mmc_div;
184
185                 /* Get MMC clock divider */
186                 mmc_div = mmc_parent_rate / mmc_rate;
187
188                 /*
189                  * We can only outphase the clocks by multiple of the
190                  * PLL's period.
191                  *
192                  * Since the MMC clock in only a divider, and the
193                  * formula to get the outphasing in degrees is deg =
194                  * 360 * delta / period
195                  *
196                  * If we simplify this formula, we can see that the
197                  * only thing that we're concerned about is the number
198                  * of period we want to outphase our clock from, and
199                  * the divider set by the MMC clock.
200                  */
201                 step = DIV_ROUND_CLOSEST(360, mmc_div);
202                 delay = DIV_ROUND_CLOSEST(degrees, step);
203         } else {
204                 delay = 0;
205         }
206
207         spin_lock_irqsave(phase->lock, flags);
208         value = readl(phase->reg);
209         value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
210         value |= delay << phase->data->offset;
211         writel(value, phase->reg);
212         spin_unlock_irqrestore(phase->lock, flags);
213
214         return 0;
215 }
216
217 static const struct clk_ops mmc_clk_ops = {
218         .get_phase      = mmc_get_phase,
219         .set_phase      = mmc_set_phase,
220 };
221
222 static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
223                                              struct mmc_phase_data *data)
224 {
225         const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
226         struct clk_init_data init = {
227                 .num_parents    = 1,
228                 .parent_names   = parent_names,
229                 .ops            = &mmc_clk_ops,
230         };
231
232         struct mmc_phase *phase;
233         struct clk *clk;
234
235         phase = kmalloc(sizeof(*phase), GFP_KERNEL);
236         if (!phase)
237                 return;
238
239         phase->hw.init = &init;
240
241         phase->reg = of_iomap(node, 0);
242         if (!phase->reg)
243                 goto err_free;
244
245         phase->data = data;
246         phase->lock = &sun4i_a10_mod0_lock;
247
248         if (of_property_read_string(node, "clock-output-names", &init.name))
249                 init.name = node->name;
250
251         clk = clk_register(NULL, &phase->hw);
252         if (IS_ERR(clk))
253                 goto err_unmap;
254
255         of_clk_add_provider(node, of_clk_src_simple_get, clk);
256
257         return;
258
259 err_unmap:
260         iounmap(phase->reg);
261 err_free:
262         kfree(phase);
263 }
264
265
266 static struct mmc_phase_data mmc_output_clk = {
267         .offset = 8,
268 };
269
270 static struct mmc_phase_data mmc_sample_clk = {
271         .offset = 20,
272 };
273
274 static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
275 {
276         sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
277 }
278 CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
279
280 static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
281 {
282         sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
283 }
284 CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);