diff options
-rw-r--r-- | Documentation/power/devices.txt | 37 | ||||
-rw-r--r-- | Documentation/power/runtime_pm.txt | 130 | ||||
-rw-r--r-- | drivers/base/power/main.c | 109 | ||||
-rw-r--r-- | drivers/base/power/runtime.c | 9 |
4 files changed, 170 insertions, 115 deletions
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index 3139fb505dce..20af7def23c8 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt | |||
@@ -126,7 +126,9 @@ The core methods to suspend and resume devices reside in struct dev_pm_ops | |||
126 | pointed to by the ops member of struct dev_pm_domain, or by the pm member of | 126 | pointed to by the ops member of struct dev_pm_domain, or by the pm member of |
127 | struct bus_type, struct device_type and struct class. They are mostly of | 127 | struct bus_type, struct device_type and struct class. They are mostly of |
128 | interest to the people writing infrastructure for platforms and buses, like PCI | 128 | interest to the people writing infrastructure for platforms and buses, like PCI |
129 | or USB, or device type and device class drivers. | 129 | or USB, or device type and device class drivers. They also are relevant to the |
130 | writers of device drivers whose subsystems (PM domains, device types, device | ||
131 | classes and bus types) don't provide all power management methods. | ||
130 | 132 | ||
131 | Bus drivers implement these methods as appropriate for the hardware and the | 133 | Bus drivers implement these methods as appropriate for the hardware and the |
132 | drivers using it; PCI works differently from USB, and so on. Not many people | 134 | drivers using it; PCI works differently from USB, and so on. Not many people |
@@ -268,32 +270,35 @@ various phases always run after tasks have been frozen and before they are | |||
268 | unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have | 270 | unfrozen. Furthermore, the *_noirq phases run at a time when IRQ handlers have |
269 | been disabled (except for those marked with the IRQF_NO_SUSPEND flag). | 271 | been disabled (except for those marked with the IRQF_NO_SUSPEND flag). |
270 | 272 | ||
271 | All phases use PM domain, bus, type, or class callbacks (that is, methods | 273 | All phases use PM domain, bus, type, class or driver callbacks (that is, methods |
272 | defined in dev->pm_domain->ops, dev->bus->pm, dev->type->pm, or dev->class->pm). | 274 | defined in dev->pm_domain->ops, dev->bus->pm, dev->type->pm, dev->class->pm or |
273 | These callbacks are regarded by the PM core as mutually exclusive. Moreover, | 275 | dev->driver->pm). These callbacks are regarded by the PM core as mutually |
274 | PM domain callbacks always take precedence over bus, type and class callbacks, | 276 | exclusive. Moreover, PM domain callbacks always take precedence over all of the |
275 | while type callbacks take precedence over bus and class callbacks, and class | 277 | other callbacks and, for example, type callbacks take precedence over bus, class |
276 | callbacks take precedence over bus callbacks. To be precise, the following | 278 | and driver callbacks. To be precise, the following rules are used to determine |
277 | rules are used to determine which callback to execute in the given phase: | 279 | which callback to execute in the given phase: |
278 | 280 | ||
279 | 1. If dev->pm_domain is present, the PM core will attempt to execute the | 281 | 1. If dev->pm_domain is present, the PM core will choose the callback |
280 | callback included in dev->pm_domain->ops. If that callback is not | 282 | included in dev->pm_domain->ops for execution |
281 | present, no action will be carried out for the given device. | ||
282 | 283 | ||
283 | 2. Otherwise, if both dev->type and dev->type->pm are present, the callback | 284 | 2. Otherwise, if both dev->type and dev->type->pm are present, the callback |
284 | included in dev->type->pm will be executed. | 285 | included in dev->type->pm will be chosen for execution. |
285 | 286 | ||
286 | 3. Otherwise, if both dev->class and dev->class->pm are present, the | 287 | 3. Otherwise, if both dev->class and dev->class->pm are present, the |
287 | callback included in dev->class->pm will be executed. | 288 | callback included in dev->class->pm will be chosen for execution. |
288 | 289 | ||
289 | 4. Otherwise, if both dev->bus and dev->bus->pm are present, the callback | 290 | 4. Otherwise, if both dev->bus and dev->bus->pm are present, the callback |
290 | included in dev->bus->pm will be executed. | 291 | included in dev->bus->pm will be chosen for execution. |
291 | 292 | ||
292 | This allows PM domains and device types to override callbacks provided by bus | 293 | This allows PM domains and device types to override callbacks provided by bus |
293 | types or device classes if necessary. | 294 | types or device classes if necessary. |
294 | 295 | ||
295 | These callbacks may in turn invoke device- or driver-specific methods stored in | 296 | The PM domain, type, class and bus callbacks may in turn invoke device- or |
296 | dev->driver->pm, but they don't have to. | 297 | driver-specific methods stored in dev->driver->pm, but they don't have to do |
298 | that. | ||
299 | |||
300 | If the subsystem callback chosen for execution is not present, the PM core will | ||
301 | execute the corresponding method from dev->driver->pm instead if there is one. | ||
297 | 302 | ||
298 | 303 | ||
299 | Entering System Suspend | 304 | Entering System Suspend |
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index c2ae8bf77d46..4abe83e1045a 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt | |||
@@ -57,6 +57,10 @@ the following: | |||
57 | 57 | ||
58 | 4. Bus type of the device, if both dev->bus and dev->bus->pm are present. | 58 | 4. Bus type of the device, if both dev->bus and dev->bus->pm are present. |
59 | 59 | ||
60 | If the subsystem chosen by applying the above rules doesn't provide the relevant | ||
61 | callback, the PM core will invoke the corresponding driver callback stored in | ||
62 | dev->driver->pm directly (if present). | ||
63 | |||
60 | The PM core always checks which callback to use in the order given above, so the | 64 | The PM core always checks which callback to use in the order given above, so the |
61 | priority order of callbacks from high to low is: PM domain, device type, class | 65 | priority order of callbacks from high to low is: PM domain, device type, class |
62 | and bus type. Moreover, the high-priority one will always take precedence over | 66 | and bus type. Moreover, the high-priority one will always take precedence over |
@@ -64,86 +68,88 @@ a low-priority one. The PM domain, bus type, device type and class callbacks | |||
64 | are referred to as subsystem-level callbacks in what follows. | 68 | are referred to as subsystem-level callbacks in what follows. |
65 | 69 | ||
66 | By default, the callbacks are always invoked in process context with interrupts | 70 | By default, the callbacks are always invoked in process context with interrupts |
67 | enabled. However, subsystems can use the pm_runtime_irq_safe() helper function | 71 | enabled. However, the pm_runtime_irq_safe() helper function can be used to tell |
68 | to tell the PM core that their ->runtime_suspend(), ->runtime_resume() and | 72 | the PM core that it is safe to run the ->runtime_suspend(), ->runtime_resume() |
69 | ->runtime_idle() callbacks may be invoked in atomic context with interrupts | 73 | and ->runtime_idle() callbacks for the given device in atomic context with |
70 | disabled for a given device. This implies that the callback routines in | 74 | interrupts disabled. This implies that the callback routines in question must |
71 | question must not block or sleep, but it also means that the synchronous helper | 75 | not block or sleep, but it also means that the synchronous helper functions |
72 | functions listed at the end of Section 4 may be used for that device within an | 76 | listed at the end of Section 4 may be used for that device within an interrupt |
73 | interrupt handler or generally in an atomic context. | 77 | handler or generally in an atomic context. |
74 | 78 | ||
75 | The subsystem-level suspend callback is _entirely_ _responsible_ for handling | 79 | The subsystem-level suspend callback, if present, is _entirely_ _responsible_ |
76 | the suspend of the device as appropriate, which may, but need not include | 80 | for handling the suspend of the device as appropriate, which may, but need not |
77 | executing the device driver's own ->runtime_suspend() callback (from the | 81 | include executing the device driver's own ->runtime_suspend() callback (from the |
78 | PM core's point of view it is not necessary to implement a ->runtime_suspend() | 82 | PM core's point of view it is not necessary to implement a ->runtime_suspend() |
79 | callback in a device driver as long as the subsystem-level suspend callback | 83 | callback in a device driver as long as the subsystem-level suspend callback |
80 | knows what to do to handle the device). | 84 | knows what to do to handle the device). |
81 | 85 | ||
82 | * Once the subsystem-level suspend callback has completed successfully | 86 | * Once the subsystem-level suspend callback (or the driver suspend callback, |
83 | for given device, the PM core regards the device as suspended, which need | 87 | if invoked directly) has completed successfully for the given device, the PM |
84 | not mean that the device has been put into a low power state. It is | 88 | core regards the device as suspended, which need not mean that it has been |
85 | supposed to mean, however, that the device will not process data and will | 89 | put into a low power state. It is supposed to mean, however, that the |
86 | not communicate with the CPU(s) and RAM until the subsystem-level resume | 90 | device will not process data and will not communicate with the CPU(s) and |
87 | callback is executed for it. The runtime PM status of a device after | 91 | RAM until the appropriate resume callback is executed for it. The runtime |
88 | successful execution of the subsystem-level suspend callback is 'suspended'. | 92 | PM status of a device after successful execution of the suspend callback is |
89 | 93 | 'suspended'. | |
90 | * If the subsystem-level suspend callback returns -EBUSY or -EAGAIN, | 94 | |
91 | the device's runtime PM status is 'active', which means that the device | 95 | * If the suspend callback returns -EBUSY or -EAGAIN, the device's runtime PM |
92 | _must_ be fully operational afterwards. | 96 | status remains 'active', which means that the device _must_ be fully |
93 | 97 | operational afterwards. | |
94 | * If the subsystem-level suspend callback returns an error code different | 98 | |
95 | from -EBUSY or -EAGAIN, the PM core regards this as a fatal error and will | 99 | * If the suspend callback returns an error code different from -EBUSY and |
96 | refuse to run the helper functions described in Section 4 for the device, | 100 | -EAGAIN, the PM core regards this as a fatal error and will refuse to run |
97 | until the status of it is directly set either to 'active', or to 'suspended' | 101 | the helper functions described in Section 4 for the device until its status |
98 | (the PM core provides special helper functions for this purpose). | 102 | is directly set to either'active', or 'suspended' (the PM core provides |
99 | 103 | special helper functions for this purpose). | |
100 | In particular, if the driver requires remote wake-up capability (i.e. hardware | 104 | |
105 | In particular, if the driver requires remote wakeup capability (i.e. hardware | ||
101 | mechanism allowing the device to request a change of its power state, such as | 106 | mechanism allowing the device to request a change of its power state, such as |
102 | PCI PME) for proper functioning and device_run_wake() returns 'false' for the | 107 | PCI PME) for proper functioning and device_run_wake() returns 'false' for the |
103 | device, then ->runtime_suspend() should return -EBUSY. On the other hand, if | 108 | device, then ->runtime_suspend() should return -EBUSY. On the other hand, if |
104 | device_run_wake() returns 'true' for the device and the device is put into a low | 109 | device_run_wake() returns 'true' for the device and the device is put into a |
105 | power state during the execution of the subsystem-level suspend callback, it is | 110 | low-power state during the execution of the suspend callback, it is expected |
106 | expected that remote wake-up will be enabled for the device. Generally, remote | 111 | that remote wakeup will be enabled for the device. Generally, remote wakeup |
107 | wake-up should be enabled for all input devices put into a low power state at | 112 | should be enabled for all input devices put into low-power states at run time. |
108 | run time. | 113 | |
109 | 114 | The subsystem-level resume callback, if present, is _entirely_ _responsible_ for | |
110 | The subsystem-level resume callback is _entirely_ _responsible_ for handling the | 115 | handling the resume of the device as appropriate, which may, but need not |
111 | resume of the device as appropriate, which may, but need not include executing | 116 | include executing the device driver's own ->runtime_resume() callback (from the |
112 | the device driver's own ->runtime_resume() callback (from the PM core's point of | 117 | PM core's point of view it is not necessary to implement a ->runtime_resume() |
113 | view it is not necessary to implement a ->runtime_resume() callback in a device | 118 | callback in a device driver as long as the subsystem-level resume callback knows |
114 | driver as long as the subsystem-level resume callback knows what to do to handle | 119 | what to do to handle the device). |
115 | the device). | 120 | |
116 | 121 | * Once the subsystem-level resume callback (or the driver resume callback, if | |
117 | * Once the subsystem-level resume callback has completed successfully, the PM | 122 | invoked directly) has completed successfully, the PM core regards the device |
118 | core regards the device as fully operational, which means that the device | 123 | as fully operational, which means that the device _must_ be able to complete |
119 | _must_ be able to complete I/O operations as needed. The runtime PM status | 124 | I/O operations as needed. The runtime PM status of the device is then |
120 | of the device is then 'active'. | 125 | 'active'. |
121 | 126 | ||
122 | * If the subsystem-level resume callback returns an error code, the PM core | 127 | * If the resume callback returns an error code, the PM core regards this as a |
123 | regards this as a fatal error and will refuse to run the helper functions | 128 | fatal error and will refuse to run the helper functions described in Section |
124 | described in Section 4 for the device, until its status is directly set | 129 | 4 for the device, until its status is directly set to either 'active', or |
125 | either to 'active' or to 'suspended' (the PM core provides special helper | 130 | 'suspended' (by means of special helper functions provided by the PM core |
126 | functions for this purpose). | 131 | for this purpose). |
127 | 132 | ||
128 | The subsystem-level idle callback is executed by the PM core whenever the device | 133 | The idle callback (a subsystem-level one, if present, or the driver one) is |
129 | appears to be idle, which is indicated to the PM core by two counters, the | 134 | executed by the PM core whenever the device appears to be idle, which is |
130 | device's usage counter and the counter of 'active' children of the device. | 135 | indicated to the PM core by two counters, the device's usage counter and the |
136 | counter of 'active' children of the device. | ||
131 | 137 | ||
132 | * If any of these counters is decreased using a helper function provided by | 138 | * If any of these counters is decreased using a helper function provided by |
133 | the PM core and it turns out to be equal to zero, the other counter is | 139 | the PM core and it turns out to be equal to zero, the other counter is |
134 | checked. If that counter also is equal to zero, the PM core executes the | 140 | checked. If that counter also is equal to zero, the PM core executes the |
135 | subsystem-level idle callback with the device as an argument. | 141 | idle callback with the device as its argument. |
136 | 142 | ||
137 | The action performed by a subsystem-level idle callback is totally dependent on | 143 | The action performed by the idle callback is totally dependent on the subsystem |
138 | the subsystem in question, but the expected and recommended action is to check | 144 | (or driver) in question, but the expected and recommended action is to check |
139 | if the device can be suspended (i.e. if all of the conditions necessary for | 145 | if the device can be suspended (i.e. if all of the conditions necessary for |
140 | suspending the device are satisfied) and to queue up a suspend request for the | 146 | suspending the device are satisfied) and to queue up a suspend request for the |
141 | device in that case. The value returned by this callback is ignored by the PM | 147 | device in that case. The value returned by this callback is ignored by the PM |
142 | core. | 148 | core. |
143 | 149 | ||
144 | The helper functions provided by the PM core, described in Section 4, guarantee | 150 | The helper functions provided by the PM core, described in Section 4, guarantee |
145 | that the following constraints are met with respect to the bus type's runtime | 151 | that the following constraints are met with respect to runtime PM callbacks for |
146 | PM callbacks: | 152 | one device: |
147 | 153 | ||
148 | (1) The callbacks are mutually exclusive (e.g. it is forbidden to execute | 154 | (1) The callbacks are mutually exclusive (e.g. it is forbidden to execute |
149 | ->runtime_suspend() in parallel with ->runtime_resume() or with another | 155 | ->runtime_suspend() in parallel with ->runtime_resume() or with another |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index b5cef7e7de23..e2cc3d2e0ecc 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -383,10 +383,15 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) | |||
383 | info = "EARLY class "; | 383 | info = "EARLY class "; |
384 | callback = pm_noirq_op(dev->class->pm, state); | 384 | callback = pm_noirq_op(dev->class->pm, state); |
385 | } else if (dev->bus && dev->bus->pm) { | 385 | } else if (dev->bus && dev->bus->pm) { |
386 | info = "EARLY "; | 386 | info = "EARLY bus "; |
387 | callback = pm_noirq_op(dev->bus->pm, state); | 387 | callback = pm_noirq_op(dev->bus->pm, state); |
388 | } | 388 | } |
389 | 389 | ||
390 | if (!callback && dev->driver && dev->driver->pm) { | ||
391 | info = "EARLY driver "; | ||
392 | callback = pm_noirq_op(dev->driver->pm, state); | ||
393 | } | ||
394 | |||
390 | error = dpm_run_callback(callback, dev, state, info); | 395 | error = dpm_run_callback(callback, dev, state, info); |
391 | 396 | ||
392 | TRACE_RESUME(error); | 397 | TRACE_RESUME(error); |
@@ -464,20 +469,20 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
464 | if (dev->pm_domain) { | 469 | if (dev->pm_domain) { |
465 | info = "power domain "; | 470 | info = "power domain "; |
466 | callback = pm_op(&dev->pm_domain->ops, state); | 471 | callback = pm_op(&dev->pm_domain->ops, state); |
467 | goto End; | 472 | goto Driver; |
468 | } | 473 | } |
469 | 474 | ||
470 | if (dev->type && dev->type->pm) { | 475 | if (dev->type && dev->type->pm) { |
471 | info = "type "; | 476 | info = "type "; |
472 | callback = pm_op(dev->type->pm, state); | 477 | callback = pm_op(dev->type->pm, state); |
473 | goto End; | 478 | goto Driver; |
474 | } | 479 | } |
475 | 480 | ||
476 | if (dev->class) { | 481 | if (dev->class) { |
477 | if (dev->class->pm) { | 482 | if (dev->class->pm) { |
478 | info = "class "; | 483 | info = "class "; |
479 | callback = pm_op(dev->class->pm, state); | 484 | callback = pm_op(dev->class->pm, state); |
480 | goto End; | 485 | goto Driver; |
481 | } else if (dev->class->resume) { | 486 | } else if (dev->class->resume) { |
482 | info = "legacy class "; | 487 | info = "legacy class "; |
483 | callback = dev->class->resume; | 488 | callback = dev->class->resume; |
@@ -487,14 +492,21 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
487 | 492 | ||
488 | if (dev->bus) { | 493 | if (dev->bus) { |
489 | if (dev->bus->pm) { | 494 | if (dev->bus->pm) { |
490 | info = ""; | 495 | info = "bus "; |
491 | callback = pm_op(dev->bus->pm, state); | 496 | callback = pm_op(dev->bus->pm, state); |
492 | } else if (dev->bus->resume) { | 497 | } else if (dev->bus->resume) { |
493 | info = "legacy "; | 498 | info = "legacy bus "; |
494 | callback = dev->bus->resume; | 499 | callback = dev->bus->resume; |
500 | goto End; | ||
495 | } | 501 | } |
496 | } | 502 | } |
497 | 503 | ||
504 | Driver: | ||
505 | if (!callback && dev->driver && dev->driver->pm) { | ||
506 | info = "driver "; | ||
507 | callback = pm_op(dev->driver->pm, state); | ||
508 | } | ||
509 | |||
498 | End: | 510 | End: |
499 | error = dpm_run_callback(callback, dev, state, info); | 511 | error = dpm_run_callback(callback, dev, state, info); |
500 | dev->power.is_suspended = false; | 512 | dev->power.is_suspended = false; |
@@ -588,24 +600,33 @@ void dpm_resume(pm_message_t state) | |||
588 | */ | 600 | */ |
589 | static void device_complete(struct device *dev, pm_message_t state) | 601 | static void device_complete(struct device *dev, pm_message_t state) |
590 | { | 602 | { |
603 | void (*callback)(struct device *) = NULL; | ||
604 | char *info = NULL; | ||
605 | |||
591 | device_lock(dev); | 606 | device_lock(dev); |
592 | 607 | ||
593 | if (dev->pm_domain) { | 608 | if (dev->pm_domain) { |
594 | pm_dev_dbg(dev, state, "completing power domain "); | 609 | info = "completing power domain "; |
595 | if (dev->pm_domain->ops.complete) | 610 | callback = dev->pm_domain->ops.complete; |
596 | dev->pm_domain->ops.complete(dev); | ||
597 | } else if (dev->type && dev->type->pm) { | 611 | } else if (dev->type && dev->type->pm) { |
598 | pm_dev_dbg(dev, state, "completing type "); | 612 | info = "completing type "; |
599 | if (dev->type->pm->complete) | 613 | callback = dev->type->pm->complete; |
600 | dev->type->pm->complete(dev); | ||
601 | } else if (dev->class && dev->class->pm) { | 614 | } else if (dev->class && dev->class->pm) { |
602 | pm_dev_dbg(dev, state, "completing class "); | 615 | info = "completing class "; |
603 | if (dev->class->pm->complete) | 616 | callback = dev->class->pm->complete; |
604 | dev->class->pm->complete(dev); | ||
605 | } else if (dev->bus && dev->bus->pm) { | 617 | } else if (dev->bus && dev->bus->pm) { |
606 | pm_dev_dbg(dev, state, "completing "); | 618 | info = "completing bus "; |
607 | if (dev->bus->pm->complete) | 619 | callback = dev->bus->pm->complete; |
608 | dev->bus->pm->complete(dev); | 620 | } |
621 | |||
622 | if (!callback && dev->driver && dev->driver->pm) { | ||
623 | info = "completing driver "; | ||
624 | callback = dev->driver->pm->complete; | ||
625 | } | ||
626 | |||
627 | if (callback) { | ||
628 | pm_dev_dbg(dev, state, info); | ||
629 | callback(dev); | ||
609 | } | 630 | } |
610 | 631 | ||
611 | device_unlock(dev); | 632 | device_unlock(dev); |
@@ -704,10 +725,15 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) | |||
704 | info = "LATE class "; | 725 | info = "LATE class "; |
705 | callback = pm_noirq_op(dev->class->pm, state); | 726 | callback = pm_noirq_op(dev->class->pm, state); |
706 | } else if (dev->bus && dev->bus->pm) { | 727 | } else if (dev->bus && dev->bus->pm) { |
707 | info = "LATE "; | 728 | info = "LATE bus "; |
708 | callback = pm_noirq_op(dev->bus->pm, state); | 729 | callback = pm_noirq_op(dev->bus->pm, state); |
709 | } | 730 | } |
710 | 731 | ||
732 | if (!callback && dev->driver && dev->driver->pm) { | ||
733 | info = "LATE driver "; | ||
734 | callback = pm_noirq_op(dev->driver->pm, state); | ||
735 | } | ||
736 | |||
711 | return dpm_run_callback(callback, dev, state, info); | 737 | return dpm_run_callback(callback, dev, state, info); |
712 | } | 738 | } |
713 | 739 | ||
@@ -832,16 +858,21 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
832 | 858 | ||
833 | if (dev->bus) { | 859 | if (dev->bus) { |
834 | if (dev->bus->pm) { | 860 | if (dev->bus->pm) { |
835 | info = ""; | 861 | info = "bus "; |
836 | callback = pm_op(dev->bus->pm, state); | 862 | callback = pm_op(dev->bus->pm, state); |
837 | } else if (dev->bus->suspend) { | 863 | } else if (dev->bus->suspend) { |
838 | pm_dev_dbg(dev, state, "legacy "); | 864 | pm_dev_dbg(dev, state, "legacy bus "); |
839 | error = legacy_suspend(dev, state, dev->bus->suspend); | 865 | error = legacy_suspend(dev, state, dev->bus->suspend); |
840 | goto End; | 866 | goto End; |
841 | } | 867 | } |
842 | } | 868 | } |
843 | 869 | ||
844 | Run: | 870 | Run: |
871 | if (!callback && dev->driver && dev->driver->pm) { | ||
872 | info = "driver "; | ||
873 | callback = pm_op(dev->driver->pm, state); | ||
874 | } | ||
875 | |||
845 | error = dpm_run_callback(callback, dev, state, info); | 876 | error = dpm_run_callback(callback, dev, state, info); |
846 | 877 | ||
847 | End: | 878 | End: |
@@ -949,6 +980,8 @@ int dpm_suspend(pm_message_t state) | |||
949 | */ | 980 | */ |
950 | static int device_prepare(struct device *dev, pm_message_t state) | 981 | static int device_prepare(struct device *dev, pm_message_t state) |
951 | { | 982 | { |
983 | int (*callback)(struct device *) = NULL; | ||
984 | char *info = NULL; | ||
952 | int error = 0; | 985 | int error = 0; |
953 | 986 | ||
954 | device_lock(dev); | 987 | device_lock(dev); |
@@ -956,25 +989,27 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
956 | dev->power.wakeup_path = device_may_wakeup(dev); | 989 | dev->power.wakeup_path = device_may_wakeup(dev); |
957 | 990 | ||
958 | if (dev->pm_domain) { | 991 | if (dev->pm_domain) { |
959 | pm_dev_dbg(dev, state, "preparing power domain "); | 992 | info = "preparing power domain "; |
960 | if (dev->pm_domain->ops.prepare) | 993 | callback = dev->pm_domain->ops.prepare; |
961 | error = dev->pm_domain->ops.prepare(dev); | ||
962 | suspend_report_result(dev->pm_domain->ops.prepare, error); | ||
963 | } else if (dev->type && dev->type->pm) { | 994 | } else if (dev->type && dev->type->pm) { |
964 | pm_dev_dbg(dev, state, "preparing type "); | 995 | info = "preparing type "; |
965 | if (dev->type->pm->prepare) | 996 | callback = dev->type->pm->prepare; |
966 | error = dev->type->pm->prepare(dev); | ||
967 | suspend_report_result(dev->type->pm->prepare, error); | ||
968 | } else if (dev->class && dev->class->pm) { | 997 | } else if (dev->class && dev->class->pm) { |
969 | pm_dev_dbg(dev, state, "preparing class "); | 998 | info = "preparing class "; |
970 | if (dev->class->pm->prepare) | 999 | callback = dev->class->pm->prepare; |
971 | error = dev->class->pm->prepare(dev); | ||
972 | suspend_report_result(dev->class->pm->prepare, error); | ||
973 | } else if (dev->bus && dev->bus->pm) { | 1000 | } else if (dev->bus && dev->bus->pm) { |
974 | pm_dev_dbg(dev, state, "preparing "); | 1001 | info = "preparing bus "; |
975 | if (dev->bus->pm->prepare) | 1002 | callback = dev->bus->pm->prepare; |
976 | error = dev->bus->pm->prepare(dev); | 1003 | } |
977 | suspend_report_result(dev->bus->pm->prepare, error); | 1004 | |
1005 | if (!callback && dev->driver && dev->driver->pm) { | ||
1006 | info = "preparing driver "; | ||
1007 | callback = dev->driver->pm->prepare; | ||
1008 | } | ||
1009 | |||
1010 | if (callback) { | ||
1011 | error = callback(dev); | ||
1012 | suspend_report_result(callback, error); | ||
978 | } | 1013 | } |
979 | 1014 | ||
980 | device_unlock(dev); | 1015 | device_unlock(dev); |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 8c78443bca8f..c56efd756531 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -250,6 +250,9 @@ static int rpm_idle(struct device *dev, int rpmflags) | |||
250 | else | 250 | else |
251 | callback = NULL; | 251 | callback = NULL; |
252 | 252 | ||
253 | if (!callback && dev->driver && dev->driver->pm) | ||
254 | callback = dev->driver->pm->runtime_idle; | ||
255 | |||
253 | if (callback) | 256 | if (callback) |
254 | __rpm_callback(callback, dev); | 257 | __rpm_callback(callback, dev); |
255 | 258 | ||
@@ -413,6 +416,9 @@ static int rpm_suspend(struct device *dev, int rpmflags) | |||
413 | else | 416 | else |
414 | callback = NULL; | 417 | callback = NULL; |
415 | 418 | ||
419 | if (!callback && dev->driver && dev->driver->pm) | ||
420 | callback = dev->driver->pm->runtime_suspend; | ||
421 | |||
416 | retval = rpm_callback(callback, dev); | 422 | retval = rpm_callback(callback, dev); |
417 | if (retval) { | 423 | if (retval) { |
418 | __update_runtime_status(dev, RPM_ACTIVE); | 424 | __update_runtime_status(dev, RPM_ACTIVE); |
@@ -633,6 +639,9 @@ static int rpm_resume(struct device *dev, int rpmflags) | |||
633 | else | 639 | else |
634 | callback = NULL; | 640 | callback = NULL; |
635 | 641 | ||
642 | if (!callback && dev->driver && dev->driver->pm) | ||
643 | callback = dev->driver->pm->runtime_resume; | ||
644 | |||
636 | retval = rpm_callback(callback, dev); | 645 | retval = rpm_callback(callback, dev); |
637 | if (retval) { | 646 | if (retval) { |
638 | __update_runtime_status(dev, RPM_SUSPENDED); | 647 | __update_runtime_status(dev, RPM_SUSPENDED); |