diff options
author | Suresh Mangipudi <smangipudi@nvidia.com> | 2011-05-06 13:57:20 +0530 |
---|---|---|
committer | Niket Sirsi <nsirsi@nvidia.com> | 2011-05-19 17:49:40 -0700 |
commit | c20a54d503e859b8b9c62c6fb446fcfe273d433b (patch) | |
tree | cd62bf6bf64f77c482f560c67b902889e0773827 /drivers | |
parent | ee550c20967fccfae7b13f2fac6271ae17339f53 (diff) |
usb: host: tegra: hotplug detection of device
Add support for usb hotplug, this change will add the following:
vbus is left enabled.
Bug 796158
Change-Id: I3c3cfa0bf8858b3be2351fe753ceb2a0229ed15d
Reviewed-on: http://git-master/r/30686
Reviewed-by: Suresh Mangipudi <smangipudi@nvidia.com>
Tested-by: Suresh Mangipudi <smangipudi@nvidia.com>
Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/fsl_tegra_udc.c | 11 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_usb2_udc.h | 8 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 74 | ||||
-rw-r--r-- | drivers/usb/otg/tegra-otg.c | 1 |
5 files changed, 66 insertions, 44 deletions
diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c index 8589ef781039..712636d8ee8e 100644 --- a/drivers/usb/gadget/fsl_tegra_udc.c +++ b/drivers/usb/gadget/fsl_tegra_udc.c @@ -80,8 +80,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) err = PTR_ERR(phy); goto err1; } - - tegra_usb_phy_power_on(phy); + tegra_usb_phy_power_on(phy, true); return 0; err1: @@ -118,18 +117,18 @@ void fsl_udc_clk_release(void) clk_put(emc_clk); } -void fsl_udc_clk_suspend(void) +void fsl_udc_clk_suspend(bool is_dpd) { - tegra_usb_phy_power_off(phy); + tegra_usb_phy_power_off(phy, is_dpd); clk_disable(udc_clk); clk_disable(sclk_clk); clk_disable(emc_clk); } -void fsl_udc_clk_resume(void) +void fsl_udc_clk_resume(bool is_dpd) { clk_enable(emc_clk); clk_enable(sclk_clk); clk_enable(udc_clk); - tegra_usb_phy_power_on(phy); + tegra_usb_phy_power_on(phy, is_dpd); } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 74ebe55a1ca0..c67230db46eb 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1216,9 +1216,9 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) udc->vbus_active = 0; udc->usb_state = USB_STATE_DEFAULT; spin_unlock_irqrestore(&udc->lock, flags); - fsl_udc_clk_suspend(); + fsl_udc_clk_suspend(false); } else if (!udc->vbus_active && is_active) { - fsl_udc_clk_resume(); + fsl_udc_clk_resume(false); /* setup the controller in the device mode */ dr_controller_setup(udc); /* setup EP0 for setup packet */ @@ -2751,7 +2751,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) if (udc_controller->transceiver) { dr_controller_stop(udc_controller); dr_controller_reset(udc_controller); - fsl_udc_clk_suspend(); + fsl_udc_clk_suspend(false); udc_controller->vbus_active = 0; udc_controller->usb_state = USB_STATE_DEFAULT; otg_set_peripheral(udc_controller->transceiver, &udc_controller->gadget); @@ -2760,7 +2760,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) #ifdef CONFIG_ARCH_TEGRA /* Power down the phy if cable is not connected */ if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) - fsl_udc_clk_suspend(); + fsl_udc_clk_suspend(false); #endif #endif @@ -2847,7 +2847,7 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) if (udc_controller->transceiver) { udc_controller->transceiver->state = OTG_STATE_UNDEFINED; } - fsl_udc_clk_suspend(); + fsl_udc_clk_suspend(true); return 0; } @@ -2868,13 +2868,13 @@ static int fsl_udc_resume(struct platform_device *pdev) /* if there is no VBUS then power down the clocks and return */ return 0; } else { - fsl_udc_clk_resume(); + fsl_udc_clk_resume(true); /* Detected VBUS set the transceiver state to device mode */ udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL; } } else { /* enable the clocks to the controller */ - fsl_udc_clk_resume(); + fsl_udc_clk_resume(true); } #if defined(CONFIG_ARCH_TEGRA) @@ -2891,7 +2891,7 @@ static int fsl_udc_resume(struct platform_device *pdev) #endif /* Power down the phy if cable is not connected */ if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) - fsl_udc_clk_suspend(); + fsl_udc_clk_suspend(false); return 0; } diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 99c36054e66c..19d113c03af6 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -587,8 +587,8 @@ struct platform_device; int fsl_udc_clk_init(struct platform_device *pdev); void fsl_udc_clk_finalize(struct platform_device *pdev); void fsl_udc_clk_release(void); -void fsl_udc_clk_suspend(void); -void fsl_udc_clk_resume(void); +void fsl_udc_clk_suspend(bool is_dpd); +void fsl_udc_clk_resume(bool is_dpd); #else static inline int fsl_udc_clk_init(struct platform_device *pdev) { @@ -600,10 +600,10 @@ static inline void fsl_udc_clk_finalize(struct platform_device *pdev) static inline void fsl_udc_clk_release(void) { } -static inline void fsl_udc_clk_suspend(void) +static inline void fsl_udc_clk_suspend(bool is_dpd) { } -static inline void fsl_udc_clk_resume(void) +static inline void fsl_udc_clk_resume(bool is_dpd) { } #endif diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index fab9edb4cc99..3a28122b451a 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -30,6 +30,10 @@ #define TEGRA_USB_SUSP_CLR (1 << 5) #define TEGRA_USB_PHY_CLK_VALID (1 << 7) #define TEGRA_USB_SRT (1 << 25) +#define TEGRA_USB_PHY_CLK_VALID_INT_ENB (1 << 9) + +#define TEGRA_USB_PORTSC1_OFFSET 0x184 +#define TEGRA_USB_PORTSC1_WKCN (1 << 20) #define TEGRA_LVL2_CLK_GATE_OVRB 0xfc #define TEGRA_USB2_CLK_OVR_ON (1 << 10) @@ -53,26 +57,43 @@ struct tegra_ehci_hcd { enum tegra_usb_phy_port_speed port_speed; }; -static void tegra_ehci_power_up(struct usb_hcd *hcd) +static void tegra_ehci_power_up(struct usb_hcd *hcd, bool is_dpd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); clk_enable(tegra->emc_clk); clk_enable(tegra->sclk_clk); - clk_enable(tegra->clk); - tegra_usb_phy_power_on(tegra->phy); + tegra_usb_phy_power_on(tegra->phy, is_dpd); tegra->host_resumed = 1; } -static void tegra_ehci_power_down(struct usb_hcd *hcd) +static void tegra_ehci_power_down(struct usb_hcd *hcd, bool is_dpd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); tegra->host_resumed = 0; - tegra_usb_phy_power_off(tegra->phy); - clk_disable(tegra->clk); - clk_disable(tegra->sclk_clk); + tegra_usb_phy_power_off(tegra->phy, is_dpd); clk_disable(tegra->emc_clk); + clk_disable(tegra->sclk_clk); +} + +static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u32 val; + + spin_lock (&ehci->lock); + val = readl(hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET); + val &= ~TEGRA_USB_PHY_CLK_VALID_INT_ENB; + writel(val , (hcd->regs + TEGRA_USB_SUSP_CTRL_OFFSET)); + + val = readl(hcd->regs + TEGRA_USB_PORTSC1_OFFSET); + val &= ~TEGRA_USB_PORTSC1_WKCN; + writel(val , (hcd->regs + TEGRA_USB_PORTSC1_OFFSET)); + + spin_unlock (&ehci->lock); + + return ehci_irq(hcd); } static int tegra_ehci_hub_control( @@ -94,7 +115,11 @@ static int tegra_ehci_hub_control( unsigned selector; struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); bool hsic = false; - + if (!tegra->host_resumed) { + if (buf) + memset (buf, 0, wLength); + return retval; + } if (tegra->phy->instance == 1) { struct tegra_ulpi_config *config = tegra->phy->config; hsic = (config->inf_type == TEGRA_USB_UHSIC); @@ -118,7 +143,7 @@ static int tegra_ehci_hub_control( if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { /* Resume completed, re-enable disconnect detection */ tegra->port_resuming = 0; - tegra_usb_phy_postresume(tegra->phy); + tegra_usb_phy_postresume(tegra->phy, false); } } else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { temp = ehci_readl(ehci, status_reg); @@ -164,7 +189,7 @@ static int tegra_ehci_hub_control( goto done; /* Disable disconnect detection during port resume */ - tegra_usb_phy_preresume(tegra->phy); + tegra_usb_phy_preresume(tegra->phy, false); ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); @@ -308,7 +333,7 @@ static void tegra_ehci_restart(struct usb_hcd *hcd) ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); } -static int tegra_usb_suspend(struct usb_hcd *hcd) +static int tegra_usb_suspend(struct usb_hcd *hcd, bool is_dpd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_regs __iomem *hw = tegra->ehci->regs; @@ -325,15 +350,14 @@ static int tegra_usb_suspend(struct usb_hcd *hcd) tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; ehci_halt(tegra->ehci); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&tegra->ehci->lock, flags); - tegra_ehci_power_down(hcd); + tegra_ehci_power_down(hcd, is_dpd); return 0; } -static int tegra_usb_resume(struct usb_hcd *hcd) +static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct usb_device *udev = hcd->self.root_hub; @@ -349,7 +373,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd) } set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - tegra_ehci_power_up(hcd); + tegra_ehci_power_up(hcd, is_dpd); if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) { /* Wait for the phy to detect new devices @@ -457,12 +481,12 @@ static void tegra_ehci_shutdown(struct usb_hcd *hcd) /* ehci_shutdown touches the USB controller registers, make sure * controller has clocks to it */ if (!tegra->host_resumed) - tegra_ehci_power_up(hcd); + tegra_ehci_power_up(hcd, false); ehci_shutdown(hcd); /* we are ready to shut down, powerdown the phy */ - tegra_ehci_power_down(hcd); + tegra_ehci_power_down(hcd, false); } static int tegra_ehci_setup(struct usb_hcd *hcd) @@ -508,7 +532,7 @@ static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) error_status = ehci_bus_suspend(hcd); if (!error_status && tegra->power_down_on_bus_suspend) { - tegra_usb_suspend(hcd); + tegra_usb_suspend(hcd, false); tegra->bus_suspended = 1; } return error_status; @@ -519,11 +543,11 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd) struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); if (tegra->bus_suspended && tegra->power_down_on_bus_suspend) { - tegra_usb_resume(hcd); + tegra_usb_resume(hcd, false); tegra->bus_suspended = 0; } - tegra_usb_phy_preresume(tegra->phy); + tegra_usb_phy_preresume(tegra->phy, false); tegra->port_resuming = 1; return ehci_bus_resume(hcd); } @@ -775,7 +799,7 @@ static const struct hc_driver tegra_ehci_hc_driver = { .flags = HCD_USB2 | HCD_MEMORY, .reset = tegra_ehci_setup, - .irq = ehci_irq, + .irq = tegra_ehci_irq, .start = ehci_run, .stop = ehci_stop, @@ -885,7 +909,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_phy; } - err = tegra_usb_phy_power_on(tegra->phy); + err = tegra_usb_phy_power_on(tegra->phy, true); if (err) { dev_err(&pdev->dev, "Failed to power on the phy\n"); goto fail; @@ -966,7 +990,7 @@ static int tegra_ehci_resume(struct platform_device *pdev) if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) return 0; - return tegra_usb_resume(hcd); + return tegra_usb_resume(hcd, true); } static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state) @@ -980,7 +1004,7 @@ static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state) if (time_before(jiffies, tegra->ehci->next_statechange)) msleep(10); - return tegra_usb_suspend(hcd); + return tegra_usb_suspend(hcd, true); } #endif @@ -1012,7 +1036,7 @@ static int tegra_ehci_remove(struct platform_device *pdev) usb_remove_hcd(hcd); usb_put_hcd(hcd); cancel_delayed_work(&tegra->work); - tegra_usb_phy_power_off(tegra->phy); + tegra_usb_phy_power_off(tegra->phy, true); tegra_usb_phy_close(tegra->phy); iounmap(hcd->regs); diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index 386bb8b922da..893b897f5957 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -342,7 +342,6 @@ static int tegra_otg_probe(struct platform_device *pdev) INIT_WORK (&tegra->work, irq_work); dev_info(&pdev->dev, "otg transceiver registered\n"); - clk_disable(tegra->clk); return 0; err_irq: |