aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Turquette <mturquette@linaro.org>2015-03-25 17:51:40 -0400
committerMichael Turquette <mturquette@linaro.org>2015-03-25 17:51:40 -0400
commitfe15dedc02e4ee29edfc84bbbf5ee42827e36ac7 (patch)
treeb64f9ceebdbf3019f3d10ecb404f6fc002223113
parentc77662a4df847e7b75ff8c5f2314dd4f022377e3 (diff)
parentf1017969661dd33ead5ba7c3f4a0793c6611441a (diff)
Merge tag 'sunxi-clocks-for-4.1' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into clk-next
Allwinner clocks changes for 4.1 The usual round of clock changes for the Allwinner SoCs. There is nothing really standing out here, but a few changes and fixes, most notably to allow the AHB clock to be parented to a PLL, instead of the CPU clock to avoid any AHB rate change due to cpufreq.
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt3
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c185
-rw-r--r--drivers/clk/sunxi/clk-usb.c233
4 files changed, 319 insertions, 103 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 60b44285250d..4fa11af3d378 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -20,6 +20,7 @@ Required properties:
20 "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23 20 "allwinner,sun8i-a23-axi-clk" - for the AXI clock on A23
21 "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates 21 "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
22 "allwinner,sun4i-a10-ahb-clk" - for the AHB clock 22 "allwinner,sun4i-a10-ahb-clk" - for the AHB clock
23 "allwinner,sun5i-a13-ahb-clk" - for the AHB clock on A13
23 "allwinner,sun9i-a80-ahb-clk" - for the AHB bus clocks on A80 24 "allwinner,sun9i-a80-ahb-clk" - for the AHB bus clocks on A80
24 "allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10 25 "allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
25 "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13 26 "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
@@ -66,6 +67,8 @@ Required properties:
66 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 67 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
67 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 68 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
68 "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31 69 "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
70 "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
71 "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
69 72
70Required properties for all clocks: 73Required properties for all clocks:
71- reg : shall be the control register address for the clock. 74- reg : shall be the control register address for the clock.
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 3a5292e3fcf8..058f273d6154 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -9,6 +9,7 @@ obj-y += clk-mod0.o
9obj-y += clk-sun8i-mbus.o 9obj-y += clk-sun8i-mbus.o
10obj-y += clk-sun9i-core.o 10obj-y += clk-sun9i-core.o
11obj-y += clk-sun9i-mmc.o 11obj-y += clk-sun9i-mmc.o
12obj-y += clk-usb.o
12 13
13obj-$(CONFIG_MFD_SUN6I_PRCM) += \ 14obj-$(CONFIG_MFD_SUN6I_PRCM) += \
14 clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \ 15 clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 379324eb5486..7e1e2bd189b6 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -482,6 +482,45 @@ static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
482} 482}
483 483
484/** 484/**
485 * sun5i_a13_get_ahb_factors() - calculates m, p factors for AHB
486 * AHB rate is calculated as follows
487 * rate = parent_rate >> p
488 */
489
490static void sun5i_a13_get_ahb_factors(u32 *freq, u32 parent_rate,
491 u8 *n, u8 *k, u8 *m, u8 *p)
492{
493 u32 div;
494
495 /* divide only */
496 if (parent_rate < *freq)
497 *freq = parent_rate;
498
499 /*
500 * user manual says valid speed is 8k ~ 276M, but tests show it
501 * can work at speeds up to 300M, just after reparenting to pll6
502 */
503 if (*freq < 8000)
504 *freq = 8000;
505 if (*freq > 300000000)
506 *freq = 300000000;
507
508 div = order_base_2(DIV_ROUND_UP(parent_rate, *freq));
509
510 /* p = 0 ~ 3 */
511 if (div > 3)
512 div = 3;
513
514 *freq = parent_rate >> div;
515
516 /* we were called to round the frequency, we can now return */
517 if (p == NULL)
518 return;
519
520 *p = div;
521}
522
523/**
485 * sun4i_get_apb1_factors() - calculates m, p factors for APB1 524 * sun4i_get_apb1_factors() - calculates m, p factors for APB1
486 * APB1 rate is calculated as follows 525 * APB1 rate is calculated as follows
487 * rate = (parent_rate >> p) / (m + 1); 526 * rate = (parent_rate >> p) / (m + 1);
@@ -616,6 +655,11 @@ static struct clk_factors_config sun6i_a31_pll6_config = {
616 .n_start = 1, 655 .n_start = 1,
617}; 656};
618 657
658static struct clk_factors_config sun5i_a13_ahb_config = {
659 .pshift = 4,
660 .pwidth = 2,
661};
662
619static struct clk_factors_config sun4i_apb1_config = { 663static struct clk_factors_config sun4i_apb1_config = {
620 .mshift = 0, 664 .mshift = 0,
621 .mwidth = 5, 665 .mwidth = 5,
@@ -676,6 +720,13 @@ static const struct factors_data sun6i_a31_pll6_data __initconst = {
676 .name = "pll6x2", 720 .name = "pll6x2",
677}; 721};
678 722
723static const struct factors_data sun5i_a13_ahb_data __initconst = {
724 .mux = 6,
725 .muxmask = BIT(1) | BIT(0),
726 .table = &sun5i_a13_ahb_config,
727 .getter = sun5i_a13_get_ahb_factors,
728};
729
679static const struct factors_data sun4i_apb1_data __initconst = { 730static const struct factors_data sun4i_apb1_data __initconst = {
680 .mux = 24, 731 .mux = 24,
681 .muxmask = BIT(1) | BIT(0), 732 .muxmask = BIT(1) | BIT(0),
@@ -838,59 +889,6 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
838 889
839 890
840/** 891/**
841 * sunxi_gates_reset... - reset bits in leaf gate clk registers handling
842 */
843
844struct gates_reset_data {
845 void __iomem *reg;
846 spinlock_t *lock;
847 struct reset_controller_dev rcdev;
848};
849
850static int sunxi_gates_reset_assert(struct reset_controller_dev *rcdev,
851 unsigned long id)
852{
853 struct gates_reset_data *data = container_of(rcdev,
854 struct gates_reset_data,
855 rcdev);
856 unsigned long flags;
857 u32 reg;
858
859 spin_lock_irqsave(data->lock, flags);
860
861 reg = readl(data->reg);
862 writel(reg & ~BIT(id), data->reg);
863
864 spin_unlock_irqrestore(data->lock, flags);
865
866 return 0;
867}
868
869static int sunxi_gates_reset_deassert(struct reset_controller_dev *rcdev,
870 unsigned long id)
871{
872 struct gates_reset_data *data = container_of(rcdev,
873 struct gates_reset_data,
874 rcdev);
875 unsigned long flags;
876 u32 reg;
877
878 spin_lock_irqsave(data->lock, flags);
879
880 reg = readl(data->reg);
881 writel(reg | BIT(id), data->reg);
882
883 spin_unlock_irqrestore(data->lock, flags);
884
885 return 0;
886}
887
888static struct reset_control_ops sunxi_gates_reset_ops = {
889 .assert = sunxi_gates_reset_assert,
890 .deassert = sunxi_gates_reset_deassert,
891};
892
893/**
894 * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks 892 * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks
895 */ 893 */
896 894
@@ -898,7 +896,6 @@ static struct reset_control_ops sunxi_gates_reset_ops = {
898 896
899struct gates_data { 897struct gates_data {
900 DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE); 898 DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
901 u32 reset_mask;
902}; 899};
903 900
904static const struct gates_data sun4i_axi_gates_data __initconst = { 901static const struct gates_data sun4i_axi_gates_data __initconst = {
@@ -997,26 +994,10 @@ static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
997 .mask = {0x1F0007}, 994 .mask = {0x1F0007},
998}; 995};
999 996
1000static const struct gates_data sun4i_a10_usb_gates_data __initconst = {
1001 .mask = {0x1C0},
1002 .reset_mask = 0x07,
1003};
1004
1005static const struct gates_data sun5i_a13_usb_gates_data __initconst = {
1006 .mask = {0x140},
1007 .reset_mask = 0x03,
1008};
1009
1010static const struct gates_data sun6i_a31_usb_gates_data __initconst = {
1011 .mask = { BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8) },
1012 .reset_mask = BIT(2) | BIT(1) | BIT(0),
1013};
1014
1015static void __init sunxi_gates_clk_setup(struct device_node *node, 997static void __init sunxi_gates_clk_setup(struct device_node *node,
1016 struct gates_data *data) 998 struct gates_data *data)
1017{ 999{
1018 struct clk_onecell_data *clk_data; 1000 struct clk_onecell_data *clk_data;
1019 struct gates_reset_data *reset_data;
1020 const char *clk_parent; 1001 const char *clk_parent;
1021 const char *clk_name; 1002 const char *clk_name;
1022 void __iomem *reg; 1003 void __iomem *reg;
@@ -1057,21 +1038,6 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
1057 clk_data->clk_num = i; 1038 clk_data->clk_num = i;
1058 1039
1059 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 1040 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
1060
1061 /* Register a reset controler for gates with reset bits */
1062 if (data->reset_mask == 0)
1063 return;
1064
1065 reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
1066 if (!reset_data)
1067 return;
1068
1069 reset_data->reg = reg;
1070 reset_data->lock = &clk_lock;
1071 reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
1072 reset_data->rcdev.ops = &sunxi_gates_reset_ops;
1073 reset_data->rcdev.of_node = node;
1074 reset_controller_register(&reset_data->rcdev);
1075} 1041}
1076 1042
1077 1043
@@ -1080,13 +1046,20 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
1080 * sunxi_divs_clk_setup() helper data 1046 * sunxi_divs_clk_setup() helper data
1081 */ 1047 */
1082 1048
1083#define SUNXI_DIVS_MAX_QTY 2 1049#define SUNXI_DIVS_MAX_QTY 4
1084#define SUNXI_DIVISOR_WIDTH 2 1050#define SUNXI_DIVISOR_WIDTH 2
1085 1051
1086struct divs_data { 1052struct divs_data {
1087 const struct factors_data *factors; /* data for the factor clock */ 1053 const struct factors_data *factors; /* data for the factor clock */
1088 int ndivs; /* number of children */ 1054 int ndivs; /* number of outputs */
1055 /*
1056 * List of outputs. Refer to the diagram for sunxi_divs_clk_setup():
1057 * self or base factor clock refers to the output from the pll
1058 * itself. The remaining refer to fixed or configurable divider
1059 * outputs.
1060 */
1089 struct { 1061 struct {
1062 u8 self; /* is it the base factor clock? (only one) */
1090 u8 fixed; /* is it a fixed divisor? if not... */ 1063 u8 fixed; /* is it a fixed divisor? if not... */
1091 struct clk_div_table *table; /* is it a table based divisor? */ 1064 struct clk_div_table *table; /* is it a table based divisor? */
1092 u8 shift; /* otherwise it's a normal divisor with this shift */ 1065 u8 shift; /* otherwise it's a normal divisor with this shift */
@@ -1109,23 +1082,27 @@ static const struct divs_data pll5_divs_data __initconst = {
1109 .div = { 1082 .div = {
1110 { .shift = 0, .pow = 0, }, /* M, DDR */ 1083 { .shift = 0, .pow = 0, }, /* M, DDR */
1111 { .shift = 16, .pow = 1, }, /* P, other */ 1084 { .shift = 16, .pow = 1, }, /* P, other */
1085 /* No output for the base factor clock */
1112 } 1086 }
1113}; 1087};
1114 1088
1115static const struct divs_data pll6_divs_data __initconst = { 1089static const struct divs_data pll6_divs_data __initconst = {
1116 .factors = &sun4i_pll6_data, 1090 .factors = &sun4i_pll6_data,
1117 .ndivs = 2, 1091 .ndivs = 4,
1118 .div = { 1092 .div = {
1119 { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */ 1093 { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */
1120 { .fixed = 2 }, /* P, other */ 1094 { .fixed = 2 }, /* P, other */
1095 { .self = 1 }, /* base factor clock, 2x */
1096 { .fixed = 4 }, /* pll6 / 4, used as ahb input */
1121 } 1097 }
1122}; 1098};
1123 1099
1124static const struct divs_data sun6i_a31_pll6_divs_data __initconst = { 1100static const struct divs_data sun6i_a31_pll6_divs_data __initconst = {
1125 .factors = &sun6i_a31_pll6_data, 1101 .factors = &sun6i_a31_pll6_data,
1126 .ndivs = 1, 1102 .ndivs = 2,
1127 .div = { 1103 .div = {
1128 { .fixed = 2 }, /* normal output */ 1104 { .fixed = 2 }, /* normal output */
1105 { .self = 1 }, /* base factor clock, 2x */
1129 } 1106 }
1130}; 1107};
1131 1108
@@ -1156,6 +1133,10 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
1156 int ndivs = SUNXI_DIVS_MAX_QTY, i = 0; 1133 int ndivs = SUNXI_DIVS_MAX_QTY, i = 0;
1157 int flags, clkflags; 1134 int flags, clkflags;
1158 1135
1136 /* if number of children known, use it */
1137 if (data->ndivs)
1138 ndivs = data->ndivs;
1139
1159 /* Set up factor clock that we will be dividing */ 1140 /* Set up factor clock that we will be dividing */
1160 pclk = sunxi_factors_clk_setup(node, data->factors); 1141 pclk = sunxi_factors_clk_setup(node, data->factors);
1161 parent = __clk_get_name(pclk); 1142 parent = __clk_get_name(pclk);
@@ -1166,7 +1147,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
1166 if (!clk_data) 1147 if (!clk_data)
1167 return; 1148 return;
1168 1149
1169 clks = kzalloc((SUNXI_DIVS_MAX_QTY+1) * sizeof(*clks), GFP_KERNEL); 1150 clks = kcalloc(ndivs, sizeof(*clks), GFP_KERNEL);
1170 if (!clks) 1151 if (!clks)
1171 goto free_clkdata; 1152 goto free_clkdata;
1172 1153
@@ -1176,15 +1157,17 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
1176 * our RAM clock! */ 1157 * our RAM clock! */
1177 clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT; 1158 clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT;
1178 1159
1179 /* if number of children known, use it */
1180 if (data->ndivs)
1181 ndivs = data->ndivs;
1182
1183 for (i = 0; i < ndivs; i++) { 1160 for (i = 0; i < ndivs; i++) {
1184 if (of_property_read_string_index(node, "clock-output-names", 1161 if (of_property_read_string_index(node, "clock-output-names",
1185 i, &clk_name) != 0) 1162 i, &clk_name) != 0)
1186 break; 1163 break;
1187 1164
1165 /* If this is the base factor clock, only update clks */
1166 if (data->div[i].self) {
1167 clk_data->clks[i] = pclk;
1168 continue;
1169 }
1170
1188 gate_hw = NULL; 1171 gate_hw = NULL;
1189 rate_hw = NULL; 1172 rate_hw = NULL;
1190 rate_ops = NULL; 1173 rate_ops = NULL;
@@ -1243,9 +1226,6 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
1243 clk_register_clkdev(clks[i], clk_name, NULL); 1226 clk_register_clkdev(clks[i], clk_name, NULL);
1244 } 1227 }
1245 1228
1246 /* The last clock available on the getter is the parent */
1247 clks[i++] = pclk;
1248
1249 /* Adjust to the real max */ 1229 /* Adjust to the real max */
1250 clk_data->clk_num = i; 1230 clk_data->clk_num = i;
1251 1231
@@ -1269,6 +1249,7 @@ static const struct of_device_id clk_factors_match[] __initconst = {
1269 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,}, 1249 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
1270 {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,}, 1250 {.compatible = "allwinner,sun8i-a23-pll1-clk", .data = &sun8i_a23_pll1_data,},
1271 {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,}, 1251 {.compatible = "allwinner,sun7i-a20-pll4-clk", .data = &sun7i_a20_pll4_data,},
1252 {.compatible = "allwinner,sun5i-a13-ahb-clk", .data = &sun5i_a13_ahb_data,},
1272 {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,}, 1253 {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
1273 {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,}, 1254 {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
1274 {} 1255 {}
@@ -1324,9 +1305,6 @@ static const struct of_device_id clk_gates_match[] __initconst = {
1324 {.compatible = "allwinner,sun9i-a80-apb1-gates-clk", .data = &sun9i_a80_apb1_gates_data,}, 1305 {.compatible = "allwinner,sun9i-a80-apb1-gates-clk", .data = &sun9i_a80_apb1_gates_data,},
1325 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, 1306 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
1326 {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,}, 1307 {.compatible = "allwinner,sun8i-a23-apb2-gates-clk", .data = &sun8i_a23_apb2_gates_data,},
1327 {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
1328 {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
1329 {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,},
1330 {} 1308 {}
1331}; 1309};
1332 1310
@@ -1348,15 +1326,15 @@ static void __init sunxi_init_clocks(const char *clocks[], int nclocks)
1348{ 1326{
1349 unsigned int i; 1327 unsigned int i;
1350 1328
1329 /* Register divided output clocks */
1330 of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup);
1331
1351 /* Register factor clocks */ 1332 /* Register factor clocks */
1352 of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); 1333 of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
1353 1334
1354 /* Register divider clocks */ 1335 /* Register divider clocks */
1355 of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup); 1336 of_sunxi_table_clock_setup(clk_div_match, sunxi_divider_clk_setup);
1356 1337
1357 /* Register divided output clocks */
1358 of_sunxi_table_clock_setup(clk_divs_match, sunxi_divs_clk_setup);
1359
1360 /* Register mux clocks */ 1338 /* Register mux clocks */
1361 of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); 1339 of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup);
1362 1340
@@ -1385,6 +1363,7 @@ static void __init sun4i_a10_init_clocks(struct device_node *node)
1385CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); 1363CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks);
1386 1364
1387static const char *sun5i_critical_clocks[] __initdata = { 1365static const char *sun5i_critical_clocks[] __initdata = {
1366 "cpu",
1388 "pll5_ddr", 1367 "pll5_ddr",
1389 "ahb_sdram", 1368 "ahb_sdram",
1390}; 1369};
diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
new file mode 100644
index 000000000000..a86ed2f8d7af
--- /dev/null
+++ b/drivers/clk/sunxi/clk-usb.c
@@ -0,0 +1,233 @@
1/*
2 * Copyright 2013-2015 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.h>
20#include <linux/of_address.h>
21#include <linux/reset-controller.h>
22#include <linux/spinlock.h>
23
24
25/**
26 * sunxi_usb_reset... - reset bits in usb clk registers handling
27 */
28
29struct usb_reset_data {
30 void __iomem *reg;
31 spinlock_t *lock;
32 struct clk *clk;
33 struct reset_controller_dev rcdev;
34};
35
36static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev,
37 unsigned long id)
38{
39 struct usb_reset_data *data = container_of(rcdev,
40 struct usb_reset_data,
41 rcdev);
42 unsigned long flags;
43 u32 reg;
44
45 clk_prepare_enable(data->clk);
46 spin_lock_irqsave(data->lock, flags);
47
48 reg = readl(data->reg);
49 writel(reg & ~BIT(id), data->reg);
50
51 spin_unlock_irqrestore(data->lock, flags);
52 clk_disable_unprepare(data->clk);
53
54 return 0;
55}
56
57static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev,
58 unsigned long id)
59{
60 struct usb_reset_data *data = container_of(rcdev,
61 struct usb_reset_data,
62 rcdev);
63 unsigned long flags;
64 u32 reg;
65
66 clk_prepare_enable(data->clk);
67 spin_lock_irqsave(data->lock, flags);
68
69 reg = readl(data->reg);
70 writel(reg | BIT(id), data->reg);
71
72 spin_unlock_irqrestore(data->lock, flags);
73 clk_disable_unprepare(data->clk);
74
75 return 0;
76}
77
78static struct reset_control_ops sunxi_usb_reset_ops = {
79 .assert = sunxi_usb_reset_assert,
80 .deassert = sunxi_usb_reset_deassert,
81};
82
83/**
84 * sunxi_usb_clk_setup() - Setup function for usb gate clocks
85 */
86
87#define SUNXI_USB_MAX_SIZE 32
88
89struct usb_clk_data {
90 u32 clk_mask;
91 u32 reset_mask;
92 bool reset_needs_clk;
93};
94
95static void __init sunxi_usb_clk_setup(struct device_node *node,
96 const struct usb_clk_data *data,
97 spinlock_t *lock)
98{
99 struct clk_onecell_data *clk_data;
100 struct usb_reset_data *reset_data;
101 const char *clk_parent;
102 const char *clk_name;
103 void __iomem *reg;
104 int qty;
105 int i = 0;
106 int j = 0;
107
108 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
109 if (IS_ERR(reg))
110 return;
111
112 clk_parent = of_clk_get_parent_name(node, 0);
113 if (!clk_parent)
114 return;
115
116 /* Worst-case size approximation and memory allocation */
117 qty = find_last_bit((unsigned long *)&data->clk_mask,
118 SUNXI_USB_MAX_SIZE);
119
120 clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
121 if (!clk_data)
122 return;
123
124 clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
125 if (!clk_data->clks) {
126 kfree(clk_data);
127 return;
128 }
129
130 for_each_set_bit(i, (unsigned long *)&data->clk_mask,
131 SUNXI_USB_MAX_SIZE) {
132 of_property_read_string_index(node, "clock-output-names",
133 j, &clk_name);
134 clk_data->clks[i] = clk_register_gate(NULL, clk_name,
135 clk_parent, 0,
136 reg, i, 0, lock);
137 WARN_ON(IS_ERR(clk_data->clks[i]));
138
139 j++;
140 }
141
142 /* Adjust to the real max */
143 clk_data->clk_num = i;
144
145 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
146
147 /* Register a reset controller for usb with reset bits */
148 if (data->reset_mask == 0)
149 return;
150
151 reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
152 if (!reset_data)
153 return;
154
155 if (data->reset_needs_clk) {
156 reset_data->clk = of_clk_get(node, 0);
157 if (IS_ERR(reset_data->clk)) {
158 pr_err("Could not get clock for reset controls\n");
159 kfree(reset_data);
160 return;
161 }
162 }
163
164 reset_data->reg = reg;
165 reset_data->lock = lock;
166 reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
167 reset_data->rcdev.ops = &sunxi_usb_reset_ops;
168 reset_data->rcdev.of_node = node;
169 reset_controller_register(&reset_data->rcdev);
170}
171
172static const struct usb_clk_data sun4i_a10_usb_clk_data __initconst = {
173 .clk_mask = BIT(8) | BIT(7) | BIT(6),
174 .reset_mask = BIT(2) | BIT(1) | BIT(0),
175};
176
177static DEFINE_SPINLOCK(sun4i_a10_usb_lock);
178
179static void __init sun4i_a10_usb_setup(struct device_node *node)
180{
181 sunxi_usb_clk_setup(node, &sun4i_a10_usb_clk_data, &sun4i_a10_usb_lock);
182}
183CLK_OF_DECLARE(sun4i_a10_usb, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup);
184
185static const struct usb_clk_data sun5i_a13_usb_clk_data __initconst = {
186 .clk_mask = BIT(8) | BIT(6),
187 .reset_mask = BIT(1) | BIT(0),
188};
189
190static void __init sun5i_a13_usb_setup(struct device_node *node)
191{
192 sunxi_usb_clk_setup(node, &sun5i_a13_usb_clk_data, &sun4i_a10_usb_lock);
193}
194CLK_OF_DECLARE(sun5i_a13_usb, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup);
195
196static const struct usb_clk_data sun6i_a31_usb_clk_data __initconst = {
197 .clk_mask = BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8),
198 .reset_mask = BIT(2) | BIT(1) | BIT(0),
199};
200
201static void __init sun6i_a31_usb_setup(struct device_node *node)
202{
203 sunxi_usb_clk_setup(node, &sun6i_a31_usb_clk_data, &sun4i_a10_usb_lock);
204}
205CLK_OF_DECLARE(sun6i_a31_usb, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup);
206
207static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = {
208 .clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
209 .reset_mask = BIT(19) | BIT(18) | BIT(17),
210 .reset_needs_clk = 1,
211};
212
213static DEFINE_SPINLOCK(a80_usb_mod_lock);
214
215static void __init sun9i_a80_usb_mod_setup(struct device_node *node)
216{
217 sunxi_usb_clk_setup(node, &sun9i_a80_usb_mod_data, &a80_usb_mod_lock);
218}
219CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup);
220
221static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst = {
222 .clk_mask = BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
223 .reset_mask = BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
224 .reset_needs_clk = 1,
225};
226
227static DEFINE_SPINLOCK(a80_usb_phy_lock);
228
229static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
230{
231 sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
232}
233CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);