Skip to content

Commit 266e4e9

Browse files
Dong Aishengbebarino
authored andcommitted
clk: add clk_bulk_get accessories
These helper function allows drivers to get several clk consumers in one operation. If any of the clk cannot be acquired then any clks that were got will be put before returning to the caller. This can relieve the driver owners' life who needs to handle many clocks, as well as each clock error reporting. Cc: Michael Turquette <mturquette@baylibre.com> Cc: Stephen Boyd <sboyd@codeaurora.org> Cc: Russell King <linux@arm.linux.org.uk> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net> Cc: Viresh Kumar <viresh.kumar@linaro.org> Cc: Mark Brown <broonie@kernel.org> Cc: Shawn Guo <shawnguo@kernel.org> Cc: Fabio Estevam <fabio.estevam@nxp.com> Cc: Sascha Hauer <kernel@pengutronix.de> Cc: Anson Huang <anson.huang@nxp.com> Cc: Robin Gong <yibin.gong@nxp.com> Cc: Bai Ping <ping.bai@nxp.com> Cc: Leonard Crestez <leonard.crestez@nxp.com> Cc: Octavian Purdila <octavian.purdila@nxp.com> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
1 parent 2ea659a commit 266e4e9

File tree

3 files changed

+269
-1
lines changed

3 files changed

+269
-1
lines changed

drivers/clk/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# common clock types
2-
obj-$(CONFIG_HAVE_CLK) += clk-devres.o
2+
obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o
33
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
44
obj-$(CONFIG_COMMON_CLK) += clk.o
55
obj-$(CONFIG_COMMON_CLK) += clk-divider.o

drivers/clk/clk-bulk.c

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

include/linux/clk.h

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,21 @@ struct clk_notifier_data {
7777
unsigned long new_rate;
7878
};
7979

80+
/**
81+
* struct clk_bulk_data - Data used for bulk clk operations.
82+
*
83+
* @id: clock consumer ID
84+
* @clk: struct clk * to store the associated clock
85+
*
86+
* The CLK APIs provide a series of clk_bulk_() API calls as
87+
* a convenience to consumers which require multiple clks. This
88+
* structure is used to manage data for these calls.
89+
*/
90+
struct clk_bulk_data {
91+
const char *id;
92+
struct clk *clk;
93+
};
94+
8095
#ifdef CONFIG_COMMON_CLK
8196

8297
/**
@@ -185,12 +200,20 @@ static inline bool clk_is_match(const struct clk *p, const struct clk *q)
185200
*/
186201
#ifdef CONFIG_HAVE_CLK_PREPARE
187202
int clk_prepare(struct clk *clk);
203+
int __must_check clk_bulk_prepare(int num_clks,
204+
const struct clk_bulk_data *clks);
188205
#else
189206
static inline int clk_prepare(struct clk *clk)
190207
{
191208
might_sleep();
192209
return 0;
193210
}
211+
212+
static inline int clk_bulk_prepare(int num_clks, struct clk_bulk_data *clks)
213+
{
214+
might_sleep();
215+
return 0;
216+
}
194217
#endif
195218

196219
/**
@@ -204,11 +227,16 @@ static inline int clk_prepare(struct clk *clk)
204227
*/
205228
#ifdef CONFIG_HAVE_CLK_PREPARE
206229
void clk_unprepare(struct clk *clk);
230+
void clk_bulk_unprepare(int num_clks, const struct clk_bulk_data *clks);
207231
#else
208232
static inline void clk_unprepare(struct clk *clk)
209233
{
210234
might_sleep();
211235
}
236+
static inline void clk_bulk_unprepare(int num_clks, struct clk_bulk_data *clks)
237+
{
238+
might_sleep();
239+
}
212240
#endif
213241

214242
#ifdef CONFIG_HAVE_CLK
@@ -229,6 +257,29 @@ static inline void clk_unprepare(struct clk *clk)
229257
*/
230258
struct clk *clk_get(struct device *dev, const char *id);
231259

