diff options
-rw-r--r-- | Documentation/driver-model/devres.txt | 4 | ||||
-rw-r--r-- | drivers/clk/clkdev.c | 142 | ||||
-rw-r--r-- | include/linux/clk.h | 32 | ||||
-rw-r--r-- | include/linux/clkdev.h | 3 |
4 files changed, 171 insertions, 10 deletions
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 2a596a4fc23e..9faac6ae3525 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt | |||
@@ -276,3 +276,7 @@ REGULATOR | |||
276 | devm_regulator_get() | 276 | devm_regulator_get() |
277 | devm_regulator_put() | 277 | devm_regulator_put() |
278 | devm_regulator_bulk_get() | 278 | devm_regulator_bulk_get() |
279 | |||
280 | CLOCK | ||
281 | devm_clk_get() | ||
282 | devm_clk_put() | ||
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 6db161f64ae0..c535cf8c5770 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c | |||
@@ -35,7 +35,12 @@ static DEFINE_MUTEX(clocks_mutex); | |||
35 | static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) | 35 | static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) |
36 | { | 36 | { |
37 | struct clk_lookup *p, *cl = NULL; | 37 | struct clk_lookup *p, *cl = NULL; |
38 | int match, best = 0; | 38 | int match, best_found = 0, best_possible = 0; |
39 | |||
40 | if (dev_id) | ||
41 | best_possible += 2; | ||
42 | if (con_id) | ||
43 | best_possible += 1; | ||
39 | 44 | ||
40 | list_for_each_entry(p, &clocks, node) { | 45 | list_for_each_entry(p, &clocks, node) { |
41 | match = 0; | 46 | match = 0; |
@@ -50,10 +55,10 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) | |||
50 | match += 1; | 55 | match += 1; |
51 | } | 56 | } |
52 | 57 | ||
53 | if (match > best) { | 58 | if (match > best_found) { |
54 | cl = p; | 59 | cl = p; |
55 | if (match != 3) | 60 | if (match != best_possible) |
56 | best = match; | 61 | best_found = match; |
57 | else | 62 | else |
58 | break; | 63 | break; |
59 | } | 64 | } |
@@ -89,6 +94,51 @@ void clk_put(struct clk *clk) | |||
89 | } | 94 | } |
90 | EXPORT_SYMBOL(clk_put); | 95 | EXPORT_SYMBOL(clk_put); |
91 | 96 | ||
97 | static void devm_clk_release(struct device *dev, void *res) | ||
98 | { | ||
99 | clk_put(*(struct clk **)res); | ||
100 | } | ||
101 | |||
102 | struct clk *devm_clk_get(struct device *dev, const char *id) | ||
103 | { | ||
104 | struct clk **ptr, *clk; | ||
105 | |||
106 | ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); | ||
107 | if (!ptr) | ||
108 | return ERR_PTR(-ENOMEM); | ||
109 | |||
110 | clk = clk_get(dev, id); | ||
111 | if (!IS_ERR(clk)) { | ||
112 | *ptr = clk; | ||
113 | devres_add(dev, ptr); | ||
114 | } else { | ||
115 | devres_free(ptr); | ||
116 | } | ||
117 | |||
118 | return clk; | ||
119 | } | ||
120 | EXPORT_SYMBOL(devm_clk_get); | ||
121 | |||
122 | static int devm_clk_match(struct device *dev, void *res, void *data) | ||
123 | { | ||
124 | struct clk **c = res; | ||
125 | if (!c || !*c) { | ||
126 | WARN_ON(!c || !*c); | ||
127 | return 0; | ||
128 | } | ||
129 | return *c == data; | ||
130 | } | ||
131 | |||
132 | void devm_clk_put(struct device *dev, struct clk *clk) | ||
133 | { | ||
134 | int ret; | ||
135 | |||
136 | ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk); | ||
137 | |||
138 | WARN_ON(ret); | ||
139 | } | ||
140 | EXPORT_SYMBOL(devm_clk_put); | ||
141 | |||
92 | void clkdev_add(struct clk_lookup *cl) | 142 | void clkdev_add(struct clk_lookup *cl) |
93 | { | 143 | { |
94 | mutex_lock(&clocks_mutex); | 144 | mutex_lock(&clocks_mutex); |
@@ -116,8 +166,9 @@ struct clk_lookup_alloc { | |||
116 | char con_id[MAX_CON_ID]; | 166 | char con_id[MAX_CON_ID]; |
117 | }; | 167 | }; |
118 | 168 | ||
119 | struct clk_lookup * __init_refok | 169 | static struct clk_lookup * __init_refok |
120 | clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) | 170 | vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, |
171 | va_list ap) | ||
121 | { | 172 | { |
122 | struct clk_lookup_alloc *cla; | 173 | struct clk_lookup_alloc *cla; |
123 | 174 | ||
@@ -132,16 +183,25 @@ clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) | |||
132 | } | 183 | } |
133 | 184 | ||
134 | if (dev_fmt) { | 185 | if (dev_fmt) { |
135 | va_list ap; | ||
136 | |||
137 | va_start(ap, dev_fmt); | ||
138 | vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); | 186 | vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); |
139 | cla->cl.dev_id = cla->dev_id; | 187 | cla->cl.dev_id = cla->dev_id; |
140 | va_end(ap); | ||
141 | } | 188 | } |
142 | 189 | ||
143 | return &cla->cl; | 190 | return &cla->cl; |
144 | } | 191 | } |
192 | |||
193 | struct clk_lookup * __init_refok | ||
194 | clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) | ||
195 | { | ||
196 | struct clk_lookup *cl; | ||
197 | va_list ap; | ||
198 | |||
199 | va_start(ap, dev_fmt); | ||
200 | cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); | ||
201 | va_end(ap); | ||
202 | |||
203 | return cl; | ||
204 | } | ||
145 | EXPORT_SYMBOL(clkdev_alloc); | 205 | EXPORT_SYMBOL(clkdev_alloc); |
146 | 206 | ||
147 | int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, | 207 | int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, |
@@ -173,3 +233,65 @@ void clkdev_drop(struct clk_lookup *cl) | |||
173 | kfree(cl); | 233 | kfree(cl); |
174 | } | 234 | } |
175 | EXPORT_SYMBOL(clkdev_drop); | 235 | EXPORT_SYMBOL(clkdev_drop); |
236 | |||
237 | /** | ||
238 | * clk_register_clkdev - register one clock lookup for a struct clk | ||
239 | * @clk: struct clk to associate with all clk_lookups | ||
240 | * @con_id: connection ID string on device | ||
241 | * @dev_id: format string describing device name | ||
242 | * | ||
243 | * con_id or dev_id may be NULL as a wildcard, just as in the rest of | ||
244 | * clkdev. | ||
245 | * | ||
246 | * To make things easier for mass registration, we detect error clks | ||
247 | * from a previous clk_register() call, and return the error code for | ||
248 | * those. This is to permit this function to be called immediately | ||
249 | * after clk_register(). | ||
250 | */ | ||
251 | int clk_register_clkdev(struct clk *clk, const char *con_id, | ||
252 | const char *dev_fmt, ...) | ||
253 | { | ||
254 | struct clk_lookup *cl; | ||
255 | va_list ap; | ||
256 | |||
257 | if (IS_ERR(clk)) | ||
258 | return PTR_ERR(clk); | ||
259 | |||
260 | va_start(ap, dev_fmt); | ||
261 | cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); | ||
262 | va_end(ap); | ||
263 | |||
264 | if (!cl) | ||
265 | return -ENOMEM; | ||
266 | |||
267 | clkdev_add(cl); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | /** | ||
273 | * clk_register_clkdevs - register a set of clk_lookup for a struct clk | ||
274 | * @clk: struct clk to associate with all clk_lookups | ||
275 | * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized | ||
276 | * @num: number of clk_lookup structures to register | ||
277 | * | ||
278 | * To make things easier for mass registration, we detect error clks | ||
279 | * from a previous clk_register() call, and return the error code for | ||
280 | * those. This is to permit this function to be called immediately | ||
281 | * after clk_register(). | ||
282 | */ | ||
283 | int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num) | ||
284 | { | ||
285 | unsigned i; | ||
286 | |||
287 | if (IS_ERR(clk)) | ||
288 | return PTR_ERR(clk); | ||
289 | |||
290 | for (i = 0; i < num; i++, cl++) { | ||
291 | cl->clk = clk; | ||
292 | clkdev_add(cl); | ||
293 | } | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | EXPORT_SYMBOL(clk_register_clkdevs); | ||
diff --git a/include/linux/clk.h b/include/linux/clk.h index 0e078bdec09f..ad5c43e8ae8a 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h | |||
@@ -101,6 +101,26 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); | |||
101 | struct clk *clk_get(struct device *dev, const char *id); | 101 | struct clk *clk_get(struct device *dev, const char *id); |
102 | 102 | ||
103 | /** | 103 | /** |
104 | * devm_clk_get - lookup and obtain a managed reference to a clock producer. | ||
105 | * @dev: device for clock "consumer" | ||
106 | * @id: clock comsumer ID | ||
107 | * | ||
108 | * Returns a struct clk corresponding to the clock producer, or | ||
109 | * valid IS_ERR() condition containing errno. The implementation | ||
110 | * uses @dev and @id to determine the clock consumer, and thereby | ||
111 | * the clock producer. (IOW, @id may be identical strings, but | ||
112 | * clk_get may return different clock producers depending on @dev.) | ||
113 | * | ||
114 | * Drivers must assume that the clock source is not enabled. | ||
115 | * | ||
116 | * devm_clk_get should not be called from within interrupt context. | ||
117 | * | ||
118 | * The clock will automatically be freed when the device is unbound | ||
119 | * from the bus. | ||
120 | */ | ||
121 | struct clk *devm_clk_get(struct device *dev, const char *id); | ||
122 | |||
123 | /** | ||
104 | * clk_prepare - prepare a clock source | 124 | * clk_prepare - prepare a clock source |
105 | * @clk: clock source | 125 | * @clk: clock source |
106 | * | 126 | * |
@@ -206,6 +226,18 @@ unsigned long clk_get_rate(struct clk *clk); | |||
206 | */ | 226 | */ |
207 | void clk_put(struct clk *clk); | 227 | void clk_put(struct clk *clk); |
208 | 228 | ||
229 | /** | ||
230 | * devm_clk_put - "free" a managed clock source | ||
231 | * @dev: device used to acuqire the clock | ||
232 | * @clk: clock source acquired with devm_clk_get() | ||
233 | * | ||
234 | * Note: drivers must ensure that all clk_enable calls made on this | ||
235 | * clock source are balanced by clk_disable calls prior to calling | ||
236 | * this function. | ||
237 | * | ||
238 | * clk_put should not be called from within interrupt context. | ||
239 | */ | ||
240 | void devm_clk_put(struct device *dev, struct clk *clk); | ||
209 | 241 | ||
210 | /* | 242 | /* |
211 | * The remaining APIs are optional for machine class support. | 243 | * The remaining APIs are optional for machine class support. |
diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index d9a4fd028c9d..a6a6f603103b 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h | |||
@@ -40,4 +40,7 @@ void clkdev_drop(struct clk_lookup *cl); | |||
40 | void clkdev_add_table(struct clk_lookup *, size_t); | 40 | void clkdev_add_table(struct clk_lookup *, size_t); |
41 | int clk_add_alias(const char *, const char *, char *, struct device *); | 41 | int clk_add_alias(const char *, const char *, char *, struct device *); |
42 | 42 | ||
43 | int clk_register_clkdev(struct clk *, const char *, const char *, ...); | ||
44 | int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); | ||
45 | |||
43 | #endif | 46 | #endif |