xref: /openbmc/linux/drivers/clk/clk-bulk.c (revision 4c6b2abf)
1ebafb63dSStephen Boyd // SPDX-License-Identifier: GPL-2.0
2266e4e9dSDong Aisheng /*
3266e4e9dSDong Aisheng  * Copyright 2017 NXP
4266e4e9dSDong Aisheng  *
5266e4e9dSDong Aisheng  * Dong Aisheng <aisheng.dong@nxp.com>
6266e4e9dSDong Aisheng  */
7266e4e9dSDong Aisheng 
8266e4e9dSDong Aisheng #include <linux/clk.h>
9616e45dfSDong Aisheng #include <linux/clk-provider.h>
10266e4e9dSDong Aisheng #include <linux/device.h>
11266e4e9dSDong Aisheng #include <linux/export.h>
12cfdc0411SDong Aisheng #include <linux/of.h>
13616e45dfSDong Aisheng #include <linux/slab.h>
14cfdc0411SDong Aisheng 
of_clk_bulk_get(struct device_node * np,int num_clks,struct clk_bulk_data * clks)15cfdc0411SDong Aisheng static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
16cfdc0411SDong Aisheng 					struct clk_bulk_data *clks)
17cfdc0411SDong Aisheng {
18cfdc0411SDong Aisheng 	int ret;
19cfdc0411SDong Aisheng 	int i;
20cfdc0411SDong Aisheng 
217f81c242SBjorn Andersson 	for (i = 0; i < num_clks; i++) {
227f81c242SBjorn Andersson 		clks[i].id = NULL;
23cfdc0411SDong Aisheng 		clks[i].clk = NULL;
247f81c242SBjorn Andersson 	}
25cfdc0411SDong Aisheng 
26cfdc0411SDong Aisheng 	for (i = 0; i < num_clks; i++) {
277f81c242SBjorn Andersson 		of_property_read_string_index(np, "clock-names", i, &clks[i].id);
28cfdc0411SDong Aisheng 		clks[i].clk = of_clk_get(np, i);
29cfdc0411SDong Aisheng 		if (IS_ERR(clks[i].clk)) {
30cfdc0411SDong Aisheng 			ret = PTR_ERR(clks[i].clk);
31cfdc0411SDong Aisheng 			pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
32cfdc0411SDong Aisheng 			       np, i, ret);
33cfdc0411SDong Aisheng 			clks[i].clk = NULL;
34cfdc0411SDong Aisheng 			goto err;
35cfdc0411SDong Aisheng 		}
36cfdc0411SDong Aisheng 	}
37cfdc0411SDong Aisheng 
38cfdc0411SDong Aisheng 	return 0;
39cfdc0411SDong Aisheng 
40cfdc0411SDong Aisheng err:
41cfdc0411SDong Aisheng 	clk_bulk_put(i, clks);
42cfdc0411SDong Aisheng 
43cfdc0411SDong Aisheng 	return ret;
44cfdc0411SDong Aisheng }
45266e4e9dSDong Aisheng 
of_clk_bulk_get_all(struct device_node * np,struct clk_bulk_data ** clks)46616e45dfSDong Aisheng static int __must_check of_clk_bulk_get_all(struct device_node *np,
47616e45dfSDong Aisheng 					    struct clk_bulk_data **clks)
48616e45dfSDong Aisheng {
49616e45dfSDong Aisheng 	struct clk_bulk_data *clk_bulk;
50616e45dfSDong Aisheng 	int num_clks;
51616e45dfSDong Aisheng 	int ret;
52616e45dfSDong Aisheng 
53616e45dfSDong Aisheng 	num_clks = of_clk_get_parent_count(np);
54616e45dfSDong Aisheng 	if (!num_clks)
55616e45dfSDong Aisheng 		return 0;
56616e45dfSDong Aisheng 
57616e45dfSDong Aisheng 	clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL);
58616e45dfSDong Aisheng 	if (!clk_bulk)
59616e45dfSDong Aisheng 		return -ENOMEM;
60616e45dfSDong Aisheng 
61616e45dfSDong Aisheng 	ret = of_clk_bulk_get(np, num_clks, clk_bulk);
62616e45dfSDong Aisheng 	if (ret) {
63616e45dfSDong Aisheng 		kfree(clk_bulk);
64616e45dfSDong Aisheng 		return ret;
65616e45dfSDong Aisheng 	}
66616e45dfSDong Aisheng 
67616e45dfSDong Aisheng 	*clks = clk_bulk;
68616e45dfSDong Aisheng 
69616e45dfSDong Aisheng 	return num_clks;
70616e45dfSDong Aisheng }
71616e45dfSDong Aisheng 
clk_bulk_put(int num_clks,struct clk_bulk_data * clks)72266e4e9dSDong Aisheng void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
73266e4e9dSDong Aisheng {
74266e4e9dSDong Aisheng 	while (--num_clks >= 0) {
75266e4e9dSDong Aisheng 		clk_put(clks[num_clks].clk);
76266e4e9dSDong Aisheng 		clks[num_clks].clk = NULL;
77266e4e9dSDong Aisheng 	}
78266e4e9dSDong Aisheng }
79266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_put);
80266e4e9dSDong Aisheng 
__clk_bulk_get(struct device * dev,int num_clks,struct clk_bulk_data * clks,bool optional)812f25528eSSylwester Nawrocki static int __clk_bulk_get(struct device *dev, int num_clks,
822f25528eSSylwester Nawrocki 			  struct clk_bulk_data *clks, bool optional)
83266e4e9dSDong Aisheng {
84266e4e9dSDong Aisheng 	int ret;
85266e4e9dSDong Aisheng 	int i;
86266e4e9dSDong Aisheng 
87266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++)
88266e4e9dSDong Aisheng 		clks[i].clk = NULL;
89266e4e9dSDong Aisheng 
90266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
91266e4e9dSDong Aisheng 		clks[i].clk = clk_get(dev, clks[i].id);
92266e4e9dSDong Aisheng 		if (IS_ERR(clks[i].clk)) {
93266e4e9dSDong Aisheng 			ret = PTR_ERR(clks[i].clk);
942f25528eSSylwester Nawrocki 			clks[i].clk = NULL;
952f25528eSSylwester Nawrocki 
962f25528eSSylwester Nawrocki 			if (ret == -ENOENT && optional)
972f25528eSSylwester Nawrocki 				continue;
982f25528eSSylwester Nawrocki 
99*4c6b2abfSYang Yingliang 			dev_err_probe(dev, ret,
100*4c6b2abfSYang Yingliang 				      "Failed to get clk '%s'\n",
101*4c6b2abfSYang Yingliang 				      clks[i].id);
102266e4e9dSDong Aisheng 			goto err;
103266e4e9dSDong Aisheng 		}
104266e4e9dSDong Aisheng 	}
105266e4e9dSDong Aisheng 
106266e4e9dSDong Aisheng 	return 0;
107266e4e9dSDong Aisheng 
108266e4e9dSDong Aisheng err:
109266e4e9dSDong Aisheng 	clk_bulk_put(i, clks);
110266e4e9dSDong Aisheng 
111266e4e9dSDong Aisheng 	return ret;
112266e4e9dSDong Aisheng }
1132f25528eSSylwester Nawrocki 
clk_bulk_get(struct device * dev,int num_clks,struct clk_bulk_data * clks)1142f25528eSSylwester Nawrocki int __must_check clk_bulk_get(struct device *dev, int num_clks,
1152f25528eSSylwester Nawrocki 			      struct clk_bulk_data *clks)
1162f25528eSSylwester Nawrocki {
1172f25528eSSylwester Nawrocki 	return __clk_bulk_get(dev, num_clks, clks, false);
1182f25528eSSylwester Nawrocki }
119266e4e9dSDong Aisheng EXPORT_SYMBOL(clk_bulk_get);
120266e4e9dSDong Aisheng 
clk_bulk_get_optional(struct device * dev,int num_clks,struct clk_bulk_data * clks)1212f25528eSSylwester Nawrocki int __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
1222f25528eSSylwester Nawrocki 				       struct clk_bulk_data *clks)
1232f25528eSSylwester Nawrocki {
1242f25528eSSylwester Nawrocki 	return __clk_bulk_get(dev, num_clks, clks, true);
1252f25528eSSylwester Nawrocki }
1262f25528eSSylwester Nawrocki EXPORT_SYMBOL_GPL(clk_bulk_get_optional);
1272f25528eSSylwester Nawrocki 
clk_bulk_put_all(int num_clks,struct clk_bulk_data * clks)128616e45dfSDong Aisheng void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
129616e45dfSDong Aisheng {
130616e45dfSDong Aisheng 	if (IS_ERR_OR_NULL(clks))
131616e45dfSDong Aisheng 		return;
132616e45dfSDong Aisheng 
133616e45dfSDong Aisheng 	clk_bulk_put(num_clks, clks);
134616e45dfSDong Aisheng 
135616e45dfSDong Aisheng 	kfree(clks);
136616e45dfSDong Aisheng }
137616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_put_all);
138616e45dfSDong Aisheng 
clk_bulk_get_all(struct device * dev,struct clk_bulk_data ** clks)139616e45dfSDong Aisheng int __must_check clk_bulk_get_all(struct device *dev,
140616e45dfSDong Aisheng 				  struct clk_bulk_data **clks)
141616e45dfSDong Aisheng {
142616e45dfSDong Aisheng 	struct device_node *np = dev_of_node(dev);
143616e45dfSDong Aisheng 
144616e45dfSDong Aisheng 	if (!np)
145616e45dfSDong Aisheng 		return 0;
146616e45dfSDong Aisheng 
147616e45dfSDong Aisheng 	return of_clk_bulk_get_all(np, clks);
148616e45dfSDong Aisheng }
149616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_get_all);
150616e45dfSDong Aisheng 
151266e4e9dSDong Aisheng #ifdef CONFIG_HAVE_CLK_PREPARE
152266e4e9dSDong Aisheng 
153266e4e9dSDong Aisheng /**
154266e4e9dSDong Aisheng  * clk_bulk_unprepare - undo preparation of a set of clock sources
155266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
156266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being unprepared
157266e4e9dSDong Aisheng  *
158266e4e9dSDong Aisheng  * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable.
159266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
160266e4e9dSDong Aisheng  */
clk_bulk_unprepare(int num_clks,const struct clk_bulk_data * clks)161266e4e9dSDong Aisheng void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks)
162266e4e9dSDong Aisheng {
163266e4e9dSDong Aisheng 	while (--num_clks >= 0)
164266e4e9dSDong Aisheng 		clk_unprepare(clks[num_clks].clk);
165266e4e9dSDong Aisheng }
166266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_unprepare);
167266e4e9dSDong Aisheng 
168266e4e9dSDong Aisheng /**
169266e4e9dSDong Aisheng  * clk_bulk_prepare - prepare a set of clocks
170266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
171266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being prepared
172266e4e9dSDong Aisheng  *
173266e4e9dSDong Aisheng  * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable.
174266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
175266e4e9dSDong Aisheng  */
clk_bulk_prepare(int num_clks,const struct clk_bulk_data * clks)176266e4e9dSDong Aisheng int __must_check clk_bulk_prepare(int num_clks,
177266e4e9dSDong Aisheng 				  const struct clk_bulk_data *clks)
178266e4e9dSDong Aisheng {
179266e4e9dSDong Aisheng 	int ret;
180266e4e9dSDong Aisheng 	int i;
181266e4e9dSDong Aisheng 
182266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
183266e4e9dSDong Aisheng 		ret = clk_prepare(clks[i].clk);
184266e4e9dSDong Aisheng 		if (ret) {
185266e4e9dSDong Aisheng 			pr_err("Failed to prepare clk '%s': %d\n",
186266e4e9dSDong Aisheng 				clks[i].id, ret);
187266e4e9dSDong Aisheng 			goto err;
188266e4e9dSDong Aisheng 		}
189266e4e9dSDong Aisheng 	}
190266e4e9dSDong Aisheng 
191266e4e9dSDong Aisheng 	return 0;
192266e4e9dSDong Aisheng 
193266e4e9dSDong Aisheng err:
194266e4e9dSDong Aisheng 	clk_bulk_unprepare(i, clks);
195266e4e9dSDong Aisheng 
196266e4e9dSDong Aisheng 	return  ret;
197266e4e9dSDong Aisheng }
1989792bf5aSBjorn Andersson EXPORT_SYMBOL_GPL(clk_bulk_prepare);
199266e4e9dSDong Aisheng 
200266e4e9dSDong Aisheng #endif /* CONFIG_HAVE_CLK_PREPARE */
201266e4e9dSDong Aisheng 
202266e4e9dSDong Aisheng /**
203266e4e9dSDong Aisheng  * clk_bulk_disable - gate a set of clocks
204266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
205266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being gated
206266e4e9dSDong Aisheng  *
207266e4e9dSDong Aisheng  * clk_bulk_disable must not sleep, which differentiates it from
208266e4e9dSDong Aisheng  * clk_bulk_unprepare. clk_bulk_disable must be called before
209266e4e9dSDong Aisheng  * clk_bulk_unprepare.
210266e4e9dSDong Aisheng  */
clk_bulk_disable(int num_clks,const struct clk_bulk_data * clks)211266e4e9dSDong Aisheng void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)
212266e4e9dSDong Aisheng {
213266e4e9dSDong Aisheng 
214266e4e9dSDong Aisheng 	while (--num_clks >= 0)
215266e4e9dSDong Aisheng 		clk_disable(clks[num_clks].clk);
216266e4e9dSDong Aisheng }
217266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_disable);
218266e4e9dSDong Aisheng 
219266e4e9dSDong Aisheng /**
220266e4e9dSDong Aisheng  * clk_bulk_enable - ungate a set of clocks
221266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
222266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being ungated
223266e4e9dSDong Aisheng  *
224266e4e9dSDong Aisheng  * clk_bulk_enable must not sleep
225266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
226266e4e9dSDong Aisheng  */
clk_bulk_enable(int num_clks,const struct clk_bulk_data * clks)227266e4e9dSDong Aisheng int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)
228266e4e9dSDong Aisheng {
229266e4e9dSDong Aisheng 	int ret;
230266e4e9dSDong Aisheng 	int i;
231266e4e9dSDong Aisheng 
232266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
233266e4e9dSDong Aisheng 		ret = clk_enable(clks[i].clk);
234266e4e9dSDong Aisheng 		if (ret) {
235266e4e9dSDong Aisheng 			pr_err("Failed to enable clk '%s': %d\n",
236266e4e9dSDong Aisheng 				clks[i].id, ret);
237266e4e9dSDong Aisheng 			goto err;
238266e4e9dSDong Aisheng 		}
239266e4e9dSDong Aisheng 	}
240266e4e9dSDong Aisheng 
241266e4e9dSDong Aisheng 	return 0;
242266e4e9dSDong Aisheng 
243266e4e9dSDong Aisheng err:
244266e4e9dSDong Aisheng 	clk_bulk_disable(i, clks);
245266e4e9dSDong Aisheng 
246266e4e9dSDong Aisheng 	return  ret;
247266e4e9dSDong Aisheng }
248266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_enable);
249