[RAMEN9610-19639][COMMON] usb: add DCTL run/stop when enumeration fail.
authorSEO HOYOUNG <hy50.seo@samsung.com>
Mon, 13 May 2019 10:44:06 +0000 (19:44 +0900)
committerKim Gunho <gunho.kim@samsung.com>
Mon, 9 Sep 2019 11:10:01 +0000 (20:10 +0900)
Change-Id: I0da546bc9c2053c3f5e8f2867022577919c3c74f
Signed-off-by: SEO HOYOUNG <hy50.seo@samsung.com>
drivers/usb/dwc3/core.h
drivers/usb/dwc3/otg.c

index 45f8ef08aab54e6bbb5518fc605716964245928c..f1383b1e66a750f70a57d2b0b2c71df73920e4c8 100644 (file)
@@ -823,6 +823,8 @@ struct dwc3_scratchpad_array {
        __le64  dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
 };
 
+#define        CHG_CONNECTED_DELAY_TIME        (10000*HZ/1000) /* 10s */
+
 /**
  * struct dwc3 - representation of our controller
  * @drd_work: workqueue used for role swapping
@@ -950,6 +952,9 @@ struct dwc3 {
        struct dwc3_request     ep0_usb_req;
        struct completion       ep0_in_setup;
 
+       /* check device state */
+       struct timer_list       usb_connect_timer;
+
        /* device lock */
        spinlock_t              lock;
 
index 2f756a5f2b1d0921d2509b3ce689807c1862d5e9..d041318087504af2e3c3bef48a35ea56034aaf95 100755 (executable)
@@ -25,6 +25,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/usb/samsung_usb.h>
 #include <linux/mfd/samsung/s2mps18-private.h>
+#include <linux/usb/composite.h>
 #ifdef CONFIG_EXYNOS_PD
 #include <soc/samsung/exynos-pm.h>
 #endif
@@ -320,6 +321,54 @@ err1:
        return ret;
 }
 
+static void retry_configuration(unsigned long data)
+{
+       struct dwc3 *dwc = (struct dwc3 *)data;
+       struct usb_gadget       *gadget = &dwc->gadget;
+       struct usb_composite_dev *cdev = get_gadget_data(gadget);
+       u32             reg;
+
+       pr_info("%s: +++\n", __func__);
+
+       if (!cdev->config) {
+
+               if (dwc->dr_mode == USB_DR_MODE_HOST)
+                       return;
+
+               pr_info("%s: retry USB enumeration\n", __func__);
+
+               /* stop */
+               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+               reg &= ~DWC3_DCTL_RUN_STOP;
+
+               if (dwc->has_hibernation)
+                       reg &= ~DWC3_DCTL_KEEP_CONNECT;
+
+               dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+               mdelay(500);
+
+               /* run */
+               if (dwc->revision <= DWC3_REVISION_187A) {
+                       reg &= ~DWC3_DCTL_TRGTULST_MASK;
+                       reg |= DWC3_DCTL_TRGTULST_RX_DET;
+               }
+
+               if (dwc->revision >= DWC3_REVISION_194A)
+                       reg &= ~DWC3_DCTL_KEEP_CONNECT;
+
+               reg |= DWC3_DCTL_RUN_STOP;
+
+               if (dwc->has_hibernation)
+                       reg |= DWC3_DCTL_KEEP_CONNECT;
+
+               dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+       } else {
+               pr_info("%s: already configuration done!!\n", __func__);
+       }
+       pr_info("%s: ---\n", __func__);
+}
+
 static int dwc3_otg_start_gadget(struct otg_fsm *fsm, int on)
 {
        struct usb_otg  *otg = fsm->otg;
@@ -363,7 +412,17 @@ static int dwc3_otg_start_gadget(struct otg_fsm *fsm, int on)
                        goto err2;
                }
 
+               pr_info("%s: start check usb configuration timer\n", __func__);
+               init_timer(&dwc->usb_connect_timer);
+               dwc->usb_connect_timer.expires = jiffies + CHG_CONNECTED_DELAY_TIME;
+               dwc->usb_connect_timer.function = retry_configuration;
+               dwc->usb_connect_timer.data = (unsigned long)dwc;
+               add_timer(&dwc->usb_connect_timer);
+
+
        } else {
+               del_timer_sync(&dwc->usb_connect_timer);
+
                if (dwc->is_not_vbus_pad)
                        dwc3_gadget_disconnect_proc(dwc);
                /* avoid missing disconnect interrupt */