diff options
author | Zhangfei Gao <zhangfei.gao@linaro.org> | 2014-05-13 08:26:59 -0400 |
---|---|---|
committer | Wei Xu <xuwei5@hisilicon.com> | 2014-09-27 22:26:49 -0400 |
commit | 20e075585973453515be6615b91901c959e0a573 (patch) | |
tree | caf4f9cf08539afac25dc49434c310ef1b85bf47 | |
parent | 7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (diff) |
clk: hix5hd2: add complex clk
Support clk of sata, usb and ethernet
Signed-off-by: Jiancheng Xue <xuejiancheng@huawei.com>
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
-rw-r--r-- | drivers/clk/hisilicon/clk-hix5hd2.c | 181 | ||||
-rw-r--r-- | include/dt-bindings/clock/hix5hd2-clock.h | 9 |
2 files changed, 190 insertions, 0 deletions
diff --git a/drivers/clk/hisilicon/clk-hix5hd2.c b/drivers/clk/hisilicon/clk-hix5hd2.c index e5fcfb4e32ef..da9ca05e6fb7 100644 --- a/drivers/clk/hisilicon/clk-hix5hd2.c +++ b/drivers/clk/hisilicon/clk-hix5hd2.c | |||
@@ -9,6 +9,8 @@ | |||
9 | 9 | ||
10 | #include <linux/of_address.h> | 10 | #include <linux/of_address.h> |
11 | #include <dt-bindings/clock/hix5hd2-clock.h> | 11 | #include <dt-bindings/clock/hix5hd2-clock.h> |
12 | #include <linux/slab.h> | ||
13 | #include <linux/delay.h> | ||
12 | #include "clk.h" | 14 | #include "clk.h" |
13 | 15 | ||
14 | static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { | 16 | static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { |
@@ -79,8 +81,184 @@ static struct hisi_gate_clock hix5hd2_gate_clks[] __initdata = { | |||
79 | CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, | 81 | CLK_SET_RATE_PARENT, 0xa0, 1, 0, }, |
80 | { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu", | 82 | { HIX5HD2_MMC_CIU_RST, "rst_mmc_ciu", "clk_mmc_ciu", |
81 | CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, }, | 83 | CLK_SET_RATE_PARENT, 0xa0, 4, CLK_GATE_SET_TO_DISABLE, }, |
84 | /* gsf */ | ||
85 | { HIX5HD2_FWD_BUS_CLK, "clk_fwd_bus", NULL, 0, 0xcc, 0, 0, }, | ||
86 | { HIX5HD2_FWD_SYS_CLK, "clk_fwd_sys", "clk_fwd_bus", 0, 0xcc, 5, 0, }, | ||
87 | { HIX5HD2_MAC0_PHY_CLK, "clk_fephy", "clk_fwd_sys", | ||
88 | CLK_SET_RATE_PARENT, 0x120, 0, 0, }, | ||
82 | }; | 89 | }; |
83 | 90 | ||
91 | enum hix5hd2_clk_type { | ||
92 | TYPE_COMPLEX, | ||
93 | TYPE_ETHER, | ||
94 | }; | ||
95 | |||
96 | struct hix5hd2_complex_clock { | ||
97 | const char *name; | ||
98 | const char *parent_name; | ||
99 | u32 id; | ||
100 | u32 ctrl_reg; | ||
101 | u32 ctrl_clk_mask; | ||
102 | u32 ctrl_rst_mask; | ||
103 | u32 phy_reg; | ||
104 | u32 phy_clk_mask; | ||
105 | u32 phy_rst_mask; | ||
106 | enum hix5hd2_clk_type type; | ||
107 | }; | ||
108 | |||
109 | struct hix5hd2_clk_complex { | ||
110 | struct clk_hw hw; | ||
111 | u32 id; | ||
112 | void __iomem *ctrl_reg; | ||
113 | u32 ctrl_clk_mask; | ||
114 | u32 ctrl_rst_mask; | ||
115 | void __iomem *phy_reg; | ||
116 | u32 phy_clk_mask; | ||
117 | u32 phy_rst_mask; | ||
118 | }; | ||
119 | |||
120 | static struct hix5hd2_complex_clock hix5hd2_complex_clks[] __initdata = { | ||
121 | {"clk_mac0", "clk_fephy", HIX5HD2_MAC0_CLK, | ||
122 | 0xcc, 0xa, 0x500, 0x120, 0, 0x10, TYPE_ETHER}, | ||
123 | {"clk_mac1", "clk_fwd_sys", HIX5HD2_MAC1_CLK, | ||
124 | 0xcc, 0x14, 0xa00, 0x168, 0x2, 0, TYPE_ETHER}, | ||
125 | {"clk_sata", NULL, HIX5HD2_SATA_CLK, | ||
126 | 0xa8, 0x1f, 0x300, 0xac, 0x1, 0x0, TYPE_COMPLEX}, | ||
127 | {"clk_usb", NULL, HIX5HD2_USB_CLK, | ||
128 | 0xb8, 0xff, 0x3f000, 0xbc, 0x7, 0x3f00, TYPE_COMPLEX}, | ||
129 | }; | ||
130 | |||
131 | #define to_complex_clk(_hw) container_of(_hw, struct hix5hd2_clk_complex, hw) | ||
132 | |||
133 | static int clk_ether_prepare(struct clk_hw *hw) | ||
134 | { | ||
135 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
136 | u32 val; | ||
137 | |||
138 | val = readl_relaxed(clk->ctrl_reg); | ||
139 | val |= clk->ctrl_clk_mask | clk->ctrl_rst_mask; | ||
140 | writel_relaxed(val, clk->ctrl_reg); | ||
141 | val &= ~(clk->ctrl_rst_mask); | ||
142 | writel_relaxed(val, clk->ctrl_reg); | ||
143 | |||
144 | val = readl_relaxed(clk->phy_reg); | ||
145 | val |= clk->phy_clk_mask; | ||
146 | val &= ~(clk->phy_rst_mask); | ||
147 | writel_relaxed(val, clk->phy_reg); | ||
148 | mdelay(10); | ||
149 | |||
150 | val &= ~(clk->phy_clk_mask); | ||
151 | val |= clk->phy_rst_mask; | ||
152 | writel_relaxed(val, clk->phy_reg); | ||
153 | mdelay(10); | ||
154 | |||
155 | val |= clk->phy_clk_mask; | ||
156 | val &= ~(clk->phy_rst_mask); | ||
157 | writel_relaxed(val, clk->phy_reg); | ||
158 | mdelay(30); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static void clk_ether_unprepare(struct clk_hw *hw) | ||
163 | { | ||
164 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
165 | u32 val; | ||
166 | |||
167 | val = readl_relaxed(clk->ctrl_reg); | ||
168 | val &= ~(clk->ctrl_clk_mask); | ||
169 | writel_relaxed(val, clk->ctrl_reg); | ||
170 | } | ||
171 | |||
172 | static struct clk_ops clk_ether_ops = { | ||
173 | .prepare = clk_ether_prepare, | ||
174 | .unprepare = clk_ether_unprepare, | ||
175 | }; | ||
176 | |||
177 | static int clk_complex_enable(struct clk_hw *hw) | ||
178 | { | ||
179 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
180 | u32 val; | ||
181 | |||
182 | val = readl_relaxed(clk->ctrl_reg); | ||
183 | val |= clk->ctrl_clk_mask; | ||
184 | val &= ~(clk->ctrl_rst_mask); | ||
185 | writel_relaxed(val, clk->ctrl_reg); | ||
186 | |||
187 | val = readl_relaxed(clk->phy_reg); | ||
188 | val |= clk->phy_clk_mask; | ||
189 | val &= ~(clk->phy_rst_mask); | ||
190 | writel_relaxed(val, clk->phy_reg); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static void clk_complex_disable(struct clk_hw *hw) | ||
196 | { | ||
197 | struct hix5hd2_clk_complex *clk = to_complex_clk(hw); | ||
198 | u32 val; | ||
199 | |||
200 | val = readl_relaxed(clk->ctrl_reg); | ||
201 | val |= clk->ctrl_rst_mask; | ||
202 | val &= ~(clk->ctrl_clk_mask); | ||
203 | writel_relaxed(val, clk->ctrl_reg); | ||
204 | |||
205 | val = readl_relaxed(clk->phy_reg); | ||
206 | val |= clk->phy_rst_mask; | ||
207 | val &= ~(clk->phy_clk_mask); | ||
208 | writel_relaxed(val, clk->phy_reg); | ||
209 | } | ||
210 | |||
211 | static struct clk_ops clk_complex_ops = { | ||
212 | .enable = clk_complex_enable, | ||
213 | .disable = clk_complex_disable, | ||
214 | }; | ||
215 | |||
216 | void __init hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, | ||
217 | int nums, struct hisi_clock_data *data) | ||
218 | { | ||
219 | void __iomem *base = data->base; | ||
220 | int i; | ||
221 | |||
222 | for (i = 0; i < nums; i++) { | ||
223 | struct hix5hd2_clk_complex *p_clk; | ||
224 | struct clk *clk; | ||
225 | struct clk_init_data init; | ||
226 | |||
227 | p_clk = kzalloc(sizeof(*p_clk), GFP_KERNEL); | ||
228 | if (!p_clk) | ||
229 | return; | ||
230 | |||
231 | init.name = clks[i].name; | ||
232 | if (clks[i].type == TYPE_ETHER) | ||
233 | init.ops = &clk_ether_ops; | ||
234 | else | ||
235 | init.ops = &clk_complex_ops; | ||
236 | |||
237 | init.flags = CLK_IS_BASIC; | ||
238 | init.parent_names = | ||
239 | (clks[i].parent_name ? &clks[i].parent_name : NULL); | ||
240 | init.num_parents = (clks[i].parent_name ? 1 : 0); | ||
241 | |||
242 | p_clk->ctrl_reg = base + clks[i].ctrl_reg; | ||
243 | p_clk->ctrl_clk_mask = clks[i].ctrl_clk_mask; | ||
244 | p_clk->ctrl_rst_mask = clks[i].ctrl_rst_mask; | ||
245 | p_clk->phy_reg = base + clks[i].phy_reg; | ||
246 | p_clk->phy_clk_mask = clks[i].phy_clk_mask; | ||
247 | p_clk->phy_rst_mask = clks[i].phy_rst_mask; | ||
248 | p_clk->hw.init = &init; | ||
249 | |||
250 | clk = clk_register(NULL, &p_clk->hw); | ||
251 | if (IS_ERR(clk)) { | ||
252 | kfree(p_clk); | ||
253 | pr_err("%s: failed to register clock %s\n", | ||
254 | __func__, clks[i].name); | ||
255 | continue; | ||
256 | } | ||
257 | |||
258 | data->clk_data.clks[clks[i].id] = clk; | ||
259 | } | ||
260 | } | ||
261 | |||
84 | static void __init hix5hd2_clk_init(struct device_node *np) | 262 | static void __init hix5hd2_clk_init(struct device_node *np) |
85 | { | 263 | { |
86 | struct hisi_clock_data *clk_data; | 264 | struct hisi_clock_data *clk_data; |
@@ -96,6 +274,9 @@ static void __init hix5hd2_clk_init(struct device_node *np) | |||
96 | clk_data); | 274 | clk_data); |
97 | hisi_clk_register_gate(hix5hd2_gate_clks, | 275 | hisi_clk_register_gate(hix5hd2_gate_clks, |
98 | ARRAY_SIZE(hix5hd2_gate_clks), clk_data); | 276 | ARRAY_SIZE(hix5hd2_gate_clks), clk_data); |
277 | hix5hd2_clk_register_complex(hix5hd2_complex_clks, | ||
278 | ARRAY_SIZE(hix5hd2_complex_clks), | ||
279 | clk_data); | ||
99 | } | 280 | } |
100 | 281 | ||
101 | CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init); | 282 | CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init); |
diff --git a/include/dt-bindings/clock/hix5hd2-clock.h b/include/dt-bindings/clock/hix5hd2-clock.h index aad579a75802..e3286695382d 100644 --- a/include/dt-bindings/clock/hix5hd2-clock.h +++ b/include/dt-bindings/clock/hix5hd2-clock.h | |||
@@ -53,6 +53,15 @@ | |||
53 | #define HIX5HD2_MMC_CIU_CLK 130 | 53 | #define HIX5HD2_MMC_CIU_CLK 130 |
54 | #define HIX5HD2_MMC_BIU_CLK 131 | 54 | #define HIX5HD2_MMC_BIU_CLK 131 |
55 | #define HIX5HD2_MMC_CIU_RST 132 | 55 | #define HIX5HD2_MMC_CIU_RST 132 |
56 | #define HIX5HD2_FWD_BUS_CLK 133 | ||
57 | #define HIX5HD2_FWD_SYS_CLK 134 | ||
58 | #define HIX5HD2_MAC0_PHY_CLK 135 | ||
59 | |||
60 | /* complex */ | ||
61 | #define HIX5HD2_MAC0_CLK 192 | ||
62 | #define HIX5HD2_MAC1_CLK 193 | ||
63 | #define HIX5HD2_SATA_CLK 194 | ||
64 | #define HIX5HD2_USB_CLK 195 | ||
56 | 65 | ||
57 | #define HIX5HD2_NR_CLKS 256 | 66 | #define HIX5HD2_NR_CLKS 256 |
58 | #endif /* __DTS_HIX5HD2_CLOCK_H */ | 67 | #endif /* __DTS_HIX5HD2_CLOCK_H */ |