diff options
author | Michael Turquette <mturquette@linaro.org> | 2015-03-25 17:51:40 -0400 |
---|---|---|
committer | Michael Turquette <mturquette@linaro.org> | 2015-03-25 17:51:40 -0400 |
commit | fe15dedc02e4ee29edfc84bbbf5ee42827e36ac7 (patch) | |
tree | b64f9ceebdbf3019f3d10ecb404f6fc002223113 | |
parent | c77662a4df847e7b75ff8c5f2314dd4f022377e3 (diff) | |
parent | f1017969661dd33ead5ba7c3f4a0793c6611441a (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.txt | 3 | ||||
-rw-r--r-- | drivers/clk/sunxi/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 185 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-usb.c | 233 |
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 | ||
70 | Required properties for all clocks: | 73 | Required 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 | |||
9 | obj-y += clk-sun8i-mbus.o | 9 | obj-y += clk-sun8i-mbus.o |
10 | obj-y += clk-sun9i-core.o | 10 | obj-y += clk-sun9i-core.o |
11 | obj-y += clk-sun9i-mmc.o | 11 | obj-y += clk-sun9i-mmc.o |
12 | obj-y += clk-usb.o | ||
12 | 13 | ||
13 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ | 14 | obj-$(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 | |||
490 | static 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 | ||
658 | static struct clk_factors_config sun5i_a13_ahb_config = { | ||
659 | .pshift = 4, | ||
660 | .pwidth = 2, | ||
661 | }; | ||
662 | |||
619 | static struct clk_factors_config sun4i_apb1_config = { | 663 | static 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 | ||
723 | static 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 | |||
679 | static const struct factors_data sun4i_apb1_data __initconst = { | 730 | static 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 | |||
844 | struct gates_reset_data { | ||
845 | void __iomem *reg; | ||
846 | spinlock_t *lock; | ||
847 | struct reset_controller_dev rcdev; | ||
848 | }; | ||
849 | |||
850 | static 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 | |||
869 | static 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 | |||
888 | static 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 | ||
899 | struct gates_data { | 897 | struct 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 | ||
904 | static const struct gates_data sun4i_axi_gates_data __initconst = { | 901 | static 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 | ||
1000 | static const struct gates_data sun4i_a10_usb_gates_data __initconst = { | ||
1001 | .mask = {0x1C0}, | ||
1002 | .reset_mask = 0x07, | ||
1003 | }; | ||
1004 | |||
1005 | static const struct gates_data sun5i_a13_usb_gates_data __initconst = { | ||
1006 | .mask = {0x140}, | ||
1007 | .reset_mask = 0x03, | ||
1008 | }; | ||
1009 | |||
1010 | static 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 | |||
1015 | static void __init sunxi_gates_clk_setup(struct device_node *node, | 997 | static 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 | ||
1086 | struct divs_data { | 1052 | struct 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 | ||
1115 | static const struct divs_data pll6_divs_data __initconst = { | 1089 | static 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 | ||
1124 | static const struct divs_data sun6i_a31_pll6_divs_data __initconst = { | 1100 | static 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) | |||
1385 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); | 1363 | CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks); |
1386 | 1364 | ||
1387 | static const char *sun5i_critical_clocks[] __initdata = { | 1365 | static 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 | |||
29 | struct usb_reset_data { | ||
30 | void __iomem *reg; | ||
31 | spinlock_t *lock; | ||
32 | struct clk *clk; | ||
33 | struct reset_controller_dev rcdev; | ||
34 | }; | ||
35 | |||
36 | static 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 | |||
57 | static 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 | |||
78 | static 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 | |||
89 | struct usb_clk_data { | ||
90 | u32 clk_mask; | ||
91 | u32 reset_mask; | ||
92 | bool reset_needs_clk; | ||
93 | }; | ||
94 | |||
95 | static 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 | |||
172 | static 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 | |||
177 | static DEFINE_SPINLOCK(sun4i_a10_usb_lock); | ||
178 | |||
179 | static 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 | } | ||
183 | CLK_OF_DECLARE(sun4i_a10_usb, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup); | ||
184 | |||
185 | static 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 | |||
190 | static 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 | } | ||
194 | CLK_OF_DECLARE(sun5i_a13_usb, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup); | ||
195 | |||
196 | static 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 | |||
201 | static 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 | } | ||
205 | CLK_OF_DECLARE(sun6i_a31_usb, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup); | ||
206 | |||
207 | static 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 | |||
213 | static DEFINE_SPINLOCK(a80_usb_mod_lock); | ||
214 | |||
215 | static 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 | } | ||
219 | CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup); | ||
220 | |||
221 | static 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 | |||
227 | static DEFINE_SPINLOCK(a80_usb_phy_lock); | ||
228 | |||
229 | static 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 | } | ||
233 | CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup); | ||