From 1b8406f6f9556f8d205ebf01035350e587c11764 Mon Sep 17 00:00:00 2001 From: Venkat Moganty Date: Thu, 29 Apr 2010 20:44:29 +0530 Subject: tegra usb:Modifications to usb power up/down sequence Removed helper thread and replaced it with Worker Queues in udc and ehci drivers to handle usbphy power up/down sequence. Made changes to turn off usb power rail based on vbus detection mechanism is selected as PMU. Fixed usb host LP0 exit sequence. Bug 667912: AVDD_USB_Power is consuming 3.82mW of power in OSIdle and ULP audio playback case. Change-Id: I3a77d0ecb4f0b81dafe705100451c42641f0bfb9 Reviewed-on: http://git-master/r/1221 Tested-by: Hanumanth Venkateswa Moganty Tested-by: Dara Ramesh Reviewed-by: Seshendra Gadagottu Tested-by: Seshendra Gadagottu Reviewed-by: Narendra Damahe Tested-by: Narendra Damahe Reviewed-by: Yu-Huan Hsu --- drivers/usb/gadget/fsl_udc_core.c | 113 ++++++++++++--- drivers/usb/gadget/fsl_usb2_udc.h | 3 + drivers/usb/host/ehci-tegra.c | 296 +++++++++++++++++++++++++++----------- drivers/usb/host/ehci.h | 1 + drivers/usb/otg/tegra-otg.c | 8 +- 5 files changed, 308 insertions(+), 113 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 199034307a37..cbf6313585c3 100755 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -74,8 +74,8 @@ static struct usb_sys_interface *usb_sys_regs; /* Charger current limit=1800mA, as per the USB charger spec */ #define USB_CHARGING_CURRENT_LIMIT_MA 1800 -/* 100msec wait time for charger detection after vbus is detected */ -#define USB_CHARGER_DETECTION_WAIT_TIME_MS 100 +/* 1 sec wait time for charger detection after vbus is detected */ +#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000 /* it is initialized in probe() */ static struct fsl_udc *udc_controller = NULL; @@ -1830,22 +1830,21 @@ static void fsl_udc_restart(struct fsl_udc *udc) } #endif + /* - * USB device controller interrupt handler + * Work thread function for handling the USB power sequence. + * + * This work thread is created to avoid the pre-emption from the ISR context. + * USB Power Rail is controlled based on the USB cable connection. + * USB Power rail function cannot be called from ISR as NvRmPmuSetVoltage() + * uses I2C driver, that waits on semaphore during the I2C transaction + * this will cause the pre-emption if called in ISR. */ -static irqreturn_t fsl_udc_irq(int irq, void *_udc) +static void fsl_udc_irq_work(struct work_struct* irq_work) { - struct fsl_udc *udc = _udc; - u32 irq_src; - irqreturn_t status = IRQ_NONE; - unsigned long flags; -#if defined(CONFIG_ARCH_TEGRA) + struct fsl_udc *udc = container_of (irq_work, struct fsl_udc, irq_work); u32 temp; -#endif - -#if defined(CONFIG_ARCH_TEGRA) - spin_lock_irqsave(&udc->lock, flags); /* check OTG tranceiver is available or not */ if (udc->transceiver) { if (udc->transceiver->state == OTG_STATE_B_PERIPHERAL) { @@ -1863,8 +1862,10 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) if (udc->vbus_active) { /* If cable disconnected, cancel any delayed work */ cancel_delayed_work(&udc->work); + spin_lock(&udc->lock); /* Reset all internal Queues and inform client driver */ reset_queues(udc); + spin_unlock(&udc->lock); /* stop the controller and turn off the clocks */ dr_controller_stop(udc); platform_udc_clk_suspend(); @@ -1876,17 +1877,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) regulator_set_current_limit(udc->vbus_regulator, 0, 0); } } - } else { - spin_unlock_irqrestore(&udc->lock, flags); - return IRQ_HANDLED; } }else { /* VBUS A session detection interrupts. When the interrupt is received, * mark the vbus active shadow. */ temp = fsl_readl(&usb_sys_regs->vbus_wakeup); - /* write back the register to clear the interrupt */ - fsl_writel(temp, &usb_sys_regs->vbus_wakeup); if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS) { if (temp & USB_SYS_VBUS_STATUS) { udc->vbus_active = 1; @@ -1899,7 +1895,9 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) } else { /* If cable disconnected, cancel any delayed work */ cancel_delayed_work(&udc->work); + spin_lock(&udc->lock); reset_queues(udc); + spin_unlock(&udc->lock); udc->vbus_active = 0; udc->usb_state = USB_STATE_DEFAULT; platform_udc_clk_suspend(); @@ -1909,9 +1907,55 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) } /* printk("USB cable dis-connected\n"); */ } - status = IRQ_HANDLED; } } +} + +/* + * USB device controller interrupt handler + */ +static irqreturn_t fsl_udc_irq(int irq, void *_udc) +{ + struct fsl_udc *udc = _udc; + u32 irq_src; + irqreturn_t status = IRQ_NONE; + unsigned long flags; +#if defined(CONFIG_ARCH_TEGRA) + u32 temp; +#endif + + +#if defined(CONFIG_ARCH_TEGRA) + spin_lock_irqsave(&udc->lock, flags); + /* check OTG tranceiver is available or not */ + if (udc->transceiver) { + if (udc->transceiver->state == OTG_STATE_B_PERIPHERAL) { + if (!udc->vbus_active) { + schedule_work(&udc->irq_work); + } + } else if (udc->transceiver->state == OTG_STATE_A_SUSPEND) { + if (udc->vbus_active) { + schedule_work(&udc->irq_work); + } else { + spin_unlock_irqrestore(&udc->lock, flags); + return IRQ_HANDLED; + } + } else { + spin_unlock_irqrestore(&udc->lock, flags); + return IRQ_HANDLED; + } + }else { + /* VBUS A session detection interrupts. When the interrupt is received, + * mark the vbus active shadow. + */ + temp = fsl_readl(&usb_sys_regs->vbus_wakeup); + /* write back the register to clear the interrupt */ + fsl_writel(temp, &usb_sys_regs->vbus_wakeup); + if (temp & USB_SYS_VBUS_WAKEUP_INT_STATUS) { + schedule_work(&udc->irq_work); + } + status = IRQ_HANDLED; + } spin_unlock_irqrestore(&udc->lock, flags); #endif @@ -2648,6 +2692,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev) /* create a delayed work for detecting the USB charger */ INIT_DELAYED_WORK(&udc_controller->work, fsl_udc_charger_detection); + /* create a work for controlling the clocks to the Phy */ + INIT_WORK(&udc_controller->irq_work, fsl_udc_irq_work); + #if defined(CONFIG_ARCH_TEGRA) #ifdef CONFIG_USB_OTG_UTILS /* Get the OTG transceiver. If OTG is enabled then transceiver @@ -2737,8 +2784,20 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) if (udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) { /* we are not in device mode, return */ return 0; + } else { + udc_controller->transceiver->state = OTG_STATE_UNDEFINED; } } + if (udc_controller->vbus_active) + { + spin_lock(&udc_controller->lock); + /* Reset all internal Queues and inform client driver */ + reset_queues(udc_controller); + udc_controller->vbus_active = 0; + udc_controller->usb_state = USB_STATE_DEFAULT; + spin_unlock(&udc_controller->lock); + } + /* stop the controller and turn off the clocks */ dr_controller_stop(udc_controller); platform_udc_clk_suspend(); return 0; @@ -2751,12 +2810,22 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) static int fsl_udc_resume(struct platform_device *pdev) { if (udc_controller->transceiver) { - if (udc_controller->transceiver->state != OTG_STATE_B_PERIPHERAL) { - /* we are not in device mode, return */ + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_ID_PIN_STATUS)) { + /* If ID status is low means host is connected, return */ return 0; } + /* enable clock and check for VBUS */ + platform_udc_clk_resume(); + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) { + /* if there is no VBUS then power down the clocks and return */ + platform_udc_clk_suspend(); + return 0; + } + } else { + /* enable the clocks to the controller */ + platform_udc_clk_resume(); } - platform_udc_clk_resume(); + #if defined(CONFIG_ARCH_TEGRA) fsl_udc_restart(udc_controller); #else diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index d2225d89ad66..5cdd6e983c8c 100755 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -447,6 +447,8 @@ struct ep_td_struct { #define USB_SYS_VBUS_WAKEUP_INT_ENABLE 0x100 #define USB_SYS_VBUS_WAKEUP_INT_STATUS 0x200 #define USB_SYS_VBUS_STATUS 0x400 +#define USB_SYS_ID_PIN_STATUS (0x4) + /*-------------------------------------------------------------------------*/ @@ -515,6 +517,7 @@ struct fsl_udc { u8 device_address; /* Device USB address */ struct regulator *vbus_regulator; /* regulator for drawing VBUS */ struct delayed_work work; /* delayed work for charger detection */ + struct work_struct irq_work; /* irq work for controling the usb power*/ }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 5c69667bd6ca..53301cb4342e 100755 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -54,22 +54,20 @@ * uses vfree and vmalloc functions which are not supposed to call from the * ISR context */ - static void tegra_ehci_busy_hint_work(struct work_struct* work) { - struct tegra_hcd_platform_data *pdata = - container_of(work, struct tegra_hcd_platform_data, work); - NvDdkUsbPhyIoctl_UsbBusyHintsOnOffInputArgs busyhint; - busyhint.OnOff = NV_TRUE; - - /* USB transfers will be done with in 1 sec, this need to be * - * fine tuned (if required). with safe limit set to 2 sec */ - busyhint.BoostDurationMs = 2000; - NvDdkUsbPhyIoctl( - pdata->hUsbPhy, - NvDdkUsbPhyIoctlType_UsbBusyHintsOnOff, - &busyhint, - NULL); + struct tegra_hcd_platform_data *pdata = + container_of(work, struct tegra_hcd_platform_data, work); + NvDdkUsbPhyIoctl_UsbBusyHintsOnOffInputArgs busyhint; + busyhint.OnOff = NV_TRUE; + + /* USB transfers will be done with in 1 sec, this need to be * + * fine tuned (if required). with safe limit set to 2 sec */ + busyhint.BoostDurationMs = 2000; + NvDdkUsbPhyIoctl(pdata->hUsbPhy, + NvDdkUsbPhyIoctlType_UsbBusyHintsOnOff, + &busyhint, + NULL); } static void tegra_ehci_power_up(struct usb_hcd *hcd) @@ -157,7 +155,6 @@ 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; @@ -190,7 +187,6 @@ 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) { @@ -203,6 +199,53 @@ static void tegra_ehci_shutdown (struct usb_hcd *hcd) tegra_ehci_power_down(hcd); } +/* + * Work thread function for handling the USB power sequence. + * + * This work thread is created to avoid the pre-emption from the ISR context. + * USB Power Rail and Vbus are controlled based on the USB cable connection. + * USB Power rail function and VBUS control function cannot be called from ISR + * as NvRmPmuSetVoltage() uses I2C driver, that waits on semaphore + * during the I2C transaction this will cause the pre-emption if called in ISR. + */ +static void tegra_ehci_irq_work(struct work_struct* irq_work) +{ + struct ehci_hcd *ehci = container_of(irq_work, struct ehci_hcd, irq_work); + struct usb_hcd *hcd = ehci_to_hcd(ehci); + struct tegra_hcd_platform_data *pdata; + u32 status; + + pdata = hcd->self.controller->platform_data; + +#ifdef CONFIG_USB_OTG_UTILS + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_OTG) + && ehci->transceiver) { + if (ehci->transceiver->state == OTG_STATE_A_HOST) { + if (!ehci->host_reinited) { + ehci->host_reinited = 1; + tegra_ehci_power_up(hcd); + tegra_ehci_restart(hcd); + } + } + } else +#endif + { + if (pdata->pUsbProperty->IdPinDetectionType == + NvOdmUsbIdPinType_CableId) { + /* read otgsc register for ID pin status change */ + status = readl(hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET); + /* Check pin status and enable/disable the power */ + if (status & TEGRA_USB_ID_PIN_STATUS) { + tegra_ehci_power_down(hcd); + } else { + tegra_ehci_power_up(hcd); + } + } + } +} + + + static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); @@ -218,9 +261,7 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) && ehci->transceiver) { if (ehci->transceiver->state == OTG_STATE_A_HOST) { if (!ehci->host_reinited) { - ehci->host_reinited = 1; - tegra_ehci_power_up(hcd); - tegra_ehci_restart(hcd); + schedule_work(&ehci->irq_work); } } else if (ehci->transceiver->state == OTG_STATE_A_SUSPEND) { if (!ehci->host_reinited) { @@ -242,12 +283,7 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) /* Check if there is any ID pin interrupt */ if (status & TEGRA_USB_ID_INT_STATUS) { - /* Check pin status and enable/disable the power */ - if (status & TEGRA_USB_ID_PIN_STATUS) { - tegra_ehci_power_down(hcd); - } else { - tegra_ehci_power_up(hcd); - } + schedule_work(&ehci->irq_work); } } } @@ -317,40 +353,45 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) return retval; } -#if defined(CONFIG_PM) + static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int err_status = 0; - -#ifdef CONFIG_USB_OTG_UTILS struct tegra_hcd_platform_data *pdata; + /* initialize the platform data pointer */ pdata = hcd->self.controller->platform_data; + +#ifdef CONFIG_USB_OTG_UTILS if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_OTG) && ehci->transceiver) { if (ehci->transceiver->state != OTG_STATE_A_HOST) { /* we are not in host mode, return */ - return err_status; + return 0; } } #endif - if (ehci->host_resumed) { - err_status = ehci_bus_suspend(hcd); - if (!err_status) - tegra_ehci_power_down(hcd); + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_Host) + && (pdata->pUsbProperty->IdPinDetectionType == + NvOdmUsbIdPinType_CableId)) { + u32 status; + /* check for ID pin status */ + status = readl(hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET); + /* If Id pin is high means host is not connected return */ + if (status & TEGRA_USB_ID_PIN_STATUS) { + return 0; + } } - return err_status; + + return ehci_bus_suspend(hcd); } static int tegra_ehci_bus_resume(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int err_status = 0; - u32 status; - struct tegra_hcd_platform_data *pdata; + /* initialize the platform data pointer */ pdata = hcd->self.controller->platform_data; @@ -359,67 +400,61 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd) && ehci->transceiver) { if (ehci->transceiver->state != OTG_STATE_A_HOST) { /* we are not in host mode, return */ - return err_status; + return 0; } } #endif - if (!ehci->host_resumed) { - tegra_ehci_power_up(hcd); - err_status = ehci_bus_resume(hcd); - } - - if ((pdata->pUsbProperty->UsbMode != NvOdmUsbModeType_OTG) + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_Host) && (pdata->pUsbProperty->IdPinDetectionType == NvOdmUsbIdPinType_CableId)) { - /* read otgsc register for ID pin status */ + u32 status; + /* read ID pin status */ status = readl(hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET); - writel(status, (hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET)); - /* If no Id pin then disable the power */ + /* If Id pin is high no host then return */ if (status & TEGRA_USB_ID_PIN_STATUS) { - tegra_ehci_power_down(hcd); + return 0; } - } - return err_status; -} -#endif + } + return ehci_bus_resume(hcd); +} static int tegra_ehci_urb_enqueue( - struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags + struct usb_hcd *hcd, + struct urb *urb, + gfp_t mem_flags ) { - struct tegra_hcd_platform_data *pdata; - int xfertype; - int transfer_buffer_length; - - pdata = hcd->self.controller->platform_data; - - xfertype = usb_endpoint_type(&urb->ep->desc); - transfer_buffer_length = urb->transfer_buffer_length; - /* Turn on the USB busy hints */ - switch (xfertype) { - case USB_ENDPOINT_XFER_INT: - if (transfer_buffer_length < 255) { - /* Do nothing for interrupt buffers < 255 */ - } else { - // signal to set the busy hints - schedule_work(&pdata->work); - } - break; - case USB_ENDPOINT_XFER_ISOC: - case USB_ENDPOINT_XFER_BULK: - // signal to set the busy hints - schedule_work(&pdata->work); - break; - case USB_ENDPOINT_XFER_CONTROL: - default: - /* Do nothing special here */ - break; - } - - return ehci_urb_enqueue(hcd, urb, mem_flags); + struct tegra_hcd_platform_data *pdata; + int xfertype; + int transfer_buffer_length; + + pdata = hcd->self.controller->platform_data; + + xfertype = usb_endpoint_type(&urb->ep->desc); + transfer_buffer_length = urb->transfer_buffer_length; + /* Turn on the USB busy hints */ + switch (xfertype) { + case USB_ENDPOINT_XFER_INT: + if (transfer_buffer_length < 255) { + /* Do nothing for interrupt buffers < 255 */ + } else { + // signal to set the busy hints + schedule_work(&pdata->work); + } + break; + case USB_ENDPOINT_XFER_ISOC: + case USB_ENDPOINT_XFER_BULK: + // signal to set the busy hints + schedule_work(&pdata->work); + break; + case USB_ENDPOINT_XFER_CONTROL: + default: + /* Do nothing special here */ + break; + } + + return ehci_urb_enqueue(hcd, urb, mem_flags); } static const struct hc_driver tegra_ehci_hc_driver = { @@ -458,6 +493,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) int irq; unsigned int temp; static u64 dummy_mask = DMA_32BIT_MASK; + struct ehci_hcd *ehci; pdata = (struct tegra_hcd_platform_data *)pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "Cannot run without platform data\n"); @@ -531,6 +567,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) set_irq_flags(irq, IRQF_VALID); + ehci = hcd_to_ehci(hcd); + INIT_WORK(&ehci->irq_work, tegra_ehci_irq_work); + e = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (e != 0) goto fail; @@ -538,7 +577,6 @@ static int tegra_ehci_probe(struct platform_device *pdev) #ifdef CONFIG_USB_OTG_UTILS if (pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_OTG) { - struct ehci_hcd *ehci = hcd_to_ehci(hcd); ehci->transceiver = otg_get_transceiver(); if (ehci->transceiver) { otg_set_host(ehci->transceiver, (struct usb_bus *)hcd); @@ -587,6 +625,86 @@ fail: return e; } +#if defined(CONFIG_PM) +static int tegra_ehci_resume(struct platform_device * pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct tegra_hcd_platform_data *pdata; + u32 status; + + /* initialize the platform data pointer */ + pdata = hcd->self.controller->platform_data; + + /* read otgsc register for ID pin status */ + status = readl(hcd->regs + TEGRA_USB_PHY_WAKEUP_REG_OFFSET); + +#ifdef CONFIG_USB_OTG_UTILS + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_OTG) + && ehci->transceiver) { + /* check if ID pin is high then no host return */ + if (status & TEGRA_USB_ID_PIN_STATUS) { + return 0; + } + else { + /* set HCD flags to start host ISR */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + ehci->host_reinited = 1; + ehci->transceiver->state = OTG_STATE_A_HOST; + } + } +#endif + + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_Host) + && (pdata->pUsbProperty->IdPinDetectionType == + NvOdmUsbIdPinType_CableId)) { + /* If no Id pin then return */ + if (status & TEGRA_USB_ID_PIN_STATUS) { + return 0; + } + } + + if (!ehci->host_resumed) { + tegra_ehci_power_up(hcd); + tegra_ehci_restart(hcd); + } + + return 0; +} + +static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + +#ifdef CONFIG_USB_OTG_UTILS + struct tegra_hcd_platform_data *pdata; + /* initialize the platform data pointer */ + pdata = hcd->self.controller->platform_data; + if ((pdata->pUsbProperty->UsbMode == NvOdmUsbModeType_OTG) + && ehci->transceiver) { + if (ehci->transceiver->state != OTG_STATE_A_HOST) { + /* we are not in host mode, return */ + return 0; + } + else { + ehci->transceiver->state = OTG_STATE_UNDEFINED; + ehci->host_reinited = 0; + ehci_halt(ehci); + /* indicate hcd flags, that hardware is not accessable now */ + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + } + } +#endif + + if (ehci->host_resumed) { + tegra_ehci_power_down(hcd); + } + + return 0; +} +#endif + static int tegra_ehci_remove(struct platform_device *pdev) { struct tegra_hcd_platform_data *pdata = pdev->dev.platform_data; @@ -612,6 +730,10 @@ static struct platform_driver tegra_ehci_driver = { .probe = tegra_ehci_probe, .remove = tegra_ehci_remove, +#if defined(CONFIG_PM) + .suspend = tegra_ehci_suspend, + .resume = tegra_ehci_resume, +#endif .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "tegra-ehci", diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 1e4394d4f363..ed2ec5b5e47d 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -135,6 +135,7 @@ struct ehci_hcd { /* one per controller */ unsigned controller_resets_phy:1; unsigned host_reinited:1; /* tegra */ unsigned host_resumed:1; /* tegra */ + struct work_struct irq_work; /* tegra irq work for power control*/ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index a17d8d90f44f..1f300308fb78 100755 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -111,16 +111,16 @@ static int tegra_otg_set_peripheral(struct otg_transceiver *otg, temp &= ~TEGRA_USB_VBUS_INT_STATUS; writel(temp, (sg_tegra_otg->regs + TEGRA_USB_WAKEUP_REG_OFFSET)); - spin_lock_irqsave(&sg_tegra_otg->lock, flags); /* Check if we detect any device connected */ if (!(temp & TEGRA_USB_ID_STATUS)) { struct usb_hcd *hcd = (struct usb_hcd *)otg->host; + spin_lock_irqsave(&sg_tegra_otg->lock, flags); otg->state = OTG_STATE_A_HOST; /* set HCD flags to start host ISR */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore(&sg_tegra_otg->lock, flags); NvDdkUsbPhyPowerUp(sg_tegra_otg->usb_phy, NV_TRUE, 0); } - spin_unlock_irqrestore(&sg_tegra_otg->lock, flags); return 0; } @@ -179,7 +179,7 @@ static int __init tegra_otg_probe(struct platform_device *pdev) NvDdkUsbPhyOpen(s_hRmGlobal, instance, &sg_tegra_otg->usb_phy) ); NV_CHECK_ERROR_CLEANUP( - NvDdkUsbPhyPowerUp(sg_tegra_otg->usb_phy, NV_TRUE, 0) + NvDdkUsbPhyPowerUp(sg_tegra_otg->usb_phy, NV_FALSE, 0) ); sg_tegra_otg->instance = pdev->id; sg_tegra_otg->dev = &pdev->dev; @@ -224,7 +224,7 @@ static int __init tegra_otg_probe(struct platform_device *pdev) goto err_otg; } - NvDdkUsbPhyPowerDown(sg_tegra_otg->usb_phy, NV_TRUE, 0); + NvDdkUsbPhyPowerDown(sg_tegra_otg->usb_phy, NV_FALSE, 0); return 0; -- cgit v1.2.3