aboutsummaryrefslogtreecommitdiff
path: root/m_suspend
blob: 21e88d359acd2cabc47b42025320ea7490eb767c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
commit af71d9fec37585c4a5e89efc38dfdc4214e9ec1e
Author: Ravi Vembu <raviv@motorola.com>
Date:   Wed Jun 8 11:31:33 2016 -0500

    IKSWM-43690: dwc3-msm: Fix racy suspend/resume on dwc3.
    
    The dwc3 msm suspend/resume routines are called from the pm
    work queue, but there is also a path for the resume to be triggered
    from the dwc3 driver. This can cause the clocks to be left on if
    there are multiple resumes followed by a suspend since the clock
    enable/disable's aren't balanced. Add a mutex around the suspend/
    resume routines.
    
    Change-Id: Idfdcb5152b02171246b16a8b24b17590015a6cf7
    Signed-off-by: Ravi Vembu <raviv@motorola.com>
    Reviewed-on: http://gerrit.mot.com/865202
    SME-Granted: SME Approvals Granted
    SLTApproved: Slta Waiver <sltawvr@motorola.com>
    Tested-by: Jira Key <jirakey@motorola.com>
    Reviewed-by: Ravi Chebolu <arc095@motorola.com>
    Submit-Approved: Jira Key <jirakey@motorola.com>

diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index d320d1b..2a4576b 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -259,6 +259,7 @@ struct dwc3_msm {
 	int			otg_fault_irq;
 	enum power_supply_usb_priority usb_priority;
 	bool			ss_compliance;
+	struct mutex		pm_lock;
 };
 
 #define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -1990,10 +1991,14 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 	bool can_suspend_ssphy;
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
-	dbg_event(dwc->ctrl_num, 0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm));
+
+	dbg_event(dwc->ctrl_num, 0xFF, "Ctl Sus Strt", atomic_read(&dwc->in_lpm));
+	mutex_lock(&mdwc->pm_lock);
 
 	if (atomic_read(&dwc->in_lpm)) {
 		dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
+		dbg_event(dwc->ctrl_num, 0xFF, "Ctl Alr Sus", 0);
+		mutex_unlock(&mdwc->pm_lock);
 		return 0;
 	}
 
@@ -2008,6 +2013,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 				dbg_print_reg(dwc->ctrl_num,
 						"PENDING DEVICE EVENT",
 						*(u32 *)(evt->buf + evt->lpos));
+				mutex_unlock(&mdwc->pm_lock);
 				return -EBUSY;
 			}
 		}
@@ -2027,6 +2033,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 		dev_dbg(mdwc->dev,
 			"%s: cable disconnected while not in idle otg state\n",
 			__func__);
+		dbg_event(dwc->ctrl_num, 0xFF, "Sus Abrt 1", 0);
+		mutex_unlock(&mdwc->pm_lock);
 		return -EBUSY;
 	}
 
@@ -2040,12 +2048,17 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 		pr_err("%s(): Trying to go in LPM with state:%d\n",
 					__func__, dwc->gadget.state);
 		pr_err("%s(): LPM is not performed.\n", __func__);
+		dbg_event(dwc->ctrl_num, 0xFF, "Sus Abrt 2", 0);
+		mutex_unlock(&mdwc->pm_lock);
 		return -EBUSY;
 	}
 
 	ret = dwc3_msm_prepare_suspend(mdwc);
-	if (ret)
+	if (ret) {
+		dbg_event(dwc->ctrl_num, 0xFF, "Sus Abrt 3", 0);
+		mutex_unlock(&mdwc->pm_lock);
 		return ret;
+	}
 
 	/* Initialize variables here */
 	can_suspend_ssphy = !(mdwc->in_host_mode &&
@@ -2144,6 +2157,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
 	}
 
 	dev_info(mdwc->dev, "DWC3 in low power mode\n");
+	dbg_event(dwc->ctrl_num, 0xFF, "Ctl Sus End", 0);
+	mutex_unlock(&mdwc->pm_lock);
 	return 0;
 }
 
@@ -2153,9 +2168,13 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
 	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
 
 	dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
+	dbg_event(dwc->ctrl_num, 0xFF, "Ctl Res Strt", 0);
+	mutex_lock(&mdwc->pm_lock);
 
 	if (!atomic_read(&dwc->in_lpm)) {
 		dev_dbg(mdwc->dev, "%s: Already resumed\n", __func__);
+		dbg_event(dwc->ctrl_num, 0xFF, "Ctl Alr Res", 0);
+		mutex_unlock(&mdwc->pm_lock);
 		return 0;
 	}
 
@@ -2259,7 +2278,8 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
 	 */
 	dwc3_pwr_event_handler(mdwc);
 
-	dbg_event(dwc->ctrl_num, 0xFF, "Ctl Res", atomic_read(&dwc->in_lpm));
+	dbg_event(dwc->ctrl_num, 0xFF, "Ctl Res End", atomic_read(&dwc->in_lpm));
+	mutex_unlock(&mdwc->pm_lock);
 
 	return 0;
 }
@@ -3000,6 +3020,7 @@ static int dwc3_msm_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, mdwc);
 	mdwc->dev = &pdev->dev;
 
+	mutex_init(&mdwc->pm_lock);
 	INIT_LIST_HEAD(&mdwc->req_complete_list);
 	INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
 	INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);