aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2015-01-27 14:54:06 -0500
committerMaxime Ripard <maxime.ripard@free-electrons.com>2015-02-23 03:25:54 -0500
commit6089ef19c9dadaf0e3378f75eca65af861cd3974 (patch)
tree0ad1a6f758611cc7e9387ee324c49cf6c04ba52f
parentc517d838eb7d07bbe9507871fab3931deccff539 (diff)
clk: sunxi: Move USB clocks to separate file
The USB clocks originally shared code with the gates clocks, but had additional reset controllers. Move these to a separate file. This will allow us to add new support for slightly different USB clocks, such as on the A80, without affecting gates clocks, and also facilitate the migration of gates clocks to a generic solution. This also cleans up the USB clocks code slightly, such as adding newlines, getting rid of the unused clkdev call, using a simple u32 instead of BITMAP for the clock masks, using BIT() macro to declare the clock bitmasks, and using of_io_request_and_map() to get the I/O address. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c88
-rw-r--r--drivers/clk/sunxi/clk-usb.c190
3 files changed, 191 insertions, 88 deletions
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..b6f28ac4f9d5 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -838,59 +838,6 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
838 838
839 839
840/** 840/**
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 841 * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks
895 */ 842 */
896 843
@@ -898,7 +845,6 @@ static struct reset_control_ops sunxi_gates_reset_ops = {
898 845
899struct gates_data { 846struct gates_data {
900 DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE); 847 DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
901 u32 reset_mask;
902}; 848};
903 849
904static const struct gates_data sun4i_axi_gates_data __initconst = { 850static const struct gates_data sun4i_axi_gates_data __initconst = {
@@ -997,26 +943,10 @@ static const struct gates_data sun8i_a23_apb2_gates_data __initconst = {
997 .mask = {0x1F0007}, 943 .mask = {0x1F0007},
998}; 944};
999 945
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, 946static void __init sunxi_gates_clk_setup(struct device_node *node,
1016 struct gates_data *data) 947 struct gates_data *data)
1017{ 948{
1018 struct clk_onecell_data *clk_data; 949 struct clk_onecell_data *clk_data;
1019 struct gates_reset_data *reset_data;
1020 const char *clk_parent; 950 const char *clk_parent;
1021 const char *clk_name; 951 const char *clk_name;
1022 void __iomem *reg; 952 void __iomem *reg;
@@ -1057,21 +987,6 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
1057 clk_data->clk_num = i; 987 clk_data->clk_num = i;
1058 988
1059 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 989 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} 990}
1076 991
1077 992
@@ -1324,9 +1239,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,}, 1239 {.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,}, 1240 {.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,}, 1241 {.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 {} 1242 {}
1331}; 1243};
1332 1244
diff --git a/drivers/clk/sunxi/clk-usb.c b/drivers/clk/sunxi/clk-usb.c
new file mode 100644
index 000000000000..f1dcc8fb5a7d
--- /dev/null
+++ b/drivers/clk/sunxi/clk-usb.c
@@ -0,0 +1,190 @@
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 reset_controller_dev rcdev;
33};
34
35static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev,
36 unsigned long id)
37{
38 struct usb_reset_data *data = container_of(rcdev,
39 struct usb_reset_data,
40 rcdev);
41 unsigned long flags;
42 u32 reg;
43
44 spin_lock_irqsave(data->lock, flags);
45
46 reg = readl(data->reg);
47 writel(reg & ~BIT(id), data->reg);
48
49 spin_unlock_irqrestore(data->lock, flags);
50
51 return 0;
52}
53
54static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev,
55 unsigned long id)
56{
57 struct usb_reset_data *data = container_of(rcdev,
58 struct usb_reset_data,
59 rcdev);
60 unsigned long flags;
61 u32 reg;
62
63 spin_lock_irqsave(data->lock, flags);
64
65 reg = readl(data->reg);
66 writel(reg | BIT(id), data->reg);
67
68 spin_unlock_irqrestore(data->lock, flags);
69
70 return 0;
71}
72
73static struct reset_control_ops sunxi_usb_reset_ops = {
74 .assert = sunxi_usb_reset_assert,
75 .deassert = sunxi_usb_reset_deassert,
76};
77
78/**
79 * sunxi_usb_clk_setup() - Setup function for usb gate clocks
80 */
81
82#define SUNXI_USB_MAX_SIZE 32
83
84struct usb_clk_data {
85 u32 clk_mask;
86 u32 reset_mask;
87};
88
89static void __init sunxi_usb_clk_setup(struct device_node *node,
90 const struct usb_clk_data *data,
91 spinlock_t *lock)
92{
93 struct clk_onecell_data *clk_data;
94 struct usb_reset_data *reset_data;
95 const char *clk_parent;
96 const char *clk_name;
97 void __iomem *reg;
98 int qty;
99 int i = 0;
100 int j = 0;
101
102 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
103 if (IS_ERR(reg))
104 return;
105
106 clk_parent = of_clk_get_parent_name(node, 0);
107 if (!clk_parent)
108 return;
109
110 /* Worst-case size approximation and memory allocation */
111 qty = find_last_bit((unsigned long *)&data->clk_mask,
112 SUNXI_USB_MAX_SIZE);
113
114 clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
115 if (!clk_data)
116 return;
117
118 clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL);
119 if (!clk_data->clks) {
120 kfree(clk_data);
121 return;
122 }
123
124 for_each_set_bit(i, (unsigned long *)&data->clk_mask,
125 SUNXI_USB_MAX_SIZE) {
126 of_property_read_string_index(node, "clock-output-names",
127 j, &clk_name);
128 clk_data->clks[i] = clk_register_gate(NULL, clk_name,
129 clk_parent, 0,
130 reg, i, 0, lock);
131 WARN_ON(IS_ERR(clk_data->clks[i]));
132
133 j++;
134 }
135
136 /* Adjust to the real max */
137 clk_data->clk_num = i;
138
139 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
140
141 /* Register a reset controller for usb with reset bits */
142 if (data->reset_mask == 0)
143 return;
144
145 reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
146 if (!reset_data)
147 return;
148
149 reset_data->reg = reg;
150 reset_data->lock = lock;
151 reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
152 reset_data->rcdev.ops = &sunxi_usb_reset_ops;
153 reset_data->rcdev.of_node = node;
154 reset_controller_register(&reset_data->rcdev);
155}
156
157static const struct usb_clk_data sun4i_a10_usb_clk_data __initconst = {
158 .clk_mask = BIT(8) | BIT(7) | BIT(6),
159 .reset_mask = BIT(2) | BIT(1) | BIT(0),
160};
161
162static DEFINE_SPINLOCK(sun4i_a10_usb_lock);
163
164static void __init sun4i_a10_usb_setup(struct device_node *node)
165{
166 sunxi_usb_clk_setup(node, &sun4i_a10_usb_clk_data, &sun4i_a10_usb_lock);
167}
168CLK_OF_DECLARE(sun4i_a10_usb, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup);
169
170static const struct usb_clk_data sun5i_a13_usb_clk_data __initconst = {
171 .clk_mask = BIT(8) | BIT(6),
172 .reset_mask = BIT(1) | BIT(0),
173};
174
175static void __init sun5i_a13_usb_setup(struct device_node *node)
176{
177 sunxi_usb_clk_setup(node, &sun5i_a13_usb_clk_data, &sun4i_a10_usb_lock);
178}
179CLK_OF_DECLARE(sun5i_a13_usb, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup);
180
181static const struct usb_clk_data sun6i_a31_usb_clk_data __initconst = {
182 .clk_mask = BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8),
183 .reset_mask = BIT(2) | BIT(1) | BIT(0),
184};
185
186static void __init sun6i_a31_usb_setup(struct device_node *node)
187{
188 sunxi_usb_clk_setup(node, &sun6i_a31_usb_clk_data, &sun4i_a10_usb_lock);
189}
190CLK_OF_DECLARE(sun6i_a31_usb, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup);