xref: /openbmc/linux/drivers/clk/clk-bulk.c (revision 266e4e9d9150e98141b85c7400f8aa3cd57a7f9b)
1*266e4e9dSDong Aisheng /*
2*266e4e9dSDong Aisheng  * Copyright 2017 NXP
3*266e4e9dSDong Aisheng  *
4*266e4e9dSDong Aisheng  * Dong Aisheng <aisheng.dong@nxp.com>
5*266e4e9dSDong Aisheng  *
6*266e4e9dSDong Aisheng  * This program is free software; you can redistribute it and/or modify it
7*266e4e9dSDong Aisheng  * under the terms and conditions of the GNU General Public License,
8*266e4e9dSDong Aisheng  * version 2, as published by the Free Software Foundation.
9*266e4e9dSDong Aisheng  *
10*266e4e9dSDong Aisheng  * This program is distributed in the hope it will be useful, but WITHOUT
11*266e4e9dSDong Aisheng  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*266e4e9dSDong Aisheng  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13*266e4e9dSDong Aisheng  * more details.
14*266e4e9dSDong Aisheng  *
15*266e4e9dSDong Aisheng  * You should have received a copy of the GNU General Public License
16*266e4e9dSDong Aisheng  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17*266e4e9dSDong Aisheng  */
18*266e4e9dSDong Aisheng 
19*266e4e9dSDong Aisheng #include <linux/clk.h>
20*266e4e9dSDong Aisheng #include <linux/device.h>
21*266e4e9dSDong Aisheng #include <linux/export.h>
22*266e4e9dSDong Aisheng 
23*266e4e9dSDong Aisheng void clk_bulk_put(int num_clks, struct clk_bulk_data *clks)
24*266e4e9dSDong Aisheng {
25*266e4e9dSDong Aisheng 	while (--num_clks >= 0) {
26*266e4e9dSDong Aisheng 		clk_put(clks[num_clks].clk);
27*266e4e9dSDong Aisheng 		clks[num_clks].clk = NULL;
28*266e4e9dSDong Aisheng 	}
29*266e4e9dSDong Aisheng }
30*266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_put);
31*266e4e9dSDong Aisheng 
32*266e4e9dSDong Aisheng int __must_check clk_bulk_get(struct device *dev, int num_clks,
33*266e4e9dSDong Aisheng 			      struct clk_bulk_data *clks)
34*266e4e9dSDong Aisheng {
35*266e4e9dSDong Aisheng 	int ret;
36*266e4e9dSDong Aisheng 	int i;
37*266e4e9dSDong Aisheng 
38*266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++)
39*266e4e9dSDong Aisheng 		clks[i].clk = NULL;
40*266e4e9dSDong Aisheng 
41*266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
42*266e4e9dSDong Aisheng 		clks[i].clk = clk_get(dev, clks[i].id);
43*266e4e9dSDong Aisheng 		if (IS_ERR(clks[i].clk)) {
44*266e4e9dSDong Aisheng 			ret = PTR_ERR(clks[i].clk);
45*266e4e9dSDong Aisheng 			dev_err(dev, "Failed to get clk '%s': %d\n",
46*266e4e9dSDong Aisheng 				clks[i].id, ret);
47*266e4e9dSDong Aisheng 			clks[i].clk = NULL;
48*266e4e9dSDong Aisheng 			goto err;
49*266e4e9dSDong Aisheng 		}
50*266e4e9dSDong Aisheng 	}
51*266e4e9dSDong Aisheng 
52*266e4e9dSDong Aisheng 	return 0;
53*266e4e9dSDong Aisheng 
54*266e4e9dSDong Aisheng err:
55*266e4e9dSDong Aisheng 	clk_bulk_put(i, clks);
56*266e4e9dSDong Aisheng 
57*266e4e9dSDong Aisheng 	return ret;
58*266e4e9dSDong Aisheng }
59*266e4e9dSDong Aisheng EXPORT_SYMBOL(clk_bulk_get);
60*266e4e9dSDong Aisheng 
61*266e4e9dSDong Aisheng #ifdef CONFIG_HAVE_CLK_PREPARE
62*266e4e9dSDong Aisheng 
63*266e4e9dSDong Aisheng /**
64*266e4e9dSDong Aisheng  * clk_bulk_unprepare - undo preparation of a set of clock sources
65*266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
66*266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being unprepared
67*266e4e9dSDong Aisheng  *
68*266e4e9dSDong Aisheng  * clk_bulk_unprepare may sleep, which differentiates it from clk_bulk_disable.
69*266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
70*266e4e9dSDong Aisheng  */
71*266e4e9dSDong Aisheng void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks)
72*266e4e9dSDong Aisheng {
73*266e4e9dSDong Aisheng 	while (--num_clks >= 0)
74*266e4e9dSDong Aisheng 		clk_unprepare(clks[num_clks].clk);
75*266e4e9dSDong Aisheng }
76*266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_unprepare);
77*266e4e9dSDong Aisheng 
78*266e4e9dSDong Aisheng /**
79*266e4e9dSDong Aisheng  * clk_bulk_prepare - prepare a set of clocks
80*266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
81*266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being prepared
82*266e4e9dSDong Aisheng  *
83*266e4e9dSDong Aisheng  * clk_bulk_prepare may sleep, which differentiates it from clk_bulk_enable.
84*266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
85*266e4e9dSDong Aisheng  */
86*266e4e9dSDong Aisheng int __must_check clk_bulk_prepare(int num_clks,
87*266e4e9dSDong Aisheng 				  const struct clk_bulk_data *clks)
88*266e4e9dSDong Aisheng {
89*266e4e9dSDong Aisheng 	int ret;
90*266e4e9dSDong Aisheng 	int i;
91*266e4e9dSDong Aisheng 
92*266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
93*266e4e9dSDong Aisheng 		ret = clk_prepare(clks[i].clk);
94*266e4e9dSDong Aisheng 		if (ret) {
95*266e4e9dSDong Aisheng 			pr_err("Failed to prepare clk '%s': %d\n",
96*266e4e9dSDong Aisheng 				clks[i].id, ret);
97*266e4e9dSDong Aisheng 			goto err;
98*266e4e9dSDong Aisheng 		}
99*266e4e9dSDong Aisheng 	}
100*266e4e9dSDong Aisheng 
101*266e4e9dSDong Aisheng 	return 0;
102*266e4e9dSDong Aisheng 
103*266e4e9dSDong Aisheng err:
104*266e4e9dSDong Aisheng 	clk_bulk_unprepare(i, clks);
105*266e4e9dSDong Aisheng 
106*266e4e9dSDong Aisheng 	return  ret;
107*266e4e9dSDong Aisheng }
108*266e4e9dSDong Aisheng 
109*266e4e9dSDong Aisheng #endif /* CONFIG_HAVE_CLK_PREPARE */
110*266e4e9dSDong Aisheng 
111*266e4e9dSDong Aisheng /**
112*266e4e9dSDong Aisheng  * clk_bulk_disable - gate a set of clocks
113*266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
114*266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being gated
115*266e4e9dSDong Aisheng  *
116*266e4e9dSDong Aisheng  * clk_bulk_disable must not sleep, which differentiates it from
117*266e4e9dSDong Aisheng  * clk_bulk_unprepare. clk_bulk_disable must be called before
118*266e4e9dSDong Aisheng  * clk_bulk_unprepare.
119*266e4e9dSDong Aisheng  */
120*266e4e9dSDong Aisheng void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks)
121*266e4e9dSDong Aisheng {
122*266e4e9dSDong Aisheng 
123*266e4e9dSDong Aisheng 	while (--num_clks >= 0)
124*266e4e9dSDong Aisheng 		clk_disable(clks[num_clks].clk);
125*266e4e9dSDong Aisheng }
126*266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_disable);
127*266e4e9dSDong Aisheng 
128*266e4e9dSDong Aisheng /**
129*266e4e9dSDong Aisheng  * clk_bulk_enable - ungate a set of clocks
130*266e4e9dSDong Aisheng  * @num_clks: the number of clk_bulk_data
131*266e4e9dSDong Aisheng  * @clks: the clk_bulk_data table being ungated
132*266e4e9dSDong Aisheng  *
133*266e4e9dSDong Aisheng  * clk_bulk_enable must not sleep
134*266e4e9dSDong Aisheng  * Returns 0 on success, -EERROR otherwise.
135*266e4e9dSDong Aisheng  */
136*266e4e9dSDong Aisheng int __must_check clk_bulk_enable(int num_clks, const struct clk_bulk_data *clks)
137*266e4e9dSDong Aisheng {
138*266e4e9dSDong Aisheng 	int ret;
139*266e4e9dSDong Aisheng 	int i;
140*266e4e9dSDong Aisheng 
141*266e4e9dSDong Aisheng 	for (i = 0; i < num_clks; i++) {
142*266e4e9dSDong Aisheng 		ret = clk_enable(clks[i].clk);
143*266e4e9dSDong Aisheng 		if (ret) {
144*266e4e9dSDong Aisheng 			pr_err("Failed to enable clk '%s': %d\n",
145*266e4e9dSDong Aisheng 				clks[i].id, ret);
146*266e4e9dSDong Aisheng 			goto err;
147*266e4e9dSDong Aisheng 		}
148*266e4e9dSDong Aisheng 	}
149*266e4e9dSDong Aisheng 
150*266e4e9dSDong Aisheng 	return 0;
151*266e4e9dSDong Aisheng 
152*266e4e9dSDong Aisheng err:
153*266e4e9dSDong Aisheng 	clk_bulk_disable(i, clks);
154*266e4e9dSDong Aisheng 
155*266e4e9dSDong Aisheng 	return  ret;
156*266e4e9dSDong Aisheng }
157*266e4e9dSDong Aisheng EXPORT_SYMBOL_GPL(clk_bulk_enable);
158