summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony LIU <junjie.liu@freescale.com>2012-03-07 15:53:56 +0800
committerJason Liu <r64343@freescale.com>2012-07-20 13:24:12 +0800
commit1562cf76782c05d8ce0d42b09c662f5051816bba (patch)
tree9624168be1c39d10a0e85e4afcebcc466f4ec202
parentd187b6a3e1a54381e05e1d0e5d888b12e0a1c6f0 (diff)
ENGR00176299-1 usb host suspend/resume can't work randomly
MSL part - after suspend bit is set, we need to set PWD bit and clear it right now to let PHY know the state change - after suspend bit is set, disconnect detection should be clear - after set resume bit, disconnect detection should be set after 30 ms - IC issue PDM refer to TKT092876 TKT092872 Signed-off-by: Tony LIU <junjie.liu@freescale.com>
-rw-r--r--arch/arm/mach-mx6/usb_dr.c109
-rw-r--r--arch/arm/mach-mx6/usb_h1.c103
-rwxr-xr-xarch/arm/plat-mxc/usb_common.c23
3 files changed, 197 insertions, 38 deletions
diff --git a/arch/arm/mach-mx6/usb_dr.c b/arch/arm/mach-mx6/usb_dr.c
index f49bb1096eed..96922a200b82 100644
--- a/arch/arm/mach-mx6/usb_dr.c
+++ b/arch/arm/mach-mx6/usb_dr.c
@@ -44,7 +44,6 @@ static u8 otg_used;
static void usbotg_wakeup_event_clear(void);
extern int clk_get_usecount(struct clk *clk);
-
/* Beginning of Common operation for DR port */
/*
@@ -71,6 +70,51 @@ static struct fsl_usb2_wakeup_platform_data dr_wakeup_config = {
.usb_wakeup_exhandle = usbotg_wakeup_event_clear,
};
+static void fsl_platform_otg_set_usb_phy_dis(
+ struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ u32 usb_phy_ctrl_dcdt = 0;
+ void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR);
+ usb_phy_ctrl_dcdt = __raw_readl(
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL) &
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT;
+ if (enable) {
+ if (usb_phy_ctrl_dcdt == 0) {
+ __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS,
+ anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_CLR);
+
+ __raw_writel(BM_USBPHY_PWD_RXPWDENV,
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_SET);
+
+ udelay(300);
+
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs)
+ + HW_USBPHY_CTRL_SET);
+
+ UOG_USBSTS |= (1 << 7);
+
+ while ((UOG_USBSTS & (1 << 7)) == 0)
+ ;
+
+ udelay(2);
+
+ __raw_writel(BM_USBPHY_PWD_RXPWDENV,
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_CLR);
+
+ __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS,
+ anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_SET);
+
+ }
+ } else {
+ if (usb_phy_ctrl_dcdt
+ == BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs)
+ + HW_USBPHY_CTRL_CLR);
+ }
+}
+
static void usbotg_internal_phy_clock_gate(bool on)
{
void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR);
@@ -325,10 +369,30 @@ static void usbotg_wakeup_event_clear(void)
#ifdef CONFIG_USB_EHCI_ARC_OTG
/* Beginning of host related operation for DR port */
-static void _host_platform_suspend(struct fsl_usb2_platform_data *pdata)
+static void _host_platform_rh_suspend(struct fsl_usb2_platform_data *pdata)
{
void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR);
u32 tmp;
+ u32 index = 0;
+
+ /* before we set and then clear PWD bit,
+ * we must wait LS to be suspend */
+ if ((UOG_PORTSC1 & (3 << 26)) != (1 << 26)) {
+ while (((UOG_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_J_STATE) &&
+ (index < 1000)) {
+ index++;
+ udelay(4);
+ }
+ } else {
+ while (((UOG_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_K_STATE) &&
+ (index < 1000)) {
+ index++;
+ udelay(4);
+ }
+ }
+
+ if (index >= 1000)
+ printk(KERN_INFO "%s big error\n", __func__);
tmp = (BM_USBPHY_PWD_TXPWDFS
| BM_USBPHY_PWD_TXPWDIBIAS
@@ -338,21 +402,30 @@ static void _host_platform_suspend(struct fsl_usb2_platform_data *pdata)
| BM_USBPHY_PWD_RXPWDDIFF
| BM_USBPHY_PWD_RXPWDRX);
__raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET);
+
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR);
+
+ fsl_platform_otg_set_usb_phy_dis(pdata, 0);
}
-static void _host_platform_resume(struct fsl_usb2_platform_data *pdata)
+static void _host_platform_rh_resume(struct fsl_usb2_platform_data *pdata)
{
- void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR);
- u32 tmp;
+ u32 index = 0;
- tmp = (BM_USBPHY_PWD_TXPWDFS
- | BM_USBPHY_PWD_TXPWDIBIAS
- | BM_USBPHY_PWD_TXPWDV2I
- | BM_USBPHY_PWD_RXPWDENV
- | BM_USBPHY_PWD_RXPWD1PT1
- | BM_USBPHY_PWD_RXPWDDIFF
- | BM_USBPHY_PWD_RXPWDRX);
- __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR);
+ if ((UOG_PORTSC1 & (3 << 26)) != (2 << 26))
+ return ;
+
+ while ((UOG_PORTSC1 & PORTSC_PORT_FORCE_RESUME)
+ && (index < 1000)) {
+ msleep(1);
+ index++;
+ }
+
+ if (index >= 1000)
+ printk(KERN_INFO "%s big error\n", __func__);
+
+ msleep(1);
+ fsl_platform_otg_set_usb_phy_dis(pdata, 1);
}
static void _host_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
@@ -487,8 +560,9 @@ void __init mx6_usb_dr_init(void)
#ifdef CONFIG_USB_EHCI_ARC_OTG
dr_utmi_config.operating_mode = DR_HOST_MODE;
dr_utmi_config.wake_up_enable = _host_wakeup_enable;
- dr_utmi_config.platform_suspend = _host_platform_suspend;
- dr_utmi_config.platform_resume = _host_platform_resume;
+ dr_utmi_config.platform_rh_suspend = _host_platform_rh_suspend;
+ dr_utmi_config.platform_rh_resume = _host_platform_rh_resume;
+ dr_utmi_config.platform_set_disconnect_det = fsl_platform_otg_set_usb_phy_dis;
dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend;
dr_utmi_config.is_wakeup_event = _is_host_wakeup;
dr_utmi_config.wakeup_pdata = &dr_wakeup_config;
@@ -499,8 +573,9 @@ void __init mx6_usb_dr_init(void)
#ifdef CONFIG_USB_GADGET_ARC
dr_utmi_config.operating_mode = DR_UDC_MODE;
dr_utmi_config.wake_up_enable = _device_wakeup_enable;
- dr_utmi_config.platform_suspend = NULL;
- dr_utmi_config.platform_resume = NULL;
+ dr_utmi_config.platform_rh_suspend = NULL;
+ dr_utmi_config.platform_rh_resume = NULL;
+ dr_utmi_config.platform_set_disconnect_det = NULL;
dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend;
dr_utmi_config.is_wakeup_event = _is_device_wakeup;
dr_utmi_config.wakeup_pdata = &dr_wakeup_config;
diff --git a/arch/arm/mach-mx6/usb_h1.c b/arch/arm/mach-mx6/usb_h1.c
index 9d2a1e758bee..8865556b8256 100644
--- a/arch/arm/mach-mx6/usb_h1.c
+++ b/arch/arm/mach-mx6/usb_h1.c
@@ -35,6 +35,51 @@ static struct clk *usb_oh3_clk;
extern int clk_get_usecount(struct clk *clk);
static struct fsl_usb2_platform_data usbh1_config;
+static void fsl_platform_h1_set_usb_phy_dis(
+ struct fsl_usb2_platform_data *pdata, bool enable)
+{
+ u32 usb_phy_ctrl_dcdt = 0;
+ void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR);
+ usb_phy_ctrl_dcdt = __raw_readl(
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL) &
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT;
+ if (enable) {
+ if (usb_phy_ctrl_dcdt == 0) {
+ __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
+ anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_CLR);
+
+ __raw_writel(BM_USBPHY_PWD_RXPWDENV,
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_SET);
+
+ udelay(300);
+
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs)
+ + HW_USBPHY_CTRL_SET);
+
+ UH1_USBSTS |= (1 << 7);
+
+ while ((UH1_USBSTS & (1 << 7)) == 0)
+ ;
+
+ udelay(2);
+
+ __raw_writel(BM_USBPHY_PWD_RXPWDENV,
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_CLR);
+
+ __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
+ anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_SET);
+
+ }
+ } else {
+ if (usb_phy_ctrl_dcdt
+ == BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs)
+ + HW_USBPHY_CTRL_CLR);
+ }
+}
+
static void usbh1_internal_phy_clock_gate(bool on)
{
void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
@@ -148,10 +193,30 @@ static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable)
}
}
-static void usbh1_platform_suspend(struct fsl_usb2_platform_data *pdata)
+static void usbh1_platform_rh_suspend(struct fsl_usb2_platform_data *pdata)
{
void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
u32 tmp;
+ u32 index = 0;
+
+ /* before we set and then clear PWD bit,
+ * we must wait LS to be J */
+ if ((UH1_PORTSC1 & (3 << 26)) != (1 << 26)) {
+ while (((UH1_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_J_STATE) &&
+ (index < 1000)) {
+ index++;
+ udelay(4);
+ }
+ } else {
+ while (((UH1_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_K_STATE) &&
+ (index < 1000)) {
+ index++;
+ udelay(4);
+ }
+ }
+
+ if (index >= 1000)
+ printk(KERN_INFO "%s big error\n", __func__);
tmp = (BM_USBPHY_PWD_TXPWDFS
| BM_USBPHY_PWD_TXPWDIBIAS
@@ -161,21 +226,30 @@ static void usbh1_platform_suspend(struct fsl_usb2_platform_data *pdata)
| BM_USBPHY_PWD_RXPWDDIFF
| BM_USBPHY_PWD_RXPWDRX);
__raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET);
+
+ __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR);
+
+ fsl_platform_h1_set_usb_phy_dis(pdata, 0);
}
-static void usbh1_platform_resume(struct fsl_usb2_platform_data *pdata)
+static void usbh1_platform_rh_resume(struct fsl_usb2_platform_data *pdata)
{
- void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR);
- u32 tmp;
+ u32 index = 0;
- tmp = (BM_USBPHY_PWD_TXPWDFS
- | BM_USBPHY_PWD_TXPWDIBIAS
- | BM_USBPHY_PWD_TXPWDV2I
- | BM_USBPHY_PWD_RXPWDENV
- | BM_USBPHY_PWD_RXPWD1PT1
- | BM_USBPHY_PWD_RXPWDDIFF
- | BM_USBPHY_PWD_RXPWDRX);
- __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR);
+ if ((UH1_PORTSC1 & (3 << 26)) != (2 << 26))
+ return ;
+
+ while ((UH1_PORTSC1 & PORTSC_PORT_FORCE_RESUME)
+ && (index < 1000)) {
+ msleep(1);
+ index++;
+ }
+
+ if (index >= 1000)
+ printk(KERN_INFO "%s big error\n", __func__);
+
+ msleep(1);
+ fsl_platform_h1_set_usb_phy_dis(pdata, 1);
}
static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable)
@@ -253,8 +327,9 @@ static struct fsl_usb2_platform_data usbh1_config = {
.power_budget = 500, /* 500 mA max power */
.wake_up_enable = _wake_up_enable,
.usb_clock_for_pm = usbh1_clock_gate,
- .platform_suspend = usbh1_platform_suspend,
- .platform_resume = usbh1_platform_resume,
+ .platform_rh_suspend = usbh1_platform_rh_suspend,
+ .platform_rh_resume = usbh1_platform_rh_resume,
+ .platform_set_disconnect_det = fsl_platform_h1_set_usb_phy_dis,
.phy_lowpower_suspend = _phy_lowpower_suspend,
.is_wakeup_event = _is_usbh1_wakeup,
.wakeup_handler = h1_wakeup_handler,
diff --git a/arch/arm/plat-mxc/usb_common.c b/arch/arm/plat-mxc/usb_common.c
index bb9c45a0127e..a4a3721246f8 100755
--- a/arch/arm/plat-mxc/usb_common.c
+++ b/arch/arm/plat-mxc/usb_common.c
@@ -900,16 +900,25 @@ EXPORT_SYMBOL(usb_event_is_otg_wakeup);
void fsl_platform_set_usb_phy_dis(struct fsl_usb2_platform_data *pdata,
bool enable)
{
+ u32 usb_phy_ctrl_dcdt = 0;
/* for HSIC, we do not need to enable disconnect detection */
if (pdata->phy_mode == FSL_USB2_PHY_HSIC)
return;
-
- if (enable)
- __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
- MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_SET);
- else
- __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
- MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL_CLR);
+ usb_phy_ctrl_dcdt = __raw_readl(
+ MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL) &
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT;
+ if (enable) {
+ if (usb_phy_ctrl_dcdt == 0)
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs)
+ + HW_USBPHY_CTRL_SET);
+ } else {
+ if (usb_phy_ctrl_dcdt
+ == BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
+ __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ MX6_IO_ADDRESS(pdata->phy_regs)
+ + HW_USBPHY_CTRL_CLR);
+ }
}
EXPORT_SYMBOL(fsl_platform_set_usb_phy_dis);
#endif