summaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea/core.c
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2013-09-24 12:47:55 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-30 18:54:07 -0700
commit864cf949981754c53de0a2efdc6c542c51d61328 (patch)
tree2324e9276920606a4676c97ed0cf8da60ff8f747 /drivers/usb/chipidea/core.c
parentaf59a8b120d18949f4f9166ccbe17348e3c9cd96 (diff)
usb: chipidea: add ci_hdrc_enter_lpm API
This API is used to let the PHY enter/leave low power mode. Before the controller going to work(at probe/resume), it needs to let the PHY leave low power mode. After the controller stopping working(at remove/suspend), it needs to let the PHY enter low power mode to save power consumption. Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/chipidea/core.c')
-rw-r--r--drivers/usb/chipidea/core.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index b20286de1436..06204b77fc4c 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -172,6 +172,27 @@ u8 hw_port_test_get(struct ci_hdrc *ci)
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
+/* The PHY enters/leaves low power mode */
+static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable)
+{
+ enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC;
+ bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm)));
+
+ if (enable && !lpm) {
+ hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),
+ PORTSC_PHCD(ci->hw_bank.lpm));
+ } else if (!enable && lpm) {
+ hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),
+ 0);
+ /*
+ * The controller needs at least 1ms to reflect
+ * PHY's status, the PHY also needs some time (less
+ * than 1ms) to leave low power mode.
+ */
+ usleep_range(1500, 2000);
+ }
+}
+
static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
{
u32 reg;
@@ -199,6 +220,8 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
if (ci->hw_ep_max > ENDPT_MAX)
return -ENODEV;
+ ci_hdrc_enter_lpm(ci, false);
+
/* Disable all interrupts bits */
hw_write(ci, OP_USBINTR, 0xffffffff, 0);
@@ -648,6 +671,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
dbg_remove_files(ci);
free_irq(ci->irq, ci);
ci_role_destroy(ci);
+ ci_hdrc_enter_lpm(ci, true);
ci_usb_phy_destroy(ci);
kfree(ci->hw_bank.regmap);