summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2009-12-16 18:11:47 -0800
committerGary King <gking@nvidia.com>2009-12-16 19:01:04 -0800
commit37b15490c16a5cc978cdfd398a8dac643f0d13da (patch)
tree04cbb7cd92991d41e6ba00445292788c07e0505a /drivers
parent31865162df46a3aa1f65341d9036533da1d79144 (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.c54
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h4
-rw-r--r--drivers/usb/gadget/tegra_udc.c11
-rw-r--r--drivers/usb/host/ehci-tegra.c21
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) {