1 From 5ca9eadcb5f5cd9af6f1650029ad64052a1a0b10 Mon Sep 17 00:00:00 2001
2 From: Chen-Yu Tsai <wens@csie.org>
3 Date: Tue, 24 Dec 2013 21:26:17 +0800
4 Subject: [PATCH] clk: sunxi: Allwinner A20 output clock support
6 This patch adds support for the external clock outputs on the
7 Allwinner A20 SoC. The clock outputs are similar to "module 0"
8 type clocks, with different offsets and widths for clock factors.
10 Signed-off-by: Chen-Yu Tsai <wens@csie.org>
12 Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
13 drivers/clk/sunxi/clk-sunxi.c | 57 +++++++++++++++++++++++
14 2 files changed, 58 insertions(+)
16 diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
17 index 941bd93..79c7197 100644
18 --- a/Documentation/devicetree/bindings/clock/sunxi.txt
19 +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
20 @@ -36,6 +36,7 @@ Required properties:
21 "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
22 "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
23 "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
24 + "allwinner,sun7i-a20-out-clk" - for the external output clocks
26 Required properties for all clocks:
27 - reg : shall be the control register address for the clock.
28 diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
29 index 8a07a68..df1f385 100644
30 --- a/drivers/clk/sunxi/clk-sunxi.c
31 +++ b/drivers/clk/sunxi/clk-sunxi.c
32 @@ -396,6 +396,47 @@ void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output)
36 + * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B
37 + * CLK_OUT rate is calculated as follows
38 + * rate = (parent_rate >> p) / (m + 1);
41 +static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
42 + u8 *n, u8 *k, u8 *m, u8 *p)
44 + u8 div, calcm, calcp;
46 + /* These clocks can only divide, so we will never be able to achieve
47 + * frequencies higher than the parent frequency */
48 + if (*freq > parent_rate)
49 + *freq = parent_rate;
51 + div = parent_rate / *freq;
55 + else if (div / 2 < 32)
57 + else if (div / 4 < 32)
62 + calcm = DIV_ROUND_UP(div, 1 << calcp);
64 + *freq = (parent_rate >> calcp) / calcm;
66 + /* we were called to round the frequency, we can now return */
77 * sunxi_factors_clk_setup() - Setup function for factor clocks
80 @@ -455,6 +496,14 @@ struct factors_data {
84 +/* user manual says "n" but it's really "p" */
85 +static struct clk_factors_config sun7i_a20_out_config = {
92 static const struct factors_data sun4i_pll1_data __initconst = {
94 .table = &sun4i_pll1_config,
95 @@ -492,6 +541,13 @@ struct factors_data {
96 .getter = sun4i_get_mod0_factors,
99 +static const struct factors_data sun7i_a20_out_data __initconst = {
102 + .table = &sun7i_a20_out_config,
103 + .getter = sun7i_a20_get_out_factors,
106 static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
107 const struct factors_data *data)
109 @@ -995,6 +1051,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
110 {.compatible = "allwinner,sun5i-a13-ahb-clk", .data = &sun5i_a13_ahb_data,},
111 {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
112 {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,},
113 + {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},