aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt13
-rw-r--r--drivers/clk/sunxi/clk-mod0.c131
2 files changed, 77 insertions, 67 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 9dc4f55a04ad..e4c42276c577 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -55,8 +55,7 @@ Required properties:
55 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 55 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
56 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 56 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
57 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 57 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
58 "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10 58 "allwinner,sun4i-a10-mmc-clk" - for the MMC clock
59 "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
60 "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks 59 "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
61 "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 60 "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
62 "allwinner,sun7i-a20-out-clk" - for the external output clocks 61 "allwinner,sun7i-a20-out-clk" - for the external output clocks
@@ -95,6 +94,10 @@ For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output
95is the normal PLL6 output, or "pll6". The second output is rate doubled 94is the normal PLL6 output, or "pll6". The second output is rate doubled
96PLL6, or "pll6x2". 95PLL6, or "pll6x2".
97 96
97The "allwinner,sun4i-a10-mmc-clk" has three different outputs: the
98main clock, with the ID 0, and the output and sample clocks, with the
99IDs 1 and 2, respectively.
100
98For example: 101For example:
99 102
100osc24M: clk@01c20050 { 103osc24M: clk@01c20050 {
@@ -138,11 +141,11 @@ cpu: cpu@01c20054 {
138}; 141};
139 142
140mmc0_clk: clk@01c20088 { 143mmc0_clk: clk@01c20088 {
141 #clock-cells = <0>; 144 #clock-cells = <1>;
142 compatible = "allwinner,sun4i-mod0-clk"; 145 compatible = "allwinner,sun4i-a10-mmc-clk";
143 reg = <0x01c20088 0x4>; 146 reg = <0x01c20088 0x4>;
144 clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; 147 clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
145 clock-output-names = "mmc0"; 148 clock-output-names = "mmc0", "mmc0_output", "mmc0_sample";
146}; 149};
147 150
148mii_phy_tx_clk: clk@2 { 151mii_phy_tx_clk: clk@2 {
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index bf8fcd8c940e..e37eb6fe19e8 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -152,14 +152,10 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
152} 152}
153CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup); 153CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
154 154
155struct mmc_phase_data {
156 u8 offset;
157};
158
159struct mmc_phase { 155struct mmc_phase {
160 struct clk_hw hw; 156 struct clk_hw hw;
157 u8 offset;
161 void __iomem *reg; 158 void __iomem *reg;
162 struct mmc_phase_data *data;
163 spinlock_t *lock; 159 spinlock_t *lock;
164}; 160};
165 161
@@ -175,7 +171,7 @@ static int mmc_get_phase(struct clk_hw *hw)
175 u8 delay; 171 u8 delay;
176 172
177 value = readl(phase->reg); 173 value = readl(phase->reg);
178 delay = (value >> phase->data->offset) & 0x3; 174 delay = (value >> phase->offset) & 0x3;
179 175
180 if (!delay) 176 if (!delay)
181 return 180; 177 return 180;
@@ -263,8 +259,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
263 259
264 spin_lock_irqsave(phase->lock, flags); 260 spin_lock_irqsave(phase->lock, flags);
265 value = readl(phase->reg); 261 value = readl(phase->reg);
266 value &= ~GENMASK(phase->data->offset + 3, phase->data->offset); 262 value &= ~GENMASK(phase->offset + 3, phase->offset);
267 value |= delay << phase->data->offset; 263 value |= delay << phase->offset;
268 writel(value, phase->reg); 264 writel(value, phase->reg);
269 spin_unlock_irqrestore(phase->lock, flags); 265 spin_unlock_irqrestore(phase->lock, flags);
270 266
@@ -276,66 +272,77 @@ static const struct clk_ops mmc_clk_ops = {
276 .set_phase = mmc_set_phase, 272 .set_phase = mmc_set_phase,
277}; 273};
278 274
279static void __init sun4i_a10_mmc_phase_setup(struct device_node *node, 275static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
280 struct mmc_phase_data *data)
281{
282 const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
283 struct clk_init_data init = {
284 .num_parents = 1,
285 .parent_names = parent_names,
286 .ops = &mmc_clk_ops,
287 };
288
289 struct mmc_phase *phase;
290 struct clk *clk;
291
292 phase = kmalloc(sizeof(*phase), GFP_KERNEL);
293 if (!phase)
294 return;
295
296 phase->hw.init = &init;
297 276
298 phase->reg = of_iomap(node, 0); 277static void __init sun4i_a10_mmc_setup(struct device_node *node)
299 if (!phase->reg) 278{
300 goto err_free; 279 struct clk_onecell_data *clk_data;
280 const char *parent;
281 void __iomem *reg;
282 int i;
301 283
302 phase->data = data; 284 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
303 phase->lock = &sun4i_a10_mod0_lock; 285 if (IS_ERR(reg)) {
286 pr_err("Couldn't map the %s clock registers\n", node->name);
287 return;
288 }
304 289
305 if (of_property_read_string(node, "clock-output-names", &init.name)) 290 clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
306 init.name = node->name; 291 if (!clk_data)
292 return;
307 293
308 clk = clk_register(NULL, &phase->hw); 294 clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
309 if (IS_ERR(clk)) 295 if (!clk_data->clks)
310 goto err_unmap; 296 goto err_free_data;
297
298 clk_data->clk_num = 3;
299 clk_data->clks[0] = sunxi_factors_register(node,
300 &sun4i_a10_mod0_data,
301 &sun4i_a10_mmc_lock, reg);
302 if (!clk_data->clks[0])
303 goto err_free_clks;
304
305 parent = __clk_get_name(clk_data->clks[0]);
306
307 for (i = 1; i < 3; i++) {
308 struct clk_init_data init = {
309 .num_parents = 1,
310 .parent_names = &parent,
311 .ops = &mmc_clk_ops,
312 };
313 struct mmc_phase *phase;
314
315 phase = kmalloc(sizeof(*phase), GFP_KERNEL);
316 if (!phase)
317 continue;
318
319 phase->hw.init = &init;
320 phase->reg = reg;
321 phase->lock = &sun4i_a10_mmc_lock;
322
323 if (i == 1)
324 phase->offset = 8;
325 else
326 phase->offset = 20;
327
328 if (of_property_read_string_index(node, "clock-output-names",
329 i, &init.name))
330 init.name = node->name;
331
332 clk_data->clks[i] = clk_register(NULL, &phase->hw);
333 if (IS_ERR(clk_data->clks[i])) {
334 kfree(phase);
335 continue;
336 }
337 }
311 338
312 of_clk_add_provider(node, of_clk_src_simple_get, clk); 339 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
313 340
314 return; 341 return;
315 342
316err_unmap: 343err_free_clks:
317 iounmap(phase->reg); 344 kfree(clk_data->clks);
318err_free: 345err_free_data:
319 kfree(phase); 346 kfree(clk_data);
320}
321
322
323static struct mmc_phase_data mmc_output_clk = {
324 .offset = 8,
325};
326
327static struct mmc_phase_data mmc_sample_clk = {
328 .offset = 20,
329};
330
331static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
332{
333 sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
334}
335CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
336
337static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
338{
339 sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
340} 347}
341CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup); 348CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);