diff options
| -rw-r--r-- | Documentation/driver-model/devres.txt | 4 | ||||
| -rw-r--r-- | drivers/clk/clkdev.c | 45 | ||||
| -rw-r--r-- | include/linux/clk.h | 32 |
3 files changed, 81 insertions, 0 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..a9a113782821 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c | |||
| @@ -89,6 +89,51 @@ void clk_put(struct clk *clk) | |||
| 89 | } | 89 | } |
| 90 | EXPORT_SYMBOL(clk_put); | 90 | EXPORT_SYMBOL(clk_put); |
| 91 | 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 | |||
| 92 | void clkdev_add(struct clk_lookup *cl) | 137 | void clkdev_add(struct clk_lookup *cl) |
| 93 | { | 138 | { |
| 94 | mutex_lock(&clocks_mutex); | 139 | mutex_lock(&clocks_mutex); |
diff --git a/include/linux/clk.h b/include/linux/clk.h index b0252726df61..70cf722ac3af 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. |