260+
/**
261+
* clk_bulk_get - lookup and obtain a number of references to clock producer.
262+
* @dev: device for clock "consumer"
263+
* @num_clks: the number of clk_bulk_data
264+
* @clks: the clk_bulk_data table of consumer
265+
*
266+
* This helper function allows drivers to get several clk consumers in one
267+
* operation. If any of the clk cannot be acquired then any clks
268+
* that were obtained will be freed before returning to the caller.
269+
*
270+
* Returns 0 if all clocks specified in clk_bulk_data table are obtained
271+
* successfully, or valid IS_ERR() condition containing errno.
272+
* The implementation uses @dev and @clk_bulk_data.id to determine the
273+
* clock consumer, and thereby the clock producer.
274+
* The clock returned is stored in each @clk_bulk_data.clk field.
275+
*
276+
* Drivers must assume that the clock source is not enabled.
277+
*
278+
* clk_bulk_get should not be called from within interrupt context.
279+
*/
280+
int __must_check clk_bulk_get(struct device *dev, int num_clks,
281+
struct clk_bulk_data *clks);
282+
232283
/**
233284
* devm_clk_get - lookup and obtain a managed reference to a clock producer.
234285
* @dev: device for clock "consumer"
@@ -278,6 +329,18 @@ struct clk *devm_get_clk_from_child(struct device *dev,
278329
*/
279330
int clk_enable(struct clk *clk);
280331

332+
/**
333+
* clk_bulk_enable - inform the system when the set of clks should be running.
334+
* @num_clks: the number of clk_bulk_data
335+
* @clks: the clk_bulk_data table of consumer
336+
*
337+
* May be called from atomic contexts.
338+
*
339+
* Returns success (0) or negative errno.
340+
*/
341+
int __must_check clk_bulk_enable(int num_clks,
342+
const struct clk_bulk_data *clks);
343+
281344
/**
282345
* clk_disable - inform the system when the clock source is no longer required.
283346
* @clk: clock source
@@ -294,6 +357,24 @@ int clk_enable(struct clk *clk);
294357
*/
295358
void clk_disable(struct clk *clk);
296359

360+
/**
361+
* clk_bulk_disable - inform the system when the set of clks is no
362+
* longer required.
363+
* @num_clks: the number of clk_bulk_data
364+
* @clks: the clk_bulk_data table of consumer
365+
*
366+
* Inform the system that a set of clks is no longer required by
367+
* a driver and may be shut down.
368+
*
369+
* May be called from atomic contexts.
370+
*
371+
* Implementation detail: if the set of clks is shared between
372+
* multiple drivers, clk_bulk_enable() calls must be balanced by the
373+
* same number of clk_bulk_disable() calls for the clock source to be
374+
* disabled.
375+
*/
376+
void clk_bulk_disable(int num_clks, const struct clk_bulk_data *clks);
377+
297378
/**
298379
* clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
299380
* This is only valid once the clock source has been enabled.
@@ -313,6 +394,19 @@ unsigned long clk_get_rate(struct clk *clk);
313394
*/
314395
void clk_put(struct clk *clk);
315396

397+
/**
398+
* clk_bulk_put - "free" the clock source
399+
* @num_clks: the number of clk_bulk_data
400+
* @clks: the clk_bulk_data table of consumer
401+
*
402+
* Note: drivers must ensure that all clk_bulk_enable calls made on this
403+
* clock source are balanced by clk_bulk_disable calls prior to calling
404+
* this function.
405+
*
406+
* clk_bulk_put should not be called from within interrupt context.
407+
*/
408+
void clk_bulk_put(int num_clks, struct clk_bulk_data *clks);
409+
316410
/**
317411
* devm_clk_put - "free" a managed clock source
318412
* @dev: device used to acquire the clock
@@ -445,6 +539,12 @@ static inline struct clk *clk_get(struct device *dev, const char *id)
445539
return NULL;
446540
}
447541

542+
static inline int clk_bulk_get(struct device *dev, int num_clks,
543+
struct clk_bulk_data *clks)
544+
{
545+
return 0;
546+
}
547+
448548
static inline struct clk *devm_clk_get(struct device *dev, const char *id)
449549
{
450550
return NULL;
@@ -458,15 +558,26 @@ static inline struct clk *devm_get_clk_from_child(struct device *dev,
458558

459559
static inline void clk_put(struct clk *clk) {}
460560

561+
static inline void clk_bulk_put(int num_clks, struct clk_bulk_data *clks) {}
562+
461563
static inline void devm_clk_put(struct device *dev, struct clk *clk) {}
462564

463565
static inline int clk_enable(struct clk *clk)
464566
{
465567
return 0;
466568
}
467569

570+
static inline int clk_bulk_enable(int num_clks, struct clk_bulk_data *clks)
571+
{
572+
return 0;
573+
}
574+
468575
static inline void clk_disable(struct clk *clk) {}
469576

577+
578+
static inline void clk_bulk_disable(int num_clks,
579+
struct clk_bulk_data *clks) {}
580+
470581
static inline unsigned long clk_get_rate(struct clk *clk)
471582
{
472583
return 0;

0 commit comments

Comments
 (0)