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