xref: /openbmc/linux/drivers/clk/clk-bulk.c (revision 2f25528e4edddc6eddd42c8d41c9c9e341c8b9da)
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 
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 
21cfdc0411SDong Aisheng 	for (i = 0; i < num_clks; i++)
22cfdc0411SDong Aisheng 		clks[i].clk = NULL;
23cfdc0411SDong Aisheng 
24cfdc0411SDong Aisheng 	for (i = 0; i < num_clks; i++) {
25cfdc0411SDong Aisheng 		clks[i].clk = of_clk_get(np, i);
26cfdc0411SDong Aisheng 		if (IS_ERR(clks[i].clk)) {
27cfdc0411SDong Aisheng 			ret = PTR_ERR(clks[i].clk);
28cfdc0411SDong Aisheng 			pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
29cfdc0411SDong Aisheng 			       np, i, ret);
30cfdc0411SDong Aisheng 			clks[i].clk = NULL;
31cfdc0411SDong Aisheng 			goto err;
32cfdc0411SDong Aisheng 		}
33cfdc0411SDong Aisheng 	}
34cfdc0411SDong Aisheng 
35cfdc0411SDong Aisheng 	return 0;
36cfdc0411SDong Aisheng 
37cfdc0411SDong Aisheng err:
38cfdc0411SDong Aisheng 	clk_bulk_put(i, clks);
39cfdc0411SDong Aisheng 
40cfdc0411SDong Aisheng 	return ret;
41cfdc0411SDong Aisheng }
42266e4e9dSDong Aisheng 
43616e45dfSDong Aisheng static int __must_check of_clk_bulk_get_all(struct device_node *np,
44616e45dfSDong Aisheng 					    struct clk_bulk_data **clks)
45616e45dfSDong Aisheng {
46616e45dfSDong Aisheng 	struct clk_bulk_data *clk_bulk;
47616e45dfSDong Aisheng 	int num_clks;
48616e45dfSDong Aisheng 	int ret;
49616e45dfSDong Aisheng 
50616e45dfSDong Aisheng 	num_clks = of_clk_get_parent_count(np);
51616e45dfSDong Aisheng 	if (!num_clks)
52616e45dfSDong Aisheng 		return 0;
53616e45dfSDong Aisheng 
54616e45dfSDong Aisheng 	clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL);
55616e45dfSDong Aisheng 	if (!clk_bulk)
56616e45dfSDong Aisheng 		return -ENOMEM;
57616e45dfSDong Aisheng 
58616e45dfSDong Aisheng 	ret = of_clk_bulk_get(np, num_clks, clk_bulk);
59616e45dfSDong Aisheng 	if (ret) {
60616e45dfSDong Aisheng 		kfree(clk_bulk);
61616e45dfSDong Aisheng 		return ret;
62616e45dfSDong Aisheng 	}
63616e45dfSDong Aisheng 
64616e45dfSDong Aisheng 	*clks = clk_bulk;
65616e45dfSDong Aisheng 
66616e45dfSDong Aisheng 	return num_clks;
67616e45dfSDong Aisheng }
68616e45dfSDong Aisheng 
69266e4e9dSDong Aisheng void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
70266e4e9dSDong Aisheng {
71266e4e9dSDong Aisheng 	while (--num_clks >= 0) {
72266e4e9dSDong Aisheng 		clk_put(clks[num_clks].clk);
73266e4e9dSDong Aisheng 		clks[num_clks].clk = NULL;
74266e4e9dSDong Aisheng 	}
75266e4e9dSDong Aisheng }
76266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_put);
77266e4e9dSDong Aisheng 
78*2f25528eSSylwester Nawrocki static int __clk_bulk_get(struct device *dev, int num_clks,
79*2f25528eSSylwester Nawrocki 			  struct clk_bulk_data *clks, bool optional)
80266e4e9dSDong Aisheng {
81266e4e9dSDong Aisheng 	int ret;
82266e4e9dSDong Aisheng 	int i;
83266e4e9dSDong Aisheng 
84266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++)
85266e4e9dSDong Aisheng 		clks[i].clk = NULL;
86266e4e9dSDong Aisheng 
87266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
88266e4e9dSDong Aisheng 		clks[i].clk = clk_get(dev, clks[i].id);
89266e4e9dSDong Aisheng 		if (IS_ERR(clks[i].clk)) {
90266e4e9dSDong Aisheng 			ret = PTR_ERR(clks[i].clk);
91*2f25528eSSylwester Nawrocki 			clks[i].clk = NULL;
92*2f25528eSSylwester Nawrocki 
93*2f25528eSSylwester Nawrocki 			if (ret == -ENOENT && optional)
94*2f25528eSSylwester Nawrocki 				continue;
95*2f25528eSSylwester Nawrocki 
96329470f2SJerome Brunet 			if (ret != -EPROBE_DEFER)
97266e4e9dSDong Aisheng 				dev_err(dev, "Failed to get clk '%s': %d\n",
98266e4e9dSDong Aisheng 					clks[i].id, ret);
99266e4e9dSDong Aisheng 			goto err;
100266e4e9dSDong Aisheng 		}
101266e4e9dSDong Aisheng 	}
102266e4e9dSDong Aisheng 
103266e4e9dSDong Aisheng 	return 0;
104266e4e9dSDong Aisheng 
105266e4e9dSDong Aisheng err:
106266e4e9dSDong Aisheng 	clk_bulk_put(i, clks);
107266e4e9dSDong Aisheng 
108266e4e9dSDong Aisheng 	return ret;
109266e4e9dSDong Aisheng }
110*2f25528eSSylwester Nawrocki 
111*2f25528eSSylwester Nawrocki int __must_check clk_bulk_get(struct device *dev, int num_clks,
112*2f25528eSSylwester Nawrocki 			      struct clk_bulk_data *clks)
113*2f25528eSSylwester Nawrocki {
114*2f25528eSSylwester Nawrocki 	return __clk_bulk_get(dev, num_clks, clks, false);
115*2f25528eSSylwester Nawrocki }
116266e4e9dSDong Aisheng EXPORT_SYMBOL(clk_bulk_get);
117266e4e9dSDong Aisheng 
118*2f25528eSSylwester Nawrocki int __must_check clk_bulk_get_optional(struct device *dev, int num_clks,
119*2f25528eSSylwester Nawrocki 				       struct clk_bulk_data *clks)
120*2f25528eSSylwester Nawrocki {
121*2f25528eSSylwester Nawrocki 	return __clk_bulk_get(dev, num_clks, clks, true);
122*2f25528eSSylwester Nawrocki }
123*2f25528eSSylwester Nawrocki EXPORT_SYMBOL_GPL(clk_bulk_get_optional);
124*2f25528eSSylwester Nawrocki 
125616e45dfSDong Aisheng void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
126616e45dfSDong Aisheng {
127616e45dfSDong Aisheng 	if (IS_ERR_OR_NULL(clks))
128616e45dfSDong Aisheng 		return;
129616e45dfSDong Aisheng 
130616e45dfSDong Aisheng 	clk_bulk_put(num_clks, clks);
131616e45dfSDong Aisheng 
132616e45dfSDong Aisheng 	kfree(clks);
133616e45dfSDong Aisheng }
134616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_put_all);
135616e45dfSDong Aisheng 
136616e45dfSDong Aisheng int __must_check clk_bulk_get_all(struct device *dev,
137616e45dfSDong Aisheng 				  struct clk_bulk_data **clks)
138616e45dfSDong Aisheng {
139616e45dfSDong Aisheng 	struct device_node *np = dev_of_node(dev);
140616e45dfSDong Aisheng 
141616e45dfSDong Aisheng 	if (!np)
142616e45dfSDong Aisheng 		return 0;
143616e45dfSDong Aisheng 
144616e45dfSDong Aisheng 	return of_clk_bulk_get_all(np, clks);
145616e45dfSDong Aisheng }
146616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_get_all);
147616e45dfSDong Aisheng 
148266e4e9dSDong Aisheng #ifdef CONFIG_HAVE_CLK_PREPARE
149266e4e9dSDong Aisheng 
150266e4e9dSDong Aisheng /**
151266e4e9dSDong Aisheng  * clk_bulk_unprepare - undo preparation of a set of clock sources
152266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
153266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being unprepared
154266e4e9dSDong Aisheng  *
155266e4e9dSDong Aisheng  * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable.
156266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
157266e4e9dSDong Aisheng  */
158266e4e9dSDong Aisheng void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks)
159266e4e9dSDong Aisheng {
160266e4e9dSDong Aisheng 	while (--num_clks >= 0)
161266e4e9dSDong Aisheng 		clk_unprepare(clks[num_clks].clk);
162266e4e9dSDong Aisheng }
163266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_unprepare);
164266e4e9dSDong Aisheng 
165266e4e9dSDong Aisheng /**
166266e4e9dSDong Aisheng  * clk_bulk_prepare - prepare a set of clocks
167266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
168266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being prepared
169266e4e9dSDong Aisheng  *
170266e4e9dSDong Aisheng  * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable.
171266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
172266e4e9dSDong Aisheng  */
173266e4e9dSDong Aisheng int __must_check clk_bulk_prepare(int num_clks,
174266e4e9dSDong Aisheng 				  const struct clk_bulk_data *clks)
175266e4e9dSDong Aisheng {
176266e4e9dSDong Aisheng 	int ret;
177266e4e9dSDong Aisheng 	int i;
178266e4e9dSDong Aisheng 
179266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
180266e4e9dSDong Aisheng 		ret = clk_prepare(clks[i].clk);
181266e4e9dSDong Aisheng 		if (ret) {
182266e4e9dSDong Aisheng 			pr_err("Failed to prepare clk '%s': %d\n",
183266e4e9dSDong Aisheng 				clks[i].id, ret);
184266e4e9dSDong Aisheng 			goto err;
185266e4e9dSDong Aisheng 		}
186266e4e9dSDong Aisheng 	}
187266e4e9dSDong Aisheng 
188266e4e9dSDong Aisheng 	return 0;
189266e4e9dSDong Aisheng 
190266e4e9dSDong Aisheng err:
191266e4e9dSDong Aisheng 	clk_bulk_unprepare(i, clks);
192266e4e9dSDong Aisheng 
193266e4e9dSDong Aisheng 	return  ret;
194266e4e9dSDong Aisheng }
1959792bf5aSBjorn Andersson EXPORT_SYMBOL_GPL(clk_bulk_prepare);
196266e4e9dSDong Aisheng 
197266e4e9dSDong Aisheng #endif /* CONFIG_HAVE_CLK_PREPARE */
198266e4e9dSDong Aisheng 
199266e4e9dSDong Aisheng /**
200266e4e9dSDong Aisheng  * clk_bulk_disable - gate a set of clocks
201266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
202266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being gated
203266e4e9dSDong Aisheng  *
204266e4e9dSDong Aisheng  * clk_bulk_disable must not sleep, which differentiates it from
205266e4e9dSDong Aisheng  * clk_bulk_unprepare. clk_bulk_disable must be called before
206266e4e9dSDong Aisheng  * clk_bulk_unprepare.
207266e4e9dSDong Aisheng  */
208266e4e9dSDong Aisheng void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)
209266e4e9dSDong Aisheng {
210266e4e9dSDong Aisheng 
211266e4e9dSDong Aisheng 	while (--num_clks >= 0)
212266e4e9dSDong Aisheng 		clk_disable(clks[num_clks].clk);
213266e4e9dSDong Aisheng }
214266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_disable);
215266e4e9dSDong Aisheng 
216266e4e9dSDong Aisheng /**
217266e4e9dSDong Aisheng  * clk_bulk_enable - ungate a set of clocks
218266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
219266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being ungated
220266e4e9dSDong Aisheng  *
221266e4e9dSDong Aisheng  * clk_bulk_enable must not sleep
222266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
223266e4e9dSDong Aisheng  */
224266e4e9dSDong Aisheng int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)
225266e4e9dSDong Aisheng {
226266e4e9dSDong Aisheng 	int ret;
227266e4e9dSDong Aisheng 	int i;
228266e4e9dSDong Aisheng 
229266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
230266e4e9dSDong Aisheng 		ret = clk_enable(clks[i].clk);
231266e4e9dSDong Aisheng 		if (ret) {
232266e4e9dSDong Aisheng 			pr_err("Failed to enable clk '%s': %d\n",
233266e4e9dSDong Aisheng 				clks[i].id, ret);
234266e4e9dSDong Aisheng 			goto err;
235266e4e9dSDong Aisheng 		}
236266e4e9dSDong Aisheng 	}
237266e4e9dSDong Aisheng 
238266e4e9dSDong Aisheng 	return 0;
239266e4e9dSDong Aisheng 
240266e4e9dSDong Aisheng err:
241266e4e9dSDong Aisheng 	clk_bulk_disable(i, clks);
242266e4e9dSDong Aisheng 
243266e4e9dSDong Aisheng 	return  ret;
244266e4e9dSDong Aisheng }
245266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_enable);
246