phy: tegra: xusb: Tegra210 host mode VBUS control
To support XUSB host controller ELPG, this commit moves VBUS control .phy_power_on()/.phy_power_off() to .phy_init()/.phy_exit(). When XUSB host controller enters ELPG, host driver invokes .phy_power_off(), VBUS should remain ON so that USB devices will not disconnect. VBUS can be turned OFF when host driver invokes .phy_exit() which indicates disabling a USB port. Signed-off-by: JC Kuo <jckuo@nvidia.com> Acked-By: Vinod Koul <vkoul@kernel.org> Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
2d10214872
commit
0baabcbedd
|
@ -1799,8 +1799,25 @@ static int tegra210_usb2_phy_init(struct phy *phy)
|
||||||
{
|
{
|
||||||
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
|
||||||
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
|
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
|
||||||
|
unsigned int index = lane->index;
|
||||||
|
struct tegra_xusb_usb2_port *port;
|
||||||
|
int err;
|
||||||
u32 value;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port->supply && port->mode == USB_DR_MODE_HOST) {
|
||||||
|
err = regulator_enable(port->supply);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&padctl->lock);
|
||||||
|
|
||||||
value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
|
value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX);
|
||||||
value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
|
value &= ~(XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_MASK <<
|
||||||
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
|
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT);
|
||||||
|
@ -1808,11 +1825,30 @@ static int tegra210_usb2_phy_init(struct phy *phy)
|
||||||
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
|
XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_SHIFT;
|
||||||
padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
|
padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX);
|
||||||
|
|
||||||
|
mutex_unlock(&padctl->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra210_usb2_phy_exit(struct phy *phy)
|
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;
|
||||||
|
struct tegra_xusb_usb2_port *port;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
port = tegra_xusb_find_usb2_port(padctl, lane->index);
|
||||||
|
if (!port) {
|
||||||
|
dev_err(&phy->dev, "no port found for USB2 lane %u\n", lane->index);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port->supply && port->mode == USB_DR_MODE_HOST) {
|
||||||
|
err = regulator_disable(port->supply);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1933,6 +1969,8 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
|
||||||
|
|
||||||
priv = to_tegra210_xusb_padctl(padctl);
|
priv = to_tegra210_xusb_padctl(padctl);
|
||||||
|
|
||||||
|
mutex_lock(&padctl->lock);
|
||||||
|
|
||||||
if (port->usb3_port_fake != -1) {
|
if (port->usb3_port_fake != -1) {
|
||||||
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
|
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
|
||||||
value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
|
value &= ~XUSB_PADCTL_SS_PORT_MAP_PORTX_MAP_MASK(
|
||||||
|
@ -2026,14 +2064,6 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
|
||||||
padctl_writel(padctl, value,
|
padctl_writel(padctl, value,
|
||||||
XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
|
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) {
|
if (pad->enable > 0) {
|
||||||
pad->enable++;
|
pad->enable++;
|
||||||
mutex_unlock(&padctl->lock);
|
mutex_unlock(&padctl->lock);
|
||||||
|
@ -2042,7 +2072,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
|
||||||
|
|
||||||
err = clk_prepare_enable(pad->clk);
|
err = clk_prepare_enable(pad->clk);
|
||||||
if (err)
|
if (err)
|
||||||
goto disable_regulator;
|
goto out;
|
||||||
|
|
||||||
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
|
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
|
||||||
value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
|
value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL1_TRK_START_TIMER_MASK <<
|
||||||
|
@ -2074,8 +2104,7 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
disable_regulator:
|
out:
|
||||||
regulator_disable(port->supply);
|
|
||||||
mutex_unlock(&padctl->lock);
|
mutex_unlock(&padctl->lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -2134,7 +2163,6 @@ static int tegra210_usb2_phy_power_off(struct phy *phy)
|
||||||
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
|
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
regulator_disable(port->supply);
|
|
||||||
mutex_unlock(&padctl->lock);
|
mutex_unlock(&padctl->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue