These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / usb / chipidea / otg.c
index ad6c87a..03b6743 100644 (file)
  */
 u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
 {
-       return hw_read(ci, OP_OTGSC, mask);
+       struct ci_hdrc_cable *cable;
+       u32 val = hw_read(ci, OP_OTGSC, mask);
+
+       /*
+        * If using extcon framework for VBUS and/or ID signal
+        * detection overwrite OTGSC register value
+        */
+       cable = &ci->platdata->vbus_extcon;
+       if (!IS_ERR(cable->edev)) {
+               if (cable->changed)
+                       val |= OTGSC_BSVIS;
+               else
+                       val &= ~OTGSC_BSVIS;
+
+               cable->changed = false;
+
+               if (cable->state)
+                       val |= OTGSC_BSV;
+               else
+                       val &= ~OTGSC_BSV;
+       }
+
+       cable = &ci->platdata->id_extcon;
+       if (!IS_ERR(cable->edev)) {
+               if (cable->changed)
+                       val |= OTGSC_IDIS;
+               else
+                       val &= ~OTGSC_IDIS;
+
+               cable->changed = false;
+
+               if (cable->state)
+                       val |= OTGSC_ID;
+               else
+                       val &= ~OTGSC_ID;
+       }
+
+       return val;
 }
 
 /**
@@ -77,9 +114,12 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
                        ci_role(ci)->name, ci->roles[role]->name);
 
                ci_role_stop(ci);
-               /* wait vbus lower than OTGSC_BSV */
-               hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
-                               CI_VBUS_STABLE_TIMEOUT_MS);
+
+               if (role == CI_ROLE_GADGET)
+                       /* wait vbus lower than OTGSC_BSV */
+                       hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
+                                       CI_VBUS_STABLE_TIMEOUT_MS);
+
                ci_role_start(ci, role);
        }
 }
@@ -118,7 +158,7 @@ static void ci_otg_work(struct work_struct *work)
 int ci_hdrc_otg_init(struct ci_hdrc *ci)
 {
        INIT_WORK(&ci->work, ci_otg_work);
-       ci->wq = create_singlethread_workqueue("ci_otg");
+       ci->wq = create_freezable_workqueue("ci_otg");
        if (!ci->wq) {
                dev_err(ci->dev, "can't create workqueue\n");
                return -ENODEV;