usb: dwc-otg: using delayed-work to detect id change event instead of id_change intrrupt
authorlyz <lyz@rock-chips.com>
Thu, 20 Nov 2014 11:09:04 +0000 (19:09 +0800)
committerlyz <lyz@rock-chips.com>
Thu, 20 Nov 2014 12:23:56 +0000 (20:23 +0800)
drivers/usb/dwc_otg_310/dwc_otg_cil_intr.c
drivers/usb/dwc_otg_310/dwc_otg_hcd_linux.c
drivers/usb/dwc_otg_310/dwc_otg_pcd.h
drivers/usb/dwc_otg_310/dwc_otg_pcd_linux.c

index 199765d6abecfd5ed60de675450bac1741d3b82f..78bf20d2a1af52da0d857505e28ca5d2b7f7f716 100755 (executable)
@@ -405,8 +405,8 @@ int32_t dwc_otg_handle_conn_id_status_change_intr(dwc_otg_core_if_t *core_if)
         * Release lock before scheduling workq as it holds spinlock during scheduling
         */
 
-       DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
-                          core_if, "connection id status change");
+       /*DWC_WORKQ_SCHEDULE(core_if->wq_otg, w_conn_id_status_change,
+                          core_if, "connection id status change");*/
        DWC_SPINLOCK(core_if->lock);
 out:
        /* Set flag and clear interrupt */
index 43527f8763ceddd2680201203f9e1b1652c7030a..b726c90baf3c238d7e9ff36e77938979f3684012 100755 (executable)
@@ -532,7 +532,7 @@ int otg20_hcd_init(struct platform_device *_dev)
            (otg_dev->core_if->usb_mode == USB_MODE_FORCE_HOST)) {
                INIT_DELAYED_WORK(&dwc_otg_hcd->host_enable_work,
                                  otg20_hcd_connect_detect);
-               schedule_delayed_work(&dwc_otg_hcd->host_enable_work, HZ >> 2);
+               schedule_delayed_work(&dwc_otg_hcd->host_enable_work, 0);
        }
        return 0;
 
index 0618692b8a6029fae8c2506986972bbbc93324ce..1c29390372f1be56dec3780263fb40bd373e1cb6 100755 (executable)
@@ -262,6 +262,7 @@ struct dwc_otg_pcd {
        /* otg check vbus work and connect work,used for power management */
        struct delayed_work reconnect;
        struct delayed_work check_vbus_work;
+       struct delayed_work check_id_work;
        /** pervent device suspend while usb connected */
        struct wake_lock wake_lock;
 
index d4db1e73930f131ebd6209369eb597b457b72a67..5d99badf5d5d7c6557f0beb9677d81db4f006018 100755 (executable)
@@ -1502,6 +1502,101 @@ static void dwc_phy_reconnect(struct work_struct *work)
        }
 }
 
