diff options
author | Tony LIU <junjie.liu@freescale.com> | 2012-03-07 15:53:56 +0800 |
---|---|---|
committer | Tony LIU <junjie.liu@freescale.com> | 2012-03-21 09:59:53 +0800 |
commit | 69d533be68e085039d0561f469dbd7c3c3a259b5 (patch) | |
tree | 6f4740ca1a814db88e0f32c44f9efd272549d033 /arch | |
parent | 0389030201f91bff05c3f28a2feb2605d558f9a8 (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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-mx6/usb_dr.c | 109 | ||||
-rw-r--r-- | arch/arm/mach-mx6/usb_h1.c | 103 | ||||
-rwxr-xr-x | arch/arm/plat-mxc/usb_common.c | 23 |
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 |