diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-08-25 09:33:50 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-08-25 09:33:50 -0400 |
commit | 5c095a0e0d600d5a5a4207eaadabd18db46395ce (patch) | |
tree | 18163d773234898e71c22d83b265a1eccfba11d9 /drivers/base/power/clock_ops.c | |
parent | 111058c3ff29a6a25216b31789046c2a330baa7d (diff) |
PM: Introduce struct pm_subsys_data
Introduce struct pm_subsys_data that may be subclassed by subsystems
to store subsystem-specific information related to the device. Move
the clock management fields accessed through the power.subsys_data
pointer in struct device to the new strucutre.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power/clock_ops.c')
-rw-r--r-- | drivers/base/power/clock_ops.c | 122 |
1 files changed, 64 insertions, 58 deletions
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 2c18d584066d..b7f1db4f5945 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c | |||
@@ -17,11 +17,6 @@ | |||
17 | 17 | ||
18 | #ifdef CONFIG_PM | 18 | #ifdef CONFIG_PM |
19 | 19 | ||
20 | struct pm_clk_data { | ||
21 | struct list_head clock_list; | ||
22 | spinlock_t lock; | ||
23 | }; | ||
24 | |||
25 | enum pce_status { | 20 | enum pce_status { |
26 | PCE_STATUS_NONE = 0, | 21 | PCE_STATUS_NONE = 0, |
27 | PCE_STATUS_ACQUIRED, | 22 | PCE_STATUS_ACQUIRED, |
@@ -36,11 +31,6 @@ struct pm_clock_entry { | |||
36 | enum pce_status status; | 31 | enum pce_status status; |
37 | }; | 32 | }; |
38 | 33 | ||
39 | static struct pm_clk_data *__to_pcd(struct device *dev) | ||
40 | { | ||
41 | return dev ? dev->power.subsys_data : NULL; | ||
42 | } | ||
43 | |||
44 | /** | 34 | /** |
45 | * pm_clk_add - Start using a device clock for power management. | 35 | * pm_clk_add - Start using a device clock for power management. |
46 | * @dev: Device whose clock is going to be used for power management. | 36 | * @dev: Device whose clock is going to be used for power management. |
@@ -51,10 +41,10 @@ static struct pm_clk_data *__to_pcd(struct device *dev) | |||
51 | */ | 41 | */ |
52 | int pm_clk_add(struct device *dev, const char *con_id) | 42 | int pm_clk_add(struct device *dev, const char *con_id) |
53 | { | 43 | { |
54 | struct pm_clk_data *pcd = __to_pcd(dev); | 44 | struct pm_subsys_data *psd = dev_to_psd(dev); |
55 | struct pm_clock_entry *ce; | 45 | struct pm_clock_entry *ce; |
56 | 46 | ||
57 | if (!pcd) | 47 | if (!psd) |
58 | return -EINVAL; | 48 | return -EINVAL; |
59 | 49 | ||
60 | ce = kzalloc(sizeof(*ce), GFP_KERNEL); | 50 | ce = kzalloc(sizeof(*ce), GFP_KERNEL); |
@@ -73,9 +63,9 @@ int pm_clk_add(struct device *dev, const char *con_id) | |||
73 | } | 63 | } |
74 | } | 64 | } |
75 | 65 | ||
76 | spin_lock_irq(&pcd->lock); | 66 | spin_lock_irq(&psd->lock); |
77 | list_add_tail(&ce->node, &pcd->clock_list); | 67 | list_add_tail(&ce->node, &psd->clock_list); |
78 | spin_unlock_irq(&pcd->lock); | 68 | spin_unlock_irq(&psd->lock); |
79 | return 0; | 69 | return 0; |
80 | } | 70 | } |
81 | 71 | ||
@@ -117,15 +107,15 @@ static void __pm_clk_remove(struct pm_clock_entry *ce) | |||
117 | */ | 107 | */ |
118 | void pm_clk_remove(struct device *dev, const char *con_id) | 108 | void pm_clk_remove(struct device *dev, const char *con_id) |
119 | { | 109 | { |
120 | struct pm_clk_data *pcd = __to_pcd(dev); | 110 | struct pm_subsys_data *psd = dev_to_psd(dev); |
121 | struct pm_clock_entry *ce; | 111 | struct pm_clock_entry *ce; |
122 | 112 | ||
123 | if (!pcd) | 113 | if (!psd) |
124 | return; | 114 | return; |
125 | 115 | ||
126 | spin_lock_irq(&pcd->lock); | 116 | spin_lock_irq(&psd->lock); |
127 | 117 | ||
128 | list_for_each_entry(ce, &pcd->clock_list, node) { | 118 | list_for_each_entry(ce, &psd->clock_list, node) { |
129 | if (!con_id && !ce->con_id) { | 119 | if (!con_id && !ce->con_id) { |
130 | __pm_clk_remove(ce); | 120 | __pm_clk_remove(ce); |
131 | break; | 121 | break; |
@@ -137,29 +127,45 @@ void pm_clk_remove(struct device *dev, const char *con_id) | |||
137 | } | 127 | } |
138 | } | 128 | } |
139 | 129 | ||
140 | spin_unlock_irq(&pcd->lock); | 130 | spin_unlock_irq(&psd->lock); |
141 | } | 131 | } |
142 | 132 | ||
143 | /** | 133 | /** |
144 | * pm_clk_init - Initialize a device's list of power management clocks. | 134 | * pm_clk_init - Initialize a device's list of power management clocks. |
145 | * @dev: Device to initialize the list of PM clocks for. | 135 | * @dev: Device to initialize the list of PM clocks for. |
146 | * | 136 | * |
147 | * Allocate a struct pm_clk_data object, initialize its lock member and | 137 | * Initialize the lock and clock_list members of the device's pm_subsys_data |
148 | * make the @dev's power.subsys_data field point to it. | 138 | * object. |
149 | */ | 139 | */ |
150 | int pm_clk_init(struct device *dev) | 140 | void pm_clk_init(struct device *dev) |
151 | { | 141 | { |
152 | struct pm_clk_data *pcd; | 142 | struct pm_subsys_data *psd = dev_to_psd(dev); |
143 | |||
144 | if (!psd) | ||
145 | return; | ||
153 | 146 | ||
154 | pcd = kzalloc(sizeof(*pcd), GFP_KERNEL); | 147 | INIT_LIST_HEAD(&psd->clock_list); |
155 | if (!pcd) { | 148 | spin_lock_init(&psd->lock); |
149 | } | ||
150 | |||
151 | /** | ||
152 | * pm_clk_create - Create and initialize a device's list of PM clocks. | ||
153 | * @dev: Device to create and initialize the list of PM clocks for. | ||
154 | * | ||
155 | * Allocate a struct pm_subsys_data object, initialize its lock and clock_list | ||
156 | * members and make the @dev's power.subsys_data field point to it. | ||
157 | */ | ||
158 | int pm_clk_create(struct device *dev) | ||
159 | { | ||
160 | struct pm_subsys_data *psd; | ||
161 | |||
162 | psd = kzalloc(sizeof(*psd), GFP_KERNEL); | ||
163 | if (!psd) { | ||
156 | dev_err(dev, "Not enough memory for PM clock data.\n"); | 164 | dev_err(dev, "Not enough memory for PM clock data.\n"); |
157 | return -ENOMEM; | 165 | return -ENOMEM; |
158 | } | 166 | } |
159 | 167 | dev->power.subsys_data = psd; | |
160 | INIT_LIST_HEAD(&pcd->clock_list); | 168 | pm_clk_init(dev); |
161 | spin_lock_init(&pcd->lock); | ||
162 | dev->power.subsys_data = pcd; | ||
163 | return 0; | 169 | return 0; |
164 | } | 170 | } |
165 | 171 | ||
@@ -168,27 +174,27 @@ int pm_clk_init(struct device *dev) | |||
168 | * @dev: Device to destroy the list of PM clocks for. | 174 | * @dev: Device to destroy the list of PM clocks for. |
169 | * | 175 | * |
170 | * Clear the @dev's power.subsys_data field, remove the list of clock entries | 176 | * Clear the @dev's power.subsys_data field, remove the list of clock entries |
171 | * from the struct pm_clk_data object pointed to by it before and free | 177 | * from the struct pm_subsys_data object pointed to by it before and free |
172 | * that object. | 178 | * that object. |
173 | */ | 179 | */ |
174 | void pm_clk_destroy(struct device *dev) | 180 | void pm_clk_destroy(struct device *dev) |
175 | { | 181 | { |
176 | struct pm_clk_data *pcd = __to_pcd(dev); | 182 | struct pm_subsys_data *psd = dev_to_psd(dev); |
177 | struct pm_clock_entry *ce, *c; | 183 | struct pm_clock_entry *ce, *c; |
178 | 184 | ||
179 | if (!pcd) | 185 | if (!psd) |
180 | return; | 186 | return; |
181 | 187 | ||
182 | dev->power.subsys_data = NULL; | 188 | dev->power.subsys_data = NULL; |
183 | 189 | ||
184 | spin_lock_irq(&pcd->lock); | 190 | spin_lock_irq(&psd->lock); |
185 | 191 | ||
186 | list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node) | 192 | list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node) |
187 | __pm_clk_remove(ce); | 193 | __pm_clk_remove(ce); |
188 | 194 | ||
189 | spin_unlock_irq(&pcd->lock); | 195 | spin_unlock_irq(&psd->lock); |
190 | 196 | ||
191 | kfree(pcd); | 197 | kfree(psd); |
192 | } | 198 | } |
193 | 199 | ||
194 | #endif /* CONFIG_PM */ | 200 | #endif /* CONFIG_PM */ |
@@ -218,18 +224,18 @@ static void pm_clk_acquire(struct device *dev, | |||
218 | */ | 224 | */ |
219 | int pm_clk_suspend(struct device *dev) | 225 | int pm_clk_suspend(struct device *dev) |
220 | { | 226 | { |
221 | struct pm_clk_data *pcd = __to_pcd(dev); | 227 | struct pm_subsys_data *psd = dev_to_psd(dev); |
222 | struct pm_clock_entry *ce; | 228 | struct pm_clock_entry *ce; |
223 | unsigned long flags; | 229 | unsigned long flags; |
224 | 230 | ||
225 | dev_dbg(dev, "%s()\n", __func__); | 231 | dev_dbg(dev, "%s()\n", __func__); |
226 | 232 | ||
227 | if (!pcd) | 233 | if (!psd) |
228 | return 0; | 234 | return 0; |
229 | 235 | ||
230 | spin_lock_irqsave(&pcd->lock, flags); | 236 | spin_lock_irqsave(&psd->lock, flags); |
231 | 237 | ||
232 | list_for_each_entry_reverse(ce, &pcd->clock_list, node) { | 238 | list_for_each_entry_reverse(ce, &psd->clock_list, node) { |
233 | if (ce->status == PCE_STATUS_NONE) | 239 | if (ce->status == PCE_STATUS_NONE) |
234 | pm_clk_acquire(dev, ce); | 240 | pm_clk_acquire(dev, ce); |
235 | 241 | ||
@@ -239,7 +245,7 @@ int pm_clk_suspend(struct device *dev) | |||
239 | } | 245 | } |
240 | } | 246 | } |
241 | 247 | ||
242 | spin_unlock_irqrestore(&pcd->lock, flags); | 248 | spin_unlock_irqrestore(&psd->lock, flags); |
243 | 249 | ||
244 | return 0; | 250 | return 0; |
245 | } | 251 | } |
@@ -250,18 +256,18 @@ int pm_clk_suspend(struct device *dev) | |||
250 | */ | 256 | */ |
251 | int pm_clk_resume(struct device *dev) | 257 | int pm_clk_resume(struct device *dev) |
252 | { | 258 | { |
253 | struct pm_clk_data *pcd = __to_pcd(dev); | 259 | struct pm_subsys_data *psd = dev_to_psd(dev); |
254 | struct pm_clock_entry *ce; | 260 | struct pm_clock_entry *ce; |
255 | unsigned long flags; | 261 | unsigned long flags; |
256 | 262 | ||
257 | dev_dbg(dev, "%s()\n", __func__); | 263 | dev_dbg(dev, "%s()\n", __func__); |
258 | 264 | ||
259 | if (!pcd) | 265 | if (!psd) |
260 | return 0; | 266 | return 0; |
261 | 267 | ||
262 | spin_lock_irqsave(&pcd->lock, flags); | 268 | spin_lock_irqsave(&psd->lock, flags); |
263 | 269 | ||
264 | list_for_each_entry(ce, &pcd->clock_list, node) { | 270 | list_for_each_entry(ce, &psd->clock_list, node) { |
265 | if (ce->status == PCE_STATUS_NONE) | 271 | if (ce->status == PCE_STATUS_NONE) |
266 | pm_clk_acquire(dev, ce); | 272 | pm_clk_acquire(dev, ce); |
267 | 273 | ||
@@ -271,7 +277,7 @@ int pm_clk_resume(struct device *dev) | |||
271 | } | 277 | } |
272 | } | 278 | } |
273 | 279 | ||
274 | spin_unlock_irqrestore(&pcd->lock, flags); | 280 | spin_unlock_irqrestore(&psd->lock, flags); |
275 | 281 | ||
276 | return 0; | 282 | return 0; |
277 | } | 283 | } |
@@ -309,7 +315,7 @@ static int pm_clk_notify(struct notifier_block *nb, | |||
309 | if (dev->pm_domain) | 315 | if (dev->pm_domain) |
310 | break; | 316 | break; |
311 | 317 | ||
312 | error = pm_clk_init(dev); | 318 | error = pm_clk_create(dev); |
313 | if (error) | 319 | if (error) |
314 | break; | 320 | break; |
315 | 321 | ||
@@ -344,22 +350,22 @@ static int pm_clk_notify(struct notifier_block *nb, | |||
344 | */ | 350 | */ |
345 | int pm_clk_suspend(struct device *dev) | 351 | int pm_clk_suspend(struct device *dev) |
346 | { | 352 | { |
347 | struct pm_clk_data *pcd = __to_pcd(dev); | 353 | struct pm_subsys_data *psd = dev_to_psd(dev); |
348 | struct pm_clock_entry *ce; | 354 | struct pm_clock_entry *ce; |
349 | unsigned long flags; | 355 | unsigned long flags; |
350 | 356 | ||
351 | dev_dbg(dev, "%s()\n", __func__); | 357 | dev_dbg(dev, "%s()\n", __func__); |
352 | 358 | ||
353 | /* If there is no driver, the clocks are already disabled. */ | 359 | /* If there is no driver, the clocks are already disabled. */ |
354 | if (!pcd || !dev->driver) | 360 | if (!psd || !dev->driver) |
355 | return 0; | 361 | return 0; |
356 | 362 | ||
357 | spin_lock_irqsave(&pcd->lock, flags); | 363 | spin_lock_irqsave(&psd->lock, flags); |
358 | 364 | ||
359 | list_for_each_entry_reverse(ce, &pcd->clock_list, node) | 365 | list_for_each_entry_reverse(ce, &psd->clock_list, node) |
360 | clk_disable(ce->clk); | 366 | clk_disable(ce->clk); |
361 | 367 | ||
362 | spin_unlock_irqrestore(&pcd->lock, flags); | 368 | spin_unlock_irqrestore(&psd->lock, flags); |
363 | 369 | ||
364 | return 0; | 370 | return 0; |
365 | } | 371 | } |
@@ -370,22 +376,22 @@ int pm_clk_suspend(struct device *dev) | |||
370 | */ | 376 | */ |
371 | int pm_clk_resume(struct device *dev) | 377 | int pm_clk_resume(struct device *dev) |
372 | { | 378 | { |
373 | struct pm_clk_data *pcd = __to_pcd(dev); | 379 | struct pm_subsys_data *psd = dev_to_psd(dev); |
374 | struct pm_clock_entry *ce; | 380 | struct pm_clock_entry *ce; |
375 | unsigned long flags; | 381 | unsigned long flags; |
376 | 382 | ||
377 | dev_dbg(dev, "%s()\n", __func__); | 383 | dev_dbg(dev, "%s()\n", __func__); |
378 | 384 | ||
379 | /* If there is no driver, the clocks should remain disabled. */ | 385 | /* If there is no driver, the clocks should remain disabled. */ |
380 | if (!pcd || !dev->driver) | 386 | if (!psd || !dev->driver) |
381 | return 0; | 387 | return 0; |
382 | 388 | ||
383 | spin_lock_irqsave(&pcd->lock, flags); | 389 | spin_lock_irqsave(&psd->lock, flags); |
384 | 390 | ||
385 | list_for_each_entry(ce, &pcd->clock_list, node) | 391 | list_for_each_entry(ce, &psd->clock_list, node) |
386 | clk_enable(ce->clk); | 392 | clk_enable(ce->clk); |
387 | 393 | ||
388 | spin_unlock_irqrestore(&pcd->lock, flags); | 394 | spin_unlock_irqrestore(&psd->lock, flags); |
389 | 395 | ||
390 | return 0; | 396 | return 0; |
391 | } | 397 | } |