diff options
author | Mike Turquette <mturquette@linaro.org> | 2013-12-31 14:35:12 -0500 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2013-12-31 14:35:12 -0500 |
commit | dbdf6ff51e3ce13ade5834b0d7d451522fcdb478 (patch) | |
tree | b5594d70cf4d484101891adbfc01798c14827fa8 | |
parent | 391e3903e63781debc52a0de73f2e922dcc3f602 (diff) | |
parent | 9ffe29d780dd5f9c662f2c32f8dc64435da726bf (diff) |
Merge branch 'clk-next-unregister' into clk-next
Conflicts:
drivers/clk/clk.c
-rw-r--r-- | arch/arm/include/asm/clkdev.h | 2 | ||||
-rw-r--r-- | arch/blackfin/include/asm/clkdev.h | 2 | ||||
-rw-r--r-- | arch/mips/include/asm/clkdev.h | 2 | ||||
-rw-r--r-- | arch/sh/include/asm/clkdev.h | 2 | ||||
-rw-r--r-- | drivers/clk/clk.c | 185 | ||||
-rw-r--r-- | drivers/clk/clk.h | 16 | ||||
-rw-r--r-- | drivers/clk/clkdev.c | 12 | ||||
-rw-r--r-- | drivers/media/platform/omap3isp/isp.c | 22 | ||||
-rw-r--r-- | drivers/media/platform/omap3isp/isp.h | 1 | ||||
-rw-r--r-- | include/linux/clk-private.h | 5 | ||||
-rw-r--r-- | include/linux/clkdev.h | 5 |
11 files changed, 235 insertions, 19 deletions
diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h index 80751c15c300..4e8a4b27d7c7 100644 --- a/arch/arm/include/asm/clkdev.h +++ b/arch/arm/include/asm/clkdev.h | |||
@@ -14,12 +14,14 @@ | |||
14 | 14 | ||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | 16 | ||
17 | #ifndef CONFIG_COMMON_CLK | ||
17 | #ifdef CONFIG_HAVE_MACH_CLKDEV | 18 | #ifdef CONFIG_HAVE_MACH_CLKDEV |
18 | #include <mach/clkdev.h> | 19 | #include <mach/clkdev.h> |
19 | #else | 20 | #else |
20 | #define __clk_get(clk) ({ 1; }) | 21 | #define __clk_get(clk) ({ 1; }) |
21 | #define __clk_put(clk) do { } while (0) | 22 | #define __clk_put(clk) do { } while (0) |
22 | #endif | 23 | #endif |
24 | #endif | ||
23 | 25 | ||
24 | static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) | 26 | static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) |
25 | { | 27 | { |
diff --git a/arch/blackfin/include/asm/clkdev.h b/arch/blackfin/include/asm/clkdev.h index 9053beda8c50..7ac2436856a5 100644 --- a/arch/blackfin/include/asm/clkdev.h +++ b/arch/blackfin/include/asm/clkdev.h | |||
@@ -8,7 +8,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) | |||
8 | return kzalloc(size, GFP_KERNEL); | 8 | return kzalloc(size, GFP_KERNEL); |
9 | } | 9 | } |
10 | 10 | ||
11 | #ifndef CONFIG_COMMON_CLK | ||
11 | #define __clk_put(clk) | 12 | #define __clk_put(clk) |
12 | #define __clk_get(clk) ({ 1; }) | 13 | #define __clk_get(clk) ({ 1; }) |
14 | #endif | ||
13 | 15 | ||
14 | #endif | 16 | #endif |
diff --git a/arch/mips/include/asm/clkdev.h b/arch/mips/include/asm/clkdev.h index 262475414e5f..1b3ad7b09dc1 100644 --- a/arch/mips/include/asm/clkdev.h +++ b/arch/mips/include/asm/clkdev.h | |||
@@ -14,8 +14,10 @@ | |||
14 | 14 | ||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | 16 | ||
17 | #ifndef CONFIG_COMMON_CLK | ||
17 | #define __clk_get(clk) ({ 1; }) | 18 | #define __clk_get(clk) ({ 1; }) |
18 | #define __clk_put(clk) do { } while (0) | 19 | #define __clk_put(clk) do { } while (0) |
20 | #endif | ||
19 | 21 | ||
20 | static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) | 22 | static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) |
21 | { | 23 | { |
diff --git a/arch/sh/include/asm/clkdev.h b/arch/sh/include/asm/clkdev.h index 6ba91868201c..c41901465fb0 100644 --- a/arch/sh/include/asm/clkdev.h +++ b/arch/sh/include/asm/clkdev.h | |||
@@ -25,7 +25,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) | |||
25 | return kzalloc(size, GFP_KERNEL); | 25 | return kzalloc(size, GFP_KERNEL); |
26 | } | 26 | } |
27 | 27 | ||
28 | #ifndef CONFIG_COMMON_CLK | ||
28 | #define __clk_put(clk) | 29 | #define __clk_put(clk) |
29 | #define __clk_get(clk) ({ 1; }) | 30 | #define __clk_get(clk) ({ 1; }) |
31 | #endif | ||
30 | 32 | ||
31 | #endif /* __CLKDEV_H__ */ | 33 | #endif /* __CLKDEV_H__ */ |
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b7f6e99e61eb..e3e03270b95e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
23 | 23 | ||
24 | #include "clk.h" | ||
25 | |||
24 | static DEFINE_SPINLOCK(enable_lock); | 26 | static DEFINE_SPINLOCK(enable_lock); |
25 | static DEFINE_MUTEX(prepare_lock); | 27 | static DEFINE_MUTEX(prepare_lock); |
26 | 28 | ||
@@ -350,6 +352,21 @@ out: | |||
350 | return ret; | 352 | return ret; |
351 | } | 353 | } |
352 | 354 | ||
355 | /** | ||
356 | * clk_debug_unregister - remove a clk node from the debugfs clk tree | ||
357 | * @clk: the clk being removed from the debugfs clk tree | ||
358 | * | ||
359 | * Dynamically removes a clk and all it's children clk nodes from the | ||
360 | * debugfs clk tree if clk->dentry points to debugfs created by | ||
361 | * clk_debug_register in __clk_init. | ||
362 | * | ||
363 | * Caller must hold prepare_lock. | ||
364 | */ | ||
365 | static void clk_debug_unregister(struct clk *clk) | ||
366 | { | ||
367 | debugfs_remove_recursive(clk->dentry); | ||
368 | } | ||
369 | |||
353 | /** | 370 | /** |
354 | * clk_debug_reparent - reparent clk node in the debugfs clk tree | 371 | * clk_debug_reparent - reparent clk node in the debugfs clk tree |
355 | * @clk: the clk being reparented | 372 | * @clk: the clk being reparented |
@@ -440,6 +457,9 @@ static inline int clk_debug_register(struct clk *clk) { return 0; } | |||
440 | static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent) | 457 | static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent) |
441 | { | 458 | { |
442 | } | 459 | } |
460 | static inline void clk_debug_unregister(struct clk *clk) | ||
461 | { | ||
462 | } | ||
443 | #endif | 463 | #endif |
444 | 464 | ||
445 | /* caller must hold prepare_lock */ | 465 | /* caller must hold prepare_lock */ |
@@ -1861,6 +1881,7 @@ int __clk_init(struct device *dev, struct clk *clk) | |||
1861 | if (clk->ops->init) | 1881 | if (clk->ops->init) |
1862 | clk->ops->init(clk->hw); | 1882 | clk->ops->init(clk->hw); |
1863 | 1883 | ||
1884 | kref_init(&clk->ref); | ||
1864 | out: | 1885 | out: |
1865 | clk_prepare_unlock(); | 1886 | clk_prepare_unlock(); |
1866 | 1887 | ||
@@ -1896,6 +1917,10 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) | |||
1896 | clk->flags = hw->init->flags; | 1917 | clk->flags = hw->init->flags; |
1897 | clk->parent_names = hw->init->parent_names; | 1918 | clk->parent_names = hw->init->parent_names; |
1898 | clk->num_parents = hw->init->num_parents; | 1919 | clk->num_parents = hw->init->num_parents; |
1920 | if (dev && dev->driver) | ||
1921 | clk->owner = dev->driver->owner; | ||
1922 | else | ||
1923 | clk->owner = NULL; | ||
1899 | 1924 | ||
1900 | ret = __clk_init(dev, clk); | 1925 | ret = __clk_init(dev, clk); |
1901 | if (ret) | 1926 | if (ret) |
@@ -1916,6 +1941,8 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) | |||
1916 | goto fail_name; | 1941 | goto fail_name; |
1917 | } | 1942 | } |
1918 | clk->ops = hw->init->ops; | 1943 | clk->ops = hw->init->ops; |
1944 | if (dev && dev->driver) | ||
1945 | clk->owner = dev->driver->owner; | ||
1919 | clk->hw = hw; | 1946 | clk->hw = hw; |
1920 | clk->flags = hw->init->flags; | 1947 | clk->flags = hw->init->flags; |
1921 | clk->num_parents = hw->init->num_parents; | 1948 | clk->num_parents = hw->init->num_parents; |
@@ -1990,13 +2017,104 @@ fail_out: | |||
1990 | } | 2017 | } |
1991 | EXPORT_SYMBOL_GPL(clk_register); | 2018 | EXPORT_SYMBOL_GPL(clk_register); |
1992 | 2019 | ||
2020 | /* | ||
2021 | * Free memory allocated for a clock. | ||
2022 | * Caller must hold prepare_lock. | ||
2023 | */ | ||
2024 | static void __clk_release(struct kref *ref) | ||
2025 | { | ||
2026 | struct clk *clk = container_of(ref, struct clk, ref); | ||
2027 | int i = clk->num_parents; | ||
2028 | |||
2029 | kfree(clk->parents); | ||
2030 | while (--i >= 0) | ||
2031 | kfree(clk->parent_names[i]); | ||
2032 | |||
2033 | kfree(clk->parent_names); | ||
2034 | kfree(clk->name); | ||
2035 | kfree(clk); | ||
2036 | } | ||
2037 | |||
2038 | /* | ||
2039 | * Empty clk_ops for unregistered clocks. These are used temporarily | ||
2040 | * after clk_unregister() was called on a clock and until last clock | ||
2041 | * consumer calls clk_put() and the struct clk object is freed. | ||
2042 | */ | ||
2043 | static int clk_nodrv_prepare_enable(struct clk_hw *hw) | ||
2044 | { | ||
2045 | return -ENXIO; | ||
2046 | } | ||
2047 | |||
2048 | static void clk_nodrv_disable_unprepare(struct clk_hw *hw) | ||
2049 | { | ||
2050 | WARN_ON_ONCE(1); | ||
2051 | } | ||
2052 | |||
2053 | static int clk_nodrv_set_rate(struct clk_hw *hw, unsigned long rate, | ||
2054 | unsigned long parent_rate) | ||
2055 | { | ||
2056 | return -ENXIO; | ||
2057 | } | ||
2058 | |||
2059 | static int clk_nodrv_set_parent(struct clk_hw *hw, u8 index) | ||
2060 | { | ||
2061 | return -ENXIO; | ||
2062 | } | ||
2063 | |||
2064 | static const struct clk_ops clk_nodrv_ops = { | ||
2065 | .enable = clk_nodrv_prepare_enable, | ||
2066 | .disable = clk_nodrv_disable_unprepare, | ||
2067 | .prepare = clk_nodrv_prepare_enable, | ||
2068 | .unprepare = clk_nodrv_disable_unprepare, | ||
2069 | .set_rate = clk_nodrv_set_rate, | ||
2070 | .set_parent = clk_nodrv_set_parent, | ||
2071 | }; | ||
2072 | |||
1993 | /** | 2073 | /** |
1994 | * clk_unregister - unregister a currently registered clock | 2074 | * clk_unregister - unregister a currently registered clock |
1995 | * @clk: clock to unregister | 2075 | * @clk: clock to unregister |
1996 | * | ||
1997 | * Currently unimplemented. | ||
1998 | */ | 2076 | */ |
1999 | void clk_unregister(struct clk *clk) {} | 2077 | void clk_unregister(struct clk *clk) |
2078 | { | ||
2079 | unsigned long flags; | ||
2080 | |||
2081 | if (!clk || WARN_ON_ONCE(IS_ERR(clk))) | ||
2082 | return; | ||
2083 | |||
2084 | clk_prepare_lock(); | ||
2085 | |||
2086 | if (clk->ops == &clk_nodrv_ops) { | ||
2087 | pr_err("%s: unregistered clock: %s\n", __func__, clk->name); | ||
2088 | goto out; | ||
2089 | } | ||
2090 | /* | ||
2091 | * Assign empty clock ops for consumers that might still hold | ||
2092 | * a reference to this clock. | ||
2093 | */ | ||
2094 | flags = clk_enable_lock(); | ||
2095 | clk->ops = &clk_nodrv_ops; | ||
2096 | clk_enable_unlock(flags); | ||
2097 | |||
2098 | if (!hlist_empty(&clk->children)) { | ||
2099 | struct clk *child; | ||
2100 | |||
2101 | /* Reparent all children to the orphan list. */ | ||
2102 | hlist_for_each_entry(child, &clk->children, child_node) | ||
2103 | clk_set_parent(child, NULL); | ||
2104 | } | ||
2105 | |||
2106 | clk_debug_unregister(clk); | ||
2107 | |||
2108 | hlist_del_init(&clk->child_node); | ||
2109 | |||
2110 | if (clk->prepare_count) | ||
2111 | pr_warn("%s: unregistering prepared clock: %s\n", | ||
2112 | __func__, clk->name); | ||
2113 | |||
2114 | kref_put(&clk->ref, __clk_release); | ||
2115 | out: | ||
2116 | clk_prepare_unlock(); | ||
2117 | } | ||
2000 | EXPORT_SYMBOL_GPL(clk_unregister); | 2118 | EXPORT_SYMBOL_GPL(clk_unregister); |
2001 | 2119 | ||
2002 | static void devm_clk_release(struct device *dev, void *res) | 2120 | static void devm_clk_release(struct device *dev, void *res) |
@@ -2056,6 +2174,31 @@ void devm_clk_unregister(struct device *dev, struct clk *clk) | |||
2056 | } | 2174 | } |
2057 | EXPORT_SYMBOL_GPL(devm_clk_unregister); | 2175 | EXPORT_SYMBOL_GPL(devm_clk_unregister); |
2058 | 2176 | ||
2177 | /* | ||
2178 | * clkdev helpers | ||
2179 | */ | ||
2180 | int __clk_get(struct clk *clk) | ||
2181 | { | ||
2182 | if (clk && !try_module_get(clk->owner)) | ||
2183 | return 0; | ||
2184 | |||
2185 | kref_get(&clk->ref); | ||
2186 | return 1; | ||
2187 | } | ||
2188 | |||
2189 | void __clk_put(struct clk *clk) | ||
2190 | { | ||
2191 | if (WARN_ON_ONCE(IS_ERR(clk))) | ||
2192 | return; | ||
2193 | |||
2194 | clk_prepare_lock(); | ||
2195 | kref_put(&clk->ref, __clk_release); | ||
2196 | clk_prepare_unlock(); | ||
2197 | |||
2198 | if (clk) | ||
2199 | module_put(clk->owner); | ||
2200 | } | ||
2201 | |||
2059 | /*** clk rate change notifiers ***/ | 2202 | /*** clk rate change notifiers ***/ |
2060 | 2203 | ||
2061 | /** | 2204 | /** |
@@ -2196,7 +2339,18 @@ static const struct of_device_id __clk_of_table_sentinel | |||
2196 | __used __section(__clk_of_table_end); | 2339 | __used __section(__clk_of_table_end); |
2197 | 2340 | ||
2198 | static LIST_HEAD(of_clk_providers); | 2341 | static LIST_HEAD(of_clk_providers); |
2199 | static DEFINE_MUTEX(of_clk_lock); | 2342 | static DEFINE_MUTEX(of_clk_mutex); |
2343 | |||
2344 | /* of_clk_provider list locking helpers */ | ||
2345 | void of_clk_lock(void) | ||
2346 | { | ||
2347 | mutex_lock(&of_clk_mutex); | ||
2348 | } | ||
2349 | |||
2350 | void of_clk_unlock(void) | ||
2351 | { | ||
2352 | mutex_unlock(&of_clk_mutex); | ||
2353 | } | ||
2200 | 2354 | ||
2201 | struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, | 2355 | struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, |
2202 | void *data) | 2356 | void *data) |
@@ -2240,9 +2394,9 @@ int of_clk_add_provider(struct device_node *np, | |||
2240 | cp->data = data; | 2394 | cp->data = data; |
2241 | cp->get = clk_src_get; | 2395 | cp->get = clk_src_get; |
2242 | 2396 | ||
2243 | mutex_lock(&of_clk_lock); | 2397 | mutex_lock(&of_clk_mutex); |
2244 | list_add(&cp->link, &of_clk_providers); | 2398 | list_add(&cp->link, &of_clk_providers); |
2245 | mutex_unlock(&of_clk_lock); | 2399 | mutex_unlock(&of_clk_mutex); |
2246 | pr_debug("Added clock from %s\n", np->full_name); | 2400 | pr_debug("Added clock from %s\n", np->full_name); |
2247 | 2401 | ||
2248 | return 0; | 2402 | return 0; |
@@ -2257,7 +2411,7 @@ void of_clk_del_provider(struct device_node *np) | |||
2257 | { | 2411 | { |
2258 | struct of_clk_provider *cp; | 2412 | struct of_clk_provider *cp; |
2259 | 2413 | ||
2260 | mutex_lock(&of_clk_lock); | 2414 | mutex_lock(&of_clk_mutex); |
2261 | list_for_each_entry(cp, &of_clk_providers, link) { | 2415 | list_for_each_entry(cp, &of_clk_providers, link) { |
2262 | if (cp->node == np) { | 2416 | if (cp->node == np) { |
2263 | list_del(&cp->link); | 2417 | list_del(&cp->link); |
@@ -2266,24 +2420,33 @@ void of_clk_del_provider(struct device_node *np) | |||
2266 | break; | 2420 | break; |
2267 | } | 2421 | } |
2268 | } | 2422 | } |
2269 | mutex_unlock(&of_clk_lock); | 2423 | mutex_unlock(&of_clk_mutex); |
2270 | } | 2424 | } |
2271 | EXPORT_SYMBOL_GPL(of_clk_del_provider); | 2425 | EXPORT_SYMBOL_GPL(of_clk_del_provider); |
2272 | 2426 | ||
2273 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) | 2427 | struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec) |
2274 | { | 2428 | { |
2275 | struct of_clk_provider *provider; | 2429 | struct of_clk_provider *provider; |
2276 | struct clk *clk = ERR_PTR(-ENOENT); | 2430 | struct clk *clk = ERR_PTR(-ENOENT); |
2277 | 2431 | ||
2278 | /* Check if we have such a provider in our array */ | 2432 | /* Check if we have such a provider in our array */ |
2279 | mutex_lock(&of_clk_lock); | ||
2280 | list_for_each_entry(provider, &of_clk_providers, link) { | 2433 | list_for_each_entry(provider, &of_clk_providers, link) { |
2281 | if (provider->node == clkspec->np) | 2434 | if (provider->node == clkspec->np) |
2282 | clk = provider->get(clkspec, provider->data); | 2435 | clk = provider->get(clkspec, provider->data); |
2283 | if (!IS_ERR(clk)) | 2436 | if (!IS_ERR(clk)) |
2284 | break; | 2437 | break; |
2285 | } | 2438 | } |
2286 | mutex_unlock(&of_clk_lock); | 2439 | |
2440 | return clk; | ||
2441 | } | ||
2442 | |||
2443 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) | ||
2444 | { | ||
2445 | struct clk *clk; | ||
2446 | |||
2447 | mutex_lock(&of_clk_mutex); | ||
2448 | clk = __of_clk_get_from_provider(clkspec); | ||
2449 | mutex_unlock(&of_clk_mutex); | ||
2287 | 2450 | ||
2288 | return clk; | 2451 | return clk; |
2289 | } | 2452 | } |
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h new file mode 100644 index 000000000000..795cc9f0dac0 --- /dev/null +++ b/drivers/clk/clk.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * linux/drivers/clk/clk.h | ||
3 | * | ||
4 | * Copyright (C) 2013 Samsung Electronics Co., Ltd. | ||
5 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) | ||
13 | struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec); | ||
14 | void of_clk_lock(void); | ||
15 | void of_clk_unlock(void); | ||
16 | #endif | ||
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 442a31363873..48f67218247c 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/clkdev.h> | 21 | #include <linux/clkdev.h> |
22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | 23 | ||
24 | #include "clk.h" | ||
25 | |||
24 | static LIST_HEAD(clocks); | 26 | static LIST_HEAD(clocks); |
25 | static DEFINE_MUTEX(clocks_mutex); | 27 | static DEFINE_MUTEX(clocks_mutex); |
26 | 28 | ||
@@ -39,7 +41,13 @@ struct clk *of_clk_get(struct device_node *np, int index) | |||
39 | if (rc) | 41 | if (rc) |
40 | return ERR_PTR(rc); | 42 | return ERR_PTR(rc); |
41 | 43 | ||
42 | clk = of_clk_get_from_provider(&clkspec); | 44 | of_clk_lock(); |
45 | clk = __of_clk_get_from_provider(&clkspec); | ||
46 | |||
47 | if (!IS_ERR(clk) && !__clk_get(clk)) | ||
48 | clk = ERR_PTR(-ENOENT); | ||
49 | |||
50 | of_clk_unlock(); | ||
43 | of_node_put(clkspec.np); | 51 | of_node_put(clkspec.np); |
44 | return clk; | 52 | return clk; |
45 | } | 53 | } |
@@ -157,7 +165,7 @@ struct clk *clk_get(struct device *dev, const char *con_id) | |||
157 | 165 | ||
158 | if (dev) { | 166 | if (dev) { |
159 | clk = of_clk_get_by_name(dev->of_node, con_id); | 167 | clk = of_clk_get_by_name(dev->of_node, con_id); |
160 | if (!IS_ERR(clk) && __clk_get(clk)) | 168 | if (!IS_ERR(clk)) |
161 | return clk; | 169 | return clk; |
162 | } | 170 | } |
163 | 171 | ||
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 1c3608039663..59106623e71e 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c | |||
@@ -290,9 +290,11 @@ static int isp_xclk_init(struct isp_device *isp) | |||
290 | struct clk_init_data init; | 290 | struct clk_init_data init; |
291 | unsigned int i; | 291 | unsigned int i; |
292 | 292 | ||
293 | for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) | ||
294 | isp->xclks[i].clk = ERR_PTR(-EINVAL); | ||
295 | |||
293 | for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) { | 296 | for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) { |
294 | struct isp_xclk *xclk = &isp->xclks[i]; | 297 | struct isp_xclk *xclk = &isp->xclks[i]; |
295 | struct clk *clk; | ||
296 | 298 | ||
297 | xclk->isp = isp; | 299 | xclk->isp = isp; |
298 | xclk->id = i == 0 ? ISP_XCLK_A : ISP_XCLK_B; | 300 | xclk->id = i == 0 ? ISP_XCLK_A : ISP_XCLK_B; |
@@ -305,10 +307,15 @@ static int isp_xclk_init(struct isp_device *isp) | |||
305 | init.num_parents = 1; | 307 | init.num_parents = 1; |
306 | 308 | ||
307 | xclk->hw.init = &init; | 309 | xclk->hw.init = &init; |
308 | 310 | /* | |
309 | clk = devm_clk_register(isp->dev, &xclk->hw); | 311 | * The first argument is NULL in order to avoid circular |
310 | if (IS_ERR(clk)) | 312 | * reference, as this driver takes reference on the |
311 | return PTR_ERR(clk); | 313 | * sensor subdevice modules and the sensors would take |
314 | * reference on this module through clk_get(). | ||
315 | */ | ||
316 | xclk->clk = clk_register(NULL, &xclk->hw); | ||
317 | if (IS_ERR(xclk->clk)) | ||
318 | return PTR_ERR(xclk->clk); | ||
312 | 319 | ||
313 | if (pdata->xclks[i].con_id == NULL && | 320 | if (pdata->xclks[i].con_id == NULL && |
314 | pdata->xclks[i].dev_id == NULL) | 321 | pdata->xclks[i].dev_id == NULL) |
@@ -320,7 +327,7 @@ static int isp_xclk_init(struct isp_device *isp) | |||
320 | 327 | ||
321 | xclk->lookup->con_id = pdata->xclks[i].con_id; | 328 | xclk->lookup->con_id = pdata->xclks[i].con_id; |
322 | xclk->lookup->dev_id = pdata->xclks[i].dev_id; | 329 | xclk->lookup->dev_id = pdata->xclks[i].dev_id; |
323 | xclk->lookup->clk = clk; | 330 | xclk->lookup->clk = xclk->clk; |
324 | 331 | ||
325 | clkdev_add(xclk->lookup); | 332 | clkdev_add(xclk->lookup); |
326 | } | 333 | } |
@@ -335,6 +342,9 @@ static void isp_xclk_cleanup(struct isp_device *isp) | |||
335 | for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) { | 342 | for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) { |
336 | struct isp_xclk *xclk = &isp->xclks[i]; | 343 | struct isp_xclk *xclk = &isp->xclks[i]; |
337 | 344 | ||
345 | if (!IS_ERR(xclk->clk)) | ||
346 | clk_unregister(xclk->clk); | ||
347 | |||
338 | if (xclk->lookup) | 348 | if (xclk->lookup) |
339 | clkdev_drop(xclk->lookup); | 349 | clkdev_drop(xclk->lookup); |
340 | } | 350 | } |
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index ce65d3ae1aa7..d1e857e41731 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h | |||
@@ -135,6 +135,7 @@ struct isp_xclk { | |||
135 | struct isp_device *isp; | 135 | struct isp_device *isp; |
136 | struct clk_hw hw; | 136 | struct clk_hw hw; |
137 | struct clk_lookup *lookup; | 137 | struct clk_lookup *lookup; |
138 | struct clk *clk; | ||
138 | enum isp_xclk_id id; | 139 | enum isp_xclk_id id; |
139 | 140 | ||
140 | spinlock_t lock; /* Protects enabled and divider */ | 141 | spinlock_t lock; /* Protects enabled and divider */ |
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 5fb086b06c83..efbf70b9fd84 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #define __LINUX_CLK_PRIVATE_H | 12 | #define __LINUX_CLK_PRIVATE_H |
13 | 13 | ||
14 | #include <linux/clk-provider.h> | 14 | #include <linux/clk-provider.h> |
15 | #include <linux/kref.h> | ||
15 | #include <linux/list.h> | 16 | #include <linux/list.h> |
16 | 17 | ||
17 | /* | 18 | /* |
@@ -25,10 +26,13 @@ | |||
25 | 26 | ||
26 | #ifdef CONFIG_COMMON_CLK | 27 | #ifdef CONFIG_COMMON_CLK |
27 | 28 | ||
29 | struct module; | ||
30 | |||
28 | struct clk { | 31 | struct clk { |
29 | const char *name; | 32 | const char *name; |
30 | const struct clk_ops *ops; | 33 | const struct clk_ops *ops; |
31 | struct clk_hw *hw; | 34 | struct clk_hw *hw; |
35 | struct module *owner; | ||
32 | struct clk *parent; | 36 | struct clk *parent; |
33 | const char **parent_names; | 37 | const char **parent_names; |
34 | struct clk **parents; | 38 | struct clk **parents; |
@@ -48,6 +52,7 @@ struct clk { | |||
48 | #ifdef CONFIG_DEBUG_FS | 52 | #ifdef CONFIG_DEBUG_FS |
49 | struct dentry *dentry; | 53 | struct dentry *dentry; |
50 | #endif | 54 | #endif |
55 | struct kref ref; | ||
51 | }; | 56 | }; |
52 | 57 | ||
53 | /* | 58 | /* |
diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index a6a6f603103b..94bad77eeb4a 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h | |||
@@ -43,4 +43,9 @@ int clk_add_alias(const char *, const char *, char *, struct device *); | |||
43 | int clk_register_clkdev(struct clk *, const char *, const char *, ...); | 43 | int clk_register_clkdev(struct clk *, const char *, const char *, ...); |
44 | int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); | 44 | int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); |
45 | 45 | ||
46 | #ifdef CONFIG_COMMON_CLK | ||
47 | int __clk_get(struct clk *clk); | ||
48 | void __clk_put(struct clk *clk); | ||
49 | #endif | ||
50 | |||
46 | #endif | 51 | #endif |