diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-11-28 19:18:27 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-11-28 19:18:27 -0500 |
commit | ef9cc993cd2e3524d86e86e9ad510e8f34b9c078 (patch) | |
tree | 4596a532436b30268c493377a4cd0bde658ce159 /drivers/base | |
parent | af261127e94c286c08bba162711307863fd4e68c (diff) | |
parent | 471f7707b6f0b18b6aa81119ed01525d9e712427 (diff) |
Merge branch 'pm-clk' into pm-runtime
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/clock_ops.c | 85 |
1 files changed, 53 insertions, 32 deletions
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 78369305e069..b32b5d47b3c5 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/pm.h> | 12 | #include <linux/pm.h> |
13 | #include <linux/pm_clock.h> | 13 | #include <linux/pm_clock.h> |
14 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
15 | #include <linux/clkdev.h> | ||
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/err.h> | 17 | #include <linux/err.h> |
17 | 18 | ||
@@ -34,14 +35,20 @@ struct pm_clock_entry { | |||
34 | /** | 35 | /** |
35 | * pm_clk_enable - Enable a clock, reporting any errors | 36 | * pm_clk_enable - Enable a clock, reporting any errors |
36 | * @dev: The device for the given clock | 37 | * @dev: The device for the given clock |
37 | * @clk: The clock being enabled. | 38 | * @ce: PM clock entry corresponding to the clock. |
38 | */ | 39 | */ |
39 | static inline int __pm_clk_enable(struct device *dev, struct clk *clk) | 40 | static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) |
40 | { | 41 | { |
41 | int ret = clk_enable(clk); | 42 | int ret; |
42 | if (ret) | 43 | |
43 | dev_err(dev, "%s: failed to enable clk %p, error %d\n", | 44 | if (ce->status < PCE_STATUS_ERROR) { |
44 | __func__, clk, ret); | 45 | ret = clk_enable(ce->clk); |
46 | if (!ret) | ||
47 | ce->status = PCE_STATUS_ENABLED; | ||
48 | else | ||
49 | dev_err(dev, "%s: failed to enable clk %p, error %d\n", | ||
50 | __func__, ce->clk, ret); | ||
51 | } | ||
45 | 52 | ||
46 | return ret; | 53 | return ret; |
47 | } | 54 | } |
@@ -53,7 +60,8 @@ static inline int __pm_clk_enable(struct device *dev, struct clk *clk) | |||
53 | */ | 60 | */ |
54 | static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) | 61 | static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) |
55 | { | 62 | { |
56 | ce->clk = clk_get(dev, ce->con_id); | 63 | if (!ce->clk) |
64 | ce->clk = clk_get(dev, ce->con_id); | ||
57 | if (IS_ERR(ce->clk)) { | 65 | if (IS_ERR(ce->clk)) { |
58 | ce->status = PCE_STATUS_ERROR; | 66 | ce->status = PCE_STATUS_ERROR; |
59 | } else { | 67 | } else { |
@@ -63,15 +71,8 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) | |||
63 | } | 71 | } |
64 | } | 72 | } |
65 | 73 | ||
66 | /** | 74 | static int __pm_clk_add(struct device *dev, const char *con_id, |
67 | * pm_clk_add - Start using a device clock for power management. | 75 | struct clk *clk) |
68 | * @dev: Device whose clock is going to be used for power management. | ||
69 | * @con_id: Connection ID of the clock. | ||
70 | * | ||
71 | * Add the clock represented by @con_id to the list of clocks used for | ||
72 | * the power management of @dev. | ||
73 | */ | ||
74 | int pm_clk_add(struct device *dev, const char *con_id) | ||
75 | { | 76 | { |
76 | struct pm_subsys_data *psd = dev_to_psd(dev); | 77 | struct pm_subsys_data *psd = dev_to_psd(dev); |
77 | struct pm_clock_entry *ce; | 78 | struct pm_clock_entry *ce; |
@@ -93,6 +94,12 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
93 | kfree(ce); | 94 | kfree(ce); |
94 | return -ENOMEM; | 95 | return -ENOMEM; |
95 | } | 96 | } |
97 | } else { | ||
98 | if (IS_ERR(ce->clk) || !__clk_get(clk)) { | ||
99 | kfree(ce); | ||
100 | return -ENOENT; | ||
101 | } | ||
102 | ce->clk = clk; | ||
96 | } | 103 | } |
97 | 104 | ||
98 | pm_clk_acquire(dev, ce); | 105 | pm_clk_acquire(dev, ce); |
@@ -104,6 +111,32 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
104 | } | 111 | } |
105 | 112 | ||
106 | /** | 113 | /** |
114 | * pm_clk_add - Start using a device clock for power management. | ||
115 | * @dev: Device whose clock is going to be used for power management. | ||
116 | * @con_id: Connection ID of the clock. | ||
117 | * | ||
118 | * Add the clock represented by @con_id to the list of clocks used for | ||
119 | * the power management of @dev. | ||
120 | */ | ||
121 | int pm_clk_add(struct device *dev, const char *con_id) | ||
122 | { | ||
123 | return __pm_clk_add(dev, con_id, NULL); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * pm_clk_add_clk - Start using a device clock for power management. | ||
128 | * @dev: Device whose clock is going to be used for power management. | ||
129 | * @clk: Clock pointer | ||
130 | * | ||
131 | * Add the clock to the list of clocks used for the power management of @dev. | ||
132 | * It will increment refcount on clock pointer, use clk_put() on it when done. | ||
133 | */ | ||
134 | int pm_clk_add_clk(struct device *dev, struct clk *clk) | ||
135 | { | ||
136 | return __pm_clk_add(dev, NULL, clk); | ||
137 | } | ||
138 | |||
139 | /** | ||
107 | * __pm_clk_remove - Destroy PM clock entry. | 140 | * __pm_clk_remove - Destroy PM clock entry. |
108 | * @ce: PM clock entry to destroy. | 141 | * @ce: PM clock entry to destroy. |
109 | */ | 142 | */ |
@@ -266,7 +299,6 @@ int pm_clk_resume(struct device *dev) | |||
266 | struct pm_subsys_data *psd = dev_to_psd(dev); | 299 | struct pm_subsys_data *psd = dev_to_psd(dev); |
267 | struct pm_clock_entry *ce; | 300 | struct pm_clock_entry *ce; |
268 | unsigned long flags; | 301 | unsigned long flags; |
269 | int ret; | ||
270 | 302 | ||
271 | dev_dbg(dev, "%s()\n", __func__); | 303 | dev_dbg(dev, "%s()\n", __func__); |
272 | 304 | ||
@@ -275,13 +307,8 @@ int pm_clk_resume(struct device *dev) | |||
275 | 307 | ||
276 | spin_lock_irqsave(&psd->lock, flags); | 308 | spin_lock_irqsave(&psd->lock, flags); |
277 | 309 | ||
278 | list_for_each_entry(ce, &psd->clock_list, node) { | 310 | list_for_each_entry(ce, &psd->clock_list, node) |
279 | if (ce->status < PCE_STATUS_ERROR) { | 311 | __pm_clk_enable(dev, ce); |
280 | ret = __pm_clk_enable(dev, ce->clk); | ||
281 | if (!ret) | ||
282 | ce->status = PCE_STATUS_ENABLED; | ||
283 | } | ||
284 | } | ||
285 | 312 | ||
286 | spin_unlock_irqrestore(&psd->lock, flags); | 313 | spin_unlock_irqrestore(&psd->lock, flags); |
287 | 314 | ||
@@ -390,7 +417,6 @@ int pm_clk_resume(struct device *dev) | |||
390 | struct pm_subsys_data *psd = dev_to_psd(dev); | 417 | struct pm_subsys_data *psd = dev_to_psd(dev); |
391 | struct pm_clock_entry *ce; | 418 | struct pm_clock_entry *ce; |
392 | unsigned long flags; | 419 | unsigned long flags; |
393 | int ret; | ||
394 | 420 | ||
395 | dev_dbg(dev, "%s()\n", __func__); | 421 | dev_dbg(dev, "%s()\n", __func__); |
396 | 422 | ||
@@ -400,13 +426,8 @@ int pm_clk_resume(struct device *dev) | |||
400 | 426 | ||
401 | spin_lock_irqsave(&psd->lock, flags); | 427 | spin_lock_irqsave(&psd->lock, flags); |
402 | 428 | ||
403 | list_for_each_entry(ce, &psd->clock_list, node) { | 429 | list_for_each_entry(ce, &psd->clock_list, node) |
404 | if (ce->status < PCE_STATUS_ERROR) { | 430 | __pm_clk_enable(dev, ce); |
405 | ret = __pm_clk_enable(dev, ce->clk); | ||
406 | if (!ret) | ||
407 | ce->status = PCE_STATUS_ENABLED; | ||
408 | } | ||
409 | } | ||
410 | 431 | ||
411 | spin_unlock_irqrestore(&psd->lock, flags); | 432 | spin_unlock_irqrestore(&psd->lock, flags); |
412 | 433 | ||