diff options
author | Gary King <gking@nvidia.com> | 2010-02-12 19:06:11 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit2@git-master-01.nvidia.com> | 2010-02-12 19:06:11 -0800 |
commit | 25a2bda5b0e8073d00d79ac21600ef071245ff1d (patch) | |
tree | 9b5e843341501fd6d9014a66685cd04f963aff9c | |
parent | 8fcf1c82e027f15eeddf7e2fe6fd9aa1b741c34d (diff) | |
parent | 32d7e93337e43181eb3fbb2af4eb66a140601de1 (diff) |
Merge "tegra usbh: whistler suspend/resume failure fix" into android-tegra-2.6.29
-rwxr-xr-x | drivers/usb/host/ehci-tegra.c | 166 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 3 |
2 files changed, 104 insertions, 65 deletions
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 505cee6c94e4..3e240fa8e892 100755 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -45,6 +45,30 @@ #define TEGRA_USB_USBMODE_REG_OFFSET (0x1a8) #define TEGRA_USB_USBMODE_HOST (3) +/* tegra usb phy power control function */ +static int tegra_usb_phy_power_up(struct usb_hcd *hcd, bool enable) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct tegra_hcd_platform_data *pdata; + NvError Err; + + pdata = hcd->self.controller->platform_data; + if (enable) + { + Err = NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0); + } + else { + Err = NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0); + } + if (Err != NvSuccess) { + pr_err("\n Usb Phy power on=%d: error=0x%x ", + enable, Err); + return -1; + } + /* set power state */ + ehci->host_resumed = enable; + return 0; +} static int tegra_ehci_hub_control ( struct usb_hcd *hcd, @@ -89,7 +113,8 @@ static int tegra_ehci_hub_control ( temp = ehci_readl(ehci, status_reg); if (!(temp & (PORT_CONNECT | PORT_CSC | PORT_PE | PORT_PEC)) && ehci->host_reinited) { - NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0); + /* power down */ + retval = tegra_usb_phy_power_up(hcd, false); ehci->transceiver->state = OTG_STATE_UNDEFINED; ehci->host_reinited = 0; } @@ -100,7 +125,7 @@ static int tegra_ehci_hub_control ( return retval; } - +#ifdef CONFIG_USB_OTG_UTILS static void tegra_ehci_restart (struct usb_hcd *hcd) { unsigned int temp; @@ -133,23 +158,20 @@ static void tegra_ehci_restart (struct usb_hcd *hcd) /* Turn On Interrupts */ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); } +#endif static void tegra_ehci_shutdown (struct usb_hcd *hcd) { - struct tegra_hcd_platform_data *pdata; - pdata = hcd->self.controller->platform_data; - /* ehci_shutdown touches the USB controller registers, make sure * controller has clocks to it, if controller is already in power up - * status, calling the NvDdkUsbPhyPowerUp will just return */ - NV_ASSERT_SUCCESS(NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0)); + * status, calling the tegra_usb_phy_power_up will just return */ + NV_ASSERT_SUCCESS(tegra_usb_phy_power_up(hcd, true)); /* call ehci shut down */ ehci_shutdown(hcd); /* we are ready to shut down, powerdown the phy */ - NV_ASSERT_SUCCESS(NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0)); + NV_ASSERT_SUCCESS(tegra_usb_phy_power_up(hcd, false)); } - static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); @@ -166,7 +188,7 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) if (ehci->transceiver->state == OTG_STATE_A_HOST) { if (!ehci->host_reinited) { ehci->host_reinited = 1; - NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0); + tegra_usb_phy_power_up(hcd, true); tegra_ehci_restart(hcd); } } else if (ehci->transceiver->state == OTG_STATE_A_SUSPEND) { @@ -191,9 +213,9 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) if (status & TEGRA_USB_ID_INT_STATUS) { /* Check pin status and enable/disable the power */ if (status & TEGRA_USB_ID_PIN_STATUS) { - NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0); + tegra_usb_phy_power_up(hcd, false); } else { - NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0); + tegra_usb_phy_power_up(hcd, true); } } } @@ -214,7 +236,7 @@ static int tegra_ehci_reinit(struct usb_hcd *hcd) NV_CHECK_ERROR_CLEANUP(NvDdkUsbPhyOpen(s_hRmGlobal, pdata->instance, &pdata->hUsbPhy)); - NV_CHECK_ERROR_CLEANUP(NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0)); + NV_CHECK_ERROR_CLEANUP(tegra_usb_phy_power_up(hcd, true)); return 0; @@ -264,6 +286,58 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) return retval; } +static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + bool host = true; +#ifdef CONFIG_USB_OTG_UTILS + struct tegra_hcd_platform_data *pdata; + pdata = hcd->self.controller->platform_data; + if (!pdata) { + pr_err("\n Null pdata in %s ", __func__); + return -1; + } + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_OTG) + && ehci->transceiver) { + if (ehci->transceiver->state != OTG_STATE_A_HOST) { + host = false; + } + } +#endif + if ((host) && (ehci->host_resumed)) { + ehci_bus_suspend(hcd); + /* power down hw after bus suspend */ + tegra_usb_phy_power_up(hcd, false); + } + return 0; +} + +static int tegra_ehci_bus_resume(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + bool host = true; +#ifdef CONFIG_USB_OTG_UTILS + struct tegra_hcd_platform_data *pdata; + pdata = hcd->self.controller->platform_data; + if (!pdata) { + pr_err("\n Null pdata in %s ", __func__); + return -1; + } + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_OTG) + && ehci->transceiver) { + if (ehci->transceiver->state != OTG_STATE_A_HOST) { + host = false; + } + } +#endif + if ((host) && (!ehci->host_resumed)) { + /* power up hw before bus resume */ + tegra_usb_phy_power_up(hcd, true); + ehci_bus_resume(hcd); + } + return 0; +} + static const struct hc_driver tegra_ehci_hc_driver = { .description = hcd_name, .product_desc = "Tegra Ehci host controller", @@ -283,8 +357,8 @@ static const struct hc_driver tegra_ehci_hc_driver = { .get_frame_number = ehci_get_frame, .hub_status_data = ehci_hub_status_data, .hub_control = tegra_ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, + .bus_suspend = tegra_ehci_bus_suspend, + .bus_resume = tegra_ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, }; @@ -319,7 +393,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) } pdata->instance = instance; - pdata->pUsbProperty = NvOdmQueryGetUsbProperty(NvOdmIoModule_Usb, + pdata->pUsbProperty = NvOdmQueryGetUsbProperty(NvOdmIoModule_Usb, instance); if (pdata->pUsbProperty->IdPinDetectionType == NvOdmUsbIdPinType_Gpio @@ -328,19 +402,19 @@ static int tegra_ehci_probe(struct platform_device *pdev) const NvOdmGpioPinInfo *pGpioPinInfo; NvU32 GpioPinCount = 0; - pGpioPinInfo = NvOdmQueryGpioPinMap(NvOdmGpioPinGroup_Usb, + pGpioPinInfo = NvOdmQueryGpioPinMap(NvOdmGpioPinGroup_Usb, instance, &GpioPinCount); /* If the ODM says ID type is GPIO, they better provide the * GPIO port and pin for that */ BUG_ON(GpioPinCount == 0); - NV_ASSERT_SUCCESS(NvRmGpioAcquirePinHandle(s_hGpioGlobal, - pGpioPinInfo[NvOdmGpioPin_UsbCableId].Port, - pGpioPinInfo[NvOdmGpioPin_UsbCableId].Pin, + NV_ASSERT_SUCCESS(NvRmGpioAcquirePinHandle(s_hGpioGlobal, + pGpioPinInfo[NvOdmGpioPin_UsbCableId].Port, + pGpioPinInfo[NvOdmGpioPin_UsbCableId].Pin, &pdata->hGpioIDpin)); - // Configure Cable ID Pin as Input Pin - NV_ASSERT_SUCCESS(NvRmGpioConfigPins(s_hGpioGlobal, + /* Configure Cable ID Pin as Input Pin */ + NV_ASSERT_SUCCESS(NvRmGpioConfigPins(s_hGpioGlobal, &pdata->hGpioIDpin, 1, NvRmGpioPinMode_InputData)); } else { @@ -353,13 +427,13 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail; } - NvRmModuleGetBaseAddress(s_hRmGlobal, + NvRmModuleGetBaseAddress(s_hRmGlobal, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, instance), &addr, &size); if (addr == 0x0 || size == 0) { e = -ENODEV; goto fail; } - NvRmPhysicalMemMap(addr, size, NVOS_MEM_READ_WRITE, + NvRmPhysicalMemMap(addr, size, NVOS_MEM_READ_WRITE, NvOsMemAttribute_Uncached, (void **)&vaddr); if (vaddr == NULL) { e = -ENOMEM; @@ -374,7 +448,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) writel((temp | TEGRA_USB_USBMODE_HOST), (hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET)); - irq = NvRmGetIrqForLogicalInterrupt(s_hRmGlobal, + irq = NvRmGetIrqForLogicalInterrupt(s_hRmGlobal, NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, instance), 0); if (irq == 0xffff) goto fail; @@ -402,7 +476,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) temp = readl(hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET); writel((temp & ~TEGRA_USB_USBMODE_HOST), (hcd->regs + TEGRA_USB_USBMODE_REG_OFFSET)); - NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0); + tegra_usb_phy_power_up(hcd, false); ehci->host_reinited = 0; } else { dev_err(&pdev->dev, "Cannot get OTG transceiver\n"); @@ -422,9 +496,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) /* Check if we detect any device connected */ if (temp & TEGRA_USB_ID_PIN_STATUS) { - NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0); + tegra_usb_phy_power_up(hcd, false); } else { - NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0); + tegra_usb_phy_power_up(hcd, true); } } } @@ -455,47 +529,11 @@ static int tegra_ehci_remove(struct platform_device *pdev) return 0; } -static int tegra_ehci_suspend(struct platform_device *pdev, - pm_message_t message) -{ - struct tegra_hcd_platform_data *pdata; - NvError Err; - pdata = (struct tegra_hcd_platform_data *)pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Cannot run without platform data\n"); - return -1; - } - Err = NvDdkUsbPhyPowerDown(pdata->hUsbPhy, NV_TRUE, 0); - if (Err != NvSuccess) { - dev_err(&pdev->dev, "\n Usb Phy down error=0x%x ", Err); - return -1; - } - return 0; -} -static int tegra_ehci_resume(struct platform_device *pdev) -{ - struct tegra_hcd_platform_data *pdata; - NvError Err; - pdata = (struct tegra_hcd_platform_data *)pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Cannot run without platform data\n"); - return -1; - } - Err = NvDdkUsbPhyPowerUp(pdata->hUsbPhy, NV_TRUE, 0); - if (Err != NvSuccess) { - dev_err(&pdev->dev, "\n Usb Phy Up error=0x%x ", Err); - return -1; - } - return 0; -} - static struct platform_driver tegra_ehci_driver = { .probe = tegra_ehci_probe, .remove = tegra_ehci_remove, .shutdown = usb_hcd_platform_shutdown, - .suspend = tegra_ehci_suspend, - .resume = tegra_ehci_resume, .driver = { .name = "tegra-ehci", } diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 091e26e40850..1e4394d4f363 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -133,7 +133,8 @@ struct ehci_hcd { /* one per controller */ unsigned big_endian_desc:1; unsigned has_amcc_usb23:1; unsigned controller_resets_phy:1; - unsigned host_reinited:1; + unsigned host_reinited:1; /* tegra */ + unsigned host_resumed:1; /* tegra */ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) |