Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'clkdev' of git://git.linaro.org/people/rmk/linux-arm

Pull clkdev updates from Russell King:
"This supplements clkdev with a device-managed API, allowing drivers
cleanup paths to be simplified. We also optimize clk_find() so that
it exits as soon as it finds a perfect match, and we provide a way to
minimise the amount of code platforms need to register clkdev entries.

Some of the code in arm-soc depends on these changes."

* 'clkdev' of git://git.linaro.org/people/rmk/linux-arm:
CLKDEV: provide helpers for common clock framework
ARM: 7392/1: CLKDEV: Optimize clk_find()
ARM: 7376/1: clkdev: Implement managed clk_get()

+171 -10
+4
Documentation/driver-model/devres.txt
··· 276 276 devm_regulator_get() 277 277 devm_regulator_put() 278 278 devm_regulator_bulk_get() 279 + 280 + CLOCK 281 + devm_clk_get() 282 + devm_clk_put()
+132 -10
drivers/clk/clkdev.c
··· 35 35 static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) 36 36 { 37 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 45 list_for_each_entry(p, &clocks, node) { 41 46 match = 0; ··· 55 50 match += 1; 56 51 } 57 52 58 - if (match > best) { 53 + if (match > best_found) { 59 54 cl = p; 60 - if (match != 3) 61 - best = match; 55 + if (match != best_possible) 56 + best_found = match; 62 57 else 63 58 break; 64 59 } ··· 94 89 } 95 90 EXPORT_SYMBOL(clk_put); 96 91 92 + static void devm_clk_release(struct device *dev, void *res) 93 + { 94 + clk_put(*(struct clk **)res); 95 + } 96 + 97 + struct clk *devm_clk_get(struct device *dev, const char *id) 98 + { 99 + struct clk **ptr, *clk; 100 + 101 + ptr = devres_alloc(devm_clk_release, sizeof(*ptr), GFP_KERNEL); 102 + if (!ptr) 103 + return ERR_PTR(-ENOMEM); 104 + 105 + clk = clk_get(dev, id); 106 + if (!IS_ERR(clk)) { 107 + *ptr = clk; 108 + devres_add(dev, ptr); 109 + } else { 110 + devres_free(ptr); 111 + } 112 + 113 + return clk; 114 + } 115 + EXPORT_SYMBOL(devm_clk_get); 116 + 117 + static int devm_clk_match(struct device *dev, void *res, void *data) 118 + { 119 + struct clk **c = res; 120 + if (!c || !*c) { 121 + WARN_ON(!c || !*c); 122 + return 0; 123 + } 124 + return *c == data; 125 + } 126 + 127 + void devm_clk_put(struct device *dev, struct clk *clk) 128 + { 129 + int ret; 130 + 131 + ret = devres_destroy(dev, devm_clk_release, devm_clk_match, clk); 132 + 133 + WARN_ON(ret); 134 + } 135 + EXPORT_SYMBOL(devm_clk_put); 136 + 97 137 void clkdev_add(struct clk_lookup *cl) 98 138 { 99 139 mutex_lock(&clocks_mutex); ··· 166 116 char con_id[MAX_CON_ID]; 167 117 }; 168 118 169 - struct clk_lookup * __init_refok 170 - clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) 119 + static struct clk_lookup * __init_refok 120 + vclkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, 121 + va_list ap) 171 122 { 172 123 struct clk_lookup_alloc *cla; 173 124 ··· 183 132 } 184 133 185 134 if (dev_fmt) { 186 - va_list ap; 187 - 188 - va_start(ap, dev_fmt); 189 135 vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap); 190 136 cla->cl.dev_id = cla->dev_id; 191 - va_end(ap); 192 137 } 193 138 194 139 return &cla->cl; 140 + } 141 + 142 + struct clk_lookup * __init_refok 143 + clkdev_alloc(struct clk *clk, const char *con_id, const char *dev_fmt, ...) 144 + { 145 + struct clk_lookup *cl; 146 + va_list ap; 147 + 148 + va_start(ap, dev_fmt); 149 + cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); 150 + va_end(ap); 151 + 152 + return cl; 195 153 } 196 154 EXPORT_SYMBOL(clkdev_alloc); 197 155 ··· 233 173 kfree(cl); 234 174 } 235 175 EXPORT_SYMBOL(clkdev_drop); 176 + 177 + /** 178 + * clk_register_clkdev - register one clock lookup for a struct clk 179 + * @clk: struct clk to associate with all clk_lookups 180 + * @con_id: connection ID string on device 181 + * @dev_id: format string describing device name 182 + * 183 + * con_id or dev_id may be NULL as a wildcard, just as in the rest of 184 + * clkdev. 185 + * 186 + * To make things easier for mass registration, we detect error clks 187 + * from a previous clk_register() call, and return the error code for 188 + * those. This is to permit this function to be called immediately 189 + * after clk_register(). 190 + */ 191 + int clk_register_clkdev(struct clk *clk, const char *con_id, 192 + const char *dev_fmt, ...) 193 + { 194 + struct clk_lookup *cl; 195 + va_list ap; 196 + 197 + if (IS_ERR(clk)) 198 + return PTR_ERR(clk); 199 + 200 + va_start(ap, dev_fmt); 201 + cl = vclkdev_alloc(clk, con_id, dev_fmt, ap); 202 + va_end(ap); 203 + 204 + if (!cl) 205 + return -ENOMEM; 206 + 207 + clkdev_add(cl); 208 + 209 + return 0; 210 + } 211 + 212 + /** 213 + * clk_register_clkdevs - register a set of clk_lookup for a struct clk 214 + * @clk: struct clk to associate with all clk_lookups 215 + * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized 216 + * @num: number of clk_lookup structures to register 217 + * 218 + * To make things easier for mass registration, we detect error clks 219 + * from a previous clk_register() call, and return the error code for 220 + * those. This is to permit this function to be called immediately 221 + * after clk_register(). 222 + */ 223 + int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num) 224 + { 225 + unsigned i; 226 + 227 + if (IS_ERR(clk)) 228 + return PTR_ERR(clk); 229 + 230 + for (i = 0; i < num; i++, cl++) { 231 + cl->clk = clk; 232 + clkdev_add(cl); 233 + } 234 + 235 + return 0; 236 + } 237 + EXPORT_SYMBOL(clk_register_clkdevs);
+32
include/linux/clk.h
··· 101 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 124 * clk_prepare - prepare a clock source 105 125 * @clk: clock source 106 126 * ··· 226 206 */ 227 207 void clk_put(struct clk *clk); 228 208 209 + /** 210 + * devm_clk_put - "free" a managed clock source 211 + * @dev: device used to acuqire the clock 212 + * @clk: clock source acquired with devm_clk_get() 213 + * 214 + * Note: drivers must ensure that all clk_enable calls made on this 215 + * clock source are balanced by clk_disable calls prior to calling 216 + * this function. 217 + * 218 + * clk_put should not be called from within interrupt context. 219 + */ 220 + void devm_clk_put(struct device *dev, struct clk *clk); 229 221 230 222 /* 231 223 * The remaining APIs are optional for machine class support.
+3
include/linux/clkdev.h
··· 40 40 void clkdev_add_table(struct clk_lookup *, size_t); 41 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 46 #endif