xref: /openbmc/linux/drivers/clk/clk-bulk.c (revision ebafb63d)
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 
78266e4e9dSDong Aisheng int __must_check clk_bulk_get(struct device *dev, int num_clks,
79266e4e9dSDong Aisheng 			      struct clk_bulk_data *clks)
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);
91329470f2SJerome Brunet 			if (ret != -EPROBE_DEFER)
92266e4e9dSDong Aisheng 				dev_err(dev, "Failed to get clk '%s': %d\n",
93266e4e9dSDong Aisheng 					clks[i].id, ret);
94266e4e9dSDong Aisheng 			clks[i].clk = NULL;
95266e4e9dSDong Aisheng 			goto err;
96266e4e9dSDong Aisheng 		}
97266e4e9dSDong Aisheng 	}
98266e4e9dSDong Aisheng 
99266e4e9dSDong Aisheng 	return 0;
100266e4e9dSDong Aisheng 
101266e4e9dSDong Aisheng err:
102266e4e9dSDong Aisheng 	clk_bulk_put(i, clks);
103266e4e9dSDong Aisheng 
104266e4e9dSDong Aisheng 	return ret;
105266e4e9dSDong Aisheng }
106266e4e9dSDong Aisheng EXPORT_SYMBOL(clk_bulk_get);
107266e4e9dSDong Aisheng 
108616e45dfSDong Aisheng void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
109616e45dfSDong Aisheng {
110616e45dfSDong Aisheng 	if (IS_ERR_OR_NULL(clks))
111616e45dfSDong Aisheng 		return;
112616e45dfSDong Aisheng 
113616e45dfSDong Aisheng 	clk_bulk_put(num_clks, clks);
114616e45dfSDong Aisheng 
115616e45dfSDong Aisheng 	kfree(clks);
116616e45dfSDong Aisheng }
117616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_put_all);
118616e45dfSDong Aisheng 
119616e45dfSDong Aisheng int __must_check clk_bulk_get_all(struct device *dev,
120616e45dfSDong Aisheng 				  struct clk_bulk_data **clks)
121616e45dfSDong Aisheng {
122616e45dfSDong Aisheng 	struct device_node *np = dev_of_node(dev);
123616e45dfSDong Aisheng 
124616e45dfSDong Aisheng 	if (!np)
125616e45dfSDong Aisheng 		return 0;
126616e45dfSDong Aisheng 
127616e45dfSDong Aisheng 	return of_clk_bulk_get_all(np, clks);
128616e45dfSDong Aisheng }
129616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_get_all);
130616e45dfSDong Aisheng 
131266e4e9dSDong Aisheng #ifdef CONFIG_HAVE_CLK_PREPARE
132266e4e9dSDong Aisheng 
133266e4e9dSDong Aisheng /**
134266e4e9dSDong Aisheng  * clk_bulk_unprepare - undo preparation of a set of clock sources
135266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
136266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being unprepared
137266e4e9dSDong Aisheng  *
138266e4e9dSDong Aisheng  * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable.
139266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
140266e4e9dSDong Aisheng  */
141266e4e9dSDong Aisheng void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks)
142266e4e9dSDong Aisheng {
143266e4e9dSDong Aisheng 	while (--num_clks >= 0)
144266e4e9dSDong Aisheng 		clk_unprepare(clks[num_clks].clk);
145266e4e9dSDong Aisheng }
146266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_unprepare);
147266e4e9dSDong Aisheng 
148266e4e9dSDong Aisheng /**
149266e4e9dSDong Aisheng  * clk_bulk_prepare - prepare a set of clocks
150266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
151266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being prepared
152266e4e9dSDong Aisheng  *
153266e4e9dSDong Aisheng  * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable.
154266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
155266e4e9dSDong Aisheng  */
156266e4e9dSDong Aisheng int __must_check clk_bulk_prepare(int num_clks,
157266e4e9dSDong Aisheng 				  const struct clk_bulk_data *clks)
158266e4e9dSDong Aisheng {
159266e4e9dSDong Aisheng 	int ret;
160266e4e9dSDong Aisheng 	int i;
161266e4e9dSDong Aisheng 
162266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
163266e4e9dSDong Aisheng 		ret = clk_prepare(clks[i].clk);
164266e4e9dSDong Aisheng 		if (ret) {
165266e4e9dSDong Aisheng 			pr_err("Failed to prepare clk '%s': %d\n",
166266e4e9dSDong Aisheng 				clks[i].id, ret);
167266e4e9dSDong Aisheng 			goto err;
168266e4e9dSDong Aisheng 		}
169266e4e9dSDong Aisheng 	}
170266e4e9dSDong Aisheng 
171266e4e9dSDong Aisheng 	return 0;
172266e4e9dSDong Aisheng 
173266e4e9dSDong Aisheng err:
174266e4e9dSDong Aisheng 	clk_bulk_unprepare(i, clks);
175266e4e9dSDong Aisheng 
176266e4e9dSDong Aisheng 	return  ret;
177266e4e9dSDong Aisheng }
1789792bf5aSBjorn Andersson EXPORT_SYMBOL_GPL(clk_bulk_prepare);
179266e4e9dSDong Aisheng 
180266e4e9dSDong Aisheng #endif /* CONFIG_HAVE_CLK_PREPARE */
181266e4e9dSDong Aisheng 
182266e4e9dSDong Aisheng /**
183266e4e9dSDong Aisheng  * clk_bulk_disable - gate a set of clocks
184266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
185266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being gated
186266e4e9dSDong Aisheng  *
187266e4e9dSDong Aisheng  * clk_bulk_disable must not sleep, which differentiates it from
188266e4e9dSDong Aisheng  * clk_bulk_unprepare. clk_bulk_disable must be called before
189266e4e9dSDong Aisheng  * clk_bulk_unprepare.
190266e4e9dSDong Aisheng  */
191266e4e9dSDong Aisheng void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)
192266e4e9dSDong Aisheng {
193266e4e9dSDong Aisheng 
194266e4e9dSDong Aisheng 	while (--num_clks >= 0)
195266e4e9dSDong Aisheng 		clk_disable(clks[num_clks].clk);
196266e4e9dSDong Aisheng }
197266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_disable);
198266e4e9dSDong Aisheng 
199266e4e9dSDong Aisheng /**
200266e4e9dSDong Aisheng  * clk_bulk_enable - ungate a set of clocks
201266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
202266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being ungated
203266e4e9dSDong Aisheng  *
204266e4e9dSDong Aisheng  * clk_bulk_enable must not sleep
205266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
206266e4e9dSDong Aisheng  */
207266e4e9dSDong Aisheng int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)
208266e4e9dSDong Aisheng {
209266e4e9dSDong Aisheng 	int ret;
210266e4e9dSDong Aisheng 	int i;
211266e4e9dSDong Aisheng 
212266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
213266e4e9dSDong Aisheng 		ret = clk_enable(clks[i].clk);
214266e4e9dSDong Aisheng 		if (ret) {
215266e4e9dSDong Aisheng 			pr_err("Failed to enable clk '%s': %d\n",
216266e4e9dSDong Aisheng 				clks[i].id, ret);
217266e4e9dSDong Aisheng 			goto err;
218266e4e9dSDong Aisheng 		}
219266e4e9dSDong Aisheng 	}
220266e4e9dSDong Aisheng 
221266e4e9dSDong Aisheng 	return 0;
222266e4e9dSDong Aisheng 
223266e4e9dSDong Aisheng err:
224266e4e9dSDong Aisheng 	clk_bulk_disable(i, clks);
225266e4e9dSDong Aisheng 
226266e4e9dSDong Aisheng 	return  ret;
227266e4e9dSDong Aisheng }
228266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_enable);
229