diff mbox series

[v2,08/12] phy: tegra: xusb: t210: support wake and sleepwalk

Message ID 20200831044043.1561074-9-jckuo@nvidia.com (mailing list archive)
State Superseded
Headers show
Series Tegra XHCI controller ELPG support | expand

Commit Message

JC Kuo Aug. 31, 2020, 4:40 a.m. UTC
This commit implements Tegra210 XUSB PADCTL wake and sleepwalk
routines. Sleepwalk logic is in PMC (always-on) hardware block.
PMC driver provides managed access to the sleepwalk registers
via regmap framework.

Signed-off-by: JC Kuo <jckuo@nvidia.com>
---
 drivers/phy/tegra/xusb-tegra210.c | 1094 ++++++++++++++++++++++++++++-
 1 file changed, 1079 insertions(+), 15 deletions(-)

Comments

Thierry Reding Aug. 31, 2020, 12:37 p.m. UTC | #1
On Mon, Aug 31, 2020 at 12:40:39PM +0800, JC Kuo wrote:
> This commit implements Tegra210 XUSB PADCTL wake and sleepwalk
> routines. Sleepwalk logic is in PMC (always-on) hardware block.
> PMC driver provides managed access to the sleepwalk registers
> via regmap framework.
> 
> Signed-off-by: JC Kuo <jckuo@nvidia.com>
> ---
>  drivers/phy/tegra/xusb-tegra210.c | 1094 ++++++++++++++++++++++++++++-
>  1 file changed, 1079 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
> index fe1ab440424d..1c03f4ec4b59 100644
> --- a/drivers/phy/tegra/xusb-tegra210.c
> +++ b/drivers/phy/tegra/xusb-tegra210.c
> @@ -16,6 +16,8 @@
>  #include <linux/regulator/consumer.h>
>  #include <linux/reset.h>
>  #include <linux/slab.h>
> +#include <linux/regmap.h>
> +#include <linux/of_platform.h>
>  
>  #include <soc/tegra/fuse.h>
>  
> @@ -52,6 +54,20 @@
>  #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
>  #define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
>  
> +#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
> +#define   USB2_PORT_WAKE_INTERRUPT_ENABLE(x)      BIT((x))
> +#define   USB2_PORT_WAKEUP_EVENT(x)               BIT((x) + 7)
> +#define   SS_PORT_WAKE_INTERRUPT_ENABLE(x)        BIT((x) + 14)
> +#define   SS_PORT_WAKEUP_EVENT(x)                 BIT((x) + 21)
> +#define   USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
> +#define   USB2_HSIC_PORT_WAKEUP_EVENT(x)          BIT((x) + 30)
> +#define   ALL_WAKE_EVENTS ( \
> +		USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
> +		USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
> +		SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
> +		SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
> +		USB2_HSIC_PORT_WAKEUP_EVENT(0))
> +
>  #define XUSB_PADCTL_ELPG_PROGRAM1 0x024
>  #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
>  #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
> @@ -90,6 +106,8 @@
>  #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
>  #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
>  #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
> +#define   RPD_CTRL(x)                      (((x) & 0x1f) << 26)
> +#define   RPD_CTRL_VALUE(x)                (((x) >> 26) & 0x1f)
>  
>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
> @@ -108,6 +126,8 @@
>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
> +#define   TCTRL_VALUE(x)                (((x) & 0x3f) >> 0)
> +#define   PCTRL_VALUE(x)                (((x) >> 6) & 0x3f)
>  
>  #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
>  #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
> @@ -251,16 +271,161 @@
>  #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
>  #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
>  
> +/* USB2 SLEEPWALK registers */
> +#define UTMIP(_port, _offset1, _offset2) \
> +		(((_port) <= 2) ? (_offset1) : (_offset2))
> +
> +#define PMC_UTMIP_UHSIC_SLEEP_CFG(x)	UTMIP(x, 0x1fc, 0x4d0)
> +#define   UTMIP_MASTER_ENABLE(x)		UTMIP(x, BIT(8 * (x)), BIT(0))
> +#define   UTMIP_FSLS_USE_PMC(x)			UTMIP(x, BIT(8 * (x) + 1), \
> +							BIT(1))
> +#define   UTMIP_PCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 2), \
> +							BIT(2))
> +#define   UTMIP_TCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 3), \
> +							BIT(3))
> +#define   UTMIP_WAKE_VAL(_port, _value)		(((_value) & 0xf) << \
> +					(UTMIP(_port, 8 * (_port) + 4, 4)))
> +#define   UTMIP_WAKE_VAL_NONE(_port)		UTMIP_WAKE_VAL(_port, 12)
> +#define   UTMIP_WAKE_VAL_ANY(_port)		UTMIP_WAKE_VAL(_port, 15)
> +
> +#define PMC_UTMIP_UHSIC_SLEEP_CFG1	(0x4d0)
> +#define   UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x)	BIT((x) + 8)
> +#define   UTMIP_RPD_CTRL_USE_PMC_PX(x)		BIT((x) + 16)
> +
> +#define PMC_UTMIP_MASTER_CONFIG		(0x274)
> +#define   UTMIP_PWR(x)				UTMIP(x, BIT(x), BIT(4))
> +#define   UHSIC_PWR(x)				BIT(3)
> +
> +#define PMC_USB_DEBOUNCE_DEL		(0xec)
> +#define   DEBOUNCE_VAL(x)			(((x) & 0xffff) << 0)
> +#define   UTMIP_LINE_DEB_CNT(x)			(((x) & 0xf) << 16)
> +#define   UHSIC_LINE_DEB_CNT(x)			(((x) & 0xf) << 20)
> +
> +#define PMC_UTMIP_UHSIC_FAKE(x)		UTMIP(x, 0x218, 0x294)
> +#define   UTMIP_FAKE_USBOP_VAL(x)		UTMIP(x, BIT(4 * (x)), BIT(8))
> +#define   UTMIP_FAKE_USBON_VAL(x)		UTMIP(x, BIT(4 * (x) + 1), \
> +							BIT(9))
> +#define   UTMIP_FAKE_USBOP_EN(x)		UTMIP(x, BIT(4 * (x) + 2), \
> +							BIT(10))
> +#define   UTMIP_FAKE_USBON_EN(x)		UTMIP(x, BIT(4 * (x) + 3), \
> +							BIT(11))
> +
> +#define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x)	UTMIP(x, 0x200, 0x288)
> +#define   UTMIP_LINEVAL_WALK_EN(x)		UTMIP(x, BIT(8 * (x) + 7), \
> +							BIT(15))
> +
> +#define PMC_USB_AO			(0xf0)
> +#define   USBOP_VAL_PD(x)			UTMIP(x, BIT(4 * (x)), BIT(20))
> +#define   USBON_VAL_PD(x)			UTMIP(x, BIT(4 * (x) + 1), \
> +							BIT(21))
> +#define   STROBE_VAL_PD(x)			BIT(12)
> +#define   DATA0_VAL_PD(x)			BIT(13)
> +#define   DATA1_VAL_PD				BIT(24)
> +
> +#define PMC_UTMIP_UHSIC_SAVED_STATE(x)	UTMIP(x, 0x1f0, 0x280)
> +#define   SPEED(_port, _value)			(((_value) & 0x3) << \
> +						(UTMIP(_port, 8 * (_port), 8)))
> +#define   UTMI_HS(_port)			SPEED(_port, 0)
> +#define   UTMI_FS(_port)			SPEED(_port, 1)
> +#define   UTMI_LS(_port)			SPEED(_port, 2)
> +#define   UTMI_RST(_port)			SPEED(_port, 3)
> +
> +#define PMC_UTMIP_UHSIC_TRIGGERS		(0x1ec)
> +#define   UTMIP_CLR_WALK_PTR(x)			UTMIP(x, BIT(x), BIT(16))
> +#define   UTMIP_CAP_CFG(x)			UTMIP(x, BIT((x) + 4), BIT(17))
> +#define   UTMIP_CLR_WAKE_ALARM(x)		UTMIP(x, BIT((x) + 12), \
> +							BIT(19))
> +#define   UHSIC_CLR_WALK_PTR			BIT(3)
> +#define   UHSIC_CLR_WAKE_ALARM			BIT(15)
> +
> +#define PMC_UTMIP_SLEEPWALK_PX(x)	UTMIP(x, 0x204 + (4 * (x)), \
> +							0x4e0)
> +/* phase A */
> +#define   UTMIP_USBOP_RPD_A			BIT(0)
> +#define   UTMIP_USBON_RPD_A			BIT(1)
> +#define   UTMIP_AP_A				BIT(4)
> +#define   UTMIP_AN_A				BIT(5)
> +#define   UTMIP_HIGHZ_A				BIT(6)
> +/* phase B */
> +#define   UTMIP_USBOP_RPD_B			BIT(8)
> +#define   UTMIP_USBON_RPD_B			BIT(9)
> +#define   UTMIP_AP_B				BIT(12)
> +#define   UTMIP_AN_B				BIT(13)
> +#define   UTMIP_HIGHZ_B				BIT(14)
> +/* phase C */
> +#define   UTMIP_USBOP_RPD_C			BIT(16)
> +#define   UTMIP_USBON_RPD_C			BIT(17)
> +#define   UTMIP_AP_C				BIT(20)
> +#define   UTMIP_AN_C				BIT(21)
> +#define   UTMIP_HIGHZ_C				BIT(22)
> +/* phase D */
> +#define   UTMIP_USBOP_RPD_D			BIT(24)
> +#define   UTMIP_USBON_RPD_D			BIT(25)
> +#define   UTMIP_AP_D				BIT(28)
> +#define   UTMIP_AN_D				BIT(29)
> +#define   UTMIP_HIGHZ_D				BIT(30)
> +
> +#define PMC_UTMIP_UHSIC_LINE_WAKEUP	(0x26c)
> +#define   UTMIP_LINE_WAKEUP_EN(x)		UTMIP(x, BIT(x), BIT(4))
> +#define   UHSIC_LINE_WAKEUP_EN			BIT(3)
> +
> +#define PMC_UTMIP_TERM_PAD_CFG		(0x1f8)
> +#define   PCTRL_VAL(x)				(((x) & 0x3f) << 1)
> +#define   TCTRL_VAL(x)				(((x) & 0x3f) << 7)
> +
> +#define PMC_UTMIP_PAD_CFGX(x)		(0x4c0 + (4 * (x)))
> +#define   RPD_CTRL_PX(x)			(((x) & 0x1f) << 22)
> +
> +#define PMC_UHSIC_SLEEP_CFG	PMC_UTMIP_UHSIC_SLEEP_CFG(0)
> +#define   UHSIC_MASTER_ENABLE			BIT(24)
> +#define   UHSIC_WAKE_VAL(_value)		(((_value) & 0xf) << 28)
> +#define   UHSIC_WAKE_VAL_SD10			UHSIC_WAKE_VAL(2)
> +#define   UHSIC_WAKE_VAL_NONE			UHSIC_WAKE_VAL(12)
> +
> +#define PMC_UHSIC_FAKE			PMC_UTMIP_UHSIC_FAKE(0)
> +#define   UHSIC_FAKE_STROBE_VAL			BIT(12)
> +#define   UHSIC_FAKE_DATA_VAL			BIT(13)
> +#define   UHSIC_FAKE_STROBE_EN			BIT(14)
> +#define   UHSIC_FAKE_DATA_EN			BIT(15)
> +
> +#define PMC_UHSIC_SAVED_STATE		PMC_UTMIP_UHSIC_SAVED_STATE(0)
> +#define   UHSIC_MODE(_value)			(((_value) & 0x1) << 24)
> +#define   UHSIC_HS				UHSIC_MODE(0)
> +#define   UHSIC_RST				UHSIC_MODE(1)
> +
> +#define PMC_UHSIC_SLEEPWALK_CFG		PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
> +#define   UHSIC_WAKE_WALK_EN			BIT(30)
> +#define   UHSIC_LINEVAL_WALK_EN			BIT(31)
> +
> +#define PMC_UHSIC_SLEEPWALK_P0		(0x210)
> +#define   UHSIC_DATA0_RPD_A			BIT(1)
> +#define   UHSIC_DATA0_RPU_B			BIT(11)
> +#define   UHSIC_DATA0_RPU_C			BIT(19)
> +#define   UHSIC_DATA0_RPU_D			BIT(27)
> +#define   UHSIC_STROBE_RPU_A			BIT(2)
> +#define   UHSIC_STROBE_RPD_B			BIT(8)
> +#define   UHSIC_STROBE_RPD_C			BIT(16)
> +#define   UHSIC_STROBE_RPD_D			BIT(24)
> +
>  struct tegra210_xusb_fuse_calibration {
>  	u32 hs_curr_level[4];
>  	u32 hs_term_range_adj;
>  	u32 rpd_ctrl;
>  };
>  
> +struct tegra210_xusb_padctl_context {
> +	u32 usb2_pad_mux;
> +	u32 usb2_port_cap;
> +	u32 ss_port_map;
> +	u32 usb3_pad_mux;
> +};
> +
>  struct tegra210_xusb_padctl {
>  	struct tegra_xusb_padctl base;
>  
>  	struct tegra210_xusb_fuse_calibration fuse;
> +	struct tegra210_xusb_padctl_context context;
> +	struct regmap *pmc_reg;

I'd move this more towards the top because it's a resource that we're
requesting early on. Also, perhaps just name it "regmap" since "pmc_reg"
could be mistaken for a "PMC register offset".

>  };
>  
>  static inline struct tegra210_xusb_padctl *
> @@ -886,6 +1051,671 @@ static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
>  	return 0;
>  }
>  
> +static int tegra210_usb3_enable_phy_sleepwalk(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	int port = tegra210_usb3_lane_map(lane);
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	if (port < 0) {
> +		dev_err(dev, "invalid usb3 port number\n");
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(dev, "phy enable sleepwalk usb3 %d\n", port);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
> +	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
> +
> +	usleep_range(100, 200);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
> +	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
> +
> +	usleep_range(250, 350);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_usb3_disable_phy_sleepwalk(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	int port = tegra210_usb3_lane_map(lane);
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	if (port < 0) {
> +		dev_err(dev, "invalid usb3 port number\n");
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(dev, "phy disable sleepwalk usb3 %d\n", port);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
> +	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
> +
> +	usleep_range(100, 200);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
> +	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_usb3_enable_phy_wake(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	int port = tegra210_usb3_lane_map(lane);
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	if (port < 0) {
> +		dev_err(dev, "invalid usb3 port number\n");
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(dev, "phy enable wake usb3 %d\n", port);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= SS_PORT_WAKEUP_EVENT(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	usleep_range(10, 20);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_usb3_disable_phy_wake(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	int port = tegra210_usb3_lane_map(lane);
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	if (port < 0) {
> +		dev_err(dev, "invalid usb3 port number\n");
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(dev, "phy disable wake usb3 %d\n", port);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	usleep_range(10, 20);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= SS_PORT_WAKEUP_EVENT(port);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_utmi_enable_phy_wake(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	unsigned int index = lane->index;
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	dev_dbg(dev, "phy enable wake on usb2 %d\n", index);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= USB2_PORT_WAKEUP_EVENT(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	usleep_range(10, 20);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_utmi_disable_phy_wake(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	unsigned int index = lane->index;
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	dev_dbg(dev, "phy disable wake on usb2 %d\n", index);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	usleep_range(10, 20);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= USB2_PORT_WAKEUP_EVENT(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_hsic_enable_phy_wake(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	unsigned int index = lane->index;
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	dev_dbg(dev, "phy enable wake on hsic %d\n", index);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	usleep_range(10, 20);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_hsic_disable_phy_wake(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	unsigned int index = lane->index;
> +	struct device *dev = padctl->dev;
> +	u32 value;
> +
> +	dev_dbg(dev, "phy disable wake on hsic %d\n", index);
> +
> +	mutex_lock(&padctl->lock);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	usleep_range(10, 20);
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	value &= ~ALL_WAKE_EVENTS;
> +	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
> +
> +	mutex_unlock(&padctl->lock);
> +
> +	return 0;
> +}
> +
> +static int tegra210_usb3_phy_remote_wake_detected(
> +			struct tegra_xusb_padctl *padctl, int port)

The 80 column limit no longer applies and you can now use up to 100
columns. There's a couple of other places where you've unnecessarily
wrapped too early.

> +{
> +	u32 value;
> +
> +	if (port < 0) {

Do we need this check here? Since this is a local helper, shouldn't all
the callers already make sure that they're not passing in invalid
values?

> +		dev_err(padctl->dev, "invalid usb3 port number %d\n",
> +					port);
> +		return false;

If you want the function to return bool, just make the return type bool
as well.

> +	}
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
> +	    (value & SS_PORT_WAKEUP_EVENT(port)))
> +		return true;
> +	else
> +		return false;

The else is not needed here.

> +}
> +
> +static int tegra210_utmi_phy_remote_wake_detected(
> +			struct tegra_xusb_padctl *padctl, int port)
> +{
> +	u32 value;
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
> +	    (value & USB2_PORT_WAKEUP_EVENT(port)))
> +		return true;
> +	else
> +		return false;
> +}
> +
> +static int tegra210_hsic_phy_remote_wake_detected(
> +			struct tegra_xusb_padctl *padctl, int port)
> +{
> +	u32 value;
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
> +	if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
> +	    (value & USB2_HSIC_PORT_WAKEUP_EVENT(port)))
> +		return true;
> +	else
> +		return false;
> +}

Perhaps you want to sort these with the USB3, HSIC and UTMI functions
above rather than sort them by type of function?

> +
> +#define padctl_pmc_readl(_priv, _offset)			\
> +({								\
> +	int rc;							\
> +	u32 val;						\

s/val/value/ here and below.

> +	rc = regmap_read(_priv->pmc_reg, _offset, &val);	\
> +	if (rc)							\
> +		return rc;					\
> +	val;							\
> +})
> +
> +#define padctl_pmc_writel(_priv, _val, _offset)			\
> +do {								\
> +	int rc;							\
> +	rc = regmap_write(_priv->pmc_reg, _offset, _val);	\
> +	if (rc)							\
> +		return rc;					\
> +} while (0)
> +
> +/* T210 USB2 SLEEPWALK APIs */

Tegra210, please. Although this really shouldn't be needed, since you
can derive as much from the function names.

> +int tegra_pmc_utmi_enable_phy_sleepwalk(struct phy *phy,
> +					enum usb_device_speed speed)

Perhaps use tegra210_ as the prefix for consistency?

> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
> +	struct device *dev = padctl->dev;
> +	unsigned int port = lane->index;
> +	u32 val, tctrl, pctrl, rpd_ctrl;

s/val/value/ here and below.

> +
> +	if (speed > USB_SPEED_HIGH)
> +		return -EINVAL;
> +
> +	dev_dbg(dev, "phy enable sleepwalk usb2 %d speed %d\n", port, speed);
> +
> +	val = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
> +	tctrl = TCTRL_VALUE(val);
> +	pctrl = PCTRL_VALUE(val);
> +
> +	val = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
> +	rpd_ctrl = RPD_CTRL_VALUE(val);
> +
> +	/* ensure sleepwalk logic is disabled */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	val &= ~UTMIP_MASTER_ENABLE(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	/* ensure sleepwalk logics are in low power mode */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
> +	val |= UTMIP_PWR(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_MASTER_CONFIG);
> +
> +	/* set debounce time */
> +	val = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
> +	val &= ~UTMIP_LINE_DEB_CNT(~0);
> +	val |= UTMIP_LINE_DEB_CNT(0x1);
> +	padctl_pmc_writel(priv, val, PMC_USB_DEBOUNCE_DEL);
> +
> +	/* ensure fake events of sleepwalk logic are desiabled */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
> +	val &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
> +			UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_FAKE(port));
> +
> +	/* ensure wake events of sleepwalk logic are not latched */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +	val &= ~UTMIP_LINE_WAKEUP_EN(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +
> +	/* disable wake event triggers of sleepwalk logic */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	val &= ~UTMIP_WAKE_VAL(port, ~0);
> +	val |= UTMIP_WAKE_VAL_NONE(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	/* power down the line state detectors of the pad */
> +	val = padctl_pmc_readl(priv, PMC_USB_AO);
> +	val |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
> +	padctl_pmc_writel(priv, val, PMC_USB_AO);
> +
> +	/* save state per speed */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
> +	val &= ~SPEED(port, ~0);
> +	if (speed == USB_SPEED_HIGH)
> +		val |= UTMI_HS(port);
> +	else if (speed == USB_SPEED_FULL)
> +		val |= UTMI_FS(port);
> +	else if (speed == USB_SPEED_LOW)
> +		val |= UTMI_LS(port);
> +	else
> +		val |= UTMI_RST(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SAVED_STATE(port));
> +
> +	/* enable the trigger of the sleepwalk logic */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
> +	val |= UTMIP_LINEVAL_WALK_EN(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
> +
> +	/* reset the walk pointer and clear the alarm of the sleepwalk logic,
> +	 * as well as capture the configuration of the USB2.0 pad
> +	 */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
> +	val |= (UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) |
> +		UTMIP_CAP_CFG(port));
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_TRIGGERS);
> +
> +	/* program electrical parameters read from XUSB PADCTL */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
> +	val &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
> +	val |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_TERM_PAD_CFG);
> +
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
> +	val &= ~RPD_CTRL_PX(~0);
> +	val |= RPD_CTRL_PX(rpd_ctrl);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_PAD_CFGX(port));
> +
> +	/* setup the pull-ups and pull-downs of the signals during the four
> +	 * stages of sleepwalk.
> +	 * if device is connected, program sleepwalk logic to maintain a J and
> +	 * keep driving K upon seeing remote wake.
> +	 */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
> +	val = (UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C |
> +		UTMIP_USBOP_RPD_D);
> +	val |= (UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C |
> +		UTMIP_USBON_RPD_D);
> +	if (speed == USB_SPEED_UNKNOWN) {
> +		val |= (UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C |
> +			UTMIP_HIGHZ_D);
> +	} else if ((speed == USB_SPEED_HIGH) || (speed == USB_SPEED_FULL)) {
> +		/* J state: D+/D- = high/low, K state: D+/D- = low/high */
> +		val |= UTMIP_HIGHZ_A;
> +		val |= UTMIP_AP_A;
> +		val |= (UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D);
> +	} else if (speed == USB_SPEED_LOW) {
> +		/* J state: D+/D- = low/high, K state: D+/D- = high/low */
> +		val |= UTMIP_HIGHZ_A;
> +		val |= UTMIP_AN_A;
> +		val |= (UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D);
> +	}
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_SLEEPWALK_PX(port));
> +
> +	/* power up the line state detectors of the pad */
> +	val = padctl_pmc_readl(priv, PMC_USB_AO);
> +	val &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
> +	padctl_pmc_writel(priv, val, PMC_USB_AO);
> +
> +	usleep_range(50, 100);
> +
> +	/* switch the electric control of the USB2.0 pad to PMC */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	val |= (UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
> +			UTMIP_TCTRL_USE_PMC(port));
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
> +	val |= (UTMIP_RPD_CTRL_USE_PMC_PX(port) |
> +			UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG1);
> +
> +	/* set the wake signaling trigger events */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	val &= ~UTMIP_WAKE_VAL(port, ~0);
> +	val |= UTMIP_WAKE_VAL_ANY(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	/* enable the wake detection */
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	val |= UTMIP_MASTER_ENABLE(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +	val |= UTMIP_LINE_WAKEUP_EN(port);
> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +
> +	return 0;
> +}
> +
> +int tegra_pmc_utmi_disable_phy_sleepwalk(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
> +	struct device *dev = padctl->dev;
> +	unsigned int port = lane->index;
> +	u32 value;
> +
> +	dev_dbg(dev, "phy disable sleepwalk usb2 %d\n", port);
> +
> +	/* disable the wake detection */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	value &= ~UTMIP_MASTER_ENABLE(port);
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +	value &= ~UTMIP_LINE_WAKEUP_EN(port);
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +
> +	/* switch the electric control of the USB2.0 pad to XUSB or USB2 */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
> +			UTMIP_TCTRL_USE_PMC(port));
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
> +	value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) |
> +			UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
> +
> +	/* disable wake event triggers of sleepwalk logic */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +	value &= ~UTMIP_WAKE_VAL(port, ~0);
> +	value |= UTMIP_WAKE_VAL_NONE(port);
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
> +
> +	/* power down the line state detectors of the port */
> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
> +	value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
> +
> +	/* clear alarm of the sleepwalk logic */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
> +	value |= UTMIP_CLR_WAKE_ALARM(port);
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
> +
> +	return 0;
> +}
> +
> +int tegra_pmc_hsic_enable_phy_sleepwalk(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
> +	struct device *dev = padctl->dev;
> +	unsigned int port = lane->index;
> +	u32 value;
> +
> +	dev_dbg(dev, "phy enable sleepwalk hsic %d\n", port);
> +
> +	/* ensure sleepwalk logic is disabled */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
> +	value &= ~UHSIC_MASTER_ENABLE;
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
> +
> +	/* ensure sleepwalk logics are in low power mode */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
> +	value |= UHSIC_PWR(port);
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
> +
> +	/* set debounce time */
> +	value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
> +	value &= ~UHSIC_LINE_DEB_CNT(~0);
> +	value |= UHSIC_LINE_DEB_CNT(0x1);
> +	padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
> +
> +	/* ensure fake events of sleepwalk logic are desiabled */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE);
> +	value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL |
> +			UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN);
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE);
> +
> +	/* ensure wake events of sleepwalk logic are not latched */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +	value &= ~UHSIC_LINE_WAKEUP_EN;
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +
> +	/* disable wake event triggers of sleepwalk logic */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
> +	value &= ~UHSIC_WAKE_VAL(~0);
> +	value |= UHSIC_WAKE_VAL_NONE;
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
> +
> +	/* power down the line state detectors of the port */
> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
> +	value |= (STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
> +
> +	/* save state, HSIC always comes up as HS */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE);
> +	value &= ~UHSIC_MODE(~0);
> +	value |= UHSIC_HS;
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE);
> +
> +	/* enable the trigger of the sleepwalk logic */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG);
> +	value |= (UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN);
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG);
> +
> +	/* reset the walk pointer and clear the alarm of the sleepwalk logic,
> +	 * as well as capture the configuration of the USB2.0 port
> +	 */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
> +	value |= (UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM);
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
> +
> +	/* setup the pull-ups and pull-downs of the signals during the four
> +	 * stages of sleepwalk.
> +	 * maintain a HSIC IDLE and keep driving HSIC RESUME upon remote wake
> +	 */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0);
> +	value = (UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C |
> +		UHSIC_DATA0_RPU_D);
> +	value |= (UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C |
> +		UHSIC_STROBE_RPD_D);
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0);
> +
> +	/* power up the line state detectors of the port */
> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
> +	value &= ~(STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
> +
> +	usleep_range(50, 100);
> +
> +	/* set the wake signaling trigger events */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
> +	value &= ~UHSIC_WAKE_VAL(~0);
> +	value |= UHSIC_WAKE_VAL_SD10;
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
> +
> +	/* enable the wake detection */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
> +	value |= UHSIC_MASTER_ENABLE;
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
> +
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +	value |= UHSIC_LINE_WAKEUP_EN;
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +
> +	return 0;
> +}
> +
> +int tegra_pmc_hsic_disable_phy_sleepwalk(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
> +	struct device *dev = padctl->dev;
> +	unsigned int port = lane->index;
> +	u32 value;
> +
> +	dev_dbg(dev, "phy disable sleepwalk hsic %d\n", port);
> +
> +	/* disable the wake detection */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
> +	value &= ~UHSIC_MASTER_ENABLE;
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
> +
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +	value &= ~UHSIC_LINE_WAKEUP_EN;
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
> +
> +	/* disable wake event triggers of sleepwalk logic */
> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
> +	value &= ~UHSIC_WAKE_VAL(~0);
> +	value |= UHSIC_WAKE_VAL_NONE;
> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
> +
> +	/* power down the line state detectors of the port */
> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
> +	value |= (STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
> +
> +	/* clear alarm of the sleepwalk logic */
> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
> +	value |= UHSIC_CLR_WAKE_ALARM;
> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
> +
> +	return 0;
> +}
> +
>  static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
>  					 unsigned int index, bool enable)
>  {
> @@ -988,8 +1818,23 @@ static int tegra210_usb2_phy_init(struct phy *phy)
>  {
>  	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>  	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	unsigned int index = lane->index;
> +	struct tegra_xusb_usb2_port *port;
> +	int err;
>  	u32 value;
>  
> +	port = tegra_xusb_find_usb2_port(padctl, index);
> +	if (!port) {
> +		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
> +		return -ENODEV;
> +	}
> +
> +	err = regulator_enable(port->supply);
> +	if (err)
> +		return err;
> +
> +	mutex_lock(&padctl->lock);
> +
>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
>  	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
>  		   XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
> @@ -997,11 +1842,29 @@ static int tegra210_usb2_phy_init(struct phy *phy)
>  		 XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
>  	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
>  
> +	mutex_unlock(&padctl->lock);
> +
>  	return 0;
>  }

How is this related to sleepwalk? Should this perhaps be a separate
patch? Looks like some hunks below are also not immediately related to
this commit. Or perhaps I don't understand how they are related.

>  
>  static int tegra210_usb2_phy_exit(struct phy *phy)
>  {
> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
> +	unsigned int index = lane->index;
> +	struct tegra_xusb_usb2_port *port;
> +	int err;
> +
> +	port = tegra_xusb_find_usb2_port(padctl, index);
> +	if (!port) {
> +		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
> +		return -ENODEV;
> +	}
> +
> +	err = regulator_disable(port->supply);
> +	if (err)
> +		return err;
> +
>  	return 0;
>  }
>  
> @@ -1122,6 +1985,8 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>  
>  	priv = to_tegra210_xusb_padctl(padctl);
>  
> +	mutex_lock(&padctl->lock);
> +
>  	if (port->usb3_port_fake != -1) {
>  		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
>  		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
> @@ -1215,14 +2080,6 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>  	padctl_writel(padctl, value,
>  		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
>  
> -	if (port->supply && port->mode == USB_DR_MODE_HOST) {
> -		err = regulator_enable(port->supply);
> -		if (err)
> -			return err;
> -	}
> -
> -	mutex_lock(&padctl->lock);
> -
>  	if (pad->enable > 0) {
>  		pad->enable++;
>  		mutex_unlock(&padctl->lock);
> @@ -1231,7 +2088,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>  
>  	err = clk_prepare_enable(pad->clk);
>  	if (err)
> -		goto disable_regulator;
> +		goto out;
>  
>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
>  	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
> @@ -1263,8 +2120,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>  
>  	return 0;
>  
> -disable_regulator:
> -	regulator_disable(port->supply);
> +out:
>  	mutex_unlock(&padctl->lock);
>  	return err;
>  }
> @@ -1275,12 +2131,12 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
>  	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
>  	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>  	struct tegra_xusb_usb2_port *port;
> +	unsigned int index = lane->index;
>  	u32 value;
>  
> -	port = tegra_xusb_find_usb2_port(padctl, lane->index);
> +	port = tegra_xusb_find_usb2_port(padctl, index);
>  	if (!port) {
> -		dev_err(&phy->dev, "no port found for USB2 lane %u\n",
> -			lane->index);
> +		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
>  		return -ENODEV;
>  	}
>  
> @@ -1318,12 +2174,19 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
>  	if (--pad->enable > 0)
>  		goto out;
>  
> +	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
> +	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD;
> +	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
> +	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR;
> +	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
> +
>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
>  	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
>  	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
>  
>  out:
> -	regulator_disable(port->supply);
>  	mutex_unlock(&padctl->lock);
>  	return 0;
>  }
> @@ -2120,6 +2983,120 @@ static const struct phy_ops tegra210_sata_phy_ops = {
>  	.owner = THIS_MODULE,
>  };
>  
> +static inline bool is_usb3_phy(struct phy *phy)
> +{
> +	return (phy->ops == &tegra210_pcie_phy_ops ||
> +		phy->ops == &tegra210_sata_phy_ops);
> +}
> +
> +static inline bool is_hsic_phy(struct phy *phy)
> +{
> +	return phy->ops == &tegra210_hsic_phy_ops;
> +}
> +
> +static inline bool is_utmi_phy(struct phy *phy)
> +{
> +	return phy->ops == &tegra210_usb2_phy_ops;
> +}
> +
> +static int
> +tegra210_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl,
> +				     struct phy *phy)
> +{
> +	if (!phy)
> +		return 0;
> +
> +	if (is_usb3_phy(phy))
> +		return tegra210_usb3_enable_phy_wake(phy);
> +	else if (is_utmi_phy(phy))
> +		return tegra210_utmi_enable_phy_wake(phy);
> +	else if (is_hsic_phy(phy))
> +		return tegra210_hsic_enable_phy_wake(phy);
> +	else
> +		return -EINVAL;
> +}

Since all of these branches return, you don't need the else and can
write this more simply as:

	if (is_usb3_phy(phy))
		return ...;

	if (is_utmi_phy(phy))
		return ...;

	if (is_hsic_phy(phy))
		return ...;

	return -EINVAL;

I'd probably also leave out the check for !phy since that should never
happen and it might be good to just let it crash in that case to make
sure that bug is found as quickly as possible.

> +
> +static int
> +tegra210_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl,
> +				      struct phy *phy)
> +{
> +	if (!phy)
> +		return 0;
> +
> +	if (is_usb3_phy(phy))
> +		return tegra210_usb3_disable_phy_wake(phy);
> +	else if (is_utmi_phy(phy))
> +		return tegra210_utmi_disable_phy_wake(phy);
> +	else if (is_hsic_phy(phy))
> +		return tegra210_hsic_disable_phy_wake(phy);
> +	else
> +		return -EINVAL;
> +}
> +
> +int tegra210_xusb_padctl_remote_wake_detected(struct phy *phy)
> +{
> +	struct tegra_xusb_lane *lane;
> +	struct tegra_xusb_padctl *padctl;
> +
> +	if (!phy)
> +		return 0;
> +
> +	lane = phy_get_drvdata(phy);
> +	padctl = lane->pad->padctl;
> +
> +	if (is_utmi_phy(phy))
> +		return tegra210_utmi_phy_remote_wake_detected(padctl,
> +					lane->index);
> +	else if (is_hsic_phy(phy))
> +		return tegra210_hsic_phy_remote_wake_detected(padctl,
> +					lane->index);
> +	else if (is_usb3_phy(phy))
> +		return tegra210_usb3_phy_remote_wake_detected(padctl,
> +					tegra210_usb3_lane_map(lane));
> +
> +	return -EINVAL;
> +}
> +
> +static int
> +tegra210_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl,
> +					  struct phy *phy,
> +					  enum usb_device_speed speed)
> +{
> +	if (!phy)
> +		return 0;
> +
> +	if (is_usb3_phy(phy))
> +		return tegra210_usb3_enable_phy_sleepwalk(phy);
> +	else if (is_utmi_phy(phy))
> +		return tegra_pmc_utmi_enable_phy_sleepwalk(phy, speed);
> +	else if (is_hsic_phy(phy))
> +		return tegra_pmc_hsic_enable_phy_sleepwalk(phy);
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int
> +tegra210_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl,
> +					   struct phy *phy)
> +{
> +	if (!phy)
> +		return 0;
> +
> +	if (is_usb3_phy(phy))
> +		return tegra210_usb3_disable_phy_sleepwalk(phy);
> +	else if (is_utmi_phy(phy))
> +		return tegra_pmc_utmi_disable_phy_sleepwalk(phy);
> +	else if (is_hsic_phy(phy))
> +		return tegra_pmc_hsic_disable_phy_sleepwalk(phy);
> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +
>  static struct tegra_xusb_pad *
>  tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl,
>  			const struct tegra_xusb_pad_soc *soc,
> @@ -2317,6 +3294,8 @@ tegra210_xusb_padctl_probe(struct device *dev,
>  			   const struct tegra_xusb_padctl_soc *soc)
>  {
>  	struct tegra210_xusb_padctl *padctl;
> +	struct device_node *node, *np = dev->of_node;
> +	struct platform_device *pmc_dev;
>  	int err;
>  
>  	padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
> @@ -2330,6 +3309,24 @@ tegra210_xusb_padctl_probe(struct device *dev,
>  	if (err < 0)
>  		return ERR_PTR(err);
>  
> +	node = of_parse_phandle(np, "nvidia,pmc", 0);
> +	if (!node) {
> +		dev_err(dev, "nvidia,pmc property is missing\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	pmc_dev = of_find_device_by_node(node);
> +	if (!pmc_dev) {
> +		dev_err(dev, "pmc device is not available\n");
> +		return ERR_PTR(-ENODEV);
> +	}
> +
> +	padctl->pmc_reg = dev_get_regmap(&pmc_dev->dev, "usb_sleepwalk");
> +	if (!padctl->pmc_reg) {
> +		dev_err(dev, "pmc regmap is not available.\n");
> +		return ERR_PTR(-ENODEV);
> +	}

We'll have to make this optional for backwards compatibility, which will
also help make this easier to merge because it doesn't all have to go in
at the same time.

Thierry

> +
>  	return &padctl->base;
>  }
>  
> @@ -2337,13 +3334,80 @@ static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
>  {
>  }
>  
> +static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
> +{
> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
> +
> +	priv->context.usb2_pad_mux =
> +		padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
> +	priv->context.usb2_port_cap =
> +		padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
> +	priv->context.ss_port_map =
> +		padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
> +	priv->context.usb3_pad_mux =
> +		padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
> +}
> +
> +static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
> +{
> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
> +	int i;
> +
> +	padctl_writel(padctl, priv->context.usb2_pad_mux,
> +		XUSB_PADCTL_USB2_PAD_MUX);
> +	padctl_writel(padctl, priv->context.usb2_port_cap,
> +		XUSB_PADCTL_USB2_PORT_CAP);
> +	padctl_writel(padctl, priv->context.ss_port_map,
> +		XUSB_PADCTL_SS_PORT_MAP);
> +
> +	for (i = 0; i <= 7; i ++)
> +		tegra210_uphy_lane_iddq_enable(padctl, i);
> +
> +	padctl_writel(padctl, priv->context.usb3_pad_mux,
> +		XUSB_PADCTL_USB3_PAD_MUX);
> +
> +	for (i = 0; i <= 7; i ++)
> +		tegra210_uphy_lane_iddq_disable(padctl, i);
> +}
> +
> +static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
> +{
> +	mutex_lock(&padctl->lock);
> +
> +	tegra210_uphy_deinit(padctl);
> +
> +	tegra210_xusb_padctl_save(padctl);
> +
> +	mutex_unlock(&padctl->lock);
> +	return 0;
> +}
> +
> +static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
> +{
> +	mutex_lock(&padctl->lock);
> +
> +	tegra210_xusb_padctl_restore(padctl);
> +
> +	tegra210_uphy_init(padctl);
> +
> +	mutex_unlock(&padctl->lock);
> +	return 0;
> +}
> +
>  static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
>  	.probe = tegra210_xusb_padctl_probe,
>  	.remove = tegra210_xusb_padctl_remove,
> +	.suspend_noirq = tegra210_xusb_padctl_suspend_noirq,
> +	.resume_noirq = tegra210_xusb_padctl_resume_noirq,
>  	.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
>  	.hsic_set_idle = tegra210_hsic_set_idle,
>  	.vbus_override = tegra210_xusb_padctl_vbus_override,
>  	.utmi_port_reset = tegra210_utmi_port_reset,
> +	.enable_phy_sleepwalk = tegra210_xusb_padctl_enable_phy_sleepwalk,
> +	.disable_phy_sleepwalk = tegra210_xusb_padctl_disable_phy_sleepwalk,
> +	.enable_phy_wake = tegra210_xusb_padctl_enable_phy_wake,
> +	.disable_phy_wake = tegra210_xusb_padctl_disable_phy_wake,
> +	.remote_wake_detected = tegra210_xusb_padctl_remote_wake_detected,
>  };
>  
>  static const char * const tegra210_xusb_padctl_supply_names[] = {
> -- 
> 2.25.1
>
kernel test robot Sept. 1, 2020, 3:14 p.m. UTC | #2
Hi JC,

I love your patch! Perhaps something to improve:

[auto build test WARNING on tegra/for-next]
[also build test WARNING on robh/for-next usb/usb-testing char-misc/char-misc-testing staging/staging-testing driver-core/driver-core-testing v5.9-rc3 next-20200828]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/JC-Kuo/Tegra-XHCI-controller-ELPG-support/20200831-124234
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
config: arm64-randconfig-r014-20200901 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project c10e63677f5d20f18010f8f68c631ddc97546f7d)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=arm64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/phy/tegra/xusb-tegra210.c:1368:5: warning: no previous prototype for function 'tegra_pmc_utmi_enable_phy_sleepwalk' [-Wmissing-prototypes]
   int tegra_pmc_utmi_enable_phy_sleepwalk(struct phy *phy,
       ^
   drivers/phy/tegra/xusb-tegra210.c:1368:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tegra_pmc_utmi_enable_phy_sleepwalk(struct phy *phy,
   ^
   static 
>> drivers/phy/tegra/xusb-tegra210.c:1527:5: warning: no previous prototype for function 'tegra_pmc_utmi_disable_phy_sleepwalk' [-Wmissing-prototypes]
   int tegra_pmc_utmi_disable_phy_sleepwalk(struct phy *phy)
       ^
   drivers/phy/tegra/xusb-tegra210.c:1527:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tegra_pmc_utmi_disable_phy_sleepwalk(struct phy *phy)
   ^
   static 
>> drivers/phy/tegra/xusb-tegra210.c:1577:5: warning: no previous prototype for function 'tegra_pmc_hsic_enable_phy_sleepwalk' [-Wmissing-prototypes]
   int tegra_pmc_hsic_enable_phy_sleepwalk(struct phy *phy)
       ^
   drivers/phy/tegra/xusb-tegra210.c:1577:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tegra_pmc_hsic_enable_phy_sleepwalk(struct phy *phy)
   ^
   static 
>> drivers/phy/tegra/xusb-tegra210.c:1680:5: warning: no previous prototype for function 'tegra_pmc_hsic_disable_phy_sleepwalk' [-Wmissing-prototypes]
   int tegra_pmc_hsic_disable_phy_sleepwalk(struct phy *phy)
       ^
   drivers/phy/tegra/xusb-tegra210.c:1680:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tegra_pmc_hsic_disable_phy_sleepwalk(struct phy *phy)
   ^
   static 
>> drivers/phy/tegra/xusb-tegra210.c:3036:5: warning: no previous prototype for function 'tegra210_xusb_padctl_remote_wake_detected' [-Wmissing-prototypes]
   int tegra210_xusb_padctl_remote_wake_detected(struct phy *phy)
       ^
   drivers/phy/tegra/xusb-tegra210.c:3036:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int tegra210_xusb_padctl_remote_wake_detected(struct phy *phy)
   ^
   static 
   5 warnings generated.

# https://github.com/0day-ci/linux/commit/85501cb657fc0bbb792dc08358e31fad69c8b13c
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review JC-Kuo/Tegra-XHCI-controller-ELPG-support/20200831-124234
git checkout 85501cb657fc0bbb792dc08358e31fad69c8b13c
vim +/tegra_pmc_utmi_enable_phy_sleepwalk +1368 drivers/phy/tegra/xusb-tegra210.c

  1366	
  1367	/* T210 USB2 SLEEPWALK APIs */
> 1368	int tegra_pmc_utmi_enable_phy_sleepwalk(struct phy *phy,
  1369						enum usb_device_speed speed)
  1370	{
  1371		struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
  1372		struct tegra_xusb_padctl *padctl = lane->pad->padctl;
  1373		struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
  1374		struct device *dev = padctl->dev;
  1375		unsigned int port = lane->index;
  1376		u32 val, tctrl, pctrl, rpd_ctrl;
  1377	
  1378		if (speed > USB_SPEED_HIGH)
  1379			return -EINVAL;
  1380	
  1381		dev_dbg(dev, "phy enable sleepwalk usb2 %d speed %d\n", port, speed);
  1382	
  1383		val = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
  1384		tctrl = TCTRL_VALUE(val);
  1385		pctrl = PCTRL_VALUE(val);
  1386	
  1387		val = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
  1388		rpd_ctrl = RPD_CTRL_VALUE(val);
  1389	
  1390		/* ensure sleepwalk logic is disabled */
  1391		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1392		val &= ~UTMIP_MASTER_ENABLE(port);
  1393		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1394	
  1395		/* ensure sleepwalk logics are in low power mode */
  1396		val = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
  1397		val |= UTMIP_PWR(port);
  1398		padctl_pmc_writel(priv, val, PMC_UTMIP_MASTER_CONFIG);
  1399	
  1400		/* set debounce time */
  1401		val = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
  1402		val &= ~UTMIP_LINE_DEB_CNT(~0);
  1403		val |= UTMIP_LINE_DEB_CNT(0x1);
  1404		padctl_pmc_writel(priv, val, PMC_USB_DEBOUNCE_DEL);
  1405	
  1406		/* ensure fake events of sleepwalk logic are desiabled */
  1407		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
  1408		val &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
  1409				UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
  1410		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_FAKE(port));
  1411	
  1412		/* ensure wake events of sleepwalk logic are not latched */
  1413		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
  1414		val &= ~UTMIP_LINE_WAKEUP_EN(port);
  1415		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
  1416	
  1417		/* disable wake event triggers of sleepwalk logic */
  1418		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1419		val &= ~UTMIP_WAKE_VAL(port, ~0);
  1420		val |= UTMIP_WAKE_VAL_NONE(port);
  1421		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1422	
  1423		/* power down the line state detectors of the pad */
  1424		val = padctl_pmc_readl(priv, PMC_USB_AO);
  1425		val |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
  1426		padctl_pmc_writel(priv, val, PMC_USB_AO);
  1427	
  1428		/* save state per speed */
  1429		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
  1430		val &= ~SPEED(port, ~0);
  1431		if (speed == USB_SPEED_HIGH)
  1432			val |= UTMI_HS(port);
  1433		else if (speed == USB_SPEED_FULL)
  1434			val |= UTMI_FS(port);
  1435		else if (speed == USB_SPEED_LOW)
  1436			val |= UTMI_LS(port);
  1437		else
  1438			val |= UTMI_RST(port);
  1439		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SAVED_STATE(port));
  1440	
  1441		/* enable the trigger of the sleepwalk logic */
  1442		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
  1443		val |= UTMIP_LINEVAL_WALK_EN(port);
  1444		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
  1445	
  1446		/* reset the walk pointer and clear the alarm of the sleepwalk logic,
  1447		 * as well as capture the configuration of the USB2.0 pad
  1448		 */
  1449		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
  1450		val |= (UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) |
  1451			UTMIP_CAP_CFG(port));
  1452		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_TRIGGERS);
  1453	
  1454		/* program electrical parameters read from XUSB PADCTL */
  1455		val = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
  1456		val &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
  1457		val |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
  1458		padctl_pmc_writel(priv, val, PMC_UTMIP_TERM_PAD_CFG);
  1459	
  1460		val = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
  1461		val &= ~RPD_CTRL_PX(~0);
  1462		val |= RPD_CTRL_PX(rpd_ctrl);
  1463		padctl_pmc_writel(priv, val, PMC_UTMIP_PAD_CFGX(port));
  1464	
  1465		/* setup the pull-ups and pull-downs of the signals during the four
  1466		 * stages of sleepwalk.
  1467		 * if device is connected, program sleepwalk logic to maintain a J and
  1468		 * keep driving K upon seeing remote wake.
  1469		 */
  1470		val = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
  1471		val = (UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C |
  1472			UTMIP_USBOP_RPD_D);
  1473		val |= (UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C |
  1474			UTMIP_USBON_RPD_D);
  1475		if (speed == USB_SPEED_UNKNOWN) {
  1476			val |= (UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C |
  1477				UTMIP_HIGHZ_D);
  1478		} else if ((speed == USB_SPEED_HIGH) || (speed == USB_SPEED_FULL)) {
  1479			/* J state: D+/D- = high/low, K state: D+/D- = low/high */
  1480			val |= UTMIP_HIGHZ_A;
  1481			val |= UTMIP_AP_A;
  1482			val |= (UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D);
  1483		} else if (speed == USB_SPEED_LOW) {
  1484			/* J state: D+/D- = low/high, K state: D+/D- = high/low */
  1485			val |= UTMIP_HIGHZ_A;
  1486			val |= UTMIP_AN_A;
  1487			val |= (UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D);
  1488		}
  1489		padctl_pmc_writel(priv, val, PMC_UTMIP_SLEEPWALK_PX(port));
  1490	
  1491		/* power up the line state detectors of the pad */
  1492		val = padctl_pmc_readl(priv, PMC_USB_AO);
  1493		val &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
  1494		padctl_pmc_writel(priv, val, PMC_USB_AO);
  1495	
  1496		usleep_range(50, 100);
  1497	
  1498		/* switch the electric control of the USB2.0 pad to PMC */
  1499		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1500		val |= (UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
  1501				UTMIP_TCTRL_USE_PMC(port));
  1502		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1503	
  1504		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
  1505		val |= (UTMIP_RPD_CTRL_USE_PMC_PX(port) |
  1506				UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
  1507		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG1);
  1508	
  1509		/* set the wake signaling trigger events */
  1510		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1511		val &= ~UTMIP_WAKE_VAL(port, ~0);
  1512		val |= UTMIP_WAKE_VAL_ANY(port);
  1513		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1514	
  1515		/* enable the wake detection */
  1516		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1517		val |= UTMIP_MASTER_ENABLE(port);
  1518		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1519	
  1520		val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
  1521		val |= UTMIP_LINE_WAKEUP_EN(port);
  1522		padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
  1523	
  1524		return 0;
  1525	}
  1526	
> 1527	int tegra_pmc_utmi_disable_phy_sleepwalk(struct phy *phy)
  1528	{
  1529		struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
  1530		struct tegra_xusb_padctl *padctl = lane->pad->padctl;
  1531		struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
  1532		struct device *dev = padctl->dev;
  1533		unsigned int port = lane->index;
  1534		u32 value;
  1535	
  1536		dev_dbg(dev, "phy disable sleepwalk usb2 %d\n", port);
  1537	
  1538		/* disable the wake detection */
  1539		value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1540		value &= ~UTMIP_MASTER_ENABLE(port);
  1541		padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1542	
  1543		value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
  1544		value &= ~UTMIP_LINE_WAKEUP_EN(port);
  1545		padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
  1546	
  1547		/* switch the electric control of the USB2.0 pad to XUSB or USB2 */
  1548		value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1549		value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
  1550				UTMIP_TCTRL_USE_PMC(port));
  1551		padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1552	
  1553		value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
  1554		value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) |
  1555				UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
  1556		padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
  1557	
  1558		/* disable wake event triggers of sleepwalk logic */
  1559		value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1560		value &= ~UTMIP_WAKE_VAL(port, ~0);
  1561		value |= UTMIP_WAKE_VAL_NONE(port);
  1562		padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
  1563	
  1564		/* power down the line state detectors of the port */
  1565		value = padctl_pmc_readl(priv, PMC_USB_AO);
  1566		value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
  1567		padctl_pmc_writel(priv, value, PMC_USB_AO);
  1568	
  1569		/* clear alarm of the sleepwalk logic */
  1570		value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
  1571		value |= UTMIP_CLR_WAKE_ALARM(port);
  1572		padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
  1573	
  1574		return 0;
  1575	}
  1576	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
