]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00176299-1 usb host suspend/resume can't work randomly
authorTony LIU <junjie.liu@freescale.com>
Wed, 7 Mar 2012 07:53:56 +0000 (15:53 +0800)
committerOliver Wendt <ow@karo-electronics.de>
Mon, 30 Sep 2013 12:11:16 +0000 (14:11 +0200)
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>
arch/arm/mach-mx6/usb_dr.c
arch/arm/mach-mx6/usb_h1.c
arch/arm/plat-mxc/usb_common.c

index f49bb1096eedcd73b7722db2298250486af2f04f..96922a200b822fe77de8a0d9d2e058851c466aea 100644 (file)
@@ -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;
index 9d2a1e758bee39a1a4aeb227b22f7bfdb688ab7b..8865556b8256275b6b1789be3541db37d3bd0f72 100644 (file)
@@ -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,
index bb9c45a0127e3f8adc9864b2043197bf17e5047f..a4a3721246f8f8e1df9a485b03cae6d66a8d7ec8 100755 (executable)
@@ -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