clk: Drop the rate range on clk_put()
[linux-2.6-microblaze.git] / drivers / clk / hisilicon / clk.c
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/of_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(sizeof(*clk_data), GFP_KERNEL);
72         if (!clk_data)
73                 goto err;
74
75         clk_data->base = base;
76         clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL);
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:
87         return NULL;
88 }
89 EXPORT_SYMBOL_GPL(hisi_clk_init);
90
91 int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
92                                          int nums, struct hisi_clock_data *data)
93 {
94         struct clk *clk;
95         int i;
96
97         for (i = 0; i < nums; i++) {
98                 clk = clk_register_fixed_rate(NULL, clks[i].name,
99                                               clks[i].parent_name,
100                                               clks[i].flags,
101                                               clks[i].fixed_rate);
102                 if (IS_ERR(clk)) {
103                         pr_err("%s: failed to register clock %s\n",
104                                __func__, clks[i].name);
105                         goto err;
106                 }
107                 data->clk_data.clks[clks[i].id] = clk;
108         }
109
110         return 0;
111
112 err:
113         while (i--)
114                 clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
115
116         return PTR_ERR(clk);
117 }
118 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
119
120 int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
121                                            int nums,
122                                            struct hisi_clock_data *data)
123 {
124         struct clk *clk;
125         int i;
126
127         for (i = 0; i < nums; i++) {
128                 clk = clk_register_fixed_factor(NULL, clks[i].name,
129                                                 clks[i].parent_name,
130                                                 clks[i].flags, clks[i].mult,
131                                                 clks[i].div);
132                 if (IS_ERR(clk)) {
133                         pr_err("%s: failed to register clock %s\n",
134                                __func__, clks[i].name);
135                         goto err;
136                 }
137                 data->clk_data.clks[clks[i].id] = clk;
138         }
139
140         return 0;
141
142 err:
143         while (i--)
144                 clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
145
146         return PTR_ERR(clk);
147 }
148 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
149
150 int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
151                                   int nums, struct hisi_clock_data *data)
152 {
153         struct clk *clk;
154         void __iomem *base = data->base;
155         int i;
156
157         for (i = 0; i < nums; i++) {
158                 u32 mask = BIT(clks[i].width) - 1;
159
160                 clk = clk_register_mux_table(NULL, clks[i].name,
161                                         clks[i].parent_names,
162                                         clks[i].num_parents, clks[i].flags,
163                                         base + clks[i].offset, clks[i].shift,
164                                         mask, clks[i].mux_flags,
165                                         (u32 *)clks[i].table, &hisi_clk_lock);
166                 if (IS_ERR(clk)) {
167                         pr_err("%s: failed to register clock %s\n",
168                                __func__, clks[i].name);
169                         goto err;
170                 }
171
172                 if (clks[i].alias)
173                         clk_register_clkdev(clk, clks[i].alias, NULL);
174
175                 data->clk_data.clks[clks[i].id] = clk;
176         }
177
178         return 0;
179
180 err:
181         while (i--)
182                 clk_unregister_mux(data->clk_data.clks[clks[i].id]);
183
184         return PTR_ERR(clk);
185 }
186 EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
187
188 int hisi_clk_register_phase(struct device *dev,
189                             const struct hisi_phase_clock *clks,
190                             int nums, struct hisi_clock_data *data)
191 {
192         void __iomem *base = data->base;
193         struct clk *clk;
194         int i;
195
196         for (i = 0; i < nums; i++) {
197                 clk = clk_register_hisi_phase(dev, &clks[i], base,
198                                               &hisi_clk_lock);
199                 if (IS_ERR(clk)) {
200                         pr_err("%s: failed to register clock %s\n", __func__,
201                                clks[i].name);
202                         return PTR_ERR(clk);
203                 }
204
205                 data->clk_data.clks[clks[i].id] = clk;
206         }
207
208         return 0;
209 }
210 EXPORT_SYMBOL_GPL(hisi_clk_register_phase);
211
212 int hisi_clk_register_divider(const struct hisi_divider_clock *clks,
213                                       int nums, struct hisi_clock_data *data)
214 {
215         struct clk *clk;
216         void __iomem *base = data->base;
217         int i;
218
219         for (i = 0; i < nums; i++) {
220                 clk = clk_register_divider_table(NULL, clks[i].name,
221                                                  clks[i].parent_name,
222                                                  clks[i].flags,
223                                                  base + clks[i].offset,
224                                                  clks[i].shift, clks[i].width,
225                                                  clks[i].div_flags,
226                                                  clks[i].table,
227                                                  &hisi_clk_lock);
228                 if (IS_ERR(clk)) {
229                         pr_err("%s: failed to register clock %s\n",
230                                __func__, clks[i].name);
231                         goto err;
232                 }
233
234                 if (clks[i].alias)
235                         clk_register_clkdev(clk, clks[i].alias, NULL);
236
237                 data->clk_data.clks[clks[i].id] = clk;
238         }
239
240         return 0;
241
242 err:
243         while (i--)
244                 clk_unregister_divider(data->clk_data.clks[clks[i].id]);
245
246         return PTR_ERR(clk);
247 }
248 EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
249
250 int hisi_clk_register_gate(const struct hisi_gate_clock *clks,
251                                        int nums, struct hisi_clock_data *data)
252 {
253         struct clk *clk;
254         void __iomem *base = data->base;
255         int i;
256
257         for (i = 0; i < nums; i++) {
258                 clk = clk_register_gate(NULL, clks[i].name,
259                                                 clks[i].parent_name,
260                                                 clks[i].flags,
261                                                 base + clks[i].offset,
262                                                 clks[i].bit_idx,
263                                                 clks[i].gate_flags,
264                                                 &hisi_clk_lock);
265                 if (IS_ERR(clk)) {
266                         pr_err("%s: failed to register clock %s\n",
267                                __func__, clks[i].name);
268                         goto err;
269                 }
270
271                 if (clks[i].alias)
272                         clk_register_clkdev(clk, clks[i].alias, NULL);
273
274                 data->clk_data.clks[clks[i].id] = clk;
275         }
276
277         return 0;
278
279 err:
280         while (i--)
281                 clk_unregister_gate(data->clk_data.clks[clks[i].id]);
282
283         return PTR_ERR(clk);
284 }
285 EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
286
287 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks,
288                                        int nums, struct hisi_clock_data *data)
289 {
290         struct clk *clk;
291         void __iomem *base = data->base;
292         int i;
293
294         for (i = 0; i < nums; i++) {
295                 clk = hisi_register_clkgate_sep(NULL, clks[i].name,
296                                                 clks[i].parent_name,
297                                                 clks[i].flags,
298                                                 base + clks[i].offset,
299                                                 clks[i].bit_idx,
300                                                 clks[i].gate_flags,
301                                                 &hisi_clk_lock);
302                 if (IS_ERR(clk)) {
303                         pr_err("%s: failed to register clock %s\n",
304                                __func__, clks[i].name);
305                         continue;
306                 }
307
308                 if (clks[i].alias)
309                         clk_register_clkdev(clk, clks[i].alias, NULL);
310
311                 data->clk_data.clks[clks[i].id] = clk;
312         }
313 }
314 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);
315
316 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks,
317                                         int nums, struct hisi_clock_data *data)
318 {
319         struct clk *clk;
320         void __iomem *base = data->base;
321         int i;
322
323         for (i = 0; i < nums; i++) {
324                 clk = hi6220_register_clkdiv(NULL, clks[i].name,
325                                                 clks[i].parent_name,
326                                                 clks[i].flags,
327                                                 base + clks[i].offset,
328                                                 clks[i].shift,
329                                                 clks[i].width,
330                                                 clks[i].mask_bit,
331                                                 &hisi_clk_lock);
332                 if (IS_ERR(clk)) {
333                         pr_err("%s: failed to register clock %s\n",
334                                __func__, clks[i].name);
335                         continue;
336                 }
337
338                 if (clks[i].alias)
339                         clk_register_clkdev(clk, clks[i].alias, NULL);
340
341                 data->clk_data.clks[clks[i].id] = clk;
342         }
343 }