JC Kuo Sept. 8, 2020, 1:14 a.m. UTC | #3
Hi Thierry,
Thanks for review.

On 8/31/20 8:37 PM, Thierry Reding wrote:
> On Mon, Aug 31, 2020 at 12:40:39PM +0800, JC Kuo wrote:
>> This commit implements Tegra210 XUSB PADCTL wake and sleepwalk
>> routines. Sleepwalk logic is in PMC (always-on) hardware block.
>> PMC driver provides managed access to the sleepwalk registers
>> via regmap framework.
>>
>> Signed-off-by: JC Kuo <jckuo@nvidia.com>
>> ---
>>  drivers/phy/tegra/xusb-tegra210.c | 1094 ++++++++++++++++++++++++++++-
>>  1 file changed, 1079 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
>> index fe1ab440424d..1c03f4ec4b59 100644
>> --- a/drivers/phy/tegra/xusb-tegra210.c
>> +++ b/drivers/phy/tegra/xusb-tegra210.c
>> @@ -16,6 +16,8 @@
>>  #include <linux/regulator/consumer.h>
>>  #include <linux/reset.h>
>>  #include <linux/slab.h>
>> +#include <linux/regmap.h>
>> +#include <linux/of_platform.h>
>>  
>>  #include <soc/tegra/fuse.h>
>>  
>> @@ -52,6 +54,20 @@
>>  #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
>>  #define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
>>  
>> +#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
>> +#define   USB2_PORT_WAKE_INTERRUPT_ENABLE(x)      BIT((x))
>> +#define   USB2_PORT_WAKEUP_EVENT(x)               BIT((x) + 7)
>> +#define   SS_PORT_WAKE_INTERRUPT_ENABLE(x)        BIT((x) + 14)
>> +#define   SS_PORT_WAKEUP_EVENT(x)                 BIT((x) + 21)
>> +#define   USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
>> +#define   USB2_HSIC_PORT_WAKEUP_EVENT(x)          BIT((x) + 30)
>> +#define   ALL_WAKE_EVENTS ( \
>> +		USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
>> +		USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
>> +		SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
>> +		SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
>> +		USB2_HSIC_PORT_WAKEUP_EVENT(0))
>> +
>>  #define XUSB_PADCTL_ELPG_PROGRAM1 0x024
>>  #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
>>  #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
>> @@ -90,6 +106,8 @@
>>  #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
>>  #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
>>  #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
>> +#define   RPD_CTRL(x)                      (((x) & 0x1f) << 26)
>> +#define   RPD_CTRL_VALUE(x)                (((x) >> 26) & 0x1f)
>>  
>>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
>>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
>> @@ -108,6 +126,8 @@
>>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
>>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
>>  #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
>> +#define   TCTRL_VALUE(x)                (((x) & 0x3f) >> 0)
>> +#define   PCTRL_VALUE(x)                (((x) >> 6) & 0x3f)
>>  
>>  #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
>>  #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
>> @@ -251,16 +271,161 @@
>>  #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
>>  #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
>>  
>> +/* USB2 SLEEPWALK registers */
>> +#define UTMIP(_port, _offset1, _offset2) \
>> +		(((_port) <= 2) ? (_offset1) : (_offset2))
>> +
>> +#define PMC_UTMIP_UHSIC_SLEEP_CFG(x)	UTMIP(x, 0x1fc, 0x4d0)
>> +#define   UTMIP_MASTER_ENABLE(x)		UTMIP(x, BIT(8 * (x)), BIT(0))
>> +#define   UTMIP_FSLS_USE_PMC(x)			UTMIP(x, BIT(8 * (x) + 1), \
>> +							BIT(1))
>> +#define   UTMIP_PCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 2), \
>> +							BIT(2))
>> +#define   UTMIP_TCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 3), \
>> +							BIT(3))
>> +#define   UTMIP_WAKE_VAL(_port, _value)		(((_value) & 0xf) << \
>> +					(UTMIP(_port, 8 * (_port) + 4, 4)))
>> +#define   UTMIP_WAKE_VAL_NONE(_port)		UTMIP_WAKE_VAL(_port, 12)
>> +#define   UTMIP_WAKE_VAL_ANY(_port)		UTMIP_WAKE_VAL(_port, 15)
>> +
>> +#define PMC_UTMIP_UHSIC_SLEEP_CFG1	(0x4d0)
>> +#define   UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x)	BIT((x) + 8)
>> +#define   UTMIP_RPD_CTRL_USE_PMC_PX(x)		BIT((x) + 16)
>> +
>> +#define PMC_UTMIP_MASTER_CONFIG		(0x274)
>> +#define   UTMIP_PWR(x)				UTMIP(x, BIT(x), BIT(4))
>> +#define   UHSIC_PWR(x)				BIT(3)
>> +
>> +#define PMC_USB_DEBOUNCE_DEL		(0xec)
>> +#define   DEBOUNCE_VAL(x)			(((x) & 0xffff) << 0)
>> +#define   UTMIP_LINE_DEB_CNT(x)			(((x) & 0xf) << 16)
>> +#define   UHSIC_LINE_DEB_CNT(x)			(((x) & 0xf) << 20)
>> +
>> +#define PMC_UTMIP_UHSIC_FAKE(x)		UTMIP(x, 0x218, 0x294)
>> +#define   UTMIP_FAKE_USBOP_VAL(x)		UTMIP(x, BIT(4 * (x)), BIT(8))
>> +#define   UTMIP_FAKE_USBON_VAL(x)		UTMIP(x, BIT(4 * (x) + 1), \
>> +							BIT(9))
>> +#define   UTMIP_FAKE_USBOP_EN(x)		UTMIP(x, BIT(4 * (x) + 2), \
>> +							BIT(10))
>> +#define   UTMIP_FAKE_USBON_EN(x)		UTMIP(x, BIT(4 * (x) + 3), \
>> +							BIT(11))
>> +
>> +#define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x)	UTMIP(x, 0x200, 0x288)
>> +#define   UTMIP_LINEVAL_WALK_EN(x)		UTMIP(x, BIT(8 * (x) + 7), \
>> +							BIT(15))
>> +
>> +#define PMC_USB_AO			(0xf0)
>> +#define   USBOP_VAL_PD(x)			UTMIP(x, BIT(4 * (x)), BIT(20))
>> +#define   USBON_VAL_PD(x)			UTMIP(x, BIT(4 * (x) + 1), \
>> +							BIT(21))
>> +#define   STROBE_VAL_PD(x)			BIT(12)
>> +#define   DATA0_VAL_PD(x)			BIT(13)
>> +#define   DATA1_VAL_PD				BIT(24)
>> +
>> +#define PMC_UTMIP_UHSIC_SAVED_STATE(x)	UTMIP(x, 0x1f0, 0x280)
>> +#define   SPEED(_port, _value)			(((_value) & 0x3) << \
>> +						(UTMIP(_port, 8 * (_port), 8)))
>> +#define   UTMI_HS(_port)			SPEED(_port, 0)
>> +#define   UTMI_FS(_port)			SPEED(_port, 1)
>> +#define   UTMI_LS(_port)			SPEED(_port, 2)
>> +#define   UTMI_RST(_port)			SPEED(_port, 3)
>> +
>> +#define PMC_UTMIP_UHSIC_TRIGGERS		(0x1ec)
>> +#define   UTMIP_CLR_WALK_PTR(x)			UTMIP(x, BIT(x), BIT(16))
>> +#define   UTMIP_CAP_CFG(x)			UTMIP(x, BIT((x) + 4), BIT(17))
>> +#define   UTMIP_CLR_WAKE_ALARM(x)		UTMIP(x, BIT((x) + 12), \
>> +							BIT(19))
>> +#define   UHSIC_CLR_WALK_PTR			BIT(3)
>> +#define   UHSIC_CLR_WAKE_ALARM			BIT(15)
>> +
>> +#define PMC_UTMIP_SLEEPWALK_PX(x)	UTMIP(x, 0x204 + (4 * (x)), \
>> +							0x4e0)
>> +/* phase A */
>> +#define   UTMIP_USBOP_RPD_A			BIT(0)
>> +#define   UTMIP_USBON_RPD_A			BIT(1)
>> +#define   UTMIP_AP_A				BIT(4)
>> +#define   UTMIP_AN_A				BIT(5)
>> +#define   UTMIP_HIGHZ_A				BIT(6)
>> +/* phase B */
>> +#define   UTMIP_USBOP_RPD_B			BIT(8)
>> +#define   UTMIP_USBON_RPD_B			BIT(9)
>> +#define   UTMIP_AP_B				BIT(12)
>> +#define   UTMIP_AN_B				BIT(13)
>> +#define   UTMIP_HIGHZ_B				BIT(14)
>> +/* phase C */
>> +#define   UTMIP_USBOP_RPD_C			BIT(16)
>> +#define   UTMIP_USBON_RPD_C			BIT(17)
>> +#define   UTMIP_AP_C				BIT(20)
>> +#define   UTMIP_AN_C				BIT(21)
>> +#define   UTMIP_HIGHZ_C				BIT(22)
>> +/* phase D */
>> +#define   UTMIP_USBOP_RPD_D			BIT(24)
>> +#define   UTMIP_USBON_RPD_D			BIT(25)
>> +#define   UTMIP_AP_D				BIT(28)
>> +#define   UTMIP_AN_D				BIT(29)
>> +#define   UTMIP_HIGHZ_D				BIT(30)
>> +
>> +#define PMC_UTMIP_UHSIC_LINE_WAKEUP	(0x26c)
>> +#define   UTMIP_LINE_WAKEUP_EN(x)		UTMIP(x, BIT(x), BIT(4))
>> +#define   UHSIC_LINE_WAKEUP_EN			BIT(3)
>> +
>> +#define PMC_UTMIP_TERM_PAD_CFG		(0x1f8)
>> +#define   PCTRL_VAL(x)				(((x) & 0x3f) << 1)
>> +#define   TCTRL_VAL(x)				(((x) & 0x3f) << 7)
>> +
>> +#define PMC_UTMIP_PAD_CFGX(x)		(0x4c0 + (4 * (x)))
>> +#define   RPD_CTRL_PX(x)			(((x) & 0x1f) << 22)
>> +
>> +#define PMC_UHSIC_SLEEP_CFG	PMC_UTMIP_UHSIC_SLEEP_CFG(0)
>> +#define   UHSIC_MASTER_ENABLE			BIT(24)
>> +#define   UHSIC_WAKE_VAL(_value)		(((_value) & 0xf) << 28)
>> +#define   UHSIC_WAKE_VAL_SD10			UHSIC_WAKE_VAL(2)
>> +#define   UHSIC_WAKE_VAL_NONE			UHSIC_WAKE_VAL(12)
>> +
>> +#define PMC_UHSIC_FAKE			PMC_UTMIP_UHSIC_FAKE(0)
>> +#define   UHSIC_FAKE_STROBE_VAL			BIT(12)
>> +#define   UHSIC_FAKE_DATA_VAL			BIT(13)
>> +#define   UHSIC_FAKE_STROBE_EN			BIT(14)
>> +#define   UHSIC_FAKE_DATA_EN			BIT(15)
>> +
>> +#define PMC_UHSIC_SAVED_STATE		PMC_UTMIP_UHSIC_SAVED_STATE(0)
>> +#define   UHSIC_MODE(_value)			(((_value) & 0x1) << 24)
>> +#define   UHSIC_HS				UHSIC_MODE(0)
>> +#define   UHSIC_RST				UHSIC_MODE(1)
>> +
>> +#define PMC_UHSIC_SLEEPWALK_CFG		PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
>> +#define   UHSIC_WAKE_WALK_EN			BIT(30)
>> +#define   UHSIC_LINEVAL_WALK_EN			BIT(31)
>> +
>> +#define PMC_UHSIC_SLEEPWALK_P0		(0x210)
>> +#define   UHSIC_DATA0_RPD_A			BIT(1)
>> +#define   UHSIC_DATA0_RPU_B			BIT(11)
>> +#define   UHSIC_DATA0_RPU_C			BIT(19)
>> +#define   UHSIC_DATA0_RPU_D			BIT(27)
>> +#define   UHSIC_STROBE_RPU_A			BIT(2)
>> +#define   UHSIC_STROBE_RPD_B			BIT(8)
>> +#define   UHSIC_STROBE_RPD_C			BIT(16)
>> +#define   UHSIC_STROBE_RPD_D			BIT(24)
>> +
>>  struct tegra210_xusb_fuse_calibration {
>>  	u32 hs_curr_level[4];
>>  	u32 hs_term_range_adj;
>>  	u32 rpd_ctrl;
>>  };
>>  
>> +struct tegra210_xusb_padctl_context {
>> +	u32 usb2_pad_mux;
>> +	u32 usb2_port_cap;
>> +	u32 ss_port_map;
>> +	u32 usb3_pad_mux;
>> +};
>> +
>>  struct tegra210_xusb_padctl {
>>  	struct tegra_xusb_padctl base;
>>  
>>  	struct tegra210_xusb_fuse_calibration fuse;
>> +	struct tegra210_xusb_padctl_context context;
>> +	struct regmap *pmc_reg;
> 
> I'd move this more towards the top because it's a resource that we're
> requesting early on. Also, perhaps just name it "regmap" since "pmc_reg"
> could be mistaken for a "PMC register offset".
> 
Yes, I will move and rename.
>>  };
>>  
>>  static inline struct tegra210_xusb_padctl *
>> @@ -886,6 +1051,671 @@ static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
>>  	return 0;
>>  }
>>  
>> +static int tegra210_usb3_enable_phy_sleepwalk(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	int port = tegra210_usb3_lane_map(lane);
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	if (port < 0) {
>> +		dev_err(dev, "invalid usb3 port number\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	dev_dbg(dev, "phy enable sleepwalk usb3 %d\n", port);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
>> +	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
>> +
>> +	usleep_range(100, 200);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
>> +	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
>> +
>> +	usleep_range(250, 350);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_usb3_disable_phy_sleepwalk(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	int port = tegra210_usb3_lane_map(lane);
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	if (port < 0) {
>> +		dev_err(dev, "invalid usb3 port number\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	dev_dbg(dev, "phy disable sleepwalk usb3 %d\n", port);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
>> +	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
>> +
>> +	usleep_range(100, 200);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
>> +	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_usb3_enable_phy_wake(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	int port = tegra210_usb3_lane_map(lane);
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	if (port < 0) {
>> +		dev_err(dev, "invalid usb3 port number\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	dev_dbg(dev, "phy enable wake usb3 %d\n", port);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= SS_PORT_WAKEUP_EVENT(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	usleep_range(10, 20);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_usb3_disable_phy_wake(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	int port = tegra210_usb3_lane_map(lane);
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	if (port < 0) {
>> +		dev_err(dev, "invalid usb3 port number\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	dev_dbg(dev, "phy disable wake usb3 %d\n", port);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	usleep_range(10, 20);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= SS_PORT_WAKEUP_EVENT(port);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_utmi_enable_phy_wake(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	unsigned int index = lane->index;
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	dev_dbg(dev, "phy enable wake on usb2 %d\n", index);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= USB2_PORT_WAKEUP_EVENT(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	usleep_range(10, 20);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_utmi_disable_phy_wake(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	unsigned int index = lane->index;
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	dev_dbg(dev, "phy disable wake on usb2 %d\n", index);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	usleep_range(10, 20);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= USB2_PORT_WAKEUP_EVENT(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_hsic_enable_phy_wake(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	unsigned int index = lane->index;
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	dev_dbg(dev, "phy enable wake on hsic %d\n", index);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	usleep_range(10, 20);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_hsic_disable_phy_wake(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	unsigned int index = lane->index;
>> +	struct device *dev = padctl->dev;
>> +	u32 value;
>> +
>> +	dev_dbg(dev, "phy disable wake on hsic %d\n", index);
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	usleep_range(10, 20);
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	value &= ~ALL_WAKE_EVENTS;
>> +	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
>> +	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tegra210_usb3_phy_remote_wake_detected(
>> +			struct tegra_xusb_padctl *padctl, int port)
> 
> The 80 column limit no longer applies and you can now use up to 100
> columns. There's a couple of other places where you've unnecessarily
> wrapped too early.
> 
Got it. Thanks.
>> +{
>> +	u32 value;
>> +
>> +	if (port < 0) {
> 
> Do we need this check here? Since this is a local helper, shouldn't all
> the callers already make sure that they're not passing in invalid
> values?
> 
I will remove it.
>> +		dev_err(padctl->dev, "invalid usb3 port number %d\n",
>> +					port);
>> +		return false;
> 
> If you want the function to return bool, just make the return type bool
> as well.
> 
I will change the return type.
>> +	}
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
>> +	    (value & SS_PORT_WAKEUP_EVENT(port)))
>> +		return true;
>> +	else
>> +		return false;
> 
> The else is not needed here.
> 
Got it. Thanks.
>> +}
>> +
>> +static int tegra210_utmi_phy_remote_wake_detected(
>> +			struct tegra_xusb_padctl *padctl, int port)
>> +{
>> +	u32 value;
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
>> +	    (value & USB2_PORT_WAKEUP_EVENT(port)))
>> +		return true;
>> +	else
>> +		return false;
>> +}
>> +
>> +static int tegra210_hsic_phy_remote_wake_detected(
>> +			struct tegra_xusb_padctl *padctl, int port)
>> +{
>> +	u32 value;
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
>> +	if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
>> +	    (value & USB2_HSIC_PORT_WAKEUP_EVENT(port)))
>> +		return true;
>> +	else
>> +		return false;
>> +}
> 
> Perhaps you want to sort these with the USB3, HSIC and UTMI functions
> above rather than sort them by type of function?
> 
Yes, I will do accordingly.
>> +
>> +#define padctl_pmc_readl(_priv, _offset)			\
>> +({								\
>> +	int rc;							\
>> +	u32 val;						\
> 
> s/val/value/ here and below.
> 
Sure.
>> +	rc = regmap_read(_priv->pmc_reg, _offset, &val);	\
>> +	if (rc)							\
>> +		return rc;					\
>> +	val;							\
>> +})
>> +
>> +#define padctl_pmc_writel(_priv, _val, _offset)			\
>> +do {								\
>> +	int rc;							\
>> +	rc = regmap_write(_priv->pmc_reg, _offset, _val);	\
>> +	if (rc)							\
>> +		return rc;					\
>> +} while (0)
>> +
>> +/* T210 USB2 SLEEPWALK APIs */
> 
> Tegra210, please. Although this really shouldn't be needed, since you
> can derive as much from the function names.
> 
I will remove it.
>> +int tegra_pmc_utmi_enable_phy_sleepwalk(struct phy *phy,
>> +					enum usb_device_speed speed)
> 
> Perhaps use tegra210_ as the prefix for consistency?
> 
Sure, will do.
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
>> +	struct device *dev = padctl->dev;
>> +	unsigned int port = lane->index;
>> +	u32 val, tctrl, pctrl, rpd_ctrl;
> 
> s/val/value/ here and below.
> 
Got it.
>> +
>> +	if (speed > USB_SPEED_HIGH)
>> +		return -EINVAL;
>> +
>> +	dev_dbg(dev, "phy enable sleepwalk usb2 %d speed %d\n", port, speed);
>> +
>> +	val = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
>> +	tctrl = TCTRL_VALUE(val);
>> +	pctrl = PCTRL_VALUE(val);
>> +
>> +	val = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
>> +	rpd_ctrl = RPD_CTRL_VALUE(val);
>> +
>> +	/* ensure sleepwalk logic is disabled */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	val &= ~UTMIP_MASTER_ENABLE(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	/* ensure sleepwalk logics are in low power mode */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
>> +	val |= UTMIP_PWR(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_MASTER_CONFIG);
>> +
>> +	/* set debounce time */
>> +	val = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
>> +	val &= ~UTMIP_LINE_DEB_CNT(~0);
>> +	val |= UTMIP_LINE_DEB_CNT(0x1);
>> +	padctl_pmc_writel(priv, val, PMC_USB_DEBOUNCE_DEL);
>> +
>> +	/* ensure fake events of sleepwalk logic are desiabled */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
>> +	val &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
>> +			UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_FAKE(port));
>> +
>> +	/* ensure wake events of sleepwalk logic are not latched */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +	val &= ~UTMIP_LINE_WAKEUP_EN(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +
>> +	/* disable wake event triggers of sleepwalk logic */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	val &= ~UTMIP_WAKE_VAL(port, ~0);
>> +	val |= UTMIP_WAKE_VAL_NONE(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	/* power down the line state detectors of the pad */
>> +	val = padctl_pmc_readl(priv, PMC_USB_AO);
>> +	val |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
>> +	padctl_pmc_writel(priv, val, PMC_USB_AO);
>> +
>> +	/* save state per speed */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
>> +	val &= ~SPEED(port, ~0);
>> +	if (speed == USB_SPEED_HIGH)
>> +		val |= UTMI_HS(port);
>> +	else if (speed == USB_SPEED_FULL)
>> +		val |= UTMI_FS(port);
>> +	else if (speed == USB_SPEED_LOW)
>> +		val |= UTMI_LS(port);
>> +	else
>> +		val |= UTMI_RST(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SAVED_STATE(port));
>> +
>> +	/* enable the trigger of the sleepwalk logic */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
>> +	val |= UTMIP_LINEVAL_WALK_EN(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
>> +
>> +	/* reset the walk pointer and clear the alarm of the sleepwalk logic,
>> +	 * as well as capture the configuration of the USB2.0 pad
>> +	 */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
>> +	val |= (UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) |
>> +		UTMIP_CAP_CFG(port));
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_TRIGGERS);
>> +
>> +	/* program electrical parameters read from XUSB PADCTL */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
>> +	val &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
>> +	val |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_TERM_PAD_CFG);
>> +
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
>> +	val &= ~RPD_CTRL_PX(~0);
>> +	val |= RPD_CTRL_PX(rpd_ctrl);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_PAD_CFGX(port));
>> +
>> +	/* setup the pull-ups and pull-downs of the signals during the four
>> +	 * stages of sleepwalk.
>> +	 * if device is connected, program sleepwalk logic to maintain a J and
>> +	 * keep driving K upon seeing remote wake.
>> +	 */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
>> +	val = (UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C |
>> +		UTMIP_USBOP_RPD_D);
>> +	val |= (UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C |
>> +		UTMIP_USBON_RPD_D);
>> +	if (speed == USB_SPEED_UNKNOWN) {
>> +		val |= (UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C |
>> +			UTMIP_HIGHZ_D);
>> +	} else if ((speed == USB_SPEED_HIGH) || (speed == USB_SPEED_FULL)) {
>> +		/* J state: D+/D- = high/low, K state: D+/D- = low/high */
>> +		val |= UTMIP_HIGHZ_A;
>> +		val |= UTMIP_AP_A;
>> +		val |= (UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D);
>> +	} else if (speed == USB_SPEED_LOW) {
>> +		/* J state: D+/D- = low/high, K state: D+/D- = high/low */
>> +		val |= UTMIP_HIGHZ_A;
>> +		val |= UTMIP_AN_A;
>> +		val |= (UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D);
>> +	}
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_SLEEPWALK_PX(port));
>> +
>> +	/* power up the line state detectors of the pad */
>> +	val = padctl_pmc_readl(priv, PMC_USB_AO);
>> +	val &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
>> +	padctl_pmc_writel(priv, val, PMC_USB_AO);
>> +
>> +	usleep_range(50, 100);
>> +
>> +	/* switch the electric control of the USB2.0 pad to PMC */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	val |= (UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
>> +			UTMIP_TCTRL_USE_PMC(port));
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
>> +	val |= (UTMIP_RPD_CTRL_USE_PMC_PX(port) |
>> +			UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG1);
>> +
>> +	/* set the wake signaling trigger events */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	val &= ~UTMIP_WAKE_VAL(port, ~0);
>> +	val |= UTMIP_WAKE_VAL_ANY(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	/* enable the wake detection */
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	val |= UTMIP_MASTER_ENABLE(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +	val |= UTMIP_LINE_WAKEUP_EN(port);
>> +	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +
>> +	return 0;
>> +}
>> +
>> +int tegra_pmc_utmi_disable_phy_sleepwalk(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
>> +	struct device *dev = padctl->dev;
>> +	unsigned int port = lane->index;
>> +	u32 value;
>> +
>> +	dev_dbg(dev, "phy disable sleepwalk usb2 %d\n", port);
>> +
>> +	/* disable the wake detection */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	value &= ~UTMIP_MASTER_ENABLE(port);
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +	value &= ~UTMIP_LINE_WAKEUP_EN(port);
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +
>> +	/* switch the electric control of the USB2.0 pad to XUSB or USB2 */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
>> +			UTMIP_TCTRL_USE_PMC(port));
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
>> +	value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) |
>> +			UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
>> +
>> +	/* disable wake event triggers of sleepwalk logic */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +	value &= ~UTMIP_WAKE_VAL(port, ~0);
>> +	value |= UTMIP_WAKE_VAL_NONE(port);
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
>> +
>> +	/* power down the line state detectors of the port */
>> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
>> +	value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
>> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
>> +
>> +	/* clear alarm of the sleepwalk logic */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
>> +	value |= UTMIP_CLR_WAKE_ALARM(port);
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
>> +
>> +	return 0;
>> +}
>> +
>> +int tegra_pmc_hsic_enable_phy_sleepwalk(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
>> +	struct device *dev = padctl->dev;
>> +	unsigned int port = lane->index;
>> +	u32 value;
>> +
>> +	dev_dbg(dev, "phy enable sleepwalk hsic %d\n", port);
>> +
>> +	/* ensure sleepwalk logic is disabled */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
>> +	value &= ~UHSIC_MASTER_ENABLE;
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
>> +
>> +	/* ensure sleepwalk logics are in low power mode */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
>> +	value |= UHSIC_PWR(port);
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
>> +
>> +	/* set debounce time */
>> +	value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
>> +	value &= ~UHSIC_LINE_DEB_CNT(~0);
>> +	value |= UHSIC_LINE_DEB_CNT(0x1);
>> +	padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
>> +
>> +	/* ensure fake events of sleepwalk logic are desiabled */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE);
>> +	value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL |
>> +			UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN);
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE);
>> +
>> +	/* ensure wake events of sleepwalk logic are not latched */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +	value &= ~UHSIC_LINE_WAKEUP_EN;
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +
>> +	/* disable wake event triggers of sleepwalk logic */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
>> +	value &= ~UHSIC_WAKE_VAL(~0);
>> +	value |= UHSIC_WAKE_VAL_NONE;
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
>> +
>> +	/* power down the line state detectors of the port */
>> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
>> +	value |= (STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
>> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
>> +
>> +	/* save state, HSIC always comes up as HS */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE);
>> +	value &= ~UHSIC_MODE(~0);
>> +	value |= UHSIC_HS;
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE);
>> +
>> +	/* enable the trigger of the sleepwalk logic */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG);
>> +	value |= (UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN);
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG);
>> +
>> +	/* reset the walk pointer and clear the alarm of the sleepwalk logic,
>> +	 * as well as capture the configuration of the USB2.0 port
>> +	 */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
>> +	value |= (UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM);
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
>> +
>> +	/* setup the pull-ups and pull-downs of the signals during the four
>> +	 * stages of sleepwalk.
>> +	 * maintain a HSIC IDLE and keep driving HSIC RESUME upon remote wake
>> +	 */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0);
>> +	value = (UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C |
>> +		UHSIC_DATA0_RPU_D);
>> +	value |= (UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C |
>> +		UHSIC_STROBE_RPD_D);
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0);
>> +
>> +	/* power up the line state detectors of the port */
>> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
>> +	value &= ~(STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
>> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
>> +
>> +	usleep_range(50, 100);
>> +
>> +	/* set the wake signaling trigger events */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
>> +	value &= ~UHSIC_WAKE_VAL(~0);
>> +	value |= UHSIC_WAKE_VAL_SD10;
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
>> +
>> +	/* enable the wake detection */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
>> +	value |= UHSIC_MASTER_ENABLE;
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
>> +
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +	value |= UHSIC_LINE_WAKEUP_EN;
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +
>> +	return 0;
>> +}
>> +
>> +int tegra_pmc_hsic_disable_phy_sleepwalk(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
>> +	struct device *dev = padctl->dev;
>> +	unsigned int port = lane->index;
>> +	u32 value;
>> +
>> +	dev_dbg(dev, "phy disable sleepwalk hsic %d\n", port);
>> +
>> +	/* disable the wake detection */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
>> +	value &= ~UHSIC_MASTER_ENABLE;
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
>> +
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +	value &= ~UHSIC_LINE_WAKEUP_EN;
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
>> +
>> +	/* disable wake event triggers of sleepwalk logic */
>> +	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
>> +	value &= ~UHSIC_WAKE_VAL(~0);
>> +	value |= UHSIC_WAKE_VAL_NONE;
>> +	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
>> +
>> +	/* power down the line state detectors of the port */
>> +	value = padctl_pmc_readl(priv, PMC_USB_AO);
>> +	value |= (STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
>> +	padctl_pmc_writel(priv, value, PMC_USB_AO);
>> +
>> +	/* clear alarm of the sleepwalk logic */
>> +	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
>> +	value |= UHSIC_CLR_WAKE_ALARM;
>> +	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
>> +
>> +	return 0;
>> +}
>> +
>>  static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
>>  					 unsigned int index, bool enable)
>>  {
>> @@ -988,8 +1818,23 @@ static int tegra210_usb2_phy_init(struct phy *phy)
>>  {
>>  	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>>  	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	unsigned int index = lane->index;
>> +	struct tegra_xusb_usb2_port *port;
>> +	int err;
>>  	u32 value;
>>  
>> +	port = tegra_xusb_find_usb2_port(padctl, index);
>> +	if (!port) {
>> +		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
>> +		return -ENODEV;
>> +	}
>> +
>> +	err = regulator_enable(port->supply);
>> +	if (err)
>> +		return err;
>> +
>> +	mutex_lock(&padctl->lock);
>> +
>>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
>>  	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
>>  		   XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
>> @@ -997,11 +1842,29 @@ static int tegra210_usb2_phy_init(struct phy *phy)
>>  		 XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
>>  	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
>>  
>> +	mutex_unlock(&padctl->lock);
>> +
>>  	return 0;
>>  }
> 
> How is this related to sleepwalk? Should this perhaps be a separate
> patch? Looks like some hunks below are also not immediately related to
> this commit. Or perhaps I don't understand how they are related.
> 
I will make it a  change. Thanks.
>>  
>>  static int tegra210_usb2_phy_exit(struct phy *phy)
>>  {
>> +	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
>> +	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>> +	unsigned int index = lane->index;
>> +	struct tegra_xusb_usb2_port *port;
>> +	int err;
>> +
>> +	port = tegra_xusb_find_usb2_port(padctl, index);
>> +	if (!port) {
>> +		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
>> +		return -ENODEV;
>> +	}
>> +
>> +	err = regulator_disable(port->supply);
>> +	if (err)
>> +		return err;
>> +
>>  	return 0;
>>  }
>>  
>> @@ -1122,6 +1985,8 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>>  
>>  	priv = to_tegra210_xusb_padctl(padctl);
>>  
>> +	mutex_lock(&padctl->lock);
>> +
>>  	if (port->usb3_port_fake != -1) {
>>  		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
>>  		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
>> @@ -1215,14 +2080,6 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>>  	padctl_writel(padctl, value,
>>  		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
>>  
>> -	if (port->supply && port->mode == USB_DR_MODE_HOST) {
>> -		err = regulator_enable(port->supply);
>> -		if (err)
>> -			return err;
>> -	}
>> -
>> -	mutex_lock(&padctl->lock);
>> -
>>  	if (pad->enable > 0) {
>>  		pad->enable++;
>>  		mutex_unlock(&padctl->lock);
>> @@ -1231,7 +2088,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>>  
>>  	err = clk_prepare_enable(pad->clk);
>>  	if (err)
>> -		goto disable_regulator;
>> +		goto out;
>>  
>>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
>>  	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
>> @@ -1263,8 +2120,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>>  
>>  	return 0;
>>  
>> -disable_regulator:
>> -	regulator_disable(port->supply);
>> +out:
>>  	mutex_unlock(&padctl->lock);
>>  	return err;
>>  }
>> @@ -1275,12 +2131,12 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
>>  	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
>>  	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
>>  	struct tegra_xusb_usb2_port *port;
>> +	unsigned int index = lane->index;
>>  	u32 value;
>>  
>> -	port = tegra_xusb_find_usb2_port(padctl, lane->index);
>> +	port = tegra_xusb_find_usb2_port(padctl, index);
>>  	if (!port) {
>> -		dev_err(&phy->dev, "no port found for USB2 lane %u\n",
>> -			lane->index);
>> +		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
>>  		return -ENODEV;
>>  	}
>>  
>> @@ -1318,12 +2174,19 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
>>  	if (--pad->enable > 0)
>>  		goto out;
>>  
>> +	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
>> +	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD;
>> +	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
>> +
>> +	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
>> +	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR;
>> +	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
>> +
>>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
>>  	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
>>  	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
>>  
>>  out:
>> -	regulator_disable(port->supply);
>>  	mutex_unlock(&padctl->lock);
>>  	return 0;
>>  }
>> @@ -2120,6 +2983,120 @@ static const struct phy_ops tegra210_sata_phy_ops = {
>>  	.owner = THIS_MODULE,
>>  };
>>  
>> +static inline bool is_usb3_phy(struct phy *phy)
>> +{
>> +	return (phy->ops == &tegra210_pcie_phy_ops ||
>> +		phy->ops == &tegra210_sata_phy_ops);
>> +}
>> +
>> +static inline bool is_hsic_phy(struct phy *phy)
>> +{
>> +	return phy->ops == &tegra210_hsic_phy_ops;
>> +}
>> +
>> +static inline bool is_utmi_phy(struct phy *phy)
>> +{
>> +	return phy->ops == &tegra210_usb2_phy_ops;
>> +}
>> +
>> +static int
>> +tegra210_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl,
>> +				     struct phy *phy)
>> +{
>> +	if (!phy)
>> +		return 0;
>> +
>> +	if (is_usb3_phy(phy))
>> +		return tegra210_usb3_enable_phy_wake(phy);
>> +	else if (is_utmi_phy(phy))
>> +		return tegra210_utmi_enable_phy_wake(phy);
>> +	else if (is_hsic_phy(phy))
>> +		return tegra210_hsic_enable_phy_wake(phy);
>> +	else
>> +		return -EINVAL;
>> +}
> 
> Since all of these branches return, you don't need the else and can
> write this more simply as:
> 
> 	if (is_usb3_phy(phy))
> 		return ...;
> 
> 	if (is_utmi_phy(phy))
> 		return ...;
> 
> 	if (is_hsic_phy(phy))
> 		return ...;
> 
> 	return -EINVAL;
> 
> I'd probably also leave out the check for !phy since that should never
> happen and it might be good to just let it crash in that case to make
> sure that bug is found as quickly as possible.
> 
Got it. I will do as suggested.
>> +
>> +static int
>> +tegra210_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl,
>> +				      struct phy *phy)
>> +{
>> +	if (!phy)
>> +		return 0;
>> +
>> +	if (is_usb3_phy(phy))
>> +		return tegra210_usb3_disable_phy_wake(phy);
>> +	else if (is_utmi_phy(phy))
>> +		return tegra210_utmi_disable_phy_wake(phy);
>> +	else if (is_hsic_phy(phy))
>> +		return tegra210_hsic_disable_phy_wake(phy);
>> +	else
>> +		return -EINVAL;
>> +}
>> +
>> +int tegra210_xusb_padctl_remote_wake_detected(struct phy *phy)
>> +{
>> +	struct tegra_xusb_lane *lane;
>> +	struct tegra_xusb_padctl *padctl;
>> +
>> +	if (!phy)
>> +		return 0;
>> +
>> +	lane = phy_get_drvdata(phy);
>> +	padctl = lane->pad->padctl;
>> +
>> +	if (is_utmi_phy(phy))
>> +		return tegra210_utmi_phy_remote_wake_detected(padctl,
>> +					lane->index);
>> +	else if (is_hsic_phy(phy))
>> +		return tegra210_hsic_phy_remote_wake_detected(padctl,
>> +					lane->index);
>> +	else if (is_usb3_phy(phy))
>> +		return tegra210_usb3_phy_remote_wake_detected(padctl,
>> +					tegra210_usb3_lane_map(lane));
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static int
>> +tegra210_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl,
>> +					  struct phy *phy,
>> +					  enum usb_device_speed speed)
>> +{
>> +	if (!phy)
>> +		return 0;
>> +
>> +	if (is_usb3_phy(phy))
>> +		return tegra210_usb3_enable_phy_sleepwalk(phy);
>> +	else if (is_utmi_phy(phy))
>> +		return tegra_pmc_utmi_enable_phy_sleepwalk(phy, speed);
>> +	else if (is_hsic_phy(phy))
>> +		return tegra_pmc_hsic_enable_phy_sleepwalk(phy);
>> +	else
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +static int
>> +tegra210_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl,
>> +					   struct phy *phy)
>> +{
>> +	if (!phy)
>> +		return 0;
>> +
>> +	if (is_usb3_phy(phy))
>> +		return tegra210_usb3_disable_phy_sleepwalk(phy);
>> +	else if (is_utmi_phy(phy))
>> +		return tegra_pmc_utmi_disable_phy_sleepwalk(phy);
>> +	else if (is_hsic_phy(phy))
>> +		return tegra_pmc_hsic_disable_phy_sleepwalk(phy);
>> +	else
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +
>>  static struct tegra_xusb_pad *
>>  tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl,
>>  			const struct tegra_xusb_pad_soc *soc,
>> @@ -2317,6 +3294,8 @@ tegra210_xusb_padctl_probe(struct device *dev,
>>  			   const struct tegra_xusb_padctl_soc *soc)
>>  {
>>  	struct tegra210_xusb_padctl *padctl;
>> +	struct device_node *node, *np = dev->of_node;
>> +	struct platform_device *pmc_dev;
>>  	int err;
>>  
>>  	padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
>> @@ -2330,6 +3309,24 @@ tegra210_xusb_padctl_probe(struct device *dev,
>>  	if (err < 0)
>>  		return ERR_PTR(err);
>>  
>> +	node = of_parse_phandle(np, "nvidia,pmc", 0);
>> +	if (!node) {
>> +		dev_err(dev, "nvidia,pmc property is missing\n");
>> +		return ERR_PTR(-ENODEV);
>> +	}
>> +
>> +	pmc_dev = of_find_device_by_node(node);
>> +	if (!pmc_dev) {
>> +		dev_err(dev, "pmc device is not available\n");
>> +		return ERR_PTR(-ENODEV);
>> +	}
>> +
>> +	padctl->pmc_reg = dev_get_regmap(&pmc_dev->dev, "usb_sleepwalk");
>> +	if (!padctl->pmc_reg) {
>> +		dev_err(dev, "pmc regmap is not available.\n");
>> +		return ERR_PTR(-ENODEV);
>> +	}
> 
> We'll have to make this optional for backwards compatibility, which will
> also help make this easier to merge because it doesn't all have to go in
> at the same time.
> 
Understood. I will make it optional in the next revision.
> Thierry
> 
>> +
>>  	return &padctl->base;
>>  }
>>  
>> @@ -2337,13 +3334,80 @@ static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
>>  {
>>  }
>>  
>> +static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
>> +{
>> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
>> +
>> +	priv->context.usb2_pad_mux =
>> +		padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
>> +	priv->context.usb2_port_cap =
>> +		padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
>> +	priv->context.ss_port_map =
>> +		padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
>> +	priv->context.usb3_pad_mux =
>> +		padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
>> +}
>> +
>> +static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
>> +{
>> +	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
>> +	int i;
>> +
>> +	padctl_writel(padctl, priv->context.usb2_pad_mux,
>> +		XUSB_PADCTL_USB2_PAD_MUX);
>> +	padctl_writel(padctl, priv->context.usb2_port_cap,
>> +		XUSB_PADCTL_USB2_PORT_CAP);
>> +	padctl_writel(padctl, priv->context.ss_port_map,
>> +		XUSB_PADCTL_SS_PORT_MAP);
>> +
>> +	for (i = 0; i <= 7; i ++)
>> +		tegra210_uphy_lane_iddq_enable(padctl, i);
>> +
>> +	padctl_writel(padctl, priv->context.usb3_pad_mux,
>> +		XUSB_PADCTL_USB3_PAD_MUX);
>> +
>> +	for (i = 0; i <= 7; i ++)
>> +		tegra210_uphy_lane_iddq_disable(padctl, i);
>> +}
>> +
>> +static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
>> +{
>> +	mutex_lock(&padctl->lock);
>> +
>> +	tegra210_uphy_deinit(padctl);
>> +
>> +	tegra210_xusb_padctl_save(padctl);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +	return 0;
>> +}
>> +
>> +static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
>> +{
>> +	mutex_lock(&padctl->lock);
>> +
>> +	tegra210_xusb_padctl_restore(padctl);
>> +
>> +	tegra210_uphy_init(padctl);
>> +
>> +	mutex_unlock(&padctl->lock);
>> +	return 0;
>> +}
>> +
>>  static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
>>  	.probe = tegra210_xusb_padctl_probe,
>>  	.remove = tegra210_xusb_padctl_remove,
>> +	.suspend_noirq = tegra210_xusb_padctl_suspend_noirq,
>> +	.resume_noirq = tegra210_xusb_padctl_resume_noirq,
>>  	.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
>>  	.hsic_set_idle = tegra210_hsic_set_idle,
>>  	.vbus_override = tegra210_xusb_padctl_vbus_override,
>>  	.utmi_port_reset = tegra210_utmi_port_reset,
>> +	.enable_phy_sleepwalk = tegra210_xusb_padctl_enable_phy_sleepwalk,
>> +	.disable_phy_sleepwalk = tegra210_xusb_padctl_disable_phy_sleepwalk,
>> +	.enable_phy_wake = tegra210_xusb_padctl_enable_phy_wake,
>> +	.disable_phy_wake = tegra210_xusb_padctl_disable_phy_wake,
>> +	.remote_wake_detected = tegra210_xusb_padctl_remote_wake_detected,
>>  };
>>  
>>  static const char * const tegra210_xusb_padctl_supply_names[] = {
>> -- 
>> 2.25.1
>>
diff mbox series

Patch

diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index fe1ab440424d..1c03f4ec4b59 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -16,6 +16,8 @@ 
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/of_platform.h>
 
 #include <soc/tegra/fuse.h>
 
@@ -52,6 +54,20 @@ 
 #define XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP(x, v) (((v) & 0x7) << ((x) * 5))
 #define XUSB_PADCTL_SS_PORT_MAP_PORT_DISABLED 0x7
 
+#define XUSB_PADCTL_ELPG_PROGRAM_0 0x20
+#define   USB2_PORT_WAKE_INTERRUPT_ENABLE(x)      BIT((x))
+#define   USB2_PORT_WAKEUP_EVENT(x)               BIT((x) + 7)
+#define   SS_PORT_WAKE_INTERRUPT_ENABLE(x)        BIT((x) + 14)
+#define   SS_PORT_WAKEUP_EVENT(x)                 BIT((x) + 21)
+#define   USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28)
+#define   USB2_HSIC_PORT_WAKEUP_EVENT(x)          BIT((x) + 30)
+#define   ALL_WAKE_EVENTS ( \
+		USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \
+		USB2_PORT_WAKEUP_EVENT(2) | USB2_PORT_WAKEUP_EVENT(3) | \
+		SS_PORT_WAKEUP_EVENT(0) | SS_PORT_WAKEUP_EVENT(1) | \
+		SS_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(3) | \
+		USB2_HSIC_PORT_WAKEUP_EVENT(0))
+
 #define XUSB_PADCTL_ELPG_PROGRAM1 0x024
 #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_VCORE_DOWN (1 << 31)
 #define XUSB_PADCTL_ELPG_PROGRAM1_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 30)
@@ -90,6 +106,8 @@ 
 #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
 #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_OVRD (1 << 1)
 #define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_OVRD (1 << 0)
+#define   RPD_CTRL(x)                      (((x) & 0x1f) << 26)
+#define   RPD_CTRL_VALUE(x)                (((x) >> 26) & 0x1f)
 
 #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284
 #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 11)
@@ -108,6 +126,8 @@ 
 #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_SHIFT 12
 #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK 0x7f
 #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_VAL 0x1e
+#define   TCTRL_VALUE(x)                (((x) & 0x3f) >> 0)
+#define   PCTRL_VALUE(x)                (((x) >> 6) & 0x3f)
 
 #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20)
 #define XUSB_PADCTL_HSIC_PAD_CTL0_RPU_STROBE (1 << 18)
@@ -251,16 +271,161 @@ 
 #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
 #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
 
+/* USB2 SLEEPWALK registers */
+#define UTMIP(_port, _offset1, _offset2) \
+		(((_port) <= 2) ? (_offset1) : (_offset2))
+
+#define PMC_UTMIP_UHSIC_SLEEP_CFG(x)	UTMIP(x, 0x1fc, 0x4d0)
+#define   UTMIP_MASTER_ENABLE(x)		UTMIP(x, BIT(8 * (x)), BIT(0))
+#define   UTMIP_FSLS_USE_PMC(x)			UTMIP(x, BIT(8 * (x) + 1), \
+							BIT(1))
+#define   UTMIP_PCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 2), \
+							BIT(2))
+#define   UTMIP_TCTRL_USE_PMC(x)		UTMIP(x, BIT(8 * (x) + 3), \
+							BIT(3))
+#define   UTMIP_WAKE_VAL(_port, _value)		(((_value) & 0xf) << \
+					(UTMIP(_port, 8 * (_port) + 4, 4)))
+#define   UTMIP_WAKE_VAL_NONE(_port)		UTMIP_WAKE_VAL(_port, 12)
+#define   UTMIP_WAKE_VAL_ANY(_port)		UTMIP_WAKE_VAL(_port, 15)
+
+#define PMC_UTMIP_UHSIC_SLEEP_CFG1	(0x4d0)
+#define   UTMIP_RPU_SWITC_LOW_USE_PMC_PX(x)	BIT((x) + 8)
+#define   UTMIP_RPD_CTRL_USE_PMC_PX(x)		BIT((x) + 16)
+
+#define PMC_UTMIP_MASTER_CONFIG		(0x274)
+#define   UTMIP_PWR(x)				UTMIP(x, BIT(x), BIT(4))
+#define   UHSIC_PWR(x)				BIT(3)
+
+#define PMC_USB_DEBOUNCE_DEL		(0xec)
+#define   DEBOUNCE_VAL(x)			(((x) & 0xffff) << 0)
+#define   UTMIP_LINE_DEB_CNT(x)			(((x) & 0xf) << 16)
+#define   UHSIC_LINE_DEB_CNT(x)			(((x) & 0xf) << 20)
+
+#define PMC_UTMIP_UHSIC_FAKE(x)		UTMIP(x, 0x218, 0x294)
+#define   UTMIP_FAKE_USBOP_VAL(x)		UTMIP(x, BIT(4 * (x)), BIT(8))
+#define   UTMIP_FAKE_USBON_VAL(x)		UTMIP(x, BIT(4 * (x) + 1), \
+							BIT(9))
+#define   UTMIP_FAKE_USBOP_EN(x)		UTMIP(x, BIT(4 * (x) + 2), \
+							BIT(10))
+#define   UTMIP_FAKE_USBON_EN(x)		UTMIP(x, BIT(4 * (x) + 3), \
+							BIT(11))
+
+#define PMC_UTMIP_UHSIC_SLEEPWALK_CFG(x)	UTMIP(x, 0x200, 0x288)
+#define   UTMIP_LINEVAL_WALK_EN(x)		UTMIP(x, BIT(8 * (x) + 7), \
+							BIT(15))
+
+#define PMC_USB_AO			(0xf0)
+#define   USBOP_VAL_PD(x)			UTMIP(x, BIT(4 * (x)), BIT(20))
+#define   USBON_VAL_PD(x)			UTMIP(x, BIT(4 * (x) + 1), \
+							BIT(21))
+#define   STROBE_VAL_PD(x)			BIT(12)
+#define   DATA0_VAL_PD(x)			BIT(13)
+#define   DATA1_VAL_PD				BIT(24)
+
+#define PMC_UTMIP_UHSIC_SAVED_STATE(x)	UTMIP(x, 0x1f0, 0x280)
+#define   SPEED(_port, _value)			(((_value) & 0x3) << \
+						(UTMIP(_port, 8 * (_port), 8)))
+#define   UTMI_HS(_port)			SPEED(_port, 0)
+#define   UTMI_FS(_port)			SPEED(_port, 1)
+#define   UTMI_LS(_port)			SPEED(_port, 2)
+#define   UTMI_RST(_port)			SPEED(_port, 3)
+
+#define PMC_UTMIP_UHSIC_TRIGGERS		(0x1ec)
+#define   UTMIP_CLR_WALK_PTR(x)			UTMIP(x, BIT(x), BIT(16))
+#define   UTMIP_CAP_CFG(x)			UTMIP(x, BIT((x) + 4), BIT(17))
+#define   UTMIP_CLR_WAKE_ALARM(x)		UTMIP(x, BIT((x) + 12), \
+							BIT(19))
+#define   UHSIC_CLR_WALK_PTR			BIT(3)
+#define   UHSIC_CLR_WAKE_ALARM			BIT(15)
+
+#define PMC_UTMIP_SLEEPWALK_PX(x)	UTMIP(x, 0x204 + (4 * (x)), \
+							0x4e0)
+/* phase A */
+#define   UTMIP_USBOP_RPD_A			BIT(0)
+#define   UTMIP_USBON_RPD_A			BIT(1)
+#define   UTMIP_AP_A				BIT(4)
+#define   UTMIP_AN_A				BIT(5)
+#define   UTMIP_HIGHZ_A				BIT(6)
+/* phase B */
+#define   UTMIP_USBOP_RPD_B			BIT(8)
+#define   UTMIP_USBON_RPD_B			BIT(9)
+#define   UTMIP_AP_B				BIT(12)
+#define   UTMIP_AN_B				BIT(13)
+#define   UTMIP_HIGHZ_B				BIT(14)
+/* phase C */
+#define   UTMIP_USBOP_RPD_C			BIT(16)
+#define   UTMIP_USBON_RPD_C			BIT(17)
+#define   UTMIP_AP_C				BIT(20)
+#define   UTMIP_AN_C				BIT(21)
+#define   UTMIP_HIGHZ_C				BIT(22)
+/* phase D */
+#define   UTMIP_USBOP_RPD_D			BIT(24)
+#define   UTMIP_USBON_RPD_D			BIT(25)
+#define   UTMIP_AP_D				BIT(28)
+#define   UTMIP_AN_D				BIT(29)
+#define   UTMIP_HIGHZ_D				BIT(30)
+
+#define PMC_UTMIP_UHSIC_LINE_WAKEUP	(0x26c)
+#define   UTMIP_LINE_WAKEUP_EN(x)		UTMIP(x, BIT(x), BIT(4))
+#define   UHSIC_LINE_WAKEUP_EN			BIT(3)
+
+#define PMC_UTMIP_TERM_PAD_CFG		(0x1f8)
+#define   PCTRL_VAL(x)				(((x) & 0x3f) << 1)
+#define   TCTRL_VAL(x)				(((x) & 0x3f) << 7)
+
+#define PMC_UTMIP_PAD_CFGX(x)		(0x4c0 + (4 * (x)))
+#define   RPD_CTRL_PX(x)			(((x) & 0x1f) << 22)
+
+#define PMC_UHSIC_SLEEP_CFG	PMC_UTMIP_UHSIC_SLEEP_CFG(0)
+#define   UHSIC_MASTER_ENABLE			BIT(24)
+#define   UHSIC_WAKE_VAL(_value)		(((_value) & 0xf) << 28)
+#define   UHSIC_WAKE_VAL_SD10			UHSIC_WAKE_VAL(2)
+#define   UHSIC_WAKE_VAL_NONE			UHSIC_WAKE_VAL(12)
+
+#define PMC_UHSIC_FAKE			PMC_UTMIP_UHSIC_FAKE(0)
+#define   UHSIC_FAKE_STROBE_VAL			BIT(12)
+#define   UHSIC_FAKE_DATA_VAL			BIT(13)
+#define   UHSIC_FAKE_STROBE_EN			BIT(14)
+#define   UHSIC_FAKE_DATA_EN			BIT(15)
+
+#define PMC_UHSIC_SAVED_STATE		PMC_UTMIP_UHSIC_SAVED_STATE(0)
+#define   UHSIC_MODE(_value)			(((_value) & 0x1) << 24)
+#define   UHSIC_HS				UHSIC_MODE(0)
+#define   UHSIC_RST				UHSIC_MODE(1)
+
+#define PMC_UHSIC_SLEEPWALK_CFG		PMC_UTMIP_UHSIC_SLEEPWALK_CFG(0)
+#define   UHSIC_WAKE_WALK_EN			BIT(30)
+#define   UHSIC_LINEVAL_WALK_EN			BIT(31)
+
+#define PMC_UHSIC_SLEEPWALK_P0		(0x210)
+#define   UHSIC_DATA0_RPD_A			BIT(1)
+#define   UHSIC_DATA0_RPU_B			BIT(11)
+#define   UHSIC_DATA0_RPU_C			BIT(19)
+#define   UHSIC_DATA0_RPU_D			BIT(27)
+#define   UHSIC_STROBE_RPU_A			BIT(2)
+#define   UHSIC_STROBE_RPD_B			BIT(8)
+#define   UHSIC_STROBE_RPD_C			BIT(16)
+#define   UHSIC_STROBE_RPD_D			BIT(24)
+
 struct tegra210_xusb_fuse_calibration {
 	u32 hs_curr_level[4];
 	u32 hs_term_range_adj;
 	u32 rpd_ctrl;
 };
 