+void id_status_change(dwc_otg_core_if_t *p, bool current_id)
+{
+       dwc_otg_core_if_t *core_if = p;
+       uint32_t count = 0;
+       gotgctl_data_t gotgctl = {.d32 = 0 };
+       dwc_otg_pcd_t *pcd = core_if->otg_dev->pcd;
+
+       gotgctl.d32 = DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+       DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
+       DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
+
+       if( core_if->usb_mode != USB_MODE_NORMAL )
+               return;
+
+       /* B-Device connector (Device Mode) */
+       if (current_id) {
+               gotgctl_data_t gotgctl_local;
+               /* Wait for switch to device mode. */
+               while (!dwc_otg_is_device_mode(core_if)) {
+                       gotgctl_local.d32 =
+                           DWC_READ_REG32(&core_if->core_global_regs->gotgctl);
+                       DWC_DEBUGPL(DBG_ANY,
+                                   "Waiting for Peripheral Mode, Mode=%s count = %d gotgctl=%08x\n",
+                                   (dwc_otg_is_host_mode(core_if) ? "Host" :
+                                    "Peripheral"), count, gotgctl_local.d32);
+                       dwc_mdelay(1);
+                       if (++count > 200)
+                               break;
+               }
+               if (count >= 200) {
+                       DWC_PRINTF("Connection id status change timed out");
+                       return;
+               }
+               core_if->op_state = B_PERIPHERAL;
+               cil_hcd_stop(core_if);
+               /* pcd->phy_suspend = 1; */
+               pcd->vbus_status = 0;
+               dwc_otg_core_init(core_if);
+               cil_pcd_start(core_if);
+               dwc_otg_pcd_start_check_vbus_work(pcd);
+       } else {
+               /* A-Device connector (Host Mode) */
+               while (!dwc_otg_is_host_mode(core_if)) {
+                       DWC_DEBUGPL(DBG_ANY, "Waiting for Host Mode, Mode=%s\n",
+                                   (dwc_otg_is_host_mode(core_if) ? "Host" :
+                                    "Peripheral"));
+                       dwc_mdelay(1);  /* vahrama previously was 100 */
+                       if (++count > 200)
+                               break;
+               }
+               if (count >= 200) {
+                       DWC_PRINTF("Connection id status change timed out");
+                       return;
+               }
+
+               core_if->op_state = A_HOST;
+
+               cancel_delayed_work(&pcd->check_vbus_work);
+
+               /*
+                * Initialize the Core for Host mode.
+                */
+               dwc_otg_core_init(core_if);
+               cil_hcd_start(core_if);
+               dwc_otg_enable_global_interrupts(core_if);
+       }
+}
+
+
+static void check_id(struct work_struct *work)
+{
+       dwc_otg_pcd_t *_pcd =
+           container_of(work, dwc_otg_pcd_t, check_id_work.work);
+       struct dwc_otg_device *otg_dev = _pcd->otg_dev;
+       struct dwc_otg_platform_data *pldata = otg_dev->pldata;
+       static int last_id = -1;
+       int id = pldata->get_status(USB_STATUS_ID);
+
+       if((last_id != id)) {
+               printk("[otg id chg] last id %d current id %d \n", last_id, id);
+               if (!id) { /* Force Host */
+                       if (pldata->phy_status == USB_PHY_SUSPEND) {
+                               pldata->clock_enable(pldata, 1);
+                               pldata->phy_suspend(pldata, USB_PHY_ENABLED);
+       }
+                       id_status_change(otg_dev->core_if, id);
+               } else { /* Force Device */
+                       id_status_change(otg_dev->core_if, id);
+               }
+       }
+       last_id = id;
+       schedule_delayed_work(&_pcd->check_id_work, (HZ));
+       return;
+}
+
 static void dwc_otg_pcd_check_vbus_work(struct work_struct *work)
 {
        dwc_otg_pcd_t *_pcd =
@@ -1509,24 +1604,7 @@ static void dwc_otg_pcd_check_vbus_work(struct work_struct *work)
        struct dwc_otg_device *otg_dev = _pcd->otg_dev;
        struct dwc_otg_platform_data *pldata = otg_dev->pldata;
 
-       if (!pldata->get_status(USB_STATUS_ID)) {
-               /* id low, host mode */
-               if (pldata->dwc_otg_uart_mode != NULL) {
-                       /* exit phy bypass to uart & enable usb phy */
-                       pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE);
-               }
-               if (pldata->phy_status) {
-                       pldata->clock_enable(pldata, 1);
-                       pldata->phy_suspend(pldata, USB_PHY_ENABLED);
-               }
-               if (pldata->bc_detect_cb != NULL)
-                       pldata->bc_detect_cb(_pcd->vbus_status =
-                                            USB_BC_TYPE_DISCNT);
-               else
-                       _pcd->vbus_status = USB_BC_TYPE_DISCNT;
-               dwc_otg_enable_global_interrupts(otg_dev->core_if);
-
-       } else if (pldata->get_status(USB_STATUS_BVABLID)) {
+       if (pldata->get_status(USB_STATUS_BVABLID)) {
                /* if usb not connect before ,then start connect */
                if (_pcd->vbus_status == USB_BC_TYPE_DISCNT) {
                        printk("***************vbus detect*****************\n");
@@ -1604,8 +1682,7 @@ connect:
                dwc_otg_msc_lock(_pcd);
 
        schedule_delayed_work(&_pcd->reconnect, 8);     /* delay 8 jiffies */
-       schedule_delayed_work(&_pcd->check_vbus_work, (HZ << 2));
-
+       schedule_delayed_work(&_pcd->check_vbus_work, (HZ));
        return;
 }
 
@@ -1615,7 +1692,8 @@ void dwc_otg_pcd_start_check_vbus_work(dwc_otg_pcd_t *pcd)
         * when receive reset int,the vbus state may not be update,so
         * always start vbus work here.
         */
-       schedule_delayed_work(&pcd->check_vbus_work, (HZ * 2));
+       schedule_delayed_work(&pcd->check_vbus_work, HZ/2);
+
 }
 
 /*
@@ -1652,6 +1730,7 @@ static void dwc_otg_pcd_work_init(dwc_otg_pcd_t *pcd,
 
        INIT_DELAYED_WORK(&pcd->reconnect, dwc_phy_reconnect);
        INIT_DELAYED_WORK(&pcd->check_vbus_work, dwc_otg_pcd_check_vbus_work);
+       INIT_DELAYED_WORK(&pcd->check_id_work, check_id);
 
        wake_lock_init(&pcd->wake_lock, WAKE_LOCK_SUSPEND, "usb_pcd");
 
@@ -1664,12 +1743,12 @@ static void dwc_otg_pcd_work_init(dwc_otg_pcd_t *pcd,
                        /* usb phy bypass to uart mode */
                        pldata->dwc_otg_uart_mode(pldata, PHY_UART_MODE);
                }
-               schedule_delayed_work(&pcd->check_vbus_work, (HZ << 3));
        }
-       else if (pldata->dwc_otg_uart_mode != NULL)
+       else if (pldata->dwc_otg_uart_mode != NULL) {
                /* host mode,enter usb phy mode */
                pldata->dwc_otg_uart_mode(pldata, PHY_USB_MODE);
-
+       }
+       schedule_delayed_work(&pcd->check_id_work, msecs_to_jiffies(HZ));
 }
 
 #endif /* DWC_HOST_ONLY */