Skip to content

Commit

Permalink
usb: dwc3-am62: Add support for system wakeup based on USB events
Browse files Browse the repository at this point in the history
The USB2SS IP in TI's AM62 SoC is capable of supporting wakeup from
deep sleep based on the following events,

1) VBUS state change
2) Overcurrent detection
3) Line state change

Wakeup from these events can enabled by setting their corresponding bits
in the WAKEUP_CONFIG register. The events to be enabled are decided based
on the current role of the controller.

When the role of the controller is host, the comparators for detecting
VBUS state change are disabled while entering low power mode. This is done
as VBUS state is not used in host mode and disabling the comparators helps
in reducing the power consumption. So, wakeup from VBUS state change should
be disabled in host mode. While operating in peripheral mode all the wakeup
events can be enabled.

Therefore, add support for the same in the suspend/resume hooks.

Signed-off-by: Aswath Govindraju <[email protected]>
Signed-off-by: Roger Quadros <[email protected]>
Acked-by: Thinh Nguyen <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Aswath-Govindraju authored and gregkh committed Mar 23, 2023
1 parent a33113f commit 84364a0
Showing 1 changed file with 39 additions and 0 deletions.
39 changes: 39 additions & 0 deletions drivers/usb/dwc3/dwc3-am62.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <linux/regmap.h>
#include <linux/pinctrl/consumer.h>

#include "core.h"

/* USB WRAPPER register offsets */
#define USBSS_PID 0x0
#define USBSS_OVERCURRENT_CTRL 0x4
Expand Down Expand Up @@ -45,6 +47,10 @@
#define USBSS_PHY_VBUS_SEL_SHIFT 1
#define USBSS_PHY_LANE_REVERSE BIT(0)

/* CORE STAT register bits */
#define USBSS_CORE_OPERATIONAL_MODE_MASK GENMASK(13, 12)
#define USBSS_CORE_OPERATIONAL_MODE_SHIFT 12

/* MODE CONTROL register bits */
#define USBSS_MODE_VALID BIT(0)

Expand Down Expand Up @@ -233,6 +239,9 @@ static int dwc3_ti_probe(struct platform_device *pdev)
reg |= USBSS_MODE_VALID;
dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg);

/* Device has capability to wakeup system from sleep */
device_set_wakeup_capable(dev, true);

/* Setting up autosuspend */
pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
Expand Down Expand Up @@ -281,6 +290,22 @@ static int dwc3_ti_remove(struct platform_device *pdev)
static int dwc3_ti_suspend_common(struct device *dev)
{
struct dwc3_data *data = dev_get_drvdata(dev);
u32 reg, current_prtcap_dir;

if (device_may_wakeup(dev)) {
reg = dwc3_ti_readl(data, USBSS_CORE_STAT);
current_prtcap_dir = (reg & USBSS_CORE_OPERATIONAL_MODE_MASK)
>> USBSS_CORE_OPERATIONAL_MODE_SHIFT;
/* Set wakeup config enable bits */
reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG);
if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) {
reg |= USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN;
} else {
reg |= USBSS_WAKEUP_CFG_OVERCURRENT_EN | USBSS_WAKEUP_CFG_LINESTATE_EN |
USBSS_WAKEUP_CFG_VBUSVALID_EN;
}
dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg);
}

clk_disable_unprepare(data->usb2_refclk);

Expand All @@ -290,9 +315,23 @@ static int dwc3_ti_suspend_common(struct device *dev)
static int dwc3_ti_resume_common(struct device *dev)
{
struct dwc3_data *data = dev_get_drvdata(dev);
u32 reg;

clk_prepare_enable(data->usb2_refclk);

if (device_may_wakeup(dev)) {
/* Clear wakeup config enable bits */
reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG);
reg &= ~(USBSS_WAKEUP_CFG_OVERCURRENT_EN | USBSS_WAKEUP_CFG_LINESTATE_EN |
USBSS_WAKEUP_CFG_VBUSVALID_EN);
dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg);
}

reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT);
/* Clear the wakeup status with wakeup clear bit */
reg |= USBSS_WAKEUP_STAT_CLR;
dwc3_ti_writel(data, USBSS_WAKEUP_STAT, reg);

return 0;
}

Expand Down

0 comments on commit 84364a0

Please sign in to comment.