Skip to content

Commit 6895ea5

Browse files
Sandeep Maheswaramgregkh
authored andcommitted
usb: dwc3: qcom: Configure wakeup interrupts during suspend
Configure DP/DM line interrupts based on the USB2 device attached to the root hub port. When HS/FS device is connected, configure the DP line as falling edge to detect both disconnect and remote wakeup scenarios. When LS device is connected, configure DM line as falling edge to detect both disconnect and remote wakeup. When no device is connected, configure both DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. Reviewed-by: Pavankumar Kondeti <[email protected]> Reviewed-by: Matthias Kaehlcke <[email protected]> Signed-off-by: Sandeep Maheswaram <[email protected]> Signed-off-by: Krishna Kurapati <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 360e823 commit 6895ea5

File tree

1 file changed

+62
-10
lines changed

1 file changed

+62
-10
lines changed

drivers/usb/dwc3/dwc3-qcom.c

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#include <linux/usb/of.h>
2121
#include <linux/reset.h>
2222
#include <linux/iopoll.h>
23-
23+
#include <linux/usb/hcd.h>
24+
#include <linux/usb.h>
2425
#include "core.h"
2526

2627
/* USB QSCRATCH Hardware registers */
@@ -76,6 +77,7 @@ struct dwc3_qcom {
7677
int dp_hs_phy_irq;
7778
int dm_hs_phy_irq;
7879
int ss_phy_irq;
80+
enum usb_device_speed usb2_speed;
7981

8082
struct extcon_dev *edev;
8183
struct extcon_dev *host_edev;
@@ -296,11 +298,34 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
296298
icc_put(qcom->icc_path_apps);
297299
}
298300

299-
static void dwc3_qcom_enable_wakeup_irq(int irq)
301+
static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
302+
{
303+
struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
304+
struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci);
305+
struct usb_device *udev;
306+
307+
/*
308+
* It is possible to query the speed of all children of
309+
* USB2.0 root hub via usb_hub_for_each_child(). DWC3 code
310+
* currently supports only 1 port per controller. So
311+
* this is sufficient.
312+
*/
313+
udev = usb_hub_find_child(hcd->self.root_hub, 1);
314+
315+
if (!udev)
316+
return USB_SPEED_UNKNOWN;
317+
318+
return udev->speed;
319+
}
320+
321+
static void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity)
300322
{
301323
if (!irq)
302324
return;
303325

326+
if (polarity)
327+
irq_set_irq_type(irq, polarity);
328+
304329
enable_irq(irq);
305330
enable_irq_wake(irq);
306331
}
@@ -318,22 +343,47 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
318343
{
319344
dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq);
320345

321-
dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
322-
323-
dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
346+
if (qcom->usb2_speed == USB_SPEED_LOW) {
347+
dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
348+
} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
349+
(qcom->usb2_speed == USB_SPEED_FULL)) {
350+
dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
351+
} else {
352+
dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
353+
dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
354+
}
324355

325356
dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq);
326357
}
327358

328359
static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
329360
{
330-
dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq);
361+
dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq, 0);
331362

332-
dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq);
363+
/*
364+
* Configure DP/DM line interrupts based on the USB2 device attached to
365+
* the root hub port. When HS/FS device is connected, configure the DP line
366+
* as falling edge to detect both disconnect and remote wakeup scenarios. When
367+
* LS device is connected, configure DM line as falling edge to detect both
368+
* disconnect and remote wakeup. When no device is connected, configure both
369+
* DP and DM lines as rising edge to detect HS/HS/LS device connect scenario.
370+
*/
333371

334-
dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq);
372+
if (qcom->usb2_speed == USB_SPEED_LOW) {
373+
dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
374+
IRQ_TYPE_EDGE_FALLING);
375+
} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
376+
(qcom->usb2_speed == USB_SPEED_FULL)) {
377+
dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
378+
IRQ_TYPE_EDGE_FALLING);
379+
} else {
380+
dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
381+
IRQ_TYPE_EDGE_RISING);
382+
dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
383+
IRQ_TYPE_EDGE_RISING);
384+
}
335385

336-
dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq);
386+
dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
337387
}
338388

339389
static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
@@ -355,8 +405,10 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
355405
if (ret)
356406
dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
357407

358-
if (device_may_wakeup(qcom->dev))
408+
if (device_may_wakeup(qcom->dev)) {
409+
qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom);
359410
dwc3_qcom_enable_interrupts(qcom);
411+
}
360412

361413
qcom->is_suspended = true;
362414

0 commit comments

Comments
 (0)