diff options
Diffstat (limited to 'drivers/clk/clkdev.c')
-rw-r--r-- | drivers/clk/clkdev.c | 142 |
1 files changed, 132 insertions, 10 deletions
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); | ||