summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuresh Mangipudi <smangipudi@nvidia.com>2011-05-12 19:19:52 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:44:22 -0800
commit5fd30e96a84e883449df6dc887148d3a6fcbde5e (patch)
tree3f593c91eb47ffed540d8ede8e5f122ebc75a93b
parentd8bc803a46daeee25035fb7856d35aa00ca89041 (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 Original-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> Rebase-Id: Rfb360adede773d791d5d891fddd90e8c2a4de686
-rw-r--r--arch/arm/mach-tegra/include/mach/usb_phy.h12
-rw-r--r--arch/arm/mach-tegra/usb_phy.c93
-rw-r--r--drivers/usb/gadget/fsl_tegra_udc.c11
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c18
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h8
-rw-r--r--drivers/usb/host/ehci-tegra.c83
-rw-r--r--drivers/usb/otg/tegra-otg.c1
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 ca4693de4f83..fe227156b97b 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)
@@ -214,6 +215,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)
@@ -566,7 +569,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;
@@ -580,7 +583,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);
@@ -712,7 +715,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;
@@ -867,24 +870,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);
@@ -892,21 +886,12 @@ 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);
-
if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
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;
@@ -917,12 +902,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;
@@ -934,7 +932,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;
@@ -946,7 +944,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;
@@ -1101,7 +1099,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;
@@ -1177,7 +1175,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;
@@ -1227,7 +1225,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;
@@ -1333,7 +1331,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;
@@ -1346,7 +1344,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;
@@ -1376,7 +1374,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;
@@ -1461,7 +1459,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;
@@ -1649,7 +1647,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:
@@ -1660,7 +1661,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;
@@ -1677,12 +1678,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,
@@ -1692,7 +1693,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
@@ -1703,7 +1704,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,
@@ -1713,10 +1714,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,
@@ -1726,10 +1727,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,
@@ -1739,7 +1740,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,
@@ -1777,7 +1778,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 f2a41a2a711c..c691a1b199d5 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 7c3bbb91f0d8..8f0eca5650df 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1377,9 +1377,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 */
@@ -3014,7 +3014,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);
@@ -3023,7 +3023,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
@@ -3124,7 +3124,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;
}
@@ -3136,7 +3136,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;
@@ -3144,7 +3144,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 */
@@ -3152,7 +3152,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)
@@ -3169,7 +3169,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 cdf1487f08be..8ce0da7ed6c6 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -717,8 +717,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)
{
@@ -730,10 +730,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 5f15a6fb5c80..5a04ac1ada31 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,24 +57,22 @@ 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);
}
@@ -140,6 +142,25 @@ static int tegra_ehci_internal_port_reset(
return retval;
}
+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,
@@ -160,6 +181,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];
@@ -183,7 +210,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);
@@ -239,7 +266,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));
@@ -352,7 +379,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);
@@ -379,7 +406,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;
@@ -392,15 +419,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;
@@ -412,7 +438,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
@@ -521,12 +547,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)
@@ -549,6 +575,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;
@@ -561,8 +589,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.
@@ -583,7 +612,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;
@@ -594,7 +623,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;
}
@@ -726,12 +755,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)
@@ -848,7 +877,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,
@@ -964,7 +993,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;
@@ -1045,7 +1074,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)
@@ -1059,7 +1088,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
@@ -1091,7 +1120,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();
}