aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhangfei Gao <zhangfei.gao@linaro.org>2014-05-13 08:26:59 -0400
committerWei Xu <xuwei5@hisilicon.com>2014-09-27 22:26:49 -0400
commit20e075585973453515be6615b91901c959e0a573 (patch)
treecaf4f9cf08539afac25dc49434c310ef1b85bf47
parent7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (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.c181
-rw-r--r--include/dt-bindings/clock/hix5hd2-clock.h9
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
14static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { 16static 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
91enum hix5hd2_clk_type {
92 TYPE_COMPLEX,
93 TYPE_ETHER,
94};
95
96struct 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
109struct 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
120static 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
133static 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
162static 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
172static struct clk_ops clk_ether_ops = {
173 .prepare = clk_ether_prepare,
174 .unprepare = clk_ether_unprepare,
175};
176
177static 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
195static 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
211static struct clk_ops clk_complex_ops = {
212 .enable = clk_complex_enable,
213 .disable = clk_complex_disable,
214};
215
216void __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
84static void __init hix5hd2_clk_init(struct device_node *np) 262static 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
101CLK_OF_DECLARE(hix5hd2_clk, "hisilicon,hix5hd2-clock", hix5hd2_clk_init); 282CLK_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 */