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