static void non_standard_charger_detect_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct dwc3_otg *dotg = container_of(dwork, struct dwc3_otg, non_standard_charger_work); struct usb_phy *phy = dotg->otg.phy; if(non_standard == true) { pr_info("%s DWC3_FLOATED_CHARGER\n", __func__); dotg->charger->chg_type = DWC3_FLOATED_CHARGER; dwc3_otg_set_power(phy, DWC3_IDEV_CHG_FLOATED); } }
/** * dwc3_otg_sm_work - workqueue function. * * @w: Pointer to the dwc3 otg workqueue * * NOTE: After any change in phy->state, * we must reschdule the state machine. */ static void dwc3_otg_sm_work(struct work_struct *w) { struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work); struct usb_phy *phy = dotg->otg.phy; struct dwc3_charger *charger = dotg->charger; bool work = 0; int ret = 0; unsigned long delay = 0; pm_runtime_resume(phy->dev); dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state)); /* Check OTG state */ switch (phy->state) { case OTG_STATE_UNDEFINED: dwc3_otg_init_sm(dotg); if (!dotg->psy) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) dev_err(phy->dev, "couldn't get usb power supply\n"); } /* Switch to A or B-Device according to ID / BSV */ if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); phy->state = OTG_STATE_B_IDLE; work = 1; } else { phy->state = OTG_STATE_B_IDLE; dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_IDLE: if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; dotg->charger_retry_count = 0; if (charger) { if (charger->chg_type == DWC3_INVALID_CHARGER) charger->start_detection(dotg->charger, false); else charger->chg_type = DWC3_INVALID_CHARGER; } } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); if (charger) { /* Has charger been detected? If no detect it */ switch (charger->chg_type) { case DWC3_DCP_CHARGER: case DWC3_PROPRIETARY_CHARGER: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); pm_runtime_put_sync(phy->dev); break; case DWC3_CDP_CHARGER: dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; case DWC3_SDP_CHARGER: dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; case DWC3_FLOATED_CHARGER: #ifdef CONFIG_ZTEMT_COMM_CHARGE dev_dbg(phy->dev, "lpm, FLOATED charger\n"); dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); pm_runtime_put_sync(phy->dev); #else if (dotg->charger_retry_count < max_chgr_retry_count) dotg->charger_retry_count++; /* * In case of floating charger, if * retry count equal to max retry count * notify PMIC about floating charger * and put Hw in low power mode. Else * perform charger detection again by * calling start_detection() with false * and then with true argument. */ if (dotg->charger_retry_count == max_chgr_retry_count) { dwc3_otg_set_power(phy, 0); pm_runtime_put_sync(phy->dev); break; } charger->start_detection(dotg->charger, false); #endif default: dev_dbg(phy->dev, "chg_det started\n"); charger->start_detection(charger, true); break; } } else { /* no charger registered, start peripheral */ if (dwc3_otg_start_peripheral(&dotg->otg, 1)) { /* * Probably set_peripheral not called * yet. We will re-try as soon as it * will be called */ dev_err(phy->dev, "enter lpm as\n" "unable to start B-device\n"); phy->state = OTG_STATE_UNDEFINED; pm_runtime_put_sync(phy->dev); return; } } } else { if (charger) charger->start_detection(dotg->charger, false); dotg->charger_retry_count = 0; dwc3_otg_set_power(phy, 0); dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_PERIPHERAL: if (!test_bit(B_SESS_VLD, &dotg->inputs) || !test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id || !bsv\n"); dwc3_otg_start_peripheral(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; if (charger) charger->chg_type = DWC3_INVALID_CHARGER; work = 1; } break; case OTG_STATE_A_IDLE: /* Switch to A-Device*/ if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; } else { phy->state = OTG_STATE_A_HOST; ret = dwc3_otg_start_host(&dotg->otg, 1); if ((ret == -EPROBE_DEFER) && dotg->vbus_retry_count < 3) { /* * Get regulator failed as regulator driver is * not up yet. Will try to start host after 1sec */ phy->state = OTG_STATE_A_IDLE; dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n"); delay = VBUS_REG_CHECK_DELAY; work = 1; dotg->vbus_retry_count++; } else if (ret) { /* * Probably set_host was not called yet. * We will re-try as soon as it will be called */ dev_dbg(phy->dev, "enter lpm as\n" "unable to start A-device\n"); phy->state = OTG_STATE_A_IDLE; pm_runtime_put_sync(phy->dev); return; } } break; case OTG_STATE_A_HOST: if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); dwc3_otg_start_host(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; } break; default: dev_err(phy->dev, "%s: invalid otg-state\n", __func__); } if (work) queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay); }
/** * dwc3_otg_sm_work - workqueue function. * * @w: Pointer to the dwc3 otg workqueue * * NOTE: After any change in phy->state, * we must reschdule the state machine. */ static void dwc3_otg_sm_work(struct work_struct *w) { struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work); struct usb_phy *phy = dotg->otg.phy; struct dwc3_charger *charger = dotg->charger; bool work = 0; int ret = 0; unsigned long delay = 0; pm_runtime_resume(phy->dev); dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state)); /* Check OTG state */ switch (phy->state) { case OTG_STATE_UNDEFINED: dwc3_otg_init_sm(dotg); if (!dotg->psy) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) dev_err(phy->dev, "couldn't get usb power supply\n"); } /* Switch to A or B-Device according to ID / BSV */ if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); phy->state = OTG_STATE_B_IDLE; work = 1; } else { phy->state = OTG_STATE_B_IDLE; dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_IDLE: if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; dotg->charger_retry_count = 0; if (charger) { if (charger->chg_type == DWC3_INVALID_CHARGER) charger->start_detection(dotg->charger, false); else charger->chg_type = DWC3_INVALID_CHARGER; } } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); if (charger) { /* Has charger been detected? If no detect it */ switch (charger->chg_type) { case DWC3_DCP_CHARGER: case DWC3_PROPRIETARY_CHARGER: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); pm_runtime_put_sync(phy->dev); break; case DWC3_CDP_CHARGER: dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; case DWC3_SDP_CHARGER: dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; pr_info("DWC3_SDP_CHARGER\n"); work = 1; break; case DWC3_FLOATED_CHARGER: if (dotg->charger_retry_count < max_chgr_retry_count) dotg->charger_retry_count++; /* * In case of floating charger, if * retry count equal to max retry count * notify PMIC about floating charger * and put Hw in low power mode. Else * perform charger detection again by * calling start_detection() with false * and then with true argument. */ if (dotg->charger_retry_count == max_chgr_retry_count) { dwc3_otg_set_power(phy, 0); pm_runtime_put_sync(phy->dev); break; } charger->start_detection(dotg->charger, false); default: dev_dbg(phy->dev, "chg_det started\n"); charger->start_detection(charger, true); break; } } else { /* no charger registered, start peripheral */ if (dwc3_otg_start_peripheral(&dotg->otg, 1)) { /* * Probably set_peripheral not called * yet. We will re-try as soon as it * will be called */ dev_err(phy->dev, "enter lpm as\n" "unable to start B-device\n"); phy->state = OTG_STATE_UNDEFINED; pm_runtime_put_sync(phy->dev); return; } } } else { if (charger) charger->start_detection(dotg->charger, false); dotg->charger_retry_count = 0; dwc3_otg_set_power(phy, 0); dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_PERIPHERAL: #ifdef CONFIG_PANTECH_USB_BLOCKING_MDMSTATE if (get_pantech_mdm_state()) dwc3_otg_set_power(phy, DWC3_BLOCKING_USB_MDMSTATE_MAX); #endif #ifndef CONFIG_PANTECH_SIO_BUG_FIX if (!test_bit(B_SESS_VLD, &dotg->inputs) || !test_bit(ID, &dotg->inputs)) { #else if (!test_bit(B_SESS_VLD, &dotg->inputs)) { #endif dev_dbg(phy->dev, "!id || !bsv\n"); dwc3_otg_start_peripheral(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; if (charger) charger->chg_type = DWC3_INVALID_CHARGER; work = 1; } break; case OTG_STATE_A_IDLE: /* Switch to A-Device*/ if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; } else { phy->state = OTG_STATE_A_HOST; ret = dwc3_otg_start_host(&dotg->otg, 1); if ((ret == -EPROBE_DEFER) && dotg->vbus_retry_count < 3) { /* * Get regulator failed as regulator driver is * not up yet. Will try to start host after 1sec */ phy->state = OTG_STATE_A_IDLE; dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n"); delay = VBUS_REG_CHECK_DELAY; work = 1; dotg->vbus_retry_count++; } else if (ret) { /* * Probably set_host was not called yet. * We will re-try as soon as it will be called */ dev_dbg(phy->dev, "enter lpm as\n" "unable to start A-device\n"); phy->state = OTG_STATE_A_IDLE; pm_runtime_put_sync(phy->dev); return; } } break; case OTG_STATE_A_HOST: if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); #ifdef CONFIG_PANTECH_SIO_BUG_FIX /* FIXME : If OTG cable is disconnecting, below process is must completed * before pm_runtime_suspend. * So we are ignored pm_runtime_suspend request. * LS4-USB tarial */ pm_runtime_get_noresume(phy->dev); #endif dwc3_otg_start_host(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; #ifdef CONFIG_PANTECH_SIO_BUG_FIX pm_runtime_put_noidle(phy->dev); #endif } break; default: dev_err(phy->dev, "%s: invalid otg-state\n", __func__); } if (work) queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay); } /** * dwc3_otg_reset - reset dwc3 otg registers. * * @w: Pointer to the dwc3 otg workqueue */ static void dwc3_otg_reset(struct dwc3_otg *dotg) { static int once; struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv; /* * OCFG[2] - OTG-Version = 1 * OCFG[1] - HNPCap = 0 * OCFG[0] - SRPCap = 0 */ if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_writel(dotg->regs, DWC3_OCFG, 0x4); /* * OCTL[6] - PeriMode = 1 * OCTL[5] - PrtPwrCtl = 0 * OCTL[4] - HNPReq = 0 * OCTL[3] - SesReq = 0 * OCTL[2] - TermSelDLPulse = 0 * OCTL[1] - DevSetHNPEn = 0 * OCTL[0] - HstSetHNPEn = 0 */ if (!once) { if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_writel(dotg->regs, DWC3_OCTL, 0x40); once++; } /* Clear all otg events (interrupts) indications */ dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF); /* Enable ID/BSV StsChngEn event*/ if (ext_xceiv && !ext_xceiv->otg_capability) dwc3_writel(dotg->regs, DWC3_OEVTEN, DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT); } /** * dwc3_otg_init - Initializes otg related registers * @dwc: Pointer to out controller context structure * * Returns 0 on success otherwise negative errno. */ int dwc3_otg_init(struct dwc3 *dwc) { u32 reg; int ret = 0; struct dwc3_otg *dotg; dev_dbg(dwc->dev, "dwc3_otg_init\n"); /* * GHWPARAMS6[10] bit is SRPSupport. * This bit also reflects DWC_USB3_EN_OTG */ reg = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); if (!(reg & DWC3_GHWPARAMS6_SRP_SUPPORT)) { /* * No OTG support in the HW core. * We return 0 to indicate no error, since this is acceptable * situation, just continue probe the dwc3 driver without otg. */ dev_dbg(dwc->dev, "dwc3_otg address space is not supported\n"); return 0; } /* Allocate and init otg instance */ dotg = kzalloc(sizeof(struct dwc3_otg), GFP_KERNEL); if (!dotg) { dev_err(dwc->dev, "unable to allocate dwc3_otg\n"); return -ENOMEM; } /* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */ dotg->irq = platform_get_irq_byname(to_platform_device(dwc->dev), "otg_irq"); if (dotg->irq < 0) { dev_err(dwc->dev, "%s: missing OTG IRQ\n", __func__); ret = -ENODEV; goto err1; } dotg->regs = dwc->regs; dotg->otg.set_peripheral = dwc3_otg_set_peripheral; dotg->otg.set_host = dwc3_otg_set_host; /* This reference is used by dwc3 modules for checking otg existance */ dwc->dotg = dotg; dotg->otg.phy = kzalloc(sizeof(struct usb_phy), GFP_KERNEL); if (!dotg->otg.phy) { dev_err(dwc->dev, "unable to allocate dwc3_otg.phy\n"); ret = -ENOMEM; goto err1; } dotg->dwc = dwc; dotg->otg.phy->otg = &dotg->otg; dotg->otg.phy->dev = dwc->dev; dotg->otg.phy->set_power = dwc3_otg_set_power; dotg->otg.phy->set_suspend = dwc3_otg_set_suspend; ret = usb_set_transceiver(dotg->otg.phy); if (ret) { dev_err(dotg->otg.phy->dev, "%s: failed to set transceiver, already exists\n", __func__); goto err2; } dotg->otg.phy->state = OTG_STATE_UNDEFINED; init_completion(&dotg->dwc3_xcvr_vbus_init); INIT_DELAYED_WORK(&dotg->sm_work, dwc3_otg_sm_work); ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED, "dwc3_otg", dotg); if (ret) { dev_err(dotg->otg.phy->dev, "failed to request irq #%d --> %d\n", dotg->irq, ret); goto err3; } pm_runtime_get(dwc->dev); return 0; err3: cancel_delayed_work_sync(&dotg->sm_work); usb_set_transceiver(NULL); err2: kfree(dotg->otg.phy); err1: dwc->dotg = NULL; kfree(dotg); return ret; }
/** * dwc3_otg_sm_work - workqueue function. * * @w: Pointer to the dwc3 otg workqueue * * NOTE: After any change in phy->state, * we must reschdule the state machine. */ static void dwc3_otg_sm_work(struct work_struct *w) { struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work); struct usb_phy *phy = dotg->otg.phy; struct dwc3_charger *charger = dotg->charger; bool work = 0; int ret = 0; unsigned long delay = 0; pm_runtime_resume(phy->dev); dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state)); /* Check OTG state */ switch (phy->state) { case OTG_STATE_UNDEFINED: dwc3_otg_init_sm(dotg); if (!dotg->psy) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) dev_err(phy->dev, "couldn't get usb power supply\n"); } /* Switch to A or B-Device according to ID / BSV */ if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); phy->state = OTG_STATE_B_IDLE; work = 1; } else { phy->state = OTG_STATE_B_IDLE; dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_IDLE: if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; dotg->charger_retry_count = 0; if (charger) { if (charger->chg_type == DWC3_INVALID_CHARGER) charger->start_detection(dotg->charger, false); else charger->chg_type = DWC3_INVALID_CHARGER; } } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); if (charger) { /* Has charger been detected? If no detect it */ switch (charger->chg_type) { case DWC3_DCP_CHARGER: case DWC3_PROPRIETARY_CHARGER: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); pm_runtime_put_sync(phy->dev); break; case DWC3_CDP_CHARGER: dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; case DWC3_SDP_CHARGER: dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; /* OPPO 2013-10-05 wangjc Add begin for support non-standard charger, HW_VERSION__12 is dvt */ #ifdef CONFIG_MACH_MSM8974_14001 #if defined(CONFIG_OPPO_DEVICE_FIND7) || defined(CONFIG_OPPO_DEVICE_FIND7WX) if(get_pcb_version() < HW_VERSION__12) { cancel_delayed_work_sync(&dotg->non_standard_charger_work); non_standard = true; schedule_delayed_work(&dotg->non_standard_charger_work, round_jiffies_relative(msecs_to_jiffies (5000))); } else { /* [email protected], 2014/01/23 Add for notify usb online earlier */ power_supply_set_online(dotg->psy, true); power_supply_changed(dotg->psy); } #else power_supply_set_online(dotg->psy, true); power_supply_changed(dotg->psy); #endif #endif /* OPPO 2013-10-05 wangjc Add end */ break; case DWC3_FLOATED_CHARGER: /* OPPO 2013-10-05 wangjc Modify begin for support non-standard charger */ #ifndef CONFIG_MACH_MSM8974_14001 if (dotg->charger_retry_count < max_chgr_retry_count) dotg->charger_retry_count++; /* * In case of floating charger, if * retry count equal to max retry count * notify PMIC about floating charger * and put Hw in low power mode. Else * perform charger detection again by * calling start_detection() with false * and then with true argument. */ if (dotg->charger_retry_count == max_chgr_retry_count) { dwc3_otg_set_power(phy, 0); pm_runtime_put_sync(phy->dev); break; } charger->start_detection(dotg->charger, false); #else dev_dbg(phy->dev, "lpm, FLOATED charger\n"); dwc3_otg_set_power(phy, DWC3_IDEV_CHG_FLOATED); pm_runtime_put_sync(phy->dev); break; #endif /* OPPO 2013-10-05 wangjc Modify end */ default: dev_dbg(phy->dev, "chg_det started\n"); /* OPPO 2013-11-18 wangjc Modify begin for detect charger type later */ #ifndef CONFIG_MACH_MSM8974_14001 charger->start_detection(charger, true); #else /* [email protected], 2014/02/24 Add for solve usb reboot problem */ cancel_delayed_work_sync(&dotg->detect_work); /* [email protected], 2014/03/25 Add for solve usb reboot problem,bug 422328 */ if (charger) charger->start_detection(dotg->charger, false); dotg->charger_retry_count = 0; dwc3_otg_set_power(phy, 0); queue_delayed_work(system_nrt_wq, &dotg->detect_work, msecs_to_jiffies(600)); #endif /* OPPO 2013-11-18 wangjc Modify end */ break; } } else { /* no charger registered, start peripheral */ if (dwc3_otg_start_peripheral(&dotg->otg, 1)) { /* * Probably set_peripheral not called * yet. We will re-try as soon as it * will be called */ dev_err(phy->dev, "enter lpm as\n" "unable to start B-device\n"); phy->state = OTG_STATE_UNDEFINED; pm_runtime_put_sync(phy->dev); return; } } } else { /* OPPO 2013-12-01 wangjc Add begin for for non standard charger detect, HW_VERSION__12 is dvt */ #ifdef CONFIG_MACH_MSM8974_14001 //#ifdef CONFIG_OPPO_DEVICE_FIND7 #if defined(CONFIG_OPPO_DEVICE_FIND7) || defined(CONFIG_OPPO_DEVICE_FIND7WX) if(get_pcb_version() < HW_VERSION__12) { cancel_delayed_work_sync(&dotg->non_standard_charger_work); } #endif #endif /* OPPO 2013-12-01 wangjc Add end */ #ifdef CONFIG_MACH_MSM8974_14001 /* [email protected], 2014/01/06 Add for solve usb reboot problem */ cancel_delayed_work_sync(&dotg->detect_work); #endif /*CONFIG_MACH_MSM8974_14001*/ if (charger) charger->start_detection(dotg->charger, false); dotg->charger_retry_count = 0; dwc3_otg_set_power(phy, 0); dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_PERIPHERAL: if (!test_bit(B_SESS_VLD, &dotg->inputs) || !test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id || !bsv\n"); dwc3_otg_start_peripheral(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; if (charger) charger->chg_type = DWC3_INVALID_CHARGER; work = 1; } break; case OTG_STATE_A_IDLE: /* Switch to A-Device*/ if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; } else { phy->state = OTG_STATE_A_HOST; ret = dwc3_otg_start_host(&dotg->otg, 1); if ((ret == -EPROBE_DEFER) && dotg->vbus_retry_count < 3) { /* * Get regulator failed as regulator driver is * not up yet. Will try to start host after 1sec */ phy->state = OTG_STATE_A_IDLE; dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n"); delay = VBUS_REG_CHECK_DELAY; work = 1; dotg->vbus_retry_count++; } else if (ret) { /* * Probably set_host was not called yet. * We will re-try as soon as it will be called */ dev_dbg(phy->dev, "enter lpm as\n" "unable to start A-device\n"); phy->state = OTG_STATE_A_IDLE; pm_runtime_put_sync(phy->dev); return; } } break; case OTG_STATE_A_HOST: if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); dwc3_otg_start_host(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; } break; default: dev_err(phy->dev, "%s: invalid otg-state\n", __func__); } if (work) queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay); }
/** * dwc3_otg_sm_work - workqueue function. * * @w: Pointer to the dwc3 otg workqueue * * NOTE: After any change in phy->state, * we must reschdule the state machine. */ static void dwc3_otg_sm_work(struct work_struct *w) { struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work); struct usb_phy *phy = dotg->otg.phy; struct dwc3_charger *charger = dotg->charger; bool work = 0; pm_runtime_resume(phy->dev); dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state)); /* Check OTG state */ switch (phy->state) { case OTG_STATE_UNDEFINED: dwc3_otg_init_sm(dotg); if (!dotg->psy) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) dev_err(phy->dev, "couldn't get usb power supply\n"); } /* Switch to A or B-Device according to ID / BSV */ if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); phy->state = OTG_STATE_B_IDLE; work = 1; } else { phy->state = OTG_STATE_B_IDLE; dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_IDLE: if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; if (charger) { if (charger->chg_type == DWC3_INVALID_CHARGER) charger->start_detection(dotg->charger, false); else charger->chg_type = DWC3_INVALID_CHARGER; } } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); if (charger) { /* Has charger been detected? If no detect it */ switch (charger->chg_type) { case DWC3_DCP_CHARGER: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); pm_runtime_put_sync(phy->dev); break; case DWC3_CDP_CHARGER: dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; case DWC3_SDP_CHARGER: dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; default: dev_dbg(phy->dev, "chg_det started\n"); charger->start_detection(charger, true); break; } } else { /* no charger registered, start peripheral */ if (dwc3_otg_start_peripheral(&dotg->otg, 1)) { /* * Probably set_peripheral not called * yet. We will re-try as soon as it * will be called */ dev_err(phy->dev, "enter lpm as\n" "unable to start B-device\n"); phy->state = OTG_STATE_UNDEFINED; pm_runtime_put_sync(phy->dev); return; } } } else { if (charger) charger->start_detection(dotg->charger, false); dwc3_otg_set_power(phy, 0); dev_dbg(phy->dev, "No device, trying to suspend\n"); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_PERIPHERAL: if (!test_bit(B_SESS_VLD, &dotg->inputs) || !test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id || !bsv\n"); dwc3_otg_start_peripheral(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; if (charger) charger->chg_type = DWC3_INVALID_CHARGER; work = 1; } break; case OTG_STATE_A_IDLE: /* Switch to A-Device*/ if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); phy->state = OTG_STATE_B_IDLE; work = 1; } else { phy->state = OTG_STATE_A_HOST; if (dwc3_otg_start_host(&dotg->otg, 1)) { /* * Probably set_host was not called yet. * We will re-try as soon as it will be called */ dev_dbg(phy->dev, "enter lpm as\n" "unable to start A-device\n"); phy->state = OTG_STATE_UNDEFINED; pm_runtime_put_sync(phy->dev); return; } } break; case OTG_STATE_A_HOST: if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); dwc3_otg_start_host(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; work = 1; } break; default: dev_err(phy->dev, "%s: invalid otg-state\n", __func__); } if (work) schedule_work(&dotg->sm_work); }
/** * dwc3_otg_sm_work - workqueue function. * * @w: Pointer to the dwc3 otg workqueue * * NOTE: After any change in phy->state, * we must reschdule the state machine. */ static void dwc3_otg_sm_work(struct work_struct *w) { struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work.work); struct usb_phy *phy = dotg->otg.phy; struct dwc3_charger *charger = dotg->charger; bool work = 0; int ret = 0; unsigned long delay = 0; pm_runtime_resume(phy->dev); dev_dbg(phy->dev, "%s state\n", usb_otg_state_string(phy->state)); /* Check OTG state */ switch (phy->state) { case OTG_STATE_UNDEFINED: dwc3_otg_init_sm(dotg); if (!dotg->psy) { dotg->psy = power_supply_get_by_name("usb"); if (!dotg->psy) dev_err(phy->dev, "couldn't get usb power supply\n"); } /* Switch to A or B-Device according to ID / BSV */ if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); phy->state = OTG_STATE_B_IDLE; work = 1; } else { phy->state = OTG_STATE_B_IDLE; dev_dbg(phy->dev, "No device, trying to suspend\n"); dbg_event(0xFF, "UNDEF put", 0); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_IDLE: if (!test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id\n"); phy->state = OTG_STATE_A_IDLE; work = 1; dotg->charger_retry_count = 0; if (charger) { if (charger->chg_type == DWC3_INVALID_CHARGER) charger->start_detection(dotg->charger, false); else charger->chg_type = DWC3_INVALID_CHARGER; } dwc3_otg_set_power(phy, 0); } else if (test_bit(B_SESS_VLD, &dotg->inputs)) { dev_dbg(phy->dev, "b_sess_vld\n"); if (charger) { /* Has charger been detected? If no detect it */ switch (charger->chg_type) { case DWC3_DCP_CHARGER: case DWC3_PROPRIETARY_CHARGER: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, dcp_max_current); dbg_event(0xFF, "PROPCHG put", 0); pm_runtime_put_sync(phy->dev); break; case DWC3_PROPRIETARY_1000MA: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, DWC3_1000MA_CHG_MAX); pm_runtime_put_sync(phy->dev); break; case DWC3_PROPRIETARY_500MA: dev_dbg(phy->dev, "lpm, DCP charger\n"); dwc3_otg_set_power(phy, DWC3_500MA_CHG_MAX); pm_runtime_put_sync(phy->dev); break; case DWC3_CDP_CHARGER: dwc3_otg_set_power(phy, DWC3_IDEV_CHG_MAX); dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; case DWC3_SDP_CHARGER: dwc3_otg_start_peripheral(&dotg->otg, 1); phy->state = OTG_STATE_B_PERIPHERAL; work = 1; break; case DWC3_FLOATED_CHARGER: if (dotg->charger_retry_count < max_chgr_retry_count) dotg->charger_retry_count++; /* * In case of floating charger, if * retry count equal to max retry count * notify PMIC about floating charger * and put Hw in low power mode. Else * perform charger detection again by * calling start_detection() with false * and then with true argument. */ if (dotg->charger_retry_count == max_chgr_retry_count) { dwc3_otg_set_power(phy, 0); dwc3_otg_set_invalid_charger(phy); dbg_event(0xFF, "FLCHG put", 0); pm_runtime_put_sync(phy->dev); break; } charger->start_detection(dotg->charger, false); delay = msecs_to_jiffies(100 * dotg->charger_retry_count); work = 1; break; default: dev_dbg(phy->dev, "chg_det started\n"); charger->start_detection(charger, true); break; } } else { /* * no charger registered, assuming SDP * and start peripheral */ phy->state = OTG_STATE_B_PERIPHERAL; if (dwc3_otg_start_peripheral(&dotg->otg, 1)) { /* * Probably set_peripheral not called * yet. We will re-try as soon as it * will be called */ dev_err(phy->dev, "enter lpm as\n" "unable to start B-device\n"); phy->state = OTG_STATE_UNDEFINED; dbg_event(0xFF, "NoCH put", 0); pm_runtime_put_sync(phy->dev); return; } } } else { if (charger) charger->start_detection(dotg->charger, false); dotg->charger_retry_count = 0; dwc3_otg_set_power(phy, 0); dev_dbg(phy->dev, "No device, trying to suspend\n"); dbg_event(0xFF, "NoDev put", 0); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_B_PERIPHERAL: if (!test_bit(B_SESS_VLD, &dotg->inputs) || !test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "!id || !bsv\n"); dwc3_otg_start_peripheral(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; if (charger) charger->chg_type = DWC3_INVALID_CHARGER; work = 1; } else if (test_bit(DWC3_OTG_SUSPEND, &dotg->inputs) && test_bit(B_SESS_VLD, &dotg->inputs)) { dbg_event(0xFF, "BPER put", 0); pm_runtime_put_sync(phy->dev); } break; case OTG_STATE_A_IDLE: /* Switch to A-Device*/ if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; clear_bit(A_VBUS_DROP_DET, &dotg->inputs); #ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION host_send_uevent(USB_HOST_EXT_EVENT_NONE); #endif } else if (test_bit(A_VBUS_DROP_DET, &dotg->inputs)) { dev_dbg(phy->dev, "vbus_drop_det\n"); /* staying on here until exit from A-Device */ } else { phy->state = OTG_STATE_A_HOST; ret = dwc3_otg_start_host(&dotg->otg, 1); if ((ret == -EPROBE_DEFER) && dotg->vbus_retry_count < 3) { /* * Get regulator failed as regulator driver is * not up yet. Will try to start host after 1sec */ phy->state = OTG_STATE_A_IDLE; dev_dbg(phy->dev, "Unable to get vbus regulator. Retrying...\n"); delay = VBUS_REG_CHECK_DELAY; work = 1; dotg->vbus_retry_count++; } else if (ret) { dev_dbg(phy->dev, "enter lpm as\n" "unable to start A-device\n"); phy->state = OTG_STATE_A_IDLE; dbg_event(0xFF, "AIDL put", 0); pm_runtime_put_sync(phy->dev); return; } else { /* * delay 1s to allow for xHCI to detect * just-attached devices before allowing * runtime suspend */ dev_dbg(phy->dev, "a_host state entered\n"); delay = VBUS_REG_CHECK_DELAY; work = 1; } } break; case OTG_STATE_A_HOST: if (test_bit(ID, &dotg->inputs)) { dev_dbg(phy->dev, "id\n"); dwc3_otg_start_host(&dotg->otg, 0); phy->state = OTG_STATE_B_IDLE; dotg->vbus_retry_count = 0; work = 1; clear_bit(A_VBUS_DROP_DET, &dotg->inputs); #ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION host_send_uevent(USB_HOST_EXT_EVENT_NONE); #endif } else if (test_bit(A_VBUS_DROP_DET, &dotg->inputs)) { dev_dbg(phy->dev, "vbus_drop_det\n"); dwc3_otg_start_host(&dotg->otg, 0); phy->state = OTG_STATE_A_IDLE; work = 1; #ifdef CONFIG_USB_HOST_EXTRA_NOTIFICATION host_send_uevent(USB_HOST_EXT_EVENT_VBUS_DROP); #endif } else { dev_dbg(phy->dev, "still in a_host state. Resuming root hub.\n"); dbg_event(0xFF, "AHOST put", 0); pm_runtime_resume(&dotg->dwc->xhci->dev); pm_runtime_put_noidle(phy->dev); } break; default: dev_err(phy->dev, "%s: invalid otg-state\n", __func__); } if (work) queue_delayed_work(system_nrt_wq, &dotg->sm_work, delay); }