USB: OTG: msm: Add PHY suspend support for MSM8960

Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Pavankumar Kondeti 2011-05-04 10:19:49 +05:30 committed by Greg Kroah-Hartman
parent 11aa5c478e
commit 04aebcbb1b
2 changed files with 56 additions and 10 deletions

View File

@ -163,6 +163,32 @@ put_3p3:
return rc; return rc;
} }
#ifdef CONFIG_PM_SLEEP
#define USB_PHY_SUSP_DIG_VOL 500000
static int msm_hsusb_config_vddcx(int high)
{
int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
int min_vol;
int ret;
if (high)
min_vol = USB_PHY_VDD_DIG_VOL_MIN;
else
min_vol = USB_PHY_SUSP_DIG_VOL;
ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
if (ret) {
pr_err("%s: unable to set the voltage for regulator "
"HSUSB_VDDCX\n", __func__);
return ret;
}
pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
return ret;
}
#endif
static int msm_hsusb_ldo_set_mode(int on) static int msm_hsusb_ldo_set_mode(int on)
{ {
int ret = 0; int ret = 0;
@ -434,27 +460,28 @@ static int msm_otg_suspend(struct msm_otg *motg)
disable_irq(motg->irq); disable_irq(motg->irq);
/* /*
* Chipidea 45-nm PHY suspend sequence:
*
* Interrupt Latch Register auto-clear feature is not present * Interrupt Latch Register auto-clear feature is not present
* in all PHY versions. Latch register is clear on read type. * in all PHY versions. Latch register is clear on read type.
* Clear latch register to avoid spurious wakeup from * Clear latch register to avoid spurious wakeup from
* low power mode (LPM). * low power mode (LPM).
*/ *
ulpi_read(otg, 0x14);
/*
* PHY comparators are disabled when PHY enters into low power * PHY comparators are disabled when PHY enters into low power
* mode (LPM). Keep PHY comparators ON in LPM only when we expect * mode (LPM). Keep PHY comparators ON in LPM only when we expect
* VBUS/Id notifications from USB PHY. Otherwise turn off USB * VBUS/Id notifications from USB PHY. Otherwise turn off USB
* PHY comparators. This save significant amount of power. * PHY comparators. This save significant amount of power.
*/ *
if (pdata->otg_control == OTG_PHY_CONTROL)
ulpi_write(otg, 0x01, 0x30);
/*
* PLL is not turned off when PHY enters into low power mode (LPM). * PLL is not turned off when PHY enters into low power mode (LPM).
* Disable PLL for maximum power savings. * Disable PLL for maximum power savings.
*/ */
ulpi_write(otg, 0x08, 0x09);
if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
ulpi_read(otg, 0x14);
if (pdata->otg_control == OTG_PHY_CONTROL)
ulpi_write(otg, 0x01, 0x30);
ulpi_write(otg, 0x08, 0x09);
}
/* /*
* PHY may take some time or even fail to enter into low power * PHY may take some time or even fail to enter into low power
@ -485,6 +512,10 @@ static int msm_otg_suspend(struct msm_otg *motg)
*/ */
writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
motg->pdata->otg_control == OTG_PMIC_CONTROL)
writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL);
clk_disable(motg->pclk); clk_disable(motg->pclk);
clk_disable(motg->clk); clk_disable(motg->clk);
if (motg->core_clk) if (motg->core_clk)
@ -493,6 +524,12 @@ static int msm_otg_suspend(struct msm_otg *motg)
if (!IS_ERR(motg->pclk_src)) if (!IS_ERR(motg->pclk_src))
clk_disable(motg->pclk_src); clk_disable(motg->pclk_src);
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
motg->pdata->otg_control == OTG_PMIC_CONTROL) {
msm_hsusb_ldo_set_mode(0);
msm_hsusb_config_vddcx(0);
}
if (device_may_wakeup(otg->dev)) if (device_may_wakeup(otg->dev))
enable_irq_wake(motg->irq); enable_irq_wake(motg->irq);
if (bus) if (bus)
@ -524,6 +561,13 @@ static int msm_otg_resume(struct msm_otg *motg)
if (motg->core_clk) if (motg->core_clk)
clk_enable(motg->core_clk); clk_enable(motg->core_clk);
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
motg->pdata->otg_control == OTG_PMIC_CONTROL) {
msm_hsusb_ldo_set_mode(1);
msm_hsusb_config_vddcx(1);
writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL);
}
temp = readl(USB_USBCMD); temp = readl(USB_USBCMD);
temp &= ~ASYNC_INTR_CTRL; temp &= ~ASYNC_INTR_CTRL;
temp &= ~ULPI_STP_CTRL; temp &= ~ULPI_STP_CTRL;

View File

@ -24,6 +24,7 @@
#define USB_PORTSC (MSM_USB_BASE + 0x0184) #define USB_PORTSC (MSM_USB_BASE + 0x0184)
#define USB_OTGSC (MSM_USB_BASE + 0x01A4) #define USB_OTGSC (MSM_USB_BASE + 0x01A4)
#define USB_USBMODE (MSM_USB_BASE + 0x01A8) #define USB_USBMODE (MSM_USB_BASE + 0x01A8)
#define USB_PHY_CTRL (MSM_USB_BASE + 0x0240)
#define USBCMD_RESET 2 #define USBCMD_RESET 2
#define USB_USBINTR (MSM_USB_BASE + 0x0148) #define USB_USBINTR (MSM_USB_BASE + 0x0148)
@ -42,6 +43,7 @@
#define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */ #define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */
#define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */ #define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */
#define PHY_RETEN (1 << 1) /* PHY retention enable/disable */
/* OTG definitions */ /* OTG definitions */
#define OTGSC_INTSTS_MASK (0x7f << 16) #define OTGSC_INTSTS_MASK (0x7f << 16)