1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright 2017 NXP |
4 | * |
5 | * Dong Aisheng <aisheng.dong@nxp.com> |
6 | */ |
7 | |
8 | #include <linux/clk.h> |
9 | #include <linux/clk-provider.h> |
10 | #include <linux/device.h> |
11 | #include <linux/export.h> |
12 | #include <linux/of.h> |
13 | #include <linux/slab.h> |
14 | |
15 | static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks, |
16 | struct clk_bulk_data *clks) |
17 | { |
18 | int ret; |
19 | int i; |
20 | |
21 | for (i = 0; i < num_clks; i++) { |
22 | clks[i].id = NULL; |
23 | clks[i].clk = NULL; |
24 | } |
25 | |
26 | for (i = 0; i < num_clks; i++) { |
27 | of_property_read_string_index(np, propname: "clock-names" , index: i, output: &clks[i].id); |
28 | clks[i].clk = of_clk_get(np, index: i); |
29 | if (IS_ERR(ptr: clks[i].clk)) { |
30 | ret = PTR_ERR(ptr: clks[i].clk); |
31 | pr_err("%pOF: Failed to get clk index: %d ret: %d\n" , |
32 | np, i, ret); |
33 | clks[i].clk = NULL; |
34 | goto err; |
35 | } |
36 | } |
37 | |
38 | return 0; |
39 | |
40 | err: |
41 | clk_bulk_put(num_clks: i, clks); |
42 | |
43 | return ret; |
44 | } |
45 | |
46 | static int __must_check of_clk_bulk_get_all(struct device_node *np, |
47 | struct clk_bulk_data **clks) |
48 | { |
49 | struct clk_bulk_data *clk_bulk; |
50 | int num_clks; |
51 | int ret; |
52 | |
53 | num_clks = of_clk_get_parent_count(np); |
54 | if (!num_clks) |
55 | return 0; |
56 | |
57 | clk_bulk = kmalloc_array(n: num_clks, size: sizeof(*clk_bulk), GFP_KERNEL); |
58 | if (!clk_bulk) |
59 | return -ENOMEM; |
60 | |
61 | ret = of_clk_bulk_get(np, num_clks, clks: clk_bulk); |
62 | if (ret) { |
63 | kfree(objp: clk_bulk); |
64 | return ret; |
65 | } |
66 | |
67 | *clks = clk_bulk; |
68 | |
69 | return num_clks; |
70 | } |
71 | |
72 | void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) |
73 | { |
74 | while (--num_clks >= 0) { |
75 | clk_put(clk: clks[num_clks].clk); |
76 | clks[num_clks].clk = NULL; |
77 | } |
78 | } |
79 | EXPORT_SYMBOL_GPL(clk_bulk_put); |
80 | |
81 | static int __clk_bulk_get(struct device *dev, int num_clks, |
82 | struct clk_bulk_data *clks, bool optional) |
83 | { |
84 | int ret; |
85 | int i; |
86 | |
87 | for (i = 0; i < num_clks; i++) |
88 | clks[i].clk = NULL; |
89 | |
90 | for (i = 0; i < num_clks; i++) { |
91 | clks[i].clk = clk_get(dev, id: clks[i].id); |
92 | if (IS_ERR(ptr: clks[i].clk)) { |
93 | ret = PTR_ERR(ptr: clks[i].clk); |
94 | clks[i].clk = NULL; |
95 | |
96 | if (ret == -ENOENT && optional) |
97 | continue; |
98 | |
99 | dev_err_probe(dev, err: ret, |
100 | fmt: "Failed to get clk '%s'\n" , |
101 | clks[i].id); |
102 | goto err; |
103 | } |
104 | } |
105 | |
106 | return 0; |
107 | |
108 | err: |
109 | clk_bulk_put(i, clks); |
110 | |
111 | return ret; |
112 | } |
113 | |
114 | int __must_check clk_bulk_get(struct device *dev, int num_clks, |
115 | struct clk_bulk_data *clks) |
116 | { |
117 | return __clk_bulk_get(dev, num_clks, clks, optional: false); |
118 | } |
119 | EXPORT_SYMBOL(clk_bulk_get); |
120 | |
121 | int __must_check clk_bulk_get_optional(struct device *dev, int num_clks, |
122 | struct clk_bulk_data *clks) |
123 | { |
124 | return __clk_bulk_get(dev, num_clks, clks, optional: true); |
125 | } |
126 | EXPORT_SYMBOL_GPL(clk_bulk_get_optional); |
127 | |
128 | void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks) |
129 | { |
130 | if (IS_ERR_OR_NULL(ptr: clks)) |
131 | return; |
132 | |
133 | clk_bulk_put(num_clks, clks); |
134 | |
135 | kfree(objp: clks); |
136 | } |
137 | EXPORT_SYMBOL(clk_bulk_put_all); |
138 | |
139 | int __must_check clk_bulk_get_all(struct device *dev, |
140 | struct clk_bulk_data **clks) |
141 | { |
142 | struct device_node *np = dev_of_node(dev); |
143 | |
144 | if (!np) |
145 | return 0; |
146 | |
147 | return of_clk_bulk_get_all(np, clks); |
148 | } |
149 | EXPORT_SYMBOL(clk_bulk_get_all); |
150 | |
151 | #ifdef CONFIG_HAVE_CLK_PREPARE |
152 | |
153 | /** |
154 | * clk_bulk_unprepare - undo preparation of a set of clock sources |
155 | * @num_clks: the number of clk_bulk_data |
156 | * @clks: the clk_bulk_data table being unprepared |
157 | * |
158 | * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable. |
159 | * Returns 0 on success, -EERROR otherwise. |
160 | */ |
161 | void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks) |
162 | { |
163 | while (--num_clks >= 0) |
164 | clk_unprepare(clk: clks[num_clks].clk); |
165 | } |
166 | EXPORT_SYMBOL_GPL(clk_bulk_unprepare); |
167 | |
168 | /** |
169 | * clk_bulk_prepare - prepare a set of clocks |
170 | * @num_clks: the number of clk_bulk_data |
171 | * @clks: the clk_bulk_data table being prepared |
172 | * |
173 | * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable. |
174 | * Returns 0 on success, -EERROR otherwise. |
175 | */ |
176 | int __must_check clk_bulk_prepare(int num_clks, |
177 | const struct clk_bulk_data *clks) |
178 | { |
179 | int ret; |
180 | int i; |
181 | |
182 | for (i = 0; i < num_clks; i++) { |
183 | ret = clk_prepare(clk: clks[i].clk); |
184 | if (ret) { |
185 | pr_err("Failed to prepare clk '%s': %d\n" , |
186 | clks[i].id, ret); |
187 | goto err; |
188 | } |
189 | } |
190 | |
191 | return 0; |
192 | |
193 | err: |
194 | clk_bulk_unprepare(i, clks); |
195 | |
196 | return ret; |
197 | } |
198 | EXPORT_SYMBOL_GPL(clk_bulk_prepare); |
199 | |
200 | #endif /* CONFIG_HAVE_CLK_PREPARE */ |
201 | |
202 | /** |
203 | * clk_bulk_disable - gate a set of clocks |
204 | * @num_clks: the number of clk_bulk_data |
205 | * @clks: the clk_bulk_data table being gated |
206 | * |
207 | * clk_bulk_disable must not sleep, which differentiates it from |
208 | * clk_bulk_unprepare. clk_bulk_disable must be called before |
209 | * clk_bulk_unprepare. |
210 | */ |
211 | void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks) |
212 | { |
213 | |
214 | while (--num_clks >= 0) |
215 | clk_disable(clk: clks[num_clks].clk); |
216 | } |
217 | EXPORT_SYMBOL_GPL(clk_bulk_disable); |
218 | |
219 | /** |
220 | * clk_bulk_enable - ungate a set of clocks |
221 | * @num_clks: the number of clk_bulk_data |
222 | * @clks: the clk_bulk_data table being ungated |
223 | * |
224 | * clk_bulk_enable must not sleep |
225 | * Returns 0 on success, -EERROR otherwise. |
226 | */ |
227 | int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks) |
228 | { |
229 | int ret; |
230 | int i; |
231 | |
232 | for (i = 0; i < num_clks; i++) { |
233 | ret = clk_enable(clk: clks[i].clk); |
234 | if (ret) { |
235 | pr_err("Failed to enable clk '%s': %d\n" , |
236 | clks[i].id, ret); |
237 | goto err; |
238 | } |
239 | } |
240 | |
241 | return 0; |
242 | |
243 | err: |
244 | clk_bulk_disable(i, clks); |
245 | |
246 | return ret; |
247 | } |
248 | EXPORT_SYMBOL_GPL(clk_bulk_enable); |
249 | |