aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/clock_ops.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/power/clock_ops.c')
-rw-r--r--drivers/base/power/clock_ops.c76
1 files changed, 39 insertions, 37 deletions
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index cb44b58d6813..b876e60a53ef 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -32,6 +32,22 @@ struct pm_clock_entry {
32}; 32};
33 33
34/** 34/**
35 * pm_clk_acquire - Acquire a device clock.
36 * @dev: Device whose clock is to be acquired.
37 * @ce: PM clock entry corresponding to the clock.
38 */
39static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
40{
41 ce->clk = clk_get(dev, ce->con_id);
42 if (IS_ERR(ce->clk)) {
43 ce->status = PCE_STATUS_ERROR;
44 } else {
45 ce->status = PCE_STATUS_ACQUIRED;
46 dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
47 }
48}
49
50/**
35 * pm_clk_add - Start using a device clock for power management. 51 * pm_clk_add - Start using a device clock for power management.
36 * @dev: Device whose clock is going to be used for power management. 52 * @dev: Device whose clock is going to be used for power management.
37 * @con_id: Connection ID of the clock. 53 * @con_id: Connection ID of the clock.
@@ -63,6 +79,8 @@ int pm_clk_add(struct device *dev, const char *con_id)
63 } 79 }
64 } 80 }
65 81
82 pm_clk_acquire(dev, ce);
83
66 spin_lock_irq(&psd->lock); 84 spin_lock_irq(&psd->lock);
67 list_add_tail(&ce->node, &psd->clock_list); 85 list_add_tail(&ce->node, &psd->clock_list);
68 spin_unlock_irq(&psd->lock); 86 spin_unlock_irq(&psd->lock);
@@ -72,17 +90,12 @@ int pm_clk_add(struct device *dev, const char *con_id)
72/** 90/**
73 * __pm_clk_remove - Destroy PM clock entry. 91 * __pm_clk_remove - Destroy PM clock entry.
74 * @ce: PM clock entry to destroy. 92 * @ce: PM clock entry to destroy.
75 *
76 * This routine must be called under the spinlock protecting the PM list of
77 * clocks corresponding the the @ce's device.
78 */ 93 */
79static void __pm_clk_remove(struct pm_clock_entry *ce) 94static void __pm_clk_remove(struct pm_clock_entry *ce)
80{ 95{
81 if (!ce) 96 if (!ce)
82 return; 97 return;
83 98
84 list_del(&ce->node);
85
86 if (ce->status < PCE_STATUS_ERROR) { 99 if (ce->status < PCE_STATUS_ERROR) {
87 if (ce->status == PCE_STATUS_ENABLED) 100 if (ce->status == PCE_STATUS_ENABLED)
88 clk_disable(ce->clk); 101 clk_disable(ce->clk);
@@ -116,18 +129,22 @@ void pm_clk_remove(struct device *dev, const char *con_id)
116 spin_lock_irq(&psd->lock); 129 spin_lock_irq(&psd->lock);
117 130
118 list_for_each_entry(ce, &psd->clock_list, node) { 131 list_for_each_entry(ce, &psd->clock_list, node) {
119 if (!con_id && !ce->con_id) { 132 if (!con_id && !ce->con_id)
120 __pm_clk_remove(ce); 133 goto remove;
121 break; 134 else if (!con_id || !ce->con_id)
122 } else if (!con_id || !ce->con_id) {
123 continue; 135 continue;
124 } else if (!strcmp(con_id, ce->con_id)) { 136 else if (!strcmp(con_id, ce->con_id))
125 __pm_clk_remove(ce); 137 goto remove;
126 break;
127 }
128 } 138 }
129 139
130 spin_unlock_irq(&psd->lock); 140 spin_unlock_irq(&psd->lock);
141 return;
142
143 remove:
144 list_del(&ce->node);
145 spin_unlock_irq(&psd->lock);
146
147 __pm_clk_remove(ce);
131} 148}
132 149
133/** 150/**
@@ -169,18 +186,26 @@ void pm_clk_destroy(struct device *dev)
169{ 186{
170 struct pm_subsys_data *psd = dev_to_psd(dev); 187 struct pm_subsys_data *psd = dev_to_psd(dev);
171 struct pm_clock_entry *ce, *c; 188 struct pm_clock_entry *ce, *c;
189 struct list_head list;
172 190
173 if (!psd) 191 if (!psd)
174 return; 192 return;
175 193
194 INIT_LIST_HEAD(&list);
195
176 spin_lock_irq(&psd->lock); 196 spin_lock_irq(&psd->lock);
177 197
178 list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node) 198 list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
179 __pm_clk_remove(ce); 199 list_move(&ce->node, &list);
180 200
181 spin_unlock_irq(&psd->lock); 201 spin_unlock_irq(&psd->lock);
182 202
183 dev_pm_put_subsys_data(dev); 203 dev_pm_put_subsys_data(dev);
204
205 list_for_each_entry_safe_reverse(ce, c, &list, node) {
206 list_del(&ce->node);
207 __pm_clk_remove(ce);
208 }
184} 209}
185 210
186#endif /* CONFIG_PM */ 211#endif /* CONFIG_PM */
@@ -188,23 +213,6 @@ void pm_clk_destroy(struct device *dev)
188#ifdef CONFIG_PM_RUNTIME 213#ifdef CONFIG_PM_RUNTIME
189 214
190/** 215/**
191 * pm_clk_acquire - Acquire a device clock.
192 * @dev: Device whose clock is to be acquired.
193 * @con_id: Connection ID of the clock.
194 */
195static void pm_clk_acquire(struct device *dev,
196 struct pm_clock_entry *ce)
197{
198 ce->clk = clk_get(dev, ce->con_id);
199 if (IS_ERR(ce->clk)) {
200 ce->status = PCE_STATUS_ERROR;
201 } else {
202 ce->status = PCE_STATUS_ACQUIRED;
203 dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
204 }
205}
206
207/**
208 * pm_clk_suspend - Disable clocks in a device's PM clock list. 216 * pm_clk_suspend - Disable clocks in a device's PM clock list.
209 * @dev: Device to disable the clocks for. 217 * @dev: Device to disable the clocks for.
210 */ 218 */
@@ -222,9 +230,6 @@ int pm_clk_suspend(struct device *dev)
222 spin_lock_irqsave(&psd->lock, flags); 230 spin_lock_irqsave(&psd->lock, flags);
223 231
224 list_for_each_entry_reverse(ce, &psd->clock_list, node) { 232 list_for_each_entry_reverse(ce, &psd->clock_list, node) {
225 if (ce->status == PCE_STATUS_NONE)
226 pm_clk_acquire(dev, ce);
227
228 if (ce->status < PCE_STATUS_ERROR) { 233 if (ce->status < PCE_STATUS_ERROR) {
229 clk_disable(ce->clk); 234 clk_disable(ce->clk);
230 ce->status = PCE_STATUS_ACQUIRED; 235 ce->status = PCE_STATUS_ACQUIRED;
@@ -254,9 +259,6 @@ int pm_clk_resume(struct device *dev)
254 spin_lock_irqsave(&psd->lock, flags); 259 spin_lock_irqsave(&psd->lock, flags);
255 260
256 list_for_each_entry(ce, &psd->clock_list, node) { 261 list_for_each_entry(ce, &psd->clock_list, node) {
257 if (ce->status == PCE_STATUS_NONE)
258 pm_clk_acquire(dev, ce);
259
260 if (ce->status < PCE_STATUS_ERROR) { 262 if (ce->status < PCE_STATUS_ERROR) {
261 clk_enable(ce->clk); 263 clk_enable(ce->clk);
262 ce->status = PCE_STATUS_ENABLED; 264 ce->status = PCE_STATUS_ENABLED;