aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c2
-rw-r--r--drivers/base/power/clock_ops.c122
-rw-r--r--include/linux/device.h5
-rw-r--r--include/linux/pm.h9
-rw-r--r--include/linux/pm_runtime.h8
5 files changed, 84 insertions, 62 deletions
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index b471b795dfc3..54d4d86883c9 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -115,7 +115,7 @@ void sh7372_add_device_to_domain(struct sh7372_pm_domain *sh7372_pd,
115 struct device *dev = &pdev->dev; 115 struct device *dev = &pdev->dev;
116 116
117 if (!dev->power.subsys_data) { 117 if (!dev->power.subsys_data) {
118 pm_clk_init(dev); 118 pm_clk_create(dev);
119 pm_clk_add(dev, NULL); 119 pm_clk_add(dev, NULL);
120 } 120 }
121 pm_genpd_add_device(&sh7372_pd->genpd, dev); 121 pm_genpd_add_device(&sh7372_pd->genpd, dev);
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
20struct pm_clk_data {
21 struct list_head clock_list;
22 spinlock_t lock;
23};
24
25enum pce_status { 20enum 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
39static 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 */
52int pm_clk_add(struct device *dev, const char *con_id) 42int 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 */
118void pm_clk_remove(struct device *dev, const char *con_id) 108void 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 */
150int pm_clk_init(struct device *dev) 140void 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 */
158int 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 */
174void pm_clk_destroy(struct device *dev) 180void 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 */
219int pm_clk_suspend(struct device *dev) 225int 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 */
251int pm_clk_resume(struct device *dev) 257int 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 */
345int pm_clk_suspend(struct device *dev) 351int 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 */
371int pm_clk_resume(struct device *dev) 377int 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}
diff --git a/include/linux/device.h b/include/linux/device.h
index c20dfbfc49b4..5d200ed0071a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -636,6 +636,11 @@ static inline void set_dev_node(struct device *dev, int node)
636} 636}
637#endif 637#endif
638 638
639static inline struct pm_subsys_data *dev_to_psd(struct device *dev)
640{
641 return dev ? dev->power.subsys_data : NULL;
642}
643
639static inline unsigned int dev_get_uevent_suppress(const struct device *dev) 644static inline unsigned int dev_get_uevent_suppress(const struct device *dev)
640{ 645{
641 return dev->kobj.uevent_suppress; 646 return dev->kobj.uevent_suppress;
diff --git a/include/linux/pm.h b/include/linux/pm.h
index f7c84c9abd30..bf5ee37388d4 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -421,6 +421,13 @@ enum rpm_request {
421 421
422struct wakeup_source; 422struct wakeup_source;
423 423
424struct pm_subsys_data {
425 spinlock_t lock;
426#ifdef CONFIG_PM_CLK
427 struct list_head clock_list;
428#endif
429};
430
424struct dev_pm_info { 431struct dev_pm_info {
425 pm_message_t power_state; 432 pm_message_t power_state;
426 unsigned int can_wakeup:1; 433 unsigned int can_wakeup:1;
@@ -462,7 +469,7 @@ struct dev_pm_info {
462 unsigned long suspended_jiffies; 469 unsigned long suspended_jiffies;
463 unsigned long accounting_timestamp; 470 unsigned long accounting_timestamp;
464#endif 471#endif
465 void *subsys_data; /* Owned by the subsystem. */ 472 struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
466}; 473};
467 474
468extern void update_pm_runtime_accounting(struct device *dev); 475extern void update_pm_runtime_accounting(struct device *dev);
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index daac05d751b2..6b90630e3c98 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -258,14 +258,18 @@ struct pm_clk_notifier_block {
258}; 258};
259 259
260#ifdef CONFIG_PM_CLK 260#ifdef CONFIG_PM_CLK
261extern int pm_clk_init(struct device *dev); 261extern void pm_clk_init(struct device *dev);
262extern int pm_clk_create(struct device *dev);
262extern void pm_clk_destroy(struct device *dev); 263extern void pm_clk_destroy(struct device *dev);
263extern int pm_clk_add(struct device *dev, const char *con_id); 264extern int pm_clk_add(struct device *dev, const char *con_id);
264extern void pm_clk_remove(struct device *dev, const char *con_id); 265extern void pm_clk_remove(struct device *dev, const char *con_id);
265extern int pm_clk_suspend(struct device *dev); 266extern int pm_clk_suspend(struct device *dev);
266extern int pm_clk_resume(struct device *dev); 267extern int pm_clk_resume(struct device *dev);
267#else 268#else
268static inline int pm_clk_init(struct device *dev) 269static inline void pm_clk_init(struct device *dev)
270{
271}
272static inline int pm_clk_create(struct device *dev)
269{ 273{
270 return -EINVAL; 274 return -EINVAL;
271} 275}