diff options
author | Mike Turquette <mturquette@linaro.org> | 2013-12-04 15:14:59 -0500 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2013-12-04 15:14:59 -0500 |
commit | 9ffe29d780dd5f9c662f2c32f8dc64435da726bf (patch) | |
tree | f583f02351c36f50c43b7e4eb2dc7d2bc6ed2dab /drivers | |
parent | cdf64eeeb0d762585e2126f3024458d199c2635d (diff) | |
parent | fcb0ee6a3d331fb23dbb546500021f6e4cac5689 (diff) |
Merge branch 'clk/clk-unregister' of git://linuxtv.org/snawrocki/samsung into clk-next-unregister
Diffstat (limited to 'drivers')
-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 |
5 files changed, 217 insertions, 19 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 77fcd069c64a..da7b33e4c5a2 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 | ||
@@ -343,6 +345,21 @@ out: | |||
343 | return ret; | 345 | return ret; |
344 | } | 346 | } |
345 | 347 | ||
348 | /** | ||
349 | * clk_debug_unregister - remove a clk node from the debugfs clk tree | ||
350 | * @clk: the clk being removed from the debugfs clk tree | ||
351 | * | ||
352 | * Dynamically removes a clk and all it's children clk nodes from the | ||
353 | * debugfs clk tree if clk->dentry points to debugfs created by | ||
354 | * clk_debug_register in __clk_init. | ||
355 | * | ||
356 | * Caller must hold prepare_lock. | ||
357 | */ | ||
358 | static void clk_debug_unregister(struct clk *clk) | ||
359 | { | ||
360 | debugfs_remove_recursive(clk->dentry); | ||
361 | } | ||
362 | |||
346 | /** | 363 | /** |
347 | * clk_debug_reparent - reparent clk node in the debugfs clk tree | 364 | * clk_debug_reparent - reparent clk node in the debugfs clk tree |
348 | * @clk: the clk being reparented | 365 | * @clk: the clk being reparented |
@@ -433,6 +450,9 @@ static inline int clk_debug_register(struct clk *clk) { return 0; } | |||
433 | static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent) | 450 | static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent) |
434 | { | 451 | { |
435 | } | 452 | } |
453 | static inline void clk_debug_unregister(struct clk *clk) | ||
454 | { | ||
455 | } | ||
436 | #endif | 456 | #endif |
437 | 457 | ||
438 | /* caller must hold prepare_lock */ | 458 | /* caller must hold prepare_lock */ |
@@ -1776,6 +1796,7 @@ int __clk_init(struct device *dev, struct clk *clk) | |||
1776 | 1796 | ||
1777 | clk_debug_register(clk); | 1797 | clk_debug_register(clk); |
1778 | 1798 | ||
1799 | kref_init(&clk->ref); | ||
1779 | out: | 1800 | out: |
1780 | clk_prepare_unlock(); | 1801 | clk_prepare_unlock(); |
1781 | 1802 | ||
@@ -1811,6 +1832,10 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) | |||
1811 | clk->flags = hw->init->flags; | 1832 | clk->flags = hw->init->flags; |
1812 | clk->parent_names = hw->init->parent_names; | 1833 | clk->parent_names = hw->init->parent_names; |
1813 | clk->num_parents = hw->init->num_parents; | 1834 | clk->num_parents = hw->init->num_parents; |
1835 | if (dev && dev->driver) | ||
1836 | clk->owner = dev->driver->owner; | ||
1837 | else | ||
1838 | clk->owner = NULL; | ||
1814 | 1839 | ||
1815 | ret = __clk_init(dev, clk); | 1840 | ret = __clk_init(dev, clk); |
1816 | if (ret) | 1841 | if (ret) |
@@ -1831,6 +1856,8 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) | |||
1831 | goto fail_name; | 1856 | goto fail_name; |
1832 | } | 1857 | } |
1833 | clk->ops = hw->init->ops; | 1858 | clk->ops = hw->init->ops; |
1859 | if (dev && dev->driver) | ||
1860 | clk->owner = dev->driver->owner; | ||
1834 | clk->hw = hw; | 1861 | clk->hw = hw; |
1835 | clk->flags = hw->init->flags; | 1862 | clk->flags = hw->init->flags; |
1836 | clk->num_parents = hw->init->num_parents; | 1863 | clk->num_parents = hw->init->num_parents; |
@@ -1905,13 +1932,104 @@ fail_out: | |||
1905 | } | 1932 | } |
1906 | EXPORT_SYMBOL_GPL(clk_register); | 1933 | EXPORT_SYMBOL_GPL(clk_register); |
1907 | 1934 | ||
1935 | /* | ||
1936 | * Free memory allocated for a clock. | ||
1937 | * Caller must hold prepare_lock. | ||
1938 | */ | ||
1939 | static void __clk_release(struct kref *ref) | ||
1940 | { | ||
1941 | struct clk *clk = container_of(ref, struct clk, ref); | ||
1942 | int i = clk->num_parents; | ||
1943 | |||
1944 | kfree(clk->parents); | ||
1945 | while (--i >= 0) | ||
1946 | kfree(clk->parent_names[i]); | ||
1947 | |||
1948 | kfree(clk->parent_names); | ||
1949 | kfree(clk->name); | ||
1950 | kfree(clk); | ||
1951 | } | ||
1952 | |||
1953 | /* | ||
1954 | * Empty clk_ops for unregistered clocks. These are used temporarily | ||
1955 | * after clk_unregister() was called on a clock and until last clock | ||
1956 | * consumer calls clk_put() and the struct clk object is freed. | ||
1957 | */ | ||
1958 | static int clk_nodrv_prepare_enable(struct clk_hw *hw) | ||
1959 | { | ||
1960 | return -ENXIO; | ||
1961 | } | ||
1962 | |||
1963 | static void clk_nodrv_disable_unprepare(struct clk_hw *hw) | ||
1964 | { | ||
1965 | WARN_ON_ONCE(1); | ||
1966 | } | ||
1967 | |||
1968 | static int clk_nodrv_set_rate(struct clk_hw *hw, unsigned long rate, | ||
1969 | unsigned long parent_rate) | ||
1970 | { | ||
1971 | return -ENXIO; | ||
1972 | } | ||
1973 | |||
1974 | static int clk_nodrv_set_parent(struct clk_hw *hw, u8 index) | ||
1975 | { | ||
1976 | return -ENXIO; | ||
1977 | } | ||
1978 | |||
1979 | static const struct clk_ops clk_nodrv_ops = { | ||
1980 | .enable = clk_nodrv_prepare_enable, | ||
1981 | .disable = clk_nodrv_disable_unprepare, | ||
1982 | .prepare = clk_nodrv_prepare_enable, | ||
1983 | .unprepare = clk_nodrv_disable_unprepare, | ||
1984 | .set_rate = clk_nodrv_set_rate, | ||
1985 | .set_parent = clk_nodrv_set_parent, | ||
1986 | }; | ||
1987 | |||
1908 | /** | 1988 | /** |
1909 | * clk_unregister - unregister a currently registered clock | 1989 | * clk_unregister - unregister a currently registered clock |
1910 | * @clk: clock to unregister | 1990 | * @clk: clock to unregister |
1911 | * | ||
1912 | * Currently unimplemented. | ||
1913 | */ | 1991 | */ |
1914 | void clk_unregister(struct clk *clk) {} | 1992 | void clk_unregister(struct clk *clk) |
1993 | { | ||
1994 | unsigned long flags; | ||
1995 | |||
1996 | if (!clk || WARN_ON_ONCE(IS_ERR(clk))) | ||
1997 | return; | ||
1998 | |||
1999 | clk_prepare_lock(); | ||
2000 | |||
2001 | if (clk->ops == &clk_nodrv_ops) { | ||
2002 | pr_err("%s: unregistered clock: %s\n", __func__, clk->name); | ||
2003 | goto out; | ||
2004 | } | ||
2005 | /* | ||
2006 | * Assign empty clock ops for consumers that might still hold | ||
2007 | * a reference to this clock. | ||
2008 | */ | ||
2009 | flags = clk_enable_lock(); | ||
2010 | clk->ops = &clk_nodrv_ops; | ||
2011 | clk_enable_unlock(flags); | ||
2012 | |||
2013 | if (!hlist_empty(&clk->children)) { | ||
2014 | struct clk *child; | ||
2015 | |||
2016 | /* Reparent all children to the orphan list. */ | ||
2017 | hlist_for_each_entry(child, &clk->children, child_node) | ||
2018 | clk_set_parent(child, NULL); | ||
2019 | } | ||
2020 | |||
2021 | clk_debug_unregister(clk); | ||
2022 | |||
2023 | hlist_del_init(&clk->child_node); | ||
2024 | |||
2025 | if (clk->prepare_count) | ||
2026 | pr_warn("%s: unregistering prepared clock: %s\n", | ||
2027 | __func__, clk->name); | ||
2028 | |||
2029 | kref_put(&clk->ref, __clk_release); | ||
2030 | out: | ||
2031 | clk_prepare_unlock(); | ||
2032 | } | ||
1915 | EXPORT_SYMBOL_GPL(clk_unregister); | 2033 | EXPORT_SYMBOL_GPL(clk_unregister); |
1916 | 2034 | ||
1917 | static void devm_clk_release(struct device *dev, void *res) | 2035 | static void devm_clk_release(struct device *dev, void *res) |
@@ -1971,6 +2089,31 @@ void devm_clk_unregister(struct device *dev, struct clk *clk) | |||
1971 | } | 2089 | } |
1972 | EXPORT_SYMBOL_GPL(devm_clk_unregister); | 2090 | EXPORT_SYMBOL_GPL(devm_clk_unregister); |
1973 | 2091 | ||
2092 | /* | ||
2093 | * clkdev helpers | ||
2094 | */ | ||
2095 | int __clk_get(struct clk *clk) | ||
2096 | { | ||
2097 | if (clk && !try_module_get(clk->owner)) | ||
2098 | return 0; | ||
2099 | |||
2100 | kref_get(&clk->ref); | ||
2101 | return 1; | ||
2102 | } | ||
2103 | |||
2104 | void __clk_put(struct clk *clk) | ||
2105 | { | ||
2106 | if (WARN_ON_ONCE(IS_ERR(clk))) | ||
2107 | return; | ||
2108 | |||
2109 | clk_prepare_lock(); | ||
2110 | kref_put(&clk->ref, __clk_release); | ||
2111 | clk_prepare_unlock(); | ||
2112 | |||
2113 | if (clk) | ||
2114 | module_put(clk->owner); | ||
2115 | } | ||
2116 | |||
1974 | /*** clk rate change notifiers ***/ | 2117 | /*** clk rate change notifiers ***/ |
1975 | 2118 | ||
1976 | /** | 2119 | /** |
@@ -2111,7 +2254,18 @@ static const struct of_device_id __clk_of_table_sentinel | |||
2111 | __used __section(__clk_of_table_end); | 2254 | __used __section(__clk_of_table_end); |
2112 | 2255 | ||
2113 | static LIST_HEAD(of_clk_providers); | 2256 | static LIST_HEAD(of_clk_providers); |
2114 | static DEFINE_MUTEX(of_clk_lock); | 2257 | static DEFINE_MUTEX(of_clk_mutex); |
2258 | |||
2259 | /* of_clk_provider list locking helpers */ | ||
2260 | void of_clk_lock(void) | ||
2261 | { | ||
2262 | mutex_lock(&of_clk_mutex); | ||
2263 | } | ||
2264 | |||
2265 | void of_clk_unlock(void) | ||
2266 | { | ||
2267 | mutex_unlock(&of_clk_mutex); | ||
2268 | } | ||
2115 | 2269 | ||
2116 | struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, | 2270 | struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, |
2117 | void *data) | 2271 | void *data) |
@@ -2155,9 +2309,9 @@ int of_clk_add_provider(struct device_node *np, | |||
2155 | cp->data = data; | 2309 | cp->data = data; |
2156 | cp->get = clk_src_get; | 2310 | cp->get = clk_src_get; |
2157 | 2311 | ||
2158 | mutex_lock(&of_clk_lock); | 2312 | mutex_lock(&of_clk_mutex); |
2159 | list_add(&cp->link, &of_clk_providers); | 2313 | list_add(&cp->link, &of_clk_providers); |
2160 | mutex_unlock(&of_clk_lock); | 2314 | mutex_unlock(&of_clk_mutex); |
2161 | pr_debug("Added clock from %s\n", np->full_name); | 2315 | pr_debug("Added clock from %s\n", np->full_name); |
2162 | 2316 | ||
2163 | return 0; | 2317 | return 0; |
@@ -2172,7 +2326,7 @@ void of_clk_del_provider(struct device_node *np) | |||
2172 | { | 2326 | { |
2173 | struct of_clk_provider *cp; | 2327 | struct of_clk_provider *cp; |
2174 | 2328 | ||
2175 | mutex_lock(&of_clk_lock); | 2329 | mutex_lock(&of_clk_mutex); |
2176 | list_for_each_entry(cp, &of_clk_providers, link) { | 2330 | list_for_each_entry(cp, &of_clk_providers, link) { |
2177 | if (cp->node == np) { | 2331 | if (cp->node == np) { |
2178 | list_del(&cp->link); | 2332 | list_del(&cp->link); |
@@ -2181,24 +2335,33 @@ void of_clk_del_provider(struct device_node *np) | |||
2181 | break; | 2335 | break; |
2182 | } | 2336 | } |
2183 | } | 2337 | } |
2184 | mutex_unlock(&of_clk_lock); | 2338 | mutex_unlock(&of_clk_mutex); |
2185 | } | 2339 | } |
2186 | EXPORT_SYMBOL_GPL(of_clk_del_provider); | 2340 | EXPORT_SYMBOL_GPL(of_clk_del_provider); |
2187 | 2341 | ||
2188 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) | 2342 | struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec) |
2189 | { | 2343 | { |
2190 | struct of_clk_provider *provider; | 2344 | struct of_clk_provider *provider; |
2191 | struct clk *clk = ERR_PTR(-ENOENT); | 2345 | struct clk *clk = ERR_PTR(-ENOENT); |
2192 | 2346 | ||
2193 | /* Check if we have such a provider in our array */ | 2347 | /* Check if we have such a provider in our array */ |
2194 | mutex_lock(&of_clk_lock); | ||
2195 | list_for_each_entry(provider, &of_clk_providers, link) { | 2348 | list_for_each_entry(provider, &of_clk_providers, link) { |
2196 | if (provider->node == clkspec->np) | 2349 | if (provider->node == clkspec->np) |
2197 | clk = provider->get(clkspec, provider->data); | 2350 | clk = provider->get(clkspec, provider->data); |
2198 | if (!IS_ERR(clk)) | 2351 | if (!IS_ERR(clk)) |
2199 | break; | 2352 | break; |
2200 | } | 2353 | } |
2201 | mutex_unlock(&of_clk_lock); | 2354 | |
2355 | return clk; | ||
2356 | } | ||
2357 | |||
2358 | struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) | ||
2359 | { | ||
2360 | struct clk *clk; | ||
2361 | |||
2362 | mutex_lock(&of_clk_mutex); | ||
2363 | clk = __of_clk_get_from_provider(clkspec); | ||
2364 | mutex_unlock(&of_clk_mutex); | ||
2202 | 2365 | ||
2203 | return clk; | 2366 | return clk; |
2204 | } | 2367 | } |
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 */ |