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