USB: OTG: Implement aggressive power management while going to LPM
USB HW can turn off the voltage regulators, OTG comparators and can enable PHY retention mode as a part of aggressive power management while going to LPM provided that PMIC has capability to detect the VBUS/ID change and doesn't have any leakage currents while turning off the regulators. 8960 doesn't have the leakage currents and PM8921 has capability to detect VBUS and ID change. Hence Implement the aggressive power management for 8960. Initialize the PHY capabilities to support aggressive power management in the probe and use it to implement aggressive power management. Change-Id: If3e966b0c81b3588caa5ca93e9e877e4f777892c Signed-off-by: Anji jonnala <anjir@codeaurora.org>
This commit is contained in:
committed by
Stephen Boyd
parent
23013f0758
commit
791188bf77
@@ -511,12 +511,14 @@ static int msm_otg_suspend(struct msm_otg *motg)
|
||||
struct usb_phy *phy = &motg->phy;
|
||||
struct usb_bus *bus = phy->otg->host;
|
||||
struct msm_otg_platform_data *pdata = motg->pdata;
|
||||
int cnt = 0;
|
||||
int cnt = 0, val;
|
||||
bool host_bus_suspend;
|
||||
|
||||
if (atomic_read(&motg->in_lpm))
|
||||
return 0;
|
||||
|
||||
disable_irq(motg->irq);
|
||||
host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
|
||||
/*
|
||||
* Chipidea 45-nm PHY suspend sequence:
|
||||
*
|
||||
@@ -541,6 +543,17 @@ static int msm_otg_suspend(struct msm_otg *motg)
|
||||
ulpi_write(phy, 0x08, 0x09);
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn off the OTG comparators, if depends on PMIC for
|
||||
* VBUS and ID notifications.
|
||||
*/
|
||||
if (motg->caps & ALLOW_PHY_COMP_DISABLE) {
|
||||
val = ulpi_read(phy, ULPI_PWR_CLK_MNG_REG);
|
||||
val |= OTG_COMP_DISABLE;
|
||||
ulpi_write(phy, val, ULPI_PWR_CLK_MNG_REG);
|
||||
motg->lpm_flags |= PHY_OTG_COMP_DISABLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* PHY may take some time or even fail to enter into low power
|
||||
* mode (LPM). Hence poll for 500 msec and reset the PHY and link
|
||||
@@ -570,9 +583,11 @@ static int msm_otg_suspend(struct msm_otg *motg)
|
||||
*/
|
||||
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);
|
||||
if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend) {
|
||||
writel_relaxed(readl_relaxed(USB_PHY_CTRL) & ~PHY_RETEN,
|
||||
USB_PHY_CTRL);
|
||||
motg->lpm_flags |= PHY_RETENTIONED;
|
||||
}
|
||||
|
||||
/* Ensure that above operation is completed before turning off clocks */
|
||||
mb();
|
||||
@@ -583,14 +598,19 @@ static int msm_otg_suspend(struct msm_otg *motg)
|
||||
if (!IS_ERR(motg->pclk_src))
|
||||
clk_disable(motg->pclk_src);
|
||||
|
||||
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
|
||||
motg->pdata->otg_control == OTG_PMIC_CONTROL) {
|
||||
if (motg->caps & ALLOW_PHY_POWER_COLLAPSE && !host_bus_suspend) {
|
||||
msm_hsusb_ldo_enable(motg, 0);
|
||||
msm_hsusb_config_vddcx(0);
|
||||
motg->lpm_flags |= PHY_PWR_COLLAPSED;
|
||||
}
|
||||
|
||||
if (device_may_wakeup(phy->dev))
|
||||
if (motg->lpm_flags & PHY_RETENTIONED)
|
||||
msm_hsusb_config_vddcx(0);
|
||||
|
||||
if (device_may_wakeup(phy->dev)) {
|
||||
enable_irq_wake(motg->irq);
|
||||
if (motg->pdata->pmic_id_irq)
|
||||
enable_irq_wake(motg->pdata->pmic_id_irq);
|
||||
}
|
||||
if (bus)
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
|
||||
|
||||
@@ -621,11 +641,16 @@ static int msm_otg_resume(struct msm_otg *motg)
|
||||
if (motg->core_clk)
|
||||
clk_enable(motg->core_clk);
|
||||
|
||||
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
|
||||
motg->pdata->otg_control == OTG_PMIC_CONTROL) {
|
||||
if (motg->lpm_flags & PHY_PWR_COLLAPSED) {
|
||||
msm_hsusb_ldo_enable(motg, 1);
|
||||
motg->lpm_flags &= ~PHY_PWR_COLLAPSED;
|
||||
}
|
||||
|
||||
if (motg->lpm_flags & PHY_RETENTIONED) {
|
||||
msm_hsusb_config_vddcx(1);
|
||||
writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL);
|
||||
writel_relaxed(readl_relaxed(USB_PHY_CTRL) | PHY_RETEN,
|
||||
USB_PHY_CTRL);
|
||||
motg->lpm_flags &= ~PHY_RETENTIONED;
|
||||
}
|
||||
|
||||
temp = readl(USB_USBCMD);
|
||||
@@ -660,8 +685,18 @@ static int msm_otg_resume(struct msm_otg *motg)
|
||||
}
|
||||
|
||||
skip_phy_resume:
|
||||
/* Turn on the OTG comparators on resume */
|
||||
if (motg->lpm_flags & PHY_OTG_COMP_DISABLED) {
|
||||
temp = ulpi_read(phy, ULPI_PWR_CLK_MNG_REG);
|
||||
temp &= ~OTG_COMP_DISABLE;
|
||||
ulpi_write(phy, temp, ULPI_PWR_CLK_MNG_REG);
|
||||
motg->lpm_flags &= ~PHY_OTG_COMP_DISABLED;
|
||||
}
|
||||
if (device_may_wakeup(phy->dev))
|
||||
disable_irq_wake(motg->irq);
|
||||
if (motg->pdata->pmic_id_irq)
|
||||
disable_irq_wake(motg->pdata->pmic_id_irq);
|
||||
}
|
||||
if (bus)
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
|
||||
|
||||
@@ -1564,7 +1599,7 @@ static irqreturn_t msm_pmic_id_irq(int irq, void *data)
|
||||
{
|
||||
struct msm_otg *motg = data;
|
||||
|
||||
if (atomic_read(&motg->in_lpm))
|
||||
if (atomic_read(&motg->in_lpm) && !motg->async_int)
|
||||
msm_otg_irq(motg->irq, motg);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -1861,13 +1896,20 @@ static int __init msm_otg_probe(struct platform_device *pdev)
|
||||
goto free_irq;
|
||||
}
|
||||
|
||||
if (motg->pdata->pmic_id_irq) {
|
||||
ret = request_irq(motg->pdata->pmic_id_irq, msm_pmic_id_irq,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"msm_otg", motg);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
|
||||
if (motg->pdata->otg_control == OTG_PMIC_CONTROL) {
|
||||
if (motg->pdata->pmic_id_irq) {
|
||||
ret = request_irq(motg->pdata->pmic_id_irq,
|
||||
msm_pmic_id_irq,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"msm_otg", motg);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
|
||||
goto remove_phy;
|
||||
}
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
|
||||
goto remove_phy;
|
||||
}
|
||||
}
|
||||
@@ -1887,6 +1929,13 @@ static int __init msm_otg_probe(struct platform_device *pdev)
|
||||
if (motg->pdata->otg_control == OTG_PMIC_CONTROL)
|
||||
pm8921_charger_register_vbus_sn(&msm_otg_set_vbus_state);
|
||||
|
||||
if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&
|
||||
motg->pdata->otg_control == OTG_PMIC_CONTROL &&
|
||||
motg->pdata->pmic_id_irq)
|
||||
motg->caps = ALLOW_PHY_POWER_COLLAPSE |
|
||||
ALLOW_PHY_RETENTION |
|
||||
ALLOW_PHY_COMP_DISABLE;
|
||||
|
||||
wake_lock(&motg->wlock);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
@@ -229,6 +229,29 @@ struct msm_otg {
|
||||
struct wake_lock wlock;
|
||||
struct notifier_block usbdev_nb;
|
||||
unsigned mA_port;
|
||||
unsigned long caps;
|
||||
/*
|
||||
* Allowing PHY power collpase turns off the HSUSB 3.3v and 1.8v
|
||||
* analog regulators while going to low power mode.
|
||||
* Currently only 8960(28nm PHY) has the support to allowing PHY
|
||||
* power collapse since it doesn't have leakage currents while
|
||||
* turning off the power rails.
|
||||
*/
|
||||
#define ALLOW_PHY_POWER_COLLAPSE BIT(0)
|
||||
/*
|
||||
* Allow PHY RETENTION mode before turning off the digital
|
||||
* voltage regulator(VDDCX).
|
||||
*/
|
||||
#define ALLOW_PHY_RETENTION BIT(1)
|
||||
/*
|
||||
* Disable the OTG comparators to save more power
|
||||
* if depends on PMIC for VBUS and ID interrupts.
|
||||
*/
|
||||
#define ALLOW_PHY_COMP_DISABLE BIT(2)
|
||||
unsigned long lpm_flags;
|
||||
#define PHY_PWR_COLLAPSED BIT(0)
|
||||
#define PHY_RETENTIONED BIT(1)
|
||||
#define PHY_OTG_COMP_DISABLED BIT(2)
|
||||
};
|
||||
|
||||
struct msm_hsic_host_platform_data {
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
#define ULPI_DATA(n) ((n) & 255)
|
||||
#define ULPI_DATA_READ(n) (((n) >> 8) & 255)
|
||||
|
||||
/* synopsys 28nm phy registers */
|
||||
#define ULPI_PWR_CLK_MNG_REG 0x89
|
||||
#define OTG_COMP_DISABLE BIT(0);
|
||||
|
||||
#define PHY_ALT_INT (1 << 28) /* PHY alternate interrupt */
|
||||
#define ASYNC_INTR_CTRL (1 << 29) /* Enable async interrupt */
|
||||
#define ULPI_STP_CTRL (1 << 30) /* Block communication with PHY */
|
||||
|
||||
Reference in New Issue
Block a user