aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/sunxi/clk-sunxi.c
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2014-06-26 11:55:43 -0400
committerMaxime Ripard <maxime.ripard@free-electrons.com>2014-07-04 06:05:17 -0400
commit515c1a4bdcd9b55e2c21e897a9ca276bd708d145 (patch)
tree8e6b064a92ac32dd444a94ab49d2bdacc371c609 /drivers/clk/sunxi/clk-sunxi.c
parentea5671bffbb2b6eefdce7e467a162ae2eef032ac (diff)
clk: sunxi: Add A23 clocks support
The clock control unit on the A23 is similar to the one found on the A31. The AHB1, APB1, APB2 gates on the A23 are almost identical to the ones on the A31, but some outputs are missing. The main CPU PLL (PLL1) however is like that on older Allwinner SoCs, such as the A10 or A20, but the N factor starts from 1 instead of 0. This patch adds support for PLL1 and all the basic clock muxes and gates. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Diffstat (limited to 'drivers/clk/sunxi/clk-sunxi.c')
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 6fe9492f84ad..8975972f6da5 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -164,6 +164,54 @@ static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
164} 164}
165 165
166/** 166/**
167 * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1
168 * PLL1 rate is calculated as follows
169 * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
170 * parent_rate is always 24Mhz
171 */
172
173static void sun8i_a23_get_pll1_factors(u32 *freq, u32 parent_rate,
174 u8 *n, u8 *k, u8 *m, u8 *p)
175{
176 u8 div;
177
178 /* Normalize value to a 6M multiple */
179 div = *freq / 6000000;
180 *freq = 6000000 * div;
181
182 /* we were called to round the frequency, we can now return */
183 if (n == NULL)
184 return;
185
186 /* m is always zero for pll1 */
187 *m = 0;
188
189 /* k is 1 only on these cases */
190 if (*freq >= 768000000 || *freq == 42000000 || *freq == 54000000)
191 *k = 1;
192 else
193 *k = 0;
194
195 /* p will be 2 for divs under 20 and odd divs under 32 */
196 if (div < 20 || (div < 32 && (div & 1)))
197 *p = 2;
198
199 /* p will be 1 for even divs under 32, divs under 40 and odd pairs
200 * of divs between 40-62 */
201 else if (div < 40 || (div < 64 && (div & 2)))
202 *p = 1;
203
204 /* any other entries have p = 0 */
205 else
206 *p = 0;
207
208 /* calculate a suitable n based on k and p */
209 div <<= *p;
210 div /= (*k + 1);
211 *n = div / 4 - 1;
212}
213
214/**
167 * sun4i_get_pll5_factors() - calculates n, k factors for PLL5 215 * sun4i_get_pll5_factors() - calculates n, k factors for PLL5
168 * PLL5 rate is calculated as follows 216 * PLL5 rate is calculated as follows
169 * rate = parent_rate * n * (k + 1) 217 * rate = parent_rate * n * (k + 1)
@@ -422,6 +470,18 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
422 .mwidth = 2, 470 .mwidth = 2,
423}; 471};
424 472
473static struct clk_factors_config sun8i_a23_pll1_config = {
474 .nshift = 8,
475 .nwidth = 5,
476 .kshift = 4,
477 .kwidth = 2,
478 .mshift = 0,
479 .mwidth = 2,
480 .pshift = 16,
481 .pwidth = 2,
482 .n_start = 1,
483};
484
425static struct clk_factors_config sun4i_pll5_config = { 485static struct clk_factors_config sun4i_pll5_config = {
426 .nshift = 8, 486 .nshift = 8,
427 .nwidth = 5, 487 .nwidth = 5,
@@ -471,6 +531,12 @@ static const struct factors_data sun6i_a31_pll1_data __initconst = {
471 .getter = sun6i_a31_get_pll1_factors, 531 .getter = sun6i_a31_get_pll1_factors,
472}; 532};
473 533
534static const struct factors_data sun8i_a23_pll1_data __initconst = {
535 .enable = 31,
536 .table = &sun8i_a23_pll1_config,
537 .getter = sun8i_a23_get_pll1_factors,
538};
539
474static const struct factors_data sun7i_a20_pll4_data __initconst = { 540static const struct factors_data sun7i_a20_pll4_data __initconst = {
475 .enable = 31, 541 .enable = 31,
476 .table = &sun4i_pll5_config, 542 .table = &sun4i_pll5_config,
@@ -673,6 +739,23 @@ static const struct div_data sun4i_axi_data __initconst = {
673 .width = 2, 739 .width = 2,
674}; 740};
675 741
742static const struct clk_div_table sun8i_a23_axi_table[] __initconst = {
743 { .val = 0, .div = 1 },
744 { .val = 1, .div = 2 },
745 { .val = 2, .div = 3 },
746 { .val = 3, .div = 4 },
747 { .val = 4, .div = 4 },
748 { .val = 5, .div = 4 },
749 { .val = 6, .div = 4 },
750 { .val = 7, .div = 4 },
751 { } /* sentinel */
752};
753
754static const struct div_data sun8i_a23_axi_data __initconst = {
755 .width = 3,
756 .table = sun8i_a23_axi_table,
757};
758
676static const struct div_data sun4i_ahb_data __initconst = { 759static const struct div_data sun4i_ahb_data __initconst = {
677 .shift = 4, 760 .shift = 4,
678 .pow = 1, 761 .pow = 1,
@@ -805,6 +888,10 @@ static const struct gates_data sun7i_a20_ahb_gates_data __initconst = {
805 .mask = { 0x12f77fff, 0x16ff3f }, 888 .mask = { 0x12f77fff, 0x16ff3f },
806}; 889};
807 890
891static const struct gates_data sun8i_a23_ahb1_gates_data __initconst = {
892 .mask = {0x25386742, 0x2505111},
893};
894
808static const struct gates_data sun4i_apb0_gates_data __initconst = { 895static const struct gates_data sun4i_apb0_gates_data __initconst = {
809 .mask = {0x4EF}, 896 .mask = {0x4EF},
810}; 897};
@@ -837,6 +924,10 @@ static const struct gates_data sun6i_a31_apb1_gates_data __initconst = {
837 .mask = {0x3031}, 924 .mask = {0x3031},
838}; 925};
839 926
927static const struct gates_data sun8i_a23_apb1_gates_data __initconst = {
928 .mask = {0x3021},
929};
930
840static const struct gates_data sun6i_a31_apb2_gates_data __initconst = { 931static const struct gates_data sun6i_a31_apb2_gates_data __initconst = {
841 .mask = {0x3F000F}, 932 .mask = {0x3F000F},
842}; 933};
@@ -845,6 +936,10 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
845 .mask = { 0xff80ff }, 936 .mask = { 0xff80ff },
846}; 937};
847 938
939static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
940 .mask = {0x1F0007},
941};
942
848static const struct gates_data sun4i_a10_usb_gates_data __initconst = { 943static const struct gates_data sun4i_a10_usb_gates_data __initconst = {
849 .mask = {0x1C0}, 944 .mask = {0x1C0},
850 .reset_mask = 0x07, 945 .reset_mask = 0x07,
@@ -1100,6 +1195,7 @@ free_clkdata:
1100static const struct of_device_id clk_factors_match[] __initconst = { 1195static const struct of_device_id clk_factors_match[] __initconst = {
1101 {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,}, 1196 {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,},
1102 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, 1197 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
1198 {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,},
1103 {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, 1199 {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
1104 {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,}, 1200 {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
1105 {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, 1201 {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
@@ -1111,6 +1207,7 @@ static const struct of_device_id clk_factors_match[] __initconst = {
1111/* Matches for divider clocks */ 1207/* Matches for divider clocks */
1112static const struct of_device_id clk_div_match[] __initconst = { 1208static const struct of_device_id clk_div_match[] __initconst = {
1113 {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,}, 1209 {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,},
1210 {.compatible = "allwinner,sun8i-a23-axi-clk", .data = &sun8i_a23_axi_data,},
1114 {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,}, 1211 {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,},
1115 {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,}, 1212 {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,},
1116 {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,}, 1213 {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
@@ -1140,6 +1237,7 @@ static const struct of_device_id clk_gates_match[] __initconst = {
1140 {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, 1237 {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
1141 {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,}, 1238 {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
1142 {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,}, 1239 {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
1240 {.compatible = "allwinner,sun8i-a23-ahb1-gates-clk", .data = &sun8i_a23_ahb1_gates_data,},
1143 {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, 1241 {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
1144 {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, 1242 {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
1145 {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, 1243 {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
@@ -1149,7 +1247,9 @@ static const struct of_device_id clk_gates_match[] __initconst = {
1149 {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, 1247 {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
1150 {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,}, 1248 {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
1151 {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,}, 1249 {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
1250 {.compatible = "allwinner,sun8i-a23-apb1-gates-clk", .data = &sun8i_a23_apb1_gates_data,},
1152 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, 1251 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
1252 {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,},
1153 {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, 1253 {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
1154 {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,}, 1254 {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
1155 {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,}, 1255 {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,},
@@ -1236,3 +1336,4 @@ static void __init sun6i_init_clocks(struct device_node *node)
1236 ARRAY_SIZE(sun6i_critical_clocks)); 1336 ARRAY_SIZE(sun6i_critical_clocks));
1237} 1337}
1238CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks); 1338CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
1339CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);