diff options
author | Tony Lindgren <tony@atomide.com> | 2018-04-16 13:27:15 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2018-05-01 09:54:17 -0400 |
commit | ef55f8215a78b7021401281e8a7fe056fd5ecdab (patch) | |
tree | 14c9515feead56c22ebcf86be4f635ecc9e79647 /drivers/bus | |
parent | e7420c2d4495cbb9c14dd8bf8b3b4e5bdded6e20 (diff) |
bus: ti-sysc: Improve suspend and resume handling
Based on testing with more devices I noticed that some devices
don't suspend or resume properly. We need to PM runtime suspend
and resume devices if we have ddata->needs_resume set.
Let's also improve the error handling and add few debug statements
to make it easier to notice suspend and resume related issues if
DEBUG is set.
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'drivers/bus')
-rw-r--r-- | drivers/bus/ti-sysc.c | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 1f90b91dbfae..145dcc0cf48c 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c | |||
@@ -662,6 +662,7 @@ awake: | |||
662 | static int sysc_suspend(struct device *dev) | 662 | static int sysc_suspend(struct device *dev) |
663 | { | 663 | { |
664 | struct sysc *ddata; | 664 | struct sysc *ddata; |
665 | int error; | ||
665 | 666 | ||
666 | ddata = dev_get_drvdata(dev); | 667 | ddata = dev_get_drvdata(dev); |
667 | 668 | ||
@@ -672,14 +673,27 @@ static int sysc_suspend(struct device *dev) | |||
672 | if (!ddata->enabled) | 673 | if (!ddata->enabled) |
673 | return 0; | 674 | return 0; |
674 | 675 | ||
676 | dev_dbg(ddata->dev, "%s %s\n", __func__, | ||
677 | ddata->name ? ddata->name : ""); | ||
678 | |||
679 | error = pm_runtime_put_sync_suspend(dev); | ||
680 | if (error < 0) { | ||
681 | dev_warn(ddata->dev, "%s not idle %i %s\n", | ||
682 | __func__, error, | ||
683 | ddata->name ? ddata->name : ""); | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
675 | ddata->needs_resume = true; | 688 | ddata->needs_resume = true; |
676 | 689 | ||
677 | return sysc_runtime_suspend(dev); | 690 | return 0; |
678 | } | 691 | } |
679 | 692 | ||
680 | static int sysc_resume(struct device *dev) | 693 | static int sysc_resume(struct device *dev) |
681 | { | 694 | { |
682 | struct sysc *ddata; | 695 | struct sysc *ddata; |
696 | int error; | ||
683 | 697 | ||
684 | ddata = dev_get_drvdata(dev); | 698 | ddata = dev_get_drvdata(dev); |
685 | 699 | ||
@@ -691,9 +705,16 @@ static int sysc_resume(struct device *dev) | |||
691 | dev_dbg(ddata->dev, "%s %s\n", __func__, | 705 | dev_dbg(ddata->dev, "%s %s\n", __func__, |
692 | ddata->name ? ddata->name : ""); | 706 | ddata->name ? ddata->name : ""); |
693 | 707 | ||
694 | ddata->needs_resume = false; | 708 | error = pm_runtime_get_sync(dev); |
709 | if (error < 0) { | ||
710 | dev_err(ddata->dev, "%s error %i %s\n", | ||
711 | __func__, error, | ||
712 | ddata->name ? ddata->name : ""); | ||
695 | 713 | ||
696 | return sysc_runtime_resume(dev); | 714 | return error; |
715 | } | ||
716 | |||
717 | ddata->needs_resume = false; | ||
697 | } | 718 | } |
698 | 719 | ||
699 | return 0; | 720 | return 0; |
@@ -735,6 +756,9 @@ static int sysc_noirq_resume(struct device *dev) | |||
735 | return 0; | 756 | return 0; |
736 | 757 | ||
737 | if (ddata->needs_resume) { | 758 | if (ddata->needs_resume) { |
759 | dev_dbg(ddata->dev, "%s %s\n", __func__, | ||
760 | ddata->name ? ddata->name : ""); | ||
761 | |||
738 | ddata->needs_resume = false; | 762 | ddata->needs_resume = false; |
739 | 763 | ||
740 | return sysc_runtime_resume(dev); | 764 | return sysc_runtime_resume(dev); |
@@ -1069,18 +1093,33 @@ static int sysc_child_suspend_noirq(struct device *dev) | |||
1069 | 1093 | ||
1070 | ddata = sysc_child_to_parent(dev); | 1094 | ddata = sysc_child_to_parent(dev); |
1071 | 1095 | ||
1096 | dev_dbg(ddata->dev, "%s %s\n", __func__, | ||
1097 | ddata->name ? ddata->name : ""); | ||
1098 | |||
1072 | error = pm_generic_suspend_noirq(dev); | 1099 | error = pm_generic_suspend_noirq(dev); |
1073 | if (error) | 1100 | if (error) { |
1101 | dev_err(dev, "%s error at %i: %i\n", | ||
1102 | __func__, __LINE__, error); | ||
1103 | |||
1074 | return error; | 1104 | return error; |
1105 | } | ||
1075 | 1106 | ||
1076 | if (!pm_runtime_status_suspended(dev)) { | 1107 | if (!pm_runtime_status_suspended(dev)) { |
1077 | error = pm_generic_runtime_suspend(dev); | 1108 | error = pm_generic_runtime_suspend(dev); |
1078 | if (error) | 1109 | if (error) { |
1110 | dev_err(dev, "%s error at %i: %i\n", | ||
1111 | __func__, __LINE__, error); | ||
1112 | |||
1079 | return error; | 1113 | return error; |
1114 | } | ||
1080 | 1115 | ||
1081 | error = sysc_runtime_suspend(ddata->dev); | 1116 | error = sysc_runtime_suspend(ddata->dev); |
1082 | if (error) | 1117 | if (error) { |
1118 | dev_err(dev, "%s error at %i: %i\n", | ||
1119 | __func__, __LINE__, error); | ||
1120 | |||
1083 | return error; | 1121 | return error; |
1122 | } | ||
1084 | 1123 | ||
1085 | ddata->child_needs_resume = true; | 1124 | ddata->child_needs_resume = true; |
1086 | } | 1125 | } |
@@ -1095,6 +1134,9 @@ static int sysc_child_resume_noirq(struct device *dev) | |||
1095 | 1134 | ||
1096 | ddata = sysc_child_to_parent(dev); | 1135 | ddata = sysc_child_to_parent(dev); |
1097 | 1136 | ||
1137 | dev_dbg(ddata->dev, "%s %s\n", __func__, | ||
1138 | ddata->name ? ddata->name : ""); | ||
1139 | |||
1098 | if (ddata->child_needs_resume) { | 1140 | if (ddata->child_needs_resume) { |
1099 | ddata->child_needs_resume = false; | 1141 | ddata->child_needs_resume = false; |
1100 | 1142 | ||