xref: /openbmc/linux/drivers/clk/clk-bulk.c (revision 616e45df7c4aa71279c07cc803a1d51f43f89f37)
1266e4e9dSDong Aisheng /*
2266e4e9dSDong Aisheng  * Copyright 2017 NXP
3266e4e9dSDong Aisheng  *
4266e4e9dSDong Aisheng  * Dong Aisheng <aisheng.dong@nxp.com>
5266e4e9dSDong Aisheng  *
6266e4e9dSDong Aisheng  * This program is free software; you can redistribute it and/or modify it
7266e4e9dSDong Aisheng  * under the terms and conditions of the GNU General Public License,
8266e4e9dSDong Aisheng  * version 2, as published by the Free Software Foundation.
9266e4e9dSDong Aisheng  *
10266e4e9dSDong Aisheng  * This program is distributed in the hope it will be useful, but WITHOUT
11266e4e9dSDong Aisheng  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12266e4e9dSDong Aisheng  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13266e4e9dSDong Aisheng  * more details.
14266e4e9dSDong Aisheng  *
15266e4e9dSDong Aisheng  * You should have received a copy of the GNU General Public License
16266e4e9dSDong Aisheng  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17266e4e9dSDong Aisheng  */
18266e4e9dSDong Aisheng 
19266e4e9dSDong Aisheng #include <linux/clk.h>
20*616e45dfSDong Aisheng #include <linux/clk-provider.h>
21266e4e9dSDong Aisheng #include <linux/device.h>
22266e4e9dSDong Aisheng #include <linux/export.h>
23cfdc0411SDong Aisheng #include <linux/of.h>
24*616e45dfSDong Aisheng #include <linux/slab.h>
25cfdc0411SDong Aisheng 
26cfdc0411SDong Aisheng static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
27cfdc0411SDong Aisheng 					struct clk_bulk_data *clks)
28cfdc0411SDong Aisheng {
29cfdc0411SDong Aisheng 	int ret;
30cfdc0411SDong Aisheng 	int i;
31cfdc0411SDong Aisheng 
32cfdc0411SDong Aisheng 	for (i = 0; i < num_clks; i++)
33cfdc0411SDong Aisheng 		clks[i].clk = NULL;
34cfdc0411SDong Aisheng 
35cfdc0411SDong Aisheng 	for (i = 0; i < num_clks; i++) {
36cfdc0411SDong Aisheng 		clks[i].clk = of_clk_get(np, i);
37cfdc0411SDong Aisheng 		if (IS_ERR(clks[i].clk)) {
38cfdc0411SDong Aisheng 			ret = PTR_ERR(clks[i].clk);
39cfdc0411SDong Aisheng 			pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
40cfdc0411SDong Aisheng 			       np, i, ret);
41cfdc0411SDong Aisheng 			clks[i].clk = NULL;
42cfdc0411SDong Aisheng 			goto err;
43cfdc0411SDong Aisheng 		}
44cfdc0411SDong Aisheng 	}
45cfdc0411SDong Aisheng 
46cfdc0411SDong Aisheng 	return 0;
47cfdc0411SDong Aisheng 
48cfdc0411SDong Aisheng err:
49cfdc0411SDong Aisheng 	clk_bulk_put(i, clks);
50cfdc0411SDong Aisheng 
51cfdc0411SDong Aisheng 	return ret;
52cfdc0411SDong Aisheng }
53266e4e9dSDong Aisheng 
54*616e45dfSDong Aisheng static int __must_check of_clk_bulk_get_all(struct device_node *np,
55*616e45dfSDong Aisheng 					    struct clk_bulk_data **clks)
56*616e45dfSDong Aisheng {
57*616e45dfSDong Aisheng 	struct clk_bulk_data *clk_bulk;
58*616e45dfSDong Aisheng 	int num_clks;
59*616e45dfSDong Aisheng 	int ret;
60*616e45dfSDong Aisheng 
61*616e45dfSDong Aisheng 	num_clks = of_clk_get_parent_count(np);
62*616e45dfSDong Aisheng 	if (!num_clks)
63*616e45dfSDong Aisheng 		return 0;
64*616e45dfSDong Aisheng 
65*616e45dfSDong Aisheng 	clk_bulk = kmalloc_array(num_clks, sizeof(*clk_bulk), GFP_KERNEL);
66*616e45dfSDong Aisheng 	if (!clk_bulk)
67*616e45dfSDong Aisheng 		return -ENOMEM;
68*616e45dfSDong Aisheng 
69*616e45dfSDong Aisheng 	ret = of_clk_bulk_get(np, num_clks, clk_bulk);
70*616e45dfSDong Aisheng 	if (ret) {
71*616e45dfSDong Aisheng 		kfree(clk_bulk);
72*616e45dfSDong Aisheng 		return ret;
73*616e45dfSDong Aisheng 	}
74*616e45dfSDong Aisheng 
75*616e45dfSDong Aisheng 	*clks = clk_bulk;
76*616e45dfSDong Aisheng 
77*616e45dfSDong Aisheng 	return num_clks;
78*616e45dfSDong Aisheng }
79*616e45dfSDong Aisheng 
80266e4e9dSDong Aisheng void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
81266e4e9dSDong Aisheng {
82266e4e9dSDong Aisheng 	while (--num_clks >= 0) {
83266e4e9dSDong Aisheng 		clk_put(clks[num_clks].clk);
84266e4e9dSDong Aisheng 		clks[num_clks].clk = NULL;
85266e4e9dSDong Aisheng 	}
86266e4e9dSDong Aisheng }
87266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_put);
88266e4e9dSDong Aisheng 
89266e4e9dSDong Aisheng int __must_check clk_bulk_get(struct device *dev, int num_clks,
90266e4e9dSDong Aisheng 			      struct clk_bulk_data *clks)
91266e4e9dSDong Aisheng {
92266e4e9dSDong Aisheng 	int ret;
93266e4e9dSDong Aisheng 	int i;
94266e4e9dSDong Aisheng 
95266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++)
96266e4e9dSDong Aisheng 		clks[i].clk = NULL;
97266e4e9dSDong Aisheng 
98266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
99266e4e9dSDong Aisheng 		clks[i].clk = clk_get(dev, clks[i].id);
100266e4e9dSDong Aisheng 		if (IS_ERR(clks[i].clk)) {
101266e4e9dSDong Aisheng 			ret = PTR_ERR(clks[i].clk);
102329470f2SJerome Brunet 			if (ret != -EPROBE_DEFER)
103266e4e9dSDong Aisheng 				dev_err(dev, "Failed to get clk '%s': %d\n",
104266e4e9dSDong Aisheng 					clks[i].id, ret);
105266e4e9dSDong Aisheng 			clks[i].clk = NULL;
106266e4e9dSDong Aisheng 			goto err;
107266e4e9dSDong Aisheng 		}
108266e4e9dSDong Aisheng 	}
109266e4e9dSDong Aisheng 
110266e4e9dSDong Aisheng 	return 0;
111266e4e9dSDong Aisheng 
112266e4e9dSDong Aisheng err:
113266e4e9dSDong Aisheng 	clk_bulk_put(i, clks);
114266e4e9dSDong Aisheng 
115266e4e9dSDong Aisheng 	return ret;
116266e4e9dSDong Aisheng }
117266e4e9dSDong Aisheng EXPORT_SYMBOL(clk_bulk_get);
118266e4e9dSDong Aisheng 
119*616e45dfSDong Aisheng void clk_bulk_put_all(int num_clks, struct clk_bulk_data *clks)
120*616e45dfSDong Aisheng {
121*616e45dfSDong Aisheng 	if (IS_ERR_OR_NULL(clks))
122*616e45dfSDong Aisheng 		return;
123*616e45dfSDong Aisheng 
124*616e45dfSDong Aisheng 	clk_bulk_put(num_clks, clks);
125*616e45dfSDong Aisheng 
126*616e45dfSDong Aisheng 	kfree(clks);
127*616e45dfSDong Aisheng }
128*616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_put_all);
129*616e45dfSDong Aisheng 
130*616e45dfSDong Aisheng int __must_check clk_bulk_get_all(struct device *dev,
131*616e45dfSDong Aisheng 				  struct clk_bulk_data **clks)
132*616e45dfSDong Aisheng {
133*616e45dfSDong Aisheng 	struct device_node *np = dev_of_node(dev);
134*616e45dfSDong Aisheng 
135*616e45dfSDong Aisheng 	if (!np)
136*616e45dfSDong Aisheng 		return 0;
137*616e45dfSDong Aisheng 
138*616e45dfSDong Aisheng 	return of_clk_bulk_get_all(np, clks);
139*616e45dfSDong Aisheng }
140*616e45dfSDong Aisheng EXPORT_SYMBOL(clk_bulk_get_all);
141*616e45dfSDong Aisheng 
142266e4e9dSDong Aisheng #ifdef CONFIG_HAVE_CLK_PREPARE
143266e4e9dSDong Aisheng 
144266e4e9dSDong Aisheng /**
145266e4e9dSDong Aisheng  * clk_bulk_unprepare - undo preparation of a set of clock sources
146266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
147266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being unprepared
148266e4e9dSDong Aisheng  *
149266e4e9dSDong Aisheng  * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable.
150266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
151266e4e9dSDong Aisheng  */
152266e4e9dSDong Aisheng void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks)
153266e4e9dSDong Aisheng {
154266e4e9dSDong Aisheng 	while (--num_clks >= 0)
155266e4e9dSDong Aisheng 		clk_unprepare(clks[num_clks].clk);
156266e4e9dSDong Aisheng }
157266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_unprepare);
158266e4e9dSDong Aisheng 
159266e4e9dSDong Aisheng /**
160266e4e9dSDong Aisheng  * clk_bulk_prepare - prepare a set of clocks
161266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
162266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being prepared
163266e4e9dSDong Aisheng  *
164266e4e9dSDong Aisheng  * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable.
165266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
166266e4e9dSDong Aisheng  */
167266e4e9dSDong Aisheng int __must_check clk_bulk_prepare(int num_clks,
168266e4e9dSDong Aisheng 				  const struct clk_bulk_data *clks)
169266e4e9dSDong Aisheng {
170266e4e9dSDong Aisheng 	int ret;
171266e4e9dSDong Aisheng 	int i;
172266e4e9dSDong Aisheng 
173266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
174266e4e9dSDong Aisheng 		ret = clk_prepare(clks[i].clk);
175266e4e9dSDong Aisheng 		if (ret) {
176266e4e9dSDong Aisheng 			pr_err("Failed to prepare clk '%s': %d\n",
177266e4e9dSDong Aisheng 				clks[i].id, ret);
178266e4e9dSDong Aisheng 			goto err;
179266e4e9dSDong Aisheng 		}
180266e4e9dSDong Aisheng 	}
181266e4e9dSDong Aisheng 
182266e4e9dSDong Aisheng 	return 0;
183266e4e9dSDong Aisheng 
184266e4e9dSDong Aisheng err:
185266e4e9dSDong Aisheng 	clk_bulk_unprepare(i, clks);
186266e4e9dSDong Aisheng 
187266e4e9dSDong Aisheng 	return  ret;
188266e4e9dSDong Aisheng }
1899792bf5aSBjorn Andersson EXPORT_SYMBOL_GPL(clk_bulk_prepare);
190266e4e9dSDong Aisheng 
191266e4e9dSDong Aisheng #endif /* CONFIG_HAVE_CLK_PREPARE */
192266e4e9dSDong Aisheng 
193266e4e9dSDong Aisheng /**
194266e4e9dSDong Aisheng  * clk_bulk_disable - gate a set of clocks
195266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
196266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being gated
197266e4e9dSDong Aisheng  *
198266e4e9dSDong Aisheng  * clk_bulk_disable must not sleep, which differentiates it from
199266e4e9dSDong Aisheng  * clk_bulk_unprepare. clk_bulk_disable must be called before
200266e4e9dSDong Aisheng  * clk_bulk_unprepare.
201266e4e9dSDong Aisheng  */
202266e4e9dSDong Aisheng void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)
203266e4e9dSDong Aisheng {
204266e4e9dSDong Aisheng 
205266e4e9dSDong Aisheng 	while (--num_clks >= 0)
206266e4e9dSDong Aisheng 		clk_disable(clks[num_clks].clk);
207266e4e9dSDong Aisheng }
208266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_disable);
209266e4e9dSDong Aisheng 
210266e4e9dSDong Aisheng /**
211266e4e9dSDong Aisheng  * clk_bulk_enable - ungate a set of clocks
212266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
213266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being ungated
214266e4e9dSDong Aisheng  *
215266e4e9dSDong Aisheng  * clk_bulk_enable must not sleep
216266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
217266e4e9dSDong Aisheng  */
218266e4e9dSDong Aisheng int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)
219266e4e9dSDong Aisheng {
220266e4e9dSDong Aisheng 	int ret;
221266e4e9dSDong Aisheng 	int i;
222266e4e9dSDong Aisheng 
223266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
224266e4e9dSDong Aisheng 		ret = clk_enable(clks[i].clk);
225266e4e9dSDong Aisheng 		if (ret) {
226266e4e9dSDong Aisheng 			pr_err("Failed to enable clk '%s': %d\n",
227266e4e9dSDong Aisheng 				clks[i].id, ret);
228266e4e9dSDong Aisheng 			goto err;
229266e4e9dSDong Aisheng 		}
230266e4e9dSDong Aisheng 	}
231266e4e9dSDong Aisheng 
232266e4e9dSDong Aisheng 	return 0;
233266e4e9dSDong Aisheng 
234266e4e9dSDong Aisheng err:
235266e4e9dSDong Aisheng 	clk_bulk_disable(i, clks);
236266e4e9dSDong Aisheng 
237266e4e9dSDong Aisheng 	return  ret;
238266e4e9dSDong Aisheng }
239266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_enable);
240