diff options
author | Suresh Mangipudi <smangipudi@nvidia.com> | 2011-05-12 19:19:52 +0530 |
---|---|---|
committer | Niket Sirsi <nsirsi@nvidia.com> | 2011-05-23 16:55:01 -0700 |
commit | 27c33da7c5760463c6e7559a2f86f90fd8661eba (patch) | |
tree | 726969cae7afe0557075d88f263842d03ec0abcc | |
parent | 40429e13014675e82e1126c5df87c9008aee92c1 (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
Bug 801533
Change-Id: I282da0a37ab4311d9d9c61f75e03228bfb15698e
Reviewed-on: http://git-master/r/30041
Reviewed-by: Suresh Mangipudi <smangipudi@nvidia.com>
Tested-by: Suresh Mangipudi <smangipudi@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/include/mach/usb_phy.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-tegra/usb_phy.c | 93 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_tegra_udc.c | 11 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 18 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_usb2_udc.h | 8 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 83 | ||||
-rw-r--r-- | drivers/usb/otg/tegra-otg.c | 1 |
7 files changed, 128 insertions, 98 deletions
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index 0d8afa9cb835..0672b049dbfa 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -95,25 +95,25 @@ struct tegra_usb_phy { int initialized; }; -typedef int (*tegra_phy_fp)(struct tegra_usb_phy *phy); +typedef int (*tegra_phy_fp)(struct tegra_usb_phy *phy, bool is_dpd); struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode, enum tegra_usb_phy_type usb_phy_type); -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy); +int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd); void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy); void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy); -void tegra_usb_phy_power_off(struct tegra_usb_phy *phy); +void tegra_usb_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd); -void tegra_usb_phy_preresume(struct tegra_usb_phy *phy); +void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd); -void tegra_usb_phy_postresume(struct tegra_usb_phy *phy); +void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd); -void tegra_ehci_post_reset(struct tegra_usb_phy *phy); +void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd); void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, enum tegra_usb_phy_port_speed port_speed); diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 851d1989b096..683ebe9a1cc8 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -73,6 +73,7 @@ #define USB_SUSP_CLR (1 << 5) #define USB_CLKEN (1 << 6) #define USB_PHY_CLK_VALID (1 << 7) +#define USB_PHY_CLK_VALID_INT_ENB (1 << 9) #define UTMIP_RESET (1 << 11) #define UHSIC_RESET (1 << 11) #define UTMIP_PHY_ENABLE (1 << 12) @@ -213,6 +214,8 @@ #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) #define USB_SUSP_CLR (1 << 5) #define USB_PHY_CLK_VALID (1 << 7) +#define USB_PHY_CLK_VALID_INT_ENB (1 << 9) + #define UTMIP_RESET (1 << 11) #define UTMIP_PHY_ENABLE (1 << 12) @@ -560,7 +563,7 @@ static int utmip_pad_power_on(struct tegra_usb_phy *phy) return 0; } -static int utmip_pad_power_off(struct tegra_usb_phy *phy) +static int utmip_pad_power_off(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val, flags; void __iomem *base = phy->pad_regs; @@ -574,7 +577,7 @@ static int utmip_pad_power_off(struct tegra_usb_phy *phy) spin_lock_irqsave(&utmip_pad_lock, flags); - if (--utmip_pad_count == 0) { + if (--utmip_pad_count == 0 && is_dpd) { val = readl(base + UTMIP_BIAS_CFG0); val |= UTMIP_OTGPD | UTMIP_BIASPD; writel(val, base + UTMIP_BIAS_CFG0); @@ -706,7 +709,7 @@ static void vbus_disable(struct tegra_usb_phy *phy) #endif } -static int utmi_phy_power_on(struct tegra_usb_phy *phy) +static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; @@ -854,24 +857,15 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) val |= HOSTPC1_DEVLC_STS; writel(val, base + HOSTPC1_DEVLC); #endif - if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { - vbus_enable(phy); - } return 0; } -static int utmi_phy_power_off(struct tegra_usb_phy *phy) +static void utmi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; - utmi_phy_clk_disable(phy); - - if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { - vbus_disable(phy); - } - if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { val = readl(base + USB_SUSP_CTRL); val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0); @@ -879,19 +873,10 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) writel(val, base + USB_SUSP_CTRL); } - val = readl(base + USB_SUSP_CTRL); - val |= UTMIP_RESET; - writel(val, base + USB_SUSP_CTRL); - val = readl(base + UTMIP_BAT_CHRG_CFG0); val |= UTMIP_PD_CHRG; writel(val, base + UTMIP_BAT_CHRG_CFG0); - val = readl(base + UTMIP_XCVR_CFG0); - val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN; - writel(val, base + UTMIP_XCVR_CFG0); - val = readl(base + UTMIP_XCVR_CFG1); val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN; @@ -902,12 +887,25 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) val |= UTMIP_BIAS_PDTRK_COUNT(0x5); writel(val, base + UTMIP_BIAS_CFG1); #endif - utmip_pad_power_off(phy); + if (phy->instance == 2) { + val = readl(base + USB_PORTSC1); + val |= USB_PORTSC1_WKCN; + writel(val, base + USB_PORTSC1); + } + + utmi_phy_clk_disable(phy); + + if (phy->instance == 2) { + val = readl(base + USB_SUSP_CTRL); + val |= USB_PHY_CLK_VALID_INT_ENB; + writel(val, base + USB_SUSP_CTRL); + } + utmip_pad_power_off(phy, is_dpd); return 0; } -static int utmi_phy_preresume(struct tegra_usb_phy *phy) +static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; @@ -919,7 +917,7 @@ static int utmi_phy_preresume(struct tegra_usb_phy *phy) return 0; } -static int utmi_phy_postresume(struct tegra_usb_phy *phy) +static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; @@ -931,7 +929,7 @@ static int utmi_phy_postresume(struct tegra_usb_phy *phy) return 0; } -static int uhsic_phy_postresume(struct tegra_usb_phy *phy) +static int uhsic_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd) { #ifdef CONFIG_ARCH_TEGRA_2x_SOC unsigned long val; @@ -1086,7 +1084,7 @@ static void ulpi_phy_restore_end(struct tegra_usb_phy *phy) #endif } -static int ulpi_phy_power_on(struct tegra_usb_phy *phy) +static int ulpi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) { int ret; unsigned long val; @@ -1161,7 +1159,7 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) return 0; } -static int ulpi_phy_power_off(struct tegra_usb_phy *phy) +static int ulpi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; @@ -1211,7 +1209,7 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy) return 0; } -static int null_phy_power_on(struct tegra_usb_phy *phy) +static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) { const struct tegra_ulpi_trimmer default_trimmer = {0, 0, 4, 4}; unsigned long val; @@ -1317,7 +1315,7 @@ static int null_phy_power_on(struct tegra_usb_phy *phy) return 0; } -static int null_phy_power_off(struct tegra_usb_phy *phy) +static int null_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; @@ -1330,7 +1328,7 @@ static int null_phy_power_off(struct tegra_usb_phy *phy) return 0; } -static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy) +static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd) { #ifndef CONFIG_ARCH_TEGRA_2x_SOC unsigned long val; @@ -1360,7 +1358,7 @@ static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy) return 0; } -static int uhsic_phy_power_on(struct tegra_usb_phy *phy) +static int uhsic_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; @@ -1445,7 +1443,7 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) return 0; } -static int uhsic_phy_power_off(struct tegra_usb_phy *phy) +static int uhsic_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) { unsigned long val; void __iomem *base = phy->regs; @@ -1633,7 +1631,10 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, } } #endif - + if (((instance == 2) || (instance == 0)) && + (phy->mode == TEGRA_USB_PHY_MODE_HOST)) { + vbus_enable(phy); + } return phy; err1: @@ -1644,7 +1645,7 @@ err0: return ERR_PTR(err); } -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) +int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) { int ret = 0; @@ -1661,12 +1662,12 @@ int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) } if (power_on[phy->usb_phy_type]) - ret = power_on[phy->usb_phy_type](phy); + ret = power_on[phy->usb_phy_type](phy, is_dpd); return ret; } -void tegra_usb_phy_power_off(struct tegra_usb_phy *phy) +void tegra_usb_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) { const tegra_phy_fp power_off[] = { utmi_phy_power_off, @@ -1676,7 +1677,7 @@ void tegra_usb_phy_power_off(struct tegra_usb_phy *phy) }; if (power_off[phy->usb_phy_type]) - power_off[phy->usb_phy_type](phy); + power_off[phy->usb_phy_type](phy, is_dpd); if (phy->reg_vdd && phy->regulator_on) { #ifdef CONFIG_ARCH_TEGRA_2x_SOC @@ -1687,7 +1688,7 @@ void tegra_usb_phy_power_off(struct tegra_usb_phy *phy) } } -void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) +void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd) { const tegra_phy_fp preresume[] = { utmi_phy_preresume, @@ -1697,10 +1698,10 @@ void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) }; if (preresume[phy->usb_phy_type]) - preresume[phy->usb_phy_type](phy); + preresume[phy->usb_phy_type](phy, is_dpd); } -void tegra_usb_phy_postresume(struct tegra_usb_phy *phy) +void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd) { const tegra_phy_fp postresume[] = { utmi_phy_postresume, @@ -1710,10 +1711,10 @@ void tegra_usb_phy_postresume(struct tegra_usb_phy *phy) }; if (postresume[phy->usb_phy_type]) - postresume[phy->usb_phy_type](phy); + postresume[phy->usb_phy_type](phy, is_dpd); } -void tegra_ehci_post_reset(struct tegra_usb_phy *phy) +void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd) { const tegra_phy_fp post_reset[] = { NULL, @@ -1723,7 +1724,7 @@ void tegra_ehci_post_reset(struct tegra_usb_phy *phy) }; if (post_reset[phy->usb_phy_type]) - post_reset[phy->usb_phy_type](phy); + post_reset[phy->usb_phy_type](phy, is_dpd); } void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, @@ -1761,7 +1762,9 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy) utmip_pad_close(phy); else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI) clk_put(phy->clk); - + if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { + vbus_disable(phy); + } clk_disable(phy->pll_u); clk_put(phy->pll_u); if (phy->reg_vbus) diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c index a20802a80c75..850825a89d01 100644 --- a/drivers/usb/gadget/fsl_tegra_udc.c +++ b/drivers/usb/gadget/fsl_tegra_udc.c @@ -86,8 +86,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: @@ -124,18 +123,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 91cbc296077a..57f47de3eed0 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1253,9 +1253,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 */ @@ -2808,7 +2808,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); @@ -2817,7 +2817,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(!vbus_enabled()) - fsl_udc_clk_suspend(); + fsl_udc_clk_suspend(false); #endif #endif @@ -2904,7 +2904,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; } @@ -2916,7 +2916,7 @@ static int fsl_udc_resume(struct platform_device *pdev) { if (udc_controller->transceiver) { /* enable clock */ - fsl_udc_clk_resume(); + fsl_udc_clk_resume(true); 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; @@ -2924,7 +2924,7 @@ static int fsl_udc_resume(struct platform_device *pdev) /* check for VBUS */ if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) { /* if there is no VBUS then power down the clocks and return */ - fsl_udc_clk_suspend(); + fsl_udc_clk_suspend(false); return 0; } else { /* Detected VBUS set the transceiver state to device mode */ @@ -2932,7 +2932,7 @@ static int fsl_udc_resume(struct platform_device *pdev) } } else { /* enable the clocks to the controller */ - fsl_udc_clk_resume(); + fsl_udc_clk_resume(true); } #if defined(CONFIG_ARCH_TEGRA) @@ -2949,7 +2949,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 5db707d00e85..025d906b1fdf 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -707,8 +707,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) { @@ -720,10 +720,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 a20725e375c0..e895a078f406 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,28 +57,45 @@ 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); + tegra_usb_phy_power_off(tegra->phy, is_dpd); clk_disable(tegra->sclk_clk); clk_disable(tegra->emc_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( struct usb_hcd *hcd, u16 typeReq, @@ -95,6 +116,12 @@ static int tegra_ehci_hub_control( 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; + } + hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC); status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; @@ -118,7 +145,7 @@ static int tegra_ehci_hub_control( tegra->port_resuming = 0; clear_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); ehci->reset_done[wIndex-1] = 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); @@ -166,7 +193,7 @@ static int tegra_ehci_hub_control( tegra->port_resuming = 1; /* Disable disconnect detection during port resume */ - tegra_usb_phy_preresume(tegra->phy); + tegra_usb_phy_preresume(tegra->phy, false); ehci_dbg(ehci, "%s:USBSTS = 0x%x", __func__, ehci_readl(ehci, &ehci->regs->status)); @@ -279,7 +306,7 @@ static void tegra_ehci_restart(struct usb_hcd *hcd) unsigned int temp; ehci_reset(ehci); - tegra_ehci_post_reset(tegra->phy); + tegra_ehci_post_reset(tegra->phy, false); /* setup the frame list and Async q heads */ ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); @@ -306,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; @@ -319,15 +346,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; @@ -339,7 +365,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd) hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC); 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 @@ -447,12 +473,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) @@ -475,6 +501,8 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) #ifndef CONFIG_ARCH_TEGRA_2x_SOC ehci->has_hostpc = 1; #endif + if (tegra->phy->instance == 0) + ehci_reset(ehci); retval = ehci_halt(ehci); if (retval) return retval; @@ -487,8 +515,9 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) hcd->has_tt = 1; ehci->sbrn = 0x20; - ehci_reset(ehci); - tegra_ehci_post_reset(tegra->phy); + if (!tegra->phy->instance == 0) + ehci_reset(ehci); + tegra_ehci_post_reset(tegra->phy, false); /* * Resetting the controller has the side effect of resetting the PHY. @@ -509,7 +538,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; @@ -520,7 +549,7 @@ 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; } @@ -652,12 +681,12 @@ static ssize_t store_ehci_power(struct device *dev, if (power_on == 0 && ehci_handle != NULL) { usb_remove_hcd(hcd); - tegra_ehci_power_down(hcd); + tegra_ehci_power_down(hcd, false); ehci_handle = NULL; } else if (power_on == 1) { if (ehci_handle) usb_remove_hcd(hcd); - tegra_ehci_power_up(hcd); + tegra_ehci_power_up(hcd, false); retval = usb_add_hcd(hcd, ehci_tegra_irq, IRQF_DISABLED | IRQF_SHARED); if (retval < 0) @@ -774,7 +803,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, @@ -890,7 +919,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; @@ -971,7 +1000,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) @@ -985,7 +1014,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 @@ -1017,7 +1046,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..2c3690150c04 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -175,7 +175,6 @@ static void irq_work(struct work_struct *work) tegra_start_host(tegra); } } - clk_disable(tegra->clk); tegra_otg_disable_clk(); } |