+struct tegra210_xusb_padctl_context {
+	u32 usb2_pad_mux;
+	u32 usb2_port_cap;
+	u32 ss_port_map;
+	u32 usb3_pad_mux;
+};
+
 struct tegra210_xusb_padctl {
 	struct tegra_xusb_padctl base;
 
 	struct tegra210_xusb_fuse_calibration fuse;
+	struct tegra210_xusb_padctl_context context;
+	struct regmap *pmc_reg;
 };
 
 static inline struct tegra210_xusb_padctl *
@@ -886,6 +1051,671 @@  static int tegra210_hsic_set_idle(struct tegra_xusb_padctl *padctl,
 	return 0;
 }
 
+static int tegra210_usb3_enable_phy_sleepwalk(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	int port = tegra210_usb3_lane_map(lane);
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	if (port < 0) {
+		dev_err(dev, "invalid usb3 port number\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "phy enable sleepwalk usb3 %d\n", port);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+	value |= XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+	usleep_range(250, 350);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_usb3_disable_phy_sleepwalk(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	int port = tegra210_usb3_lane_map(lane);
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	if (port < 0) {
+		dev_err(dev, "invalid usb3 port number\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "phy disable sleepwalk usb3 %d\n", port);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM1);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM1_SSPX_ELPG_CLAMP_EN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM1);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_usb3_enable_phy_wake(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	int port = tegra210_usb3_lane_map(lane);
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	if (port < 0) {
+		dev_err(dev, "invalid usb3 port number\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "phy enable wake usb3 %d\n", port);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= SS_PORT_WAKEUP_EVENT(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	usleep_range(10, 20);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= SS_PORT_WAKE_INTERRUPT_ENABLE(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_usb3_disable_phy_wake(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	int port = tegra210_usb3_lane_map(lane);
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	if (port < 0) {
+		dev_err(dev, "invalid usb3 port number\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "phy disable wake usb3 %d\n", port);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	usleep_range(10, 20);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= SS_PORT_WAKEUP_EVENT(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_utmi_enable_phy_wake(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	unsigned int index = lane->index;
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	dev_dbg(dev, "phy enable wake on usb2 %d\n", index);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= USB2_PORT_WAKEUP_EVENT(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	usleep_range(10, 20);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_utmi_disable_phy_wake(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	unsigned int index = lane->index;
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	dev_dbg(dev, "phy disable wake on usb2 %d\n", index);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	usleep_range(10, 20);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= USB2_PORT_WAKEUP_EVENT(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_hsic_enable_phy_wake(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	unsigned int index = lane->index;
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	dev_dbg(dev, "phy enable wake on hsic %d\n", index);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	usleep_range(10, 20);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_hsic_disable_phy_wake(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	unsigned int index = lane->index;
+	struct device *dev = padctl->dev;
+	u32 value;
+
+	dev_dbg(dev, "phy disable wake on hsic %d\n", index);
+
+	mutex_lock(&padctl->lock);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value &= ~USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	usleep_range(10, 20);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	value &= ~ALL_WAKE_EVENTS;
+	value |= USB2_HSIC_PORT_WAKEUP_EVENT(index);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_0);
+
+	mutex_unlock(&padctl->lock);
+
+	return 0;
+}
+
+static int tegra210_usb3_phy_remote_wake_detected(
+			struct tegra_xusb_padctl *padctl, int port)
+{
+	u32 value;
+
+	if (port < 0) {
+		dev_err(padctl->dev, "invalid usb3 port number %d\n",
+					port);
+		return false;
+	}
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	if ((value & SS_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
+	    (value & SS_PORT_WAKEUP_EVENT(port)))
+		return true;
+	else
+		return false;
+}
+
+static int tegra210_utmi_phy_remote_wake_detected(
+			struct tegra_xusb_padctl *padctl, int port)
+{
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	if ((value & USB2_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
+	    (value & USB2_PORT_WAKEUP_EVENT(port)))
+		return true;
+	else
+		return false;
+}
+
+static int tegra210_hsic_phy_remote_wake_detected(
+			struct tegra_xusb_padctl *padctl, int port)
+{
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_0);
+	if ((value & USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(port)) &&
+	    (value & USB2_HSIC_PORT_WAKEUP_EVENT(port)))
+		return true;
+	else
+		return false;
+}
+
+#define padctl_pmc_readl(_priv, _offset)			\
+({								\
+	int rc;							\
+	u32 val;						\
+	rc = regmap_read(_priv->pmc_reg, _offset, &val);	\
+	if (rc)							\
+		return rc;					\
+	val;							\
+})
+
+#define padctl_pmc_writel(_priv, _val, _offset)			\
+do {								\
+	int rc;							\
+	rc = regmap_write(_priv->pmc_reg, _offset, _val);	\
+	if (rc)							\
+		return rc;					\
+} while (0)
+
+/* T210 USB2 SLEEPWALK APIs */
+int tegra_pmc_utmi_enable_phy_sleepwalk(struct phy *phy,
+					enum usb_device_speed speed)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+	struct device *dev = padctl->dev;
+	unsigned int port = lane->index;
+	u32 val, tctrl, pctrl, rpd_ctrl;
+
+	if (speed > USB_SPEED_HIGH)
+		return -EINVAL;
+
+	dev_dbg(dev, "phy enable sleepwalk usb2 %d speed %d\n", port, speed);
+
+	val = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
+	tctrl = TCTRL_VALUE(val);
+	pctrl = PCTRL_VALUE(val);
+
+	val = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+	rpd_ctrl = RPD_CTRL_VALUE(val);
+
+	/* ensure sleepwalk logic is disabled */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	val &= ~UTMIP_MASTER_ENABLE(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	/* ensure sleepwalk logics are in low power mode */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
+	val |= UTMIP_PWR(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_MASTER_CONFIG);
+
+	/* set debounce time */
+	val = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
+	val &= ~UTMIP_LINE_DEB_CNT(~0);
+	val |= UTMIP_LINE_DEB_CNT(0x1);
+	padctl_pmc_writel(priv, val, PMC_USB_DEBOUNCE_DEL);
+
+	/* ensure fake events of sleepwalk logic are desiabled */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_FAKE(port));
+	val &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
+			UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_FAKE(port));
+
+	/* ensure wake events of sleepwalk logic are not latched */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+	val &= ~UTMIP_LINE_WAKEUP_EN(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+	/* disable wake event triggers of sleepwalk logic */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	val &= ~UTMIP_WAKE_VAL(port, ~0);
+	val |= UTMIP_WAKE_VAL_NONE(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	/* power down the line state detectors of the pad */
+	val = padctl_pmc_readl(priv, PMC_USB_AO);
+	val |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
+	padctl_pmc_writel(priv, val, PMC_USB_AO);
+
+	/* save state per speed */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
+	val &= ~SPEED(port, ~0);
+	if (speed == USB_SPEED_HIGH)
+		val |= UTMI_HS(port);
+	else if (speed == USB_SPEED_FULL)
+		val |= UTMI_FS(port);
+	else if (speed == USB_SPEED_LOW)
+		val |= UTMI_LS(port);
+	else
+		val |= UTMI_RST(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SAVED_STATE(port));
+
+	/* enable the trigger of the sleepwalk logic */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
+	val |= UTMIP_LINEVAL_WALK_EN(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
+
+	/* reset the walk pointer and clear the alarm of the sleepwalk logic,
+	 * as well as capture the configuration of the USB2.0 pad
+	 */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+	val |= (UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) |
+		UTMIP_CAP_CFG(port));
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_TRIGGERS);
+
+	/* program electrical parameters read from XUSB PADCTL */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
+	val &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
+	val |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
+	padctl_pmc_writel(priv, val, PMC_UTMIP_TERM_PAD_CFG);
+
+	val = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
+	val &= ~RPD_CTRL_PX(~0);
+	val |= RPD_CTRL_PX(rpd_ctrl);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_PAD_CFGX(port));
+
+	/* setup the pull-ups and pull-downs of the signals during the four
+	 * stages of sleepwalk.
+	 * if device is connected, program sleepwalk logic to maintain a J and
+	 * keep driving K upon seeing remote wake.
+	 */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
+	val = (UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C |
+		UTMIP_USBOP_RPD_D);
+	val |= (UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C |
+		UTMIP_USBON_RPD_D);
+	if (speed == USB_SPEED_UNKNOWN) {
+		val |= (UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C |
+			UTMIP_HIGHZ_D);
+	} else if ((speed == USB_SPEED_HIGH) || (speed == USB_SPEED_FULL)) {
+		/* J state: D+/D- = high/low, K state: D+/D- = low/high */
+		val |= UTMIP_HIGHZ_A;
+		val |= UTMIP_AP_A;
+		val |= (UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D);
+	} else if (speed == USB_SPEED_LOW) {
+		/* J state: D+/D- = low/high, K state: D+/D- = high/low */
+		val |= UTMIP_HIGHZ_A;
+		val |= UTMIP_AN_A;
+		val |= (UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D);
+	}
+	padctl_pmc_writel(priv, val, PMC_UTMIP_SLEEPWALK_PX(port));
+
+	/* power up the line state detectors of the pad */
+	val = padctl_pmc_readl(priv, PMC_USB_AO);
+	val &= ~(USBOP_VAL_PD(port) | USBON_VAL_PD(port));
+	padctl_pmc_writel(priv, val, PMC_USB_AO);
+
+	usleep_range(50, 100);
+
+	/* switch the electric control of the USB2.0 pad to PMC */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	val |= (UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
+			UTMIP_TCTRL_USE_PMC(port));
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+	val |= (UTMIP_RPD_CTRL_USE_PMC_PX(port) |
+			UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+
+	/* set the wake signaling trigger events */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	val &= ~UTMIP_WAKE_VAL(port, ~0);
+	val |= UTMIP_WAKE_VAL_ANY(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	/* enable the wake detection */
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	val |= UTMIP_MASTER_ENABLE(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	val = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+	val |= UTMIP_LINE_WAKEUP_EN(port);
+	padctl_pmc_writel(priv, val, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+	return 0;
+}
+
+int tegra_pmc_utmi_disable_phy_sleepwalk(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+	struct device *dev = padctl->dev;
+	unsigned int port = lane->index;
+	u32 value;
+
+	dev_dbg(dev, "phy disable sleepwalk usb2 %d\n", port);
+
+	/* disable the wake detection */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	value &= ~UTMIP_MASTER_ENABLE(port);
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+	value &= ~UTMIP_LINE_WAKEUP_EN(port);
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+	/* switch the electric control of the USB2.0 pad to XUSB or USB2 */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	value &= ~(UTMIP_FSLS_USE_PMC(port) | UTMIP_PCTRL_USE_PMC(port) |
+			UTMIP_TCTRL_USE_PMC(port));
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+	value &= ~(UTMIP_RPD_CTRL_USE_PMC_PX(port) |
+			UTMIP_RPU_SWITC_LOW_USE_PMC_PX(port));
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG1);
+
+	/* disable wake event triggers of sleepwalk logic */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+	value &= ~UTMIP_WAKE_VAL(port, ~0);
+	value |= UTMIP_WAKE_VAL_NONE(port);
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
+
+	/* power down the line state detectors of the port */
+	value = padctl_pmc_readl(priv, PMC_USB_AO);
+	value |= (USBOP_VAL_PD(port) | USBON_VAL_PD(port));
+	padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+	/* clear alarm of the sleepwalk logic */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+	value |= UTMIP_CLR_WAKE_ALARM(port);
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
+
+	return 0;
+}
+
+int tegra_pmc_hsic_enable_phy_sleepwalk(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+	struct device *dev = padctl->dev;
+	unsigned int port = lane->index;
+	u32 value;
+
+	dev_dbg(dev, "phy enable sleepwalk hsic %d\n", port);
+
+	/* ensure sleepwalk logic is disabled */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+	value &= ~UHSIC_MASTER_ENABLE;
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+	/* ensure sleepwalk logics are in low power mode */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
+	value |= UHSIC_PWR(port);
+	padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
+
+	/* set debounce time */
+	value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
+	value &= ~UHSIC_LINE_DEB_CNT(~0);
+	value |= UHSIC_LINE_DEB_CNT(0x1);
+	padctl_pmc_writel(priv, value, PMC_USB_DEBOUNCE_DEL);
+
+	/* ensure fake events of sleepwalk logic are desiabled */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_FAKE);
+	value &= ~(UHSIC_FAKE_STROBE_VAL | UHSIC_FAKE_DATA_VAL |
+			UHSIC_FAKE_STROBE_EN | UHSIC_FAKE_DATA_EN);
+	padctl_pmc_writel(priv, value, PMC_UHSIC_FAKE);
+
+	/* ensure wake events of sleepwalk logic are not latched */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+	value &= ~UHSIC_LINE_WAKEUP_EN;
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+	/* disable wake event triggers of sleepwalk logic */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+	value &= ~UHSIC_WAKE_VAL(~0);
+	value |= UHSIC_WAKE_VAL_NONE;
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+	/* power down the line state detectors of the port */
+	value = padctl_pmc_readl(priv, PMC_USB_AO);
+	value |= (STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
+	padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+	/* save state, HSIC always comes up as HS */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SAVED_STATE);
+	value &= ~UHSIC_MODE(~0);
+	value |= UHSIC_HS;
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SAVED_STATE);
+
+	/* enable the trigger of the sleepwalk logic */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_CFG);
+	value |= (UHSIC_WAKE_WALK_EN | UHSIC_LINEVAL_WALK_EN);
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_CFG);
+
+	/* reset the walk pointer and clear the alarm of the sleepwalk logic,
+	 * as well as capture the configuration of the USB2.0 port
+	 */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+	value |= (UHSIC_CLR_WALK_PTR | UHSIC_CLR_WAKE_ALARM);
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
+
+	/* setup the pull-ups and pull-downs of the signals during the four
+	 * stages of sleepwalk.
+	 * maintain a HSIC IDLE and keep driving HSIC RESUME upon remote wake
+	 */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEPWALK_P0);
+	value = (UHSIC_DATA0_RPD_A | UHSIC_DATA0_RPU_B | UHSIC_DATA0_RPU_C |
+		UHSIC_DATA0_RPU_D);
+	value |= (UHSIC_STROBE_RPU_A | UHSIC_STROBE_RPD_B | UHSIC_STROBE_RPD_C |
+		UHSIC_STROBE_RPD_D);
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEPWALK_P0);
+
+	/* power up the line state detectors of the port */
+	value = padctl_pmc_readl(priv, PMC_USB_AO);
+	value &= ~(STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
+	padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+	usleep_range(50, 100);
+
+	/* set the wake signaling trigger events */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+	value &= ~UHSIC_WAKE_VAL(~0);
+	value |= UHSIC_WAKE_VAL_SD10;
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+	/* enable the wake detection */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+	value |= UHSIC_MASTER_ENABLE;
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+	value |= UHSIC_LINE_WAKEUP_EN;
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+	return 0;
+}
+
+int tegra_pmc_hsic_disable_phy_sleepwalk(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+	struct device *dev = padctl->dev;
+	unsigned int port = lane->index;
+	u32 value;
+
+	dev_dbg(dev, "phy disable sleepwalk hsic %d\n", port);
+
+	/* disable the wake detection */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+	value &= ~UHSIC_MASTER_ENABLE;
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+	value &= ~UHSIC_LINE_WAKEUP_EN;
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_LINE_WAKEUP);
+
+	/* disable wake event triggers of sleepwalk logic */
+	value = padctl_pmc_readl(priv, PMC_UHSIC_SLEEP_CFG);
+	value &= ~UHSIC_WAKE_VAL(~0);
+	value |= UHSIC_WAKE_VAL_NONE;
+	padctl_pmc_writel(priv, value, PMC_UHSIC_SLEEP_CFG);
+
+	/* power down the line state detectors of the port */
+	value = padctl_pmc_readl(priv, PMC_USB_AO);
+	value |= (STROBE_VAL_PD(port) | DATA0_VAL_PD(port) | DATA1_VAL_PD);
+	padctl_pmc_writel(priv, value, PMC_USB_AO);
+
+	/* clear alarm of the sleepwalk logic */
+	value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
+	value |= UHSIC_CLR_WAKE_ALARM;
+	padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
+
+	return 0;
+}
+
 static int tegra210_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
 					 unsigned int index, bool enable)
 {
@@ -988,8 +1818,23 @@  static int tegra210_usb2_phy_init(struct phy *phy)
 {
 	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	unsigned int index = lane->index;
+	struct tegra_xusb_usb2_port *port;
+	int err;
 	u32 value;
 
+	port = tegra_xusb_find_usb2_port(padctl, index);
+	if (!port) {
+		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
+		return -ENODEV;
+	}
+
+	err = regulator_enable(port->supply);
+	if (err)
+		return err;
+
+	mutex_lock(&padctl->lock);
+
 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
 	value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
 		   XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
@@ -997,11 +1842,29 @@  static int tegra210_usb2_phy_init(struct phy *phy)
 		 XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
 
+	mutex_unlock(&padctl->lock);
+
 	return 0;
 }
 
 static int tegra210_usb2_phy_exit(struct phy *phy)
 {
+	struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+	unsigned int index = lane->index;
+	struct tegra_xusb_usb2_port *port;
+	int err;
+
+	port = tegra_xusb_find_usb2_port(padctl, index);
+	if (!port) {
+		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
+		return -ENODEV;
+	}
+
+	err = regulator_disable(port->supply);
+	if (err)
+		return err;
+
 	return 0;
 }
 
@@ -1122,6 +1985,8 @@  static int tegra210_usb2_phy_power_on(struct phy *phy)
 
 	priv = to_tegra210_xusb_padctl(padctl);
 
+	mutex_lock(&padctl->lock);
+
 	if (port->usb3_port_fake != -1) {
 		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
 		value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
@@ -1215,14 +2080,6 @@  static int tegra210_usb2_phy_power_on(struct phy *phy)
 	padctl_writel(padctl, value,
 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
 
-	if (port->supply && port->mode == USB_DR_MODE_HOST) {
-		err = regulator_enable(port->supply);
-		if (err)
-			return err;
-	}
-
-	mutex_lock(&padctl->lock);
-
 	if (pad->enable > 0) {
 		pad->enable++;
 		mutex_unlock(&padctl->lock);
@@ -1231,7 +2088,7 @@  static int tegra210_usb2_phy_power_on(struct phy *phy)
 
 	err = clk_prepare_enable(pad->clk);
 	if (err)
-		goto disable_regulator;
+		goto out;
 
 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
 	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
@@ -1263,8 +2120,7 @@  static int tegra210_usb2_phy_power_on(struct phy *phy)
 
 	return 0;
 
-disable_regulator:
-	regulator_disable(port->supply);
+out:
 	mutex_unlock(&padctl->lock);
 	return err;
 }
@@ -1275,12 +2131,12 @@  static int tegra210_usb2_phy_power_off(struct phy *phy)
 	struct tegra_xusb_usb2_pad *pad = to_usb2_pad(lane->pad);
 	struct tegra_xusb_padctl *padctl = lane->pad->padctl;
 	struct tegra_xusb_usb2_port *port;
+	unsigned int index = lane->index;
 	u32 value;
 
-	port = tegra_xusb_find_usb2_port(padctl, lane->index);
+	port = tegra_xusb_find_usb2_port(padctl, index);
 	if (!port) {
-		dev_err(&phy->dev, "no port found for USB2 lane %u\n",
-			lane->index);
+		dev_err(&phy->dev, "no port found for USB2 lane %u\n", index);
 		return -ENODEV;
 	}
 
@@ -1318,12 +2174,19 @@  static int tegra210_usb2_phy_power_off(struct phy *phy)
 	if (--pad->enable > 0)
 		goto out;
 
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
+	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
+	value |= XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
+
 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
 	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
 
 out:
-	regulator_disable(port->supply);
 	mutex_unlock(&padctl->lock);
 	return 0;
 }
@@ -2120,6 +2983,120 @@  static const struct phy_ops tegra210_sata_phy_ops = {
 	.owner = THIS_MODULE,
 };
 
+static inline bool is_usb3_phy(struct phy *phy)
+{
+	return (phy->ops == &tegra210_pcie_phy_ops ||
+		phy->ops == &tegra210_sata_phy_ops);
+}
+
+static inline bool is_hsic_phy(struct phy *phy)
+{
+	return phy->ops == &tegra210_hsic_phy_ops;
+}
+
+static inline bool is_utmi_phy(struct phy *phy)
+{
+	return phy->ops == &tegra210_usb2_phy_ops;
+}
+
+static int
+tegra210_xusb_padctl_enable_phy_wake(struct tegra_xusb_padctl *padctl,
+				     struct phy *phy)
+{
+	if (!phy)
+		return 0;
+
+	if (is_usb3_phy(phy))
+		return tegra210_usb3_enable_phy_wake(phy);
+	else if (is_utmi_phy(phy))
+		return tegra210_utmi_enable_phy_wake(phy);
+	else if (is_hsic_phy(phy))
+		return tegra210_hsic_enable_phy_wake(phy);
+	else
+		return -EINVAL;
+}
+
+static int
+tegra210_xusb_padctl_disable_phy_wake(struct tegra_xusb_padctl *padctl,
+				      struct phy *phy)
+{
+	if (!phy)
+		return 0;
+
+	if (is_usb3_phy(phy))
+		return tegra210_usb3_disable_phy_wake(phy);
+	else if (is_utmi_phy(phy))
+		return tegra210_utmi_disable_phy_wake(phy);
+	else if (is_hsic_phy(phy))
+		return tegra210_hsic_disable_phy_wake(phy);
+	else
+		return -EINVAL;
+}
+
+int tegra210_xusb_padctl_remote_wake_detected(struct phy *phy)
+{
+	struct tegra_xusb_lane *lane;
+	struct tegra_xusb_padctl *padctl;
+
+	if (!phy)
+		return 0;
+
+	lane = phy_get_drvdata(phy);
+	padctl = lane->pad->padctl;
+
+	if (is_utmi_phy(phy))
+		return tegra210_utmi_phy_remote_wake_detected(padctl,
+					lane->index);
+	else if (is_hsic_phy(phy))
+		return tegra210_hsic_phy_remote_wake_detected(padctl,
+					lane->index);
+	else if (is_usb3_phy(phy))
+		return tegra210_usb3_phy_remote_wake_detected(padctl,
+					tegra210_usb3_lane_map(lane));
+
+	return -EINVAL;
+}
+
+static int
+tegra210_xusb_padctl_enable_phy_sleepwalk(struct tegra_xusb_padctl *padctl,
+					  struct phy *phy,
+					  enum usb_device_speed speed)
+{
+	if (!phy)
+		return 0;
+
+	if (is_usb3_phy(phy))
+		return tegra210_usb3_enable_phy_sleepwalk(phy);
+	else if (is_utmi_phy(phy))
+		return tegra_pmc_utmi_enable_phy_sleepwalk(phy, speed);
+	else if (is_hsic_phy(phy))
+		return tegra_pmc_hsic_enable_phy_sleepwalk(phy);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int
+tegra210_xusb_padctl_disable_phy_sleepwalk(struct tegra_xusb_padctl *padctl,
+					   struct phy *phy)
+{
+	if (!phy)
+		return 0;
+
+	if (is_usb3_phy(phy))
+		return tegra210_usb3_disable_phy_sleepwalk(phy);
+	else if (is_utmi_phy(phy))
+		return tegra_pmc_utmi_disable_phy_sleepwalk(phy);
+	else if (is_hsic_phy(phy))
+		return tegra_pmc_hsic_disable_phy_sleepwalk(phy);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+
 static struct tegra_xusb_pad *
 tegra210_sata_pad_probe(struct tegra_xusb_padctl *padctl,
 			const struct tegra_xusb_pad_soc *soc,
@@ -2317,6 +3294,8 @@  tegra210_xusb_padctl_probe(struct device *dev,
 			   const struct tegra_xusb_padctl_soc *soc)
 {
 	struct tegra210_xusb_padctl *padctl;
+	struct device_node *node, *np = dev->of_node;
+	struct platform_device *pmc_dev;
 	int err;
 
 	padctl = devm_kzalloc(dev, sizeof(*padctl), GFP_KERNEL);
@@ -2330,6 +3309,24 @@  tegra210_xusb_padctl_probe(struct device *dev,
 	if (err < 0)
 		return ERR_PTR(err);
 
+	node = of_parse_phandle(np, "nvidia,pmc", 0);
+	if (!node) {
+		dev_err(dev, "nvidia,pmc property is missing\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	pmc_dev = of_find_device_by_node(node);
+	if (!pmc_dev) {
+		dev_err(dev, "pmc device is not available\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	padctl->pmc_reg = dev_get_regmap(&pmc_dev->dev, "usb_sleepwalk");
+	if (!padctl->pmc_reg) {
+		dev_err(dev, "pmc regmap is not available.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
 	return &padctl->base;
 }
 
@@ -2337,13 +3334,80 @@  static void tegra210_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
 {
 }
 
+static void tegra210_xusb_padctl_save(struct tegra_xusb_padctl *padctl)
+{
+	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+
+	priv->context.usb2_pad_mux =
+		padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
+	priv->context.usb2_port_cap =
+		padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
+	priv->context.ss_port_map =
+		padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
+	priv->context.usb3_pad_mux =
+		padctl_readl(padctl, XUSB_PADCTL_USB3_PAD_MUX);
+}
+
+static void tegra210_xusb_padctl_restore(struct tegra_xusb_padctl *padctl)
+{
+	struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
+	int i;
+
+	padctl_writel(padctl, priv->context.usb2_pad_mux,
+		XUSB_PADCTL_USB2_PAD_MUX);
+	padctl_writel(padctl, priv->context.usb2_port_cap,
+		XUSB_PADCTL_USB2_PORT_CAP);
+	padctl_writel(padctl, priv->context.ss_port_map,
+		XUSB_PADCTL_SS_PORT_MAP);
+
+	for (i = 0; i <= 7; i ++)
+		tegra210_uphy_lane_iddq_enable(padctl, i);
+
+	padctl_writel(padctl, priv->context.usb3_pad_mux,
+		XUSB_PADCTL_USB3_PAD_MUX);
+
+	for (i = 0; i <= 7; i ++)
+		tegra210_uphy_lane_iddq_disable(padctl, i);
+}
+
+static int tegra210_xusb_padctl_suspend_noirq(struct tegra_xusb_padctl *padctl)
+{
+	mutex_lock(&padctl->lock);
+
+	tegra210_uphy_deinit(padctl);
+
+	tegra210_xusb_padctl_save(padctl);
+
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
+static int tegra210_xusb_padctl_resume_noirq(struct tegra_xusb_padctl *padctl)
+{
+	mutex_lock(&padctl->lock);
+
+	tegra210_xusb_padctl_restore(padctl);
+
+	tegra210_uphy_init(padctl);
+
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
 static const struct tegra_xusb_padctl_ops tegra210_xusb_padctl_ops = {
 	.probe = tegra210_xusb_padctl_probe,
 	.remove = tegra210_xusb_padctl_remove,
+	.suspend_noirq = tegra210_xusb_padctl_suspend_noirq,
+	.resume_noirq = tegra210_xusb_padctl_resume_noirq,
 	.usb3_set_lfps_detect = tegra210_usb3_set_lfps_detect,
 	.hsic_set_idle = tegra210_hsic_set_idle,
 	.vbus_override = tegra210_xusb_padctl_vbus_override,
 	.utmi_port_reset = tegra210_utmi_port_reset,
+	.enable_phy_sleepwalk = tegra210_xusb_padctl_enable_phy_sleepwalk,
+	.disable_phy_sleepwalk = tegra210_xusb_padctl_disable_phy_sleepwalk,
+	.enable_phy_wake = tegra210_xusb_padctl_enable_phy_wake,
+	.disable_phy_wake = tegra210_xusb_padctl_disable_phy_wake,
+	.remote_wake_detected = tegra210_xusb_padctl_remote_wake_detected,
 };
 
 static const char * const tegra210_xusb_padctl_supply_names[] = {