diff options
author | Gary King <gking@nvidia.com> | 2009-12-16 18:11:47 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2009-12-16 19:01:04 -0800 |
commit | 37b15490c16a5cc978cdfd398a8dac643f0d13da (patch) | |
tree | 04cbb7cd92991d41e6ba00445292788c07e0505a /drivers | |
parent | 31865162df46a3aa1f65341d9036533da1d79144 (diff) |
tegra: reduce power of USB phy and USB pll
use VBUS_WAKEUP_EVENT rather than A_SESSION_VALID for cable detection.
disable OTG_BIAS circuitry when no cable connected
set UTMIP to reset when device is suspended
reduces measured idle USB power from 36mW to 3mW
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 54 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_usb2_udc.h | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/tegra_udc.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 21 |
4 files changed, 52 insertions, 38 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 9ab3f663ee3c..640a778047f3 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -293,12 +293,12 @@ static void dr_controller_run(struct fsl_udc *udc) #define FSL_UDC_RUN_TIMEOUT 1000 /* Enable cable detection interrupt, without setting the - * USB_SYS_VBUS_ASESSION_CHANGED bit. USB_SYS_VBUS_ASESSION_CHANGED - * bit is clear on write */ - temp = fsl_readl(&usb_sys_regs->vbus_sensors); - temp |= USB_SYS_VBUS_ASESSION_INT_EN; - temp &= ~USB_SYS_VBUS_ASESSION_CHANGED; - fsl_writel(temp, &usb_sys_regs->vbus_sensors); + * USB_SYS_VBUS_WAKEUP_INT bit. USB_SYS_VBUS_WAKEUP_INT is + * clear on write */ + temp = fsl_readl(&usb_sys_regs->vbus_wakeup); + temp |= (USB_SYS_VBUS_WAKEUP_INT_ENABLE | USB_SYS_VBUS_WAKEUP_ENABLE); + temp &= ~USB_SYS_VBUS_WAKEUP_INT_STATUS; + fsl_writel(temp, &usb_sys_regs->vbus_wakeup); #endif @@ -596,14 +596,20 @@ static int fsl_ep_disable(struct usb_ep *_ep) return -EINVAL; } - /* disable ep on controller */ - ep_num = ep_index(ep); - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl &= ~EPCTRL_TX_ENABLE; - else - epctrl &= ~EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); +#if defined(CONFIG_ARCH_TEGRA) + /* Touch the registers if cable is connected and phy is on */ + if (fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS) +#endif + { + /* disable ep on controller */ + ep_num = ep_index(ep); + epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); + if (ep_is_in(ep)) + epctrl &= ~EPCTRL_TX_ENABLE; + else + epctrl &= ~EPCTRL_RX_ENABLE; + fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); + } udc = (struct fsl_udc *)ep->udc; spin_lock_irqsave(&udc->lock, flags); @@ -1025,6 +1031,12 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep) unsigned long timeout; #define FSL_UDC_FLUSH_TIMEOUT 1000 +#if defined(CONFIG_ARCH_TEGRA) + /* Touch the registers if cable is connected and phy is on */ + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) + return; +#endif + if (!_ep) { return; } else { @@ -1771,9 +1783,9 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) /* VBUS A session detection interrupts. When the interrupt is received, * the mark the vbus active shadow. */ - temp = fsl_readl(&usb_sys_regs->vbus_sensors); - if (temp & USB_SYS_VBUS_ASESSION_CHANGED) { - if (temp & USB_SYS_VBUS_ASESSION) { + temp = fsl_readl(&usb_sys_regs->vbus_wakeup); + if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS) { + if (temp & USB_SYS_VBUS_STATUS) { udc->vbus_active = 1; //printk(KERN_INFO "USB cable connected\n"); } else { @@ -1783,7 +1795,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) //printk("USB cable dis-connected\n"); } /* write back the register to clear the interrupt */ - fsl_writel(temp, &usb_sys_regs->vbus_sensors); + fsl_writel(temp, &usb_sys_regs->vbus_wakeup); if (udc->vbus_active) { platform_udc_clk_resume(); @@ -2490,6 +2502,12 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err_unregister; } create_proc_file(); + +#if defined(CONFIG_ARCH_TEGRA) + /* Power down the phy if cable is not connected */ + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) + platform_udc_clk_suspend(); +#endif return 0; err_unregister: diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index d8a626763f7b..b06d36c1cd4c 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -443,6 +443,10 @@ struct ep_td_struct { #define USB_SYS_VBUS_ASESSION_INT_EN 0x10000 #define USB_SYS_VBUS_ASESSION_CHANGED 0x20000 #define USB_SYS_VBUS_ASESSION 0x40000 +#define USB_SYS_VBUS_WAKEUP_ENABLE 0x40000000 +#define USB_SYS_VBUS_WAKEUP_INT_ENABLE 0x100 +#define USB_SYS_VBUS_WAKEUP_INT_STATUS 0x200 +#define USB_SYS_VBUS_STATUS 0x400 /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c index eb2da0c6e93e..c7cad5873916 100644 --- a/drivers/usb/gadget/tegra_udc.c +++ b/drivers/usb/gadget/tegra_udc.c @@ -33,22 +33,11 @@ NvDdkUsbPhyHandle s_hUsbPhy; int tegra_udc_clk_init(struct platform_device *pdev) { NvError nverr; - NvDdkUsbPhyIoctl_VBusStatusOutputArgs Status; nverr = NvDdkUsbPhyOpen(s_hRmGlobal, pdev->id, &s_hUsbPhy); if (nverr != NvSuccess) return -ENODEV; - NV_ASSERT_SUCCESS( - NvDdkUsbPhyIoctl(s_hUsbPhy, - NvDdkUsbPhyIoctlType_VBusStatus, - NULL, &Status)); - - if (Status.VBusDetected) { - NV_ASSERT_SUCCESS(NvDdkUsbPhyPowerUp(s_hUsbPhy, 0)); - } else { - NV_ASSERT_SUCCESS(NvDdkUsbPhyPowerDown(s_hUsbPhy, 0)); - } printk("tegra_udc_clk_init called\n"); return 0; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index b4b9677f52fe..b3f031975396 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -40,10 +40,12 @@ /* FIXME: Power Management is un-ported so temporarily disable it */ #undef CONFIG_PM -#define TEGRA_USB_ID_INT_ENABLE (1 << 24) -#define TEGRA_USB_ID_INT_STATUS (1 << 16) -#define TEGRA_USB_ID_PIN_STATUS (1 << 8) -#define TEGRA_USB_OTG_REG_OFFSET (0x1a4) +#define TEGRA_USB_ID_INT_ENABLE (1 << 0) +#define TEGRA_USB_ID_INT_STATUS (1 << 1) +#define TEGRA_USB_ID_PIN_STATUS (1 << 2) +#define TEGRA_USB_ID_PIN_WAKEUP_ENABLE (1 << 6) +#define TEGRA_USB_PHY_WAKEUP_REG_OFFSET (0x408) + static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) { @@ -58,8 +60,8 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) if (pdata->pUsbProperty->IdPinDetectionType == NvOdmUsbIdPinType_CableId) { /* read otgsc register for ID pin status change */ - status = readl(hcd->regs + TEGRA_USB_OTG_REG_OFFSET); - writel(status, (hcd->regs + TEGRA_USB_OTG_REG_OFFSET)); + status = readl(hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET); + writel(status, (hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET)); /* Check if there is any ID pin interrupt */ if (status & TEGRA_USB_ID_INT_STATUS) { @@ -260,9 +262,10 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (pdata->pUsbProperty->IdPinDetectionType == NvOdmUsbIdPinType_CableId) { /* enable the cable ID interrupt */ - temp = readl(hcd->regs + TEGRA_USB_OTG_REG_OFFSET); - writel((temp | TEGRA_USB_ID_INT_ENABLE), - (hcd->regs + TEGRA_USB_OTG_REG_OFFSET)); + temp = readl(hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET); + temp |= TEGRA_USB_ID_INT_ENABLE; + temp |= TEGRA_USB_ID_PIN_WAKEUP_ENABLE; + writel(temp, (hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET)); /* Check if we detect any device connected */ if (temp & TEGRA_USB_ID_PIN_STATUS) { |