diff options
Diffstat (limited to 'drivers/base/power/main.c')
-rw-r--r-- | drivers/base/power/main.c | 175 |
1 files changed, 93 insertions, 82 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 83404973f97a..052dc53eef38 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -423,26 +423,22 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) | |||
423 | TRACE_DEVICE(dev); | 423 | TRACE_DEVICE(dev); |
424 | TRACE_RESUME(0); | 424 | TRACE_RESUME(0); |
425 | 425 | ||
426 | if (dev->bus && dev->bus->pm) { | 426 | if (dev->pwr_domain) { |
427 | pm_dev_dbg(dev, state, "EARLY "); | 427 | pm_dev_dbg(dev, state, "EARLY power domain "); |
428 | error = pm_noirq_op(dev, dev->bus->pm, state); | 428 | pm_noirq_op(dev, &dev->pwr_domain->ops, state); |
429 | if (error) | ||
430 | goto End; | ||
431 | } | 429 | } |
432 | 430 | ||
433 | if (dev->type && dev->type->pm) { | 431 | if (dev->type && dev->type->pm) { |
434 | pm_dev_dbg(dev, state, "EARLY type "); | 432 | pm_dev_dbg(dev, state, "EARLY type "); |
435 | error = pm_noirq_op(dev, dev->type->pm, state); | 433 | error = pm_noirq_op(dev, dev->type->pm, state); |
436 | if (error) | 434 | } else if (dev->class && dev->class->pm) { |
437 | goto End; | ||
438 | } | ||
439 | |||
440 | if (dev->class && dev->class->pm) { | ||
441 | pm_dev_dbg(dev, state, "EARLY class "); | 435 | pm_dev_dbg(dev, state, "EARLY class "); |
442 | error = pm_noirq_op(dev, dev->class->pm, state); | 436 | error = pm_noirq_op(dev, dev->class->pm, state); |
437 | } else if (dev->bus && dev->bus->pm) { | ||
438 | pm_dev_dbg(dev, state, "EARLY "); | ||
439 | error = pm_noirq_op(dev, dev->bus->pm, state); | ||
443 | } | 440 | } |
444 | 441 | ||
445 | End: | ||
446 | TRACE_RESUME(error); | 442 | TRACE_RESUME(error); |
447 | return error; | 443 | return error; |
448 | } | 444 | } |
@@ -518,36 +514,39 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) | |||
518 | 514 | ||
519 | dev->power.in_suspend = false; | 515 | dev->power.in_suspend = false; |
520 | 516 | ||
521 | if (dev->bus) { | 517 | if (dev->pwr_domain) { |
522 | if (dev->bus->pm) { | 518 | pm_dev_dbg(dev, state, "power domain "); |
523 | pm_dev_dbg(dev, state, ""); | 519 | pm_op(dev, &dev->pwr_domain->ops, state); |
524 | error = pm_op(dev, dev->bus->pm, state); | ||
525 | } else if (dev->bus->resume) { | ||
526 | pm_dev_dbg(dev, state, "legacy "); | ||
527 | error = legacy_resume(dev, dev->bus->resume); | ||
528 | } | ||
529 | if (error) | ||
530 | goto End; | ||
531 | } | 520 | } |
532 | 521 | ||
533 | if (dev->type) { | 522 | if (dev->type && dev->type->pm) { |
534 | if (dev->type->pm) { | 523 | pm_dev_dbg(dev, state, "type "); |
535 | pm_dev_dbg(dev, state, "type "); | 524 | error = pm_op(dev, dev->type->pm, state); |
536 | error = pm_op(dev, dev->type->pm, state); | 525 | goto End; |
537 | } | ||
538 | if (error) | ||
539 | goto End; | ||
540 | } | 526 | } |
541 | 527 | ||
542 | if (dev->class) { | 528 | if (dev->class) { |
543 | if (dev->class->pm) { | 529 | if (dev->class->pm) { |
544 | pm_dev_dbg(dev, state, "class "); | 530 | pm_dev_dbg(dev, state, "class "); |
545 | error = pm_op(dev, dev->class->pm, state); | 531 | error = pm_op(dev, dev->class->pm, state); |
532 | goto End; | ||
546 | } else if (dev->class->resume) { | 533 | } else if (dev->class->resume) { |
547 | pm_dev_dbg(dev, state, "legacy class "); | 534 | pm_dev_dbg(dev, state, "legacy class "); |
548 | error = legacy_resume(dev, dev->class->resume); | 535 | error = legacy_resume(dev, dev->class->resume); |
536 | goto End; | ||
549 | } | 537 | } |
550 | } | 538 | } |
539 | |||
540 | if (dev->bus) { | ||
541 | if (dev->bus->pm) { | ||
542 | pm_dev_dbg(dev, state, ""); | ||
543 | error = pm_op(dev, dev->bus->pm, state); | ||
544 | } else if (dev->bus->resume) { | ||
545 | pm_dev_dbg(dev, state, "legacy "); | ||
546 | error = legacy_resume(dev, dev->bus->resume); | ||
547 | } | ||
548 | } | ||
549 | |||
551 | End: | 550 | End: |
552 | device_unlock(dev); | 551 | device_unlock(dev); |
553 | complete_all(&dev->power.completion); | 552 | complete_all(&dev->power.completion); |
@@ -629,19 +628,23 @@ static void device_complete(struct device *dev, pm_message_t state) | |||
629 | { | 628 | { |
630 | device_lock(dev); | 629 | device_lock(dev); |
631 | 630 | ||
632 | if (dev->class && dev->class->pm && dev->class->pm->complete) { | 631 | if (dev->pwr_domain && dev->pwr_domain->ops.complete) { |
633 | pm_dev_dbg(dev, state, "completing class "); | 632 | pm_dev_dbg(dev, state, "completing power domain "); |
634 | dev->class->pm->complete(dev); | 633 | dev->pwr_domain->ops.complete(dev); |
635 | } | 634 | } |
636 | 635 | ||
637 | if (dev->type && dev->type->pm && dev->type->pm->complete) { | 636 | if (dev->type && dev->type->pm) { |
638 | pm_dev_dbg(dev, state, "completing type "); | 637 | pm_dev_dbg(dev, state, "completing type "); |
639 | dev->type->pm->complete(dev); | 638 | if (dev->type->pm->complete) |
640 | } | 639 | dev->type->pm->complete(dev); |
641 | 640 | } else if (dev->class && dev->class->pm) { | |
642 | if (dev->bus && dev->bus->pm && dev->bus->pm->complete) { | 641 | pm_dev_dbg(dev, state, "completing class "); |
642 | if (dev->class->pm->complete) | ||
643 | dev->class->pm->complete(dev); | ||
644 | } else if (dev->bus && dev->bus->pm) { | ||
643 | pm_dev_dbg(dev, state, "completing "); | 645 | pm_dev_dbg(dev, state, "completing "); |
644 | dev->bus->pm->complete(dev); | 646 | if (dev->bus->pm->complete) |
647 | dev->bus->pm->complete(dev); | ||
645 | } | 648 | } |
646 | 649 | ||
647 | device_unlock(dev); | 650 | device_unlock(dev); |
@@ -669,7 +672,6 @@ static void dpm_complete(pm_message_t state) | |||
669 | mutex_unlock(&dpm_list_mtx); | 672 | mutex_unlock(&dpm_list_mtx); |
670 | 673 | ||
671 | device_complete(dev, state); | 674 | device_complete(dev, state); |
672 | pm_runtime_put_sync(dev); | ||
673 | 675 | ||
674 | mutex_lock(&dpm_list_mtx); | 676 | mutex_lock(&dpm_list_mtx); |
675 | put_device(dev); | 677 | put_device(dev); |
@@ -727,29 +729,31 @@ static pm_message_t resume_event(pm_message_t sleep_state) | |||
727 | */ | 729 | */ |
728 | static int device_suspend_noirq(struct device *dev, pm_message_t state) | 730 | static int device_suspend_noirq(struct device *dev, pm_message_t state) |
729 | { | 731 | { |
730 | int error = 0; | 732 | int error; |
731 | |||
732 | if (dev->class && dev->class->pm) { | ||
733 | pm_dev_dbg(dev, state, "LATE class "); | ||
734 | error = pm_noirq_op(dev, dev->class->pm, state); | ||
735 | if (error) | ||
736 | goto End; | ||
737 | } | ||
738 | 733 | ||
739 | if (dev->type && dev->type->pm) { | 734 | if (dev->type && dev->type->pm) { |
740 | pm_dev_dbg(dev, state, "LATE type "); | 735 | pm_dev_dbg(dev, state, "LATE type "); |
741 | error = pm_noirq_op(dev, dev->type->pm, state); | 736 | error = pm_noirq_op(dev, dev->type->pm, state); |
742 | if (error) | 737 | if (error) |
743 | goto End; | 738 | return error; |
744 | } | 739 | } else if (dev->class && dev->class->pm) { |
745 | 740 | pm_dev_dbg(dev, state, "LATE class "); | |
746 | if (dev->bus && dev->bus->pm) { | 741 | error = pm_noirq_op(dev, dev->class->pm, state); |
742 | if (error) | ||
743 | return error; | ||
744 | } else if (dev->bus && dev->bus->pm) { | ||
747 | pm_dev_dbg(dev, state, "LATE "); | 745 | pm_dev_dbg(dev, state, "LATE "); |
748 | error = pm_noirq_op(dev, dev->bus->pm, state); | 746 | error = pm_noirq_op(dev, dev->bus->pm, state); |
747 | if (error) | ||
748 | return error; | ||
749 | } | 749 | } |
750 | 750 | ||
751 | End: | 751 | if (dev->pwr_domain) { |
752 | return error; | 752 | pm_dev_dbg(dev, state, "LATE power domain "); |
753 | pm_noirq_op(dev, &dev->pwr_domain->ops, state); | ||
754 | } | ||
755 | |||
756 | return 0; | ||
753 | } | 757 | } |
754 | 758 | ||
755 | /** | 759 | /** |
@@ -836,25 +840,22 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
836 | goto End; | 840 | goto End; |
837 | } | 841 | } |
838 | 842 | ||
843 | if (dev->type && dev->type->pm) { | ||
844 | pm_dev_dbg(dev, state, "type "); | ||
845 | error = pm_op(dev, dev->type->pm, state); | ||
846 | goto Domain; | ||
847 | } | ||
848 | |||
839 | if (dev->class) { | 849 | if (dev->class) { |
840 | if (dev->class->pm) { | 850 | if (dev->class->pm) { |
841 | pm_dev_dbg(dev, state, "class "); | 851 | pm_dev_dbg(dev, state, "class "); |
842 | error = pm_op(dev, dev->class->pm, state); | 852 | error = pm_op(dev, dev->class->pm, state); |
853 | goto Domain; | ||
843 | } else if (dev->class->suspend) { | 854 | } else if (dev->class->suspend) { |
844 | pm_dev_dbg(dev, state, "legacy class "); | 855 | pm_dev_dbg(dev, state, "legacy class "); |
845 | error = legacy_suspend(dev, state, dev->class->suspend); | 856 | error = legacy_suspend(dev, state, dev->class->suspend); |
857 | goto Domain; | ||
846 | } | 858 | } |
847 | if (error) | ||
848 | goto End; | ||
849 | } | ||
850 | |||
851 | if (dev->type) { | ||
852 | if (dev->type->pm) { | ||
853 | pm_dev_dbg(dev, state, "type "); | ||
854 | error = pm_op(dev, dev->type->pm, state); | ||
855 | } | ||
856 | if (error) | ||
857 | goto End; | ||
858 | } | 859 | } |
859 | 860 | ||
860 | if (dev->bus) { | 861 | if (dev->bus) { |
@@ -867,6 +868,12 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) | |||
867 | } | 868 | } |
868 | } | 869 | } |
869 | 870 | ||
871 | Domain: | ||
872 | if (!error && dev->pwr_domain) { | ||
873 | pm_dev_dbg(dev, state, "power domain "); | ||
874 | pm_op(dev, &dev->pwr_domain->ops, state); | ||
875 | } | ||
876 | |||
870 | End: | 877 | End: |
871 | device_unlock(dev); | 878 | device_unlock(dev); |
872 | complete_all(&dev->power.completion); | 879 | complete_all(&dev->power.completion); |
@@ -957,27 +964,34 @@ static int device_prepare(struct device *dev, pm_message_t state) | |||
957 | 964 | ||
958 | device_lock(dev); | 965 | device_lock(dev); |
959 | 966 | ||
960 | if (dev->bus && dev->bus->pm && dev->bus->pm->prepare) { | 967 | if (dev->type && dev->type->pm) { |
968 | pm_dev_dbg(dev, state, "preparing type "); | ||
969 | if (dev->type->pm->prepare) | ||
970 | error = dev->type->pm->prepare(dev); | ||
971 | suspend_report_result(dev->type->pm->prepare, error); | ||
972 | if (error) | ||
973 | goto End; | ||
974 | } else if (dev->class && dev->class->pm) { | ||
975 | pm_dev_dbg(dev, state, "preparing class "); | ||
976 | if (dev->class->pm->prepare) | ||
977 | error = dev->class->pm->prepare(dev); | ||
978 | suspend_report_result(dev->class->pm->prepare, error); | ||
979 | if (error) | ||
980 | goto End; | ||
981 | } else if (dev->bus && dev->bus->pm) { | ||
961 | pm_dev_dbg(dev, state, "preparing "); | 982 | pm_dev_dbg(dev, state, "preparing "); |
962 | error = dev->bus->pm->prepare(dev); | 983 | if (dev->bus->pm->prepare) |
984 | error = dev->bus->pm->prepare(dev); | ||
963 | suspend_report_result(dev->bus->pm->prepare, error); | 985 | suspend_report_result(dev->bus->pm->prepare, error); |
964 | if (error) | 986 | if (error) |
965 | goto End; | 987 | goto End; |
966 | } | 988 | } |
967 | 989 | ||
968 | if (dev->type && dev->type->pm && dev->type->pm->prepare) { | 990 | if (dev->pwr_domain && dev->pwr_domain->ops.prepare) { |
969 | pm_dev_dbg(dev, state, "preparing type "); | 991 | pm_dev_dbg(dev, state, "preparing power domain "); |
970 | error = dev->type->pm->prepare(dev); | 992 | dev->pwr_domain->ops.prepare(dev); |
971 | suspend_report_result(dev->type->pm->prepare, error); | ||
972 | if (error) | ||
973 | goto End; | ||
974 | } | 993 | } |
975 | 994 | ||
976 | if (dev->class && dev->class->pm && dev->class->pm->prepare) { | ||
977 | pm_dev_dbg(dev, state, "preparing class "); | ||
978 | error = dev->class->pm->prepare(dev); | ||
979 | suspend_report_result(dev->class->pm->prepare, error); | ||
980 | } | ||
981 | End: | 995 | End: |
982 | device_unlock(dev); | 996 | device_unlock(dev); |
983 | 997 | ||
@@ -1005,12 +1019,9 @@ static int dpm_prepare(pm_message_t state) | |||
1005 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) | 1019 | if (pm_runtime_barrier(dev) && device_may_wakeup(dev)) |
1006 | pm_wakeup_event(dev, 0); | 1020 | pm_wakeup_event(dev, 0); |
1007 | 1021 | ||
1008 | if (pm_wakeup_pending()) { | 1022 | pm_runtime_put_sync(dev); |
1009 | pm_runtime_put_sync(dev); | 1023 | error = pm_wakeup_pending() ? |
1010 | error = -EBUSY; | 1024 | -EBUSY : device_prepare(dev, state); |
1011 | } else { | ||
1012 | error = device_prepare(dev, state); | ||
1013 | } | ||
1014 | 1025 | ||
1015 | mutex_lock(&dpm_list_mtx); | 1026 | mutex_lock(&dpm_list_mtx); |
1016 | if (error) { | 1027 | if (error) { |