xref: /linux/drivers/clk/hisilicon/clk.c (revision 7b03559044d20bb4cfa1a19df79dd1b52e27fb3a)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Hisilicon clock driver
4  *
5  * Copyright (c) 2012-2013 Hisilicon Limited.
6  * Copyright (c) 2012-2013 Linaro Limited.
7  *
8  * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
9  *	   Xin Li <li.xin@linaro.org>
10  */
11 
12 #include <linux/kernel.h>
13 #include <linux/clkdev.h>
14 #include <linux/clk-provider.h>
15 #include <linux/delay.h>
16 #include <linux/io.h>
17 #include <linux/of.h>
18 #include <linux/of_address.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 
22 #include "clk.h"
23 
24 static DEFINE_SPINLOCK(hisi_clk_lock);
25 
26 struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev,
27 						int nr_clks)
28 {
29 	struct hisi_clock_data *clk_data;
30 	struct resource *res;
31 	struct clk **clk_table;
32 
33 	clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
34 	if (!clk_data)
35 		return NULL;
36 
37 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
38 	if (!res)
39 		return NULL;
40 	clk_data->base = devm_ioremap(&pdev->dev,
41 				res->start, resource_size(res));
42 	if (!clk_data->base)
43 		return NULL;
44 
45 	clk_table = devm_kmalloc_array(&pdev->dev, nr_clks,
46 				       sizeof(*clk_table),
47 				       GFP_KERNEL);
48 	if (!clk_table)
49 		return NULL;
50 
51 	clk_data->clk_data.clks = clk_table;
52 	clk_data->clk_data.clk_num = nr_clks;
53 
54 	return clk_data;
55 }
56 EXPORT_SYMBOL_GPL(hisi_clk_alloc);
57 
58 struct hisi_clock_data *hisi_clk_init(struct device_node *np,
59 					     int nr_clks)
60 {
61 	struct hisi_clock_data *clk_data;
62 	struct clk **clk_table;
63 	void __iomem *base;
64 
65 	base = of_iomap(np, 0);
66 	if (!base) {
67 		pr_err("%s: failed to map clock registers\n", __func__);
68 		goto err;
69 	}
70 
71 	clk_data = kzalloc_obj(*clk_data);
72 	if (!clk_data)
73 		goto err_base;
74 
75 	clk_data->base = base;
76 	clk_table = kzalloc_objs(*clk_table, nr_clks);
77 	if (!clk_table)
78 		goto err_data;
79 
80 	clk_data->clk_data.clks = clk_table;
81 	clk_data->clk_data.clk_num = nr_clks;
82 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
83 	return clk_data;
84 err_data:
85 	kfree(clk_data);
86 err_base:
87 	iounmap(base);
88 err:
89 	return NULL;
90 }
91 EXPORT_SYMBOL_GPL(hisi_clk_init);
92 
93 int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
94 					 int nums, struct hisi_clock_data *data)
95 {
96 	struct clk *clk;
97 	int i;
98 
99 	for (i = 0; i < nums; i++) {
100 		clk = clk_register_fixed_rate(NULL, clks[i].name,
101 					      clks[i].parent_name,
102 					      clks[i].flags,
103 					      clks[i].fixed_rate);
104 		if (IS_ERR(clk)) {
105 			pr_err("%s: failed to register clock %s\n",
106 			       __func__, clks[i].name);
107 			goto err;
108 		}
109 		data->clk_data.clks[clks[i].id] = clk;
110 	}
111 
112 	return 0;
113 
114 err:
115 	while (i--)
116 		clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
117 
118 	return PTR_ERR(clk);
119 }
120 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
121 
122 int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
123 					   int nums,
124 					   struct hisi_clock_data *data)
125 {
126 	struct clk *clk;
127 	int i;
128 
129 	for (i = 0; i < nums; i++) {
130 		clk = clk_register_fixed_factor(NULL, clks[i].name,
131 						clks[i].parent_name,
132 						clks[i].flags, clks[i].mult,
133 						clks[i].div);
134 		if (IS_ERR(clk)) {
135 			pr_err("%s: failed to register clock %s\n",
136 			       __func__, clks[i].name);
137 			goto err;
138 		}
139 		data->clk_data.clks[clks[i].id] = clk;
140 	}
141 
142 	return 0;
143 
144 err:
145 	while (i--)
146 		clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
147 
148 	return PTR_ERR(clk);
149 }
150 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
151 
152 int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
153 				  int nums, struct hisi_clock_data *data)
154 {
155 	struct clk *clk;
156 	void __iomem *base = data->base;
157 	int i;
158 
159 	for (i = 0; i < nums; i++) {
160 		u32 mask = BIT(clks[i].width) - 1;
161 
162 		clk = clk_register_mux_table(NULL, clks[i].name,
163 					clks[i].parent_names,
164 					clks[i].num_parents, clks[i].flags,
165 					base + clks[i].offset, clks[i].shift,
166 					mask, clks[i].mux_flags,
167 					clks[i].table, &hisi_clk_lock);
168 		if (IS_ERR(clk)) {
169 			pr_err("%s: failed to register clock %s\n",
170 			       __func__, clks[i].name);
171 			goto err;
172 		}
173 
174 		if (clks[i].alias)
175 			clk_register_clkdev(clk, clks[i].alias, NULL);
176 
177 		data->clk_data.clks[clks[i].id] = clk;
178 	}
179 
180 	return 0;
181 
182 err:
183 	while (i--)
184 		clk_unregister_mux(data->clk_data.clks[clks[i].id]);
185 
186 	return PTR_ERR(clk);
187 }
188 EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
189 
190 int hisi_clk_register_phase(struct device *dev,
191 			    const struct hisi_phase_clock *clks,
192 			    int nums, struct hisi_clock_data *data)
193 {
194 	void __iomem *base = data->base;
195 	struct clk *clk;
196 	int i;
197 
198 	for (i = 0; i < nums; i++) {
199 		clk = clk_register_hisi_phase(dev, &clks[i], base,
200 					      &hisi_clk_lock);
201 		if (IS_ERR(clk)) {
202 			pr_err("%s: failed to register clock %s\n", __func__,
203 			       clks[i].name);
204 			return PTR_ERR(clk);
205 		}
206 
207 		data->clk_data.clks[clks[i].id] = clk;
208 	}
209 
210 	return 0;
211 }
212 EXPORT_SYMBOL_GPL(hisi_clk_register_phase);
213 
214 int hisi_clk_register_divider(const struct hisi_divider_clock *clks,
215 				      int nums, struct hisi_clock_data *data)
216 {
217 	struct clk *clk;
218 	void __iomem *base = data->base;
219 	int i;
220 
221 	for (i = 0; i < nums; i++) {
222 		clk = clk_register_divider_table(NULL, clks[i].name,
223 						 clks[i].parent_name,
224 						 clks[i].flags,
225 						 base + clks[i].offset,
226 						 clks[i].shift, clks[i].width,
227 						 clks[i].div_flags,
228 						 clks[i].table,
229 						 &hisi_clk_lock);
230 		if (IS_ERR(clk)) {
231 			pr_err("%s: failed to register clock %s\n",
232 			       __func__, clks[i].name);
233 			goto err;
234 		}
235 
236 		if (clks[i].alias)
237 			clk_register_clkdev(clk, clks[i].alias, NULL);
238 
239 		data->clk_data.clks[clks[i].id] = clk;
240 	}
241 
242 	return 0;
243 
244 err:
245 	while (i--)
246 		clk_unregister_divider(data->clk_data.clks[clks[i].id]);
247 
248 	return PTR_ERR(clk);
249 }
250 EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
251 
252 int hisi_clk_register_gate(const struct hisi_gate_clock *clks,
253 				       int nums, struct hisi_clock_data *data)
254 {
255 	struct clk *clk;
256 	void __iomem *base = data->base;
257 	int i;
258 
259 	for (i = 0; i < nums; i++) {
260 		clk = clk_register_gate(NULL, clks[i].name,
261 						clks[i].parent_name,
262 						clks[i].flags,
263 						base + clks[i].offset,
264 						clks[i].bit_idx,
265 						clks[i].gate_flags,
266 						&hisi_clk_lock);
267 		if (IS_ERR(clk)) {
268 			pr_err("%s: failed to register clock %s\n",
269 			       __func__, clks[i].name);
270 			goto err;
271 		}
272 
273 		if (clks[i].alias)
274 			clk_register_clkdev(clk, clks[i].alias, NULL);
275 
276 		data->clk_data.clks[clks[i].id] = clk;
277 	}
278 
279 	return 0;
280 
281 err:
282 	while (i--)
283 		clk_unregister_gate(data->clk_data.clks[clks[i].id]);
284 
285 	return PTR_ERR(clk);
286 }
287 EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
288 
289 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks,
290 				       int nums, struct hisi_clock_data *data)
291 {
292 	struct clk *clk;
293 	void __iomem *base = data->base;
294 	int i;
295 
296 	for (i = 0; i < nums; i++) {
297 		clk = hisi_register_clkgate_sep(NULL, clks[i].name,
298 						clks[i].parent_name,
299 						clks[i].flags,
300 						base + clks[i].offset,
301 						clks[i].bit_idx,
302 						clks[i].gate_flags,
303 						&hisi_clk_lock);
304 		if (IS_ERR(clk)) {
305 			pr_err("%s: failed to register clock %s\n",
306 			       __func__, clks[i].name);
307 			continue;
308 		}
309 
310 		if (clks[i].alias)
311 			clk_register_clkdev(clk, clks[i].alias, NULL);
312 
313 		data->clk_data.clks[clks[i].id] = clk;
314 	}
315 }
316 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);
317 
318 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks,
319 					int nums, struct hisi_clock_data *data)
320 {
321 	struct clk *clk;
322 	void __iomem *base = data->base;
323 	int i;
324 
325 	for (i = 0; i < nums; i++) {
326 		clk = hi6220_register_clkdiv(NULL, clks[i].name,
327 						clks[i].parent_name,
328 						clks[i].flags,
329 						base + clks[i].offset,
330 						clks[i].shift,
331 						clks[i].width,
332 						clks[i].mask_bit,
333 						&hisi_clk_lock);
334 		if (IS_ERR(clk)) {
335 			pr_err("%s: failed to register clock %s\n",
336 			       __func__, clks[i].name);
337 			continue;
338 		}
339 
340 		if (clks[i].alias)
341 			clk_register_clkdev(clk, clks[i].alias, NULL);
342 
343 		data->clk_data.clks[clks[i].id] = clk;
344 	}
345 }
346