diff options
author | Mark Brown <broonie@sirena.org.uk> | 2012-04-05 06:42:09 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-04-19 14:34:18 -0400 |
commit | a8a97db984bdc5e89d42e41891543d2daaf314cb (patch) | |
tree | f265e535723e3e2b7011f7e16d782d24e3589e02 | |
parent | e816b57a337ea3b755de72bec38c10c864f23015 (diff) |
ARM: 7376/1: clkdev: Implement managed clk_get()
Allow clk API users to simplify their cleanup paths by providing a
managed version of clk_get() and clk_put().
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-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 2a596a4fc23..9faac6ae352 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 6db161f64ae..a9a11378282 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 b0252726df6..70cf722ac3a 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. |