aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmilio López <emilio@elopez.com.ar>2013-12-22 22:32:39 -0500
committerEmilio López <emilio@elopez.com.ar>2013-12-28 15:08:22 -0500
commit7551769a225f3e600d6455e63ae00d51df37ff59 (patch)
treee2682fcc3bd43d228022be9be528f5ac58ab5046
parentd584c1331d6421e2387eab10b11fa6f08b4a4b5f (diff)
clk: sunxi: mod0 support
This commit implements support for the "module 0" type of clocks, as used by MMC, IR, NAND, SATA and other components. Signed-off-by: Emilio López <emilio@elopez.com.ar> Acked-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt5
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c57
2 files changed, 61 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 80b2a39b17a2..46d8433b2a8c 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -35,10 +35,13 @@ Required properties:
35 "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20 35 "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
36 "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31 36 "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
37 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 37 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
38 "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
38 39
39Required properties for all clocks: 40Required properties for all clocks:
40- reg : shall be the control register address for the clock. 41- reg : shall be the control register address for the clock.
41- clocks : shall be the input parent clock(s) phandle for the clock 42- clocks : shall be the input parent clock(s) phandle for the clock. For
43 multiplexed clocks, the list order must match the hardware
44 programming order.
42- #clock-cells : from common clock binding; shall be set to 0 except for 45- #clock-cells : from common clock binding; shall be set to 0 except for
43 "allwinner,*-gates-clk" where it shall be set to 1 46 "allwinner,*-gates-clk" where it shall be set to 1
44 47
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index e90df083a36d..75fbc48129be 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -295,6 +295,47 @@ static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate,
295 295
296 296
297/** 297/**
298 * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks
299 * MMC rate is calculated as follows
300 * rate = (parent_rate >> p) / (m + 1);
301 */
302
303static void sun4i_get_mod0_factors(u32 *freq, u32 parent_rate,
304 u8 *n, u8 *k, u8 *m, u8 *p)
305{
306 u8 div, calcm, calcp;
307
308 /* These clocks can only divide, so we will never be able to achieve
309 * frequencies higher than the parent frequency */
310 if (*freq > parent_rate)
311 *freq = parent_rate;
312
313 div = parent_rate / *freq;
314
315 if (div < 16)
316 calcp = 0;
317 else if (div / 2 < 16)
318 calcp = 1;
319 else if (div / 4 < 16)
320 calcp = 2;
321 else
322 calcp = 3;
323
324 calcm = DIV_ROUND_UP(div, 1 << calcp);
325
326 *freq = (parent_rate >> calcp) / calcm;
327
328 /* we were called to round the frequency, we can now return */
329 if (n == NULL)
330 return;
331
332 *m = calcm - 1;
333 *p = calcp;
334}
335
336
337
338/**
298 * sunxi_factors_clk_setup() - Setup function for factor clocks 339 * sunxi_factors_clk_setup() - Setup function for factor clocks
299 */ 340 */
300 341
@@ -341,6 +382,14 @@ static struct clk_factors_config sun4i_apb1_config = {
341 .pwidth = 2, 382 .pwidth = 2,
342}; 383};
343 384
385/* user manual says "n" but it's really "p" */
386static struct clk_factors_config sun4i_mod0_config = {
387 .mshift = 0,
388 .mwidth = 4,
389 .pshift = 16,
390 .pwidth = 2,
391};
392
344static const struct factors_data sun4i_pll1_data __initconst = { 393static const struct factors_data sun4i_pll1_data __initconst = {
345 .enable = 31, 394 .enable = 31,
346 .table = &sun4i_pll1_config, 395 .table = &sun4i_pll1_config,
@@ -364,6 +413,13 @@ static const struct factors_data sun4i_apb1_data __initconst = {
364 .getter = sun4i_get_apb1_factors, 413 .getter = sun4i_get_apb1_factors,
365}; 414};
366 415
416static const struct factors_data sun4i_mod0_data __initconst = {
417 .enable = 31,
418 .mux = 24,
419 .table = &sun4i_mod0_config,
420 .getter = sun4i_get_mod0_factors,
421};
422
367static struct clk * __init sunxi_factors_clk_setup(struct device_node *node, 423static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
368 const struct factors_data *data) 424 const struct factors_data *data)
369{ 425{
@@ -852,6 +908,7 @@ static const struct of_device_id clk_factors_match[] __initconst = {
852 {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, 908 {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
853 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, 909 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
854 {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,}, 910 {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
911 {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,},
855 {} 912 {}
856}; 913};
857 914