in tegra/xusb-tegra210.c [1335:1506]
static int tegra210_pmc_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
enum usb_device_speed speed)
{
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
struct tegra210_xusb_padctl *priv = to_tegra210_xusb_padctl(padctl);
unsigned int port = lane->index;
u32 value, tctrl, pctrl, rpd_ctrl;
if (!priv->regmap)
return -EOPNOTSUPP;
if (speed > USB_SPEED_HIGH)
return -EINVAL;
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
tctrl = TCTRL_VALUE(value);
pctrl = PCTRL_VALUE(value);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
rpd_ctrl = RPD_CTRL_VALUE(value);
/* ensure sleepwalk logic is disabled */
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));
/* ensure sleepwalk logics are in low power mode */
value = padctl_pmc_readl(priv, PMC_UTMIP_MASTER_CONFIG);
value |= UTMIP_PWR(port);
padctl_pmc_writel(priv, value, PMC_UTMIP_MASTER_CONFIG);
/* set debounce time */
value = padctl_pmc_readl(priv, PMC_USB_DEBOUNCE_DEL);
value &= ~UTMIP_LINE_DEB_CNT(~0);
value |= UTMIP_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_UTMIP_UHSIC_FAKE(port));
value &= ~(UTMIP_FAKE_USBOP_VAL(port) | UTMIP_FAKE_USBON_VAL(port) |
UTMIP_FAKE_USBOP_EN(port) | UTMIP_FAKE_USBON_EN(port));
padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_FAKE(port));
/* ensure wake events of sleepwalk logic are not latched */
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);
/* 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 pad */
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);
/* save state per speed */
value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SAVED_STATE(port));
value &= ~SPEED(port, ~0);
switch (speed) {
case USB_SPEED_HIGH:
value |= UTMI_HS(port);
break;
case USB_SPEED_FULL:
value |= UTMI_FS(port);
break;
case USB_SPEED_LOW:
value |= UTMI_LS(port);
break;
default:
value |= UTMI_RST(port);
break;
}
padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SAVED_STATE(port));
/* enable the trigger of the sleepwalk logic */
value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEPWALK_CFG(port));
value |= UTMIP_LINEVAL_WALK_EN(port);
padctl_pmc_writel(priv, value, 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.
*/
value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_TRIGGERS);
value |= UTMIP_CLR_WALK_PTR(port) | UTMIP_CLR_WAKE_ALARM(port) | UTMIP_CAP_CFG(port);
padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_TRIGGERS);
/* program electrical parameters read from XUSB PADCTL */
value = padctl_pmc_readl(priv, PMC_UTMIP_TERM_PAD_CFG);
value &= ~(TCTRL_VAL(~0) | PCTRL_VAL(~0));
value |= (TCTRL_VAL(tctrl) | PCTRL_VAL(pctrl));
padctl_pmc_writel(priv, value, PMC_UTMIP_TERM_PAD_CFG);
value = padctl_pmc_readl(priv, PMC_UTMIP_PAD_CFGX(port));
value &= ~RPD_CTRL_PX(~0);
value |= RPD_CTRL_PX(rpd_ctrl);
padctl_pmc_writel(priv, value, PMC_UTMIP_PAD_CFGX(port));
/*
* Set up the pull-ups and pull-downs of the signals during the four
* stages of sleepwalk. If a device is connected, program sleepwalk
* logic to maintain a J and keep driving K upon seeing remote wake.
*/
value = padctl_pmc_readl(priv, PMC_UTMIP_SLEEPWALK_PX(port));
value = UTMIP_USBOP_RPD_A | UTMIP_USBOP_RPD_B | UTMIP_USBOP_RPD_C | UTMIP_USBOP_RPD_D;
value |= UTMIP_USBON_RPD_A | UTMIP_USBON_RPD_B | UTMIP_USBON_RPD_C | UTMIP_USBON_RPD_D;
switch (speed) {
case USB_SPEED_HIGH:
case USB_SPEED_FULL:
/* J state: D+/D- = high/low, K state: D+/D- = low/high */
value |= UTMIP_HIGHZ_A;
value |= UTMIP_AP_A;
value |= UTMIP_AN_B | UTMIP_AN_C | UTMIP_AN_D;
break;
case USB_SPEED_LOW:
/* J state: D+/D- = low/high, K state: D+/D- = high/low */
value |= UTMIP_HIGHZ_A;
value |= UTMIP_AN_A;
value |= UTMIP_AP_B | UTMIP_AP_C | UTMIP_AP_D;
break;
default:
value |= UTMIP_HIGHZ_A | UTMIP_HIGHZ_B | UTMIP_HIGHZ_C | UTMIP_HIGHZ_D;
break;
}
padctl_pmc_writel(priv, value, PMC_UTMIP_SLEEPWALK_PX(port));
/* power up the line state detectors of the pad */
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);
usleep_range(50, 100);
/* switch the electric control of the USB2.0 pad to PMC */
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);
/* set the wake signaling trigger events */
value = padctl_pmc_readl(priv, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
value &= ~UTMIP_WAKE_VAL(port, ~0);
value |= UTMIP_WAKE_VAL_ANY(port);
padctl_pmc_writel(priv, value, PMC_UTMIP_UHSIC_SLEEP_CFG(port));
/* enable 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);
return 0;
}