static ssize_t store_vbus_evt(struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long flags; struct dwc_otg2 *otg = dwc3_get_otg(); if (count != 2) { otg_err(otg, "return EINVAL\n"); return -EINVAL; } if (count > 0 && buf[count-1] == '\n') ((char *) buf)[count-1] = 0; switch (buf[0]) { case '1': otg_dbg(otg, "Change the VBUS to High\n"); otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT; spin_lock_irqsave(&otg->lock, flags); dwc3_wakeup_otg_thread(otg); spin_unlock_irqrestore(&otg->lock, flags); return count; case '0': otg_dbg(otg, "Change the VBUS to Low\n"); otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT; spin_lock_irqsave(&otg->lock, flags); dwc3_wakeup_otg_thread(otg); spin_unlock_irqrestore(&otg->lock, flags); return count; default: return -EINVAL; } return count; }
static int dwc3_intel_byt_handle_notification(struct notifier_block *nb, unsigned long event, void *data) { struct dwc_otg2 *otg = dwc3_get_otg(); int state, val; unsigned long flags; if (!otg) return NOTIFY_BAD; val = *(int *)data; spin_lock_irqsave(&otg->lock, flags); switch (event) { case USB_EVENT_VBUS: if (val) { otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT; otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT; } else { otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT; otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT; } state = NOTIFY_OK; break; default: otg_dbg(otg, "DWC OTG Notify unknow notify message\n"); state = NOTIFY_DONE; } dwc3_wakeup_otg_thread(otg); spin_unlock_irqrestore(&otg->lock, flags); return state; }
static void stop_main_thread(struct dwc_otg2 *otg) { mutex_lock(&lock); if (otg->main_thread) { otg_dbg(otg, "Stopping OTG main thread\n"); otg->state = DWC_STATE_EXIT; dwc3_wakeup_otg_thread(otg); } mutex_unlock(&lock); }
static ssize_t store_otg_id(struct device *_dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long flags; struct dwc_otg2 *otg = dwc3_get_otg(); if (!otg) return 0; if (count != 2) { otg_err(otg, "return EINVAL\n"); return -EINVAL; } if (count > 0 && buf[count-1] == '\n') ((char *) buf)[count-1] = 0; switch (buf[0]) { case 'a': case 'A': otg_dbg(otg, "Change ID to A\n"); otg->user_events |= USER_ID_A_CHANGE_EVENT; spin_lock_irqsave(&otg->lock, flags); dwc3_wakeup_otg_thread(otg); otg_id = 0; spin_unlock_irqrestore(&otg->lock, flags); return count; case 'b': case 'B': otg_dbg(otg, "Change ID to B\n"); otg->user_events |= USER_ID_B_CHANGE_EVENT; spin_lock_irqsave(&otg->lock, flags); dwc3_wakeup_otg_thread(otg); otg_id = 1; spin_unlock_irqrestore(&otg->lock, flags); return count; default: otg_err(otg, "Just support change ID to A!\n"); return -EINVAL; } return count; }
static void dwc_a_bus_drop(struct usb_phy *x) { struct dwc_otg2 *otg = dwc3_get_otg(); unsigned long flags; if (otg->usb2_phy.vbus_state == VBUS_DISABLED) { spin_lock_irqsave(&otg->lock, flags); otg->user_events |= USER_A_BUS_DROP; dwc3_wakeup_otg_thread(otg); spin_unlock_irqrestore(&otg->lock, flags); } }
static void dwc_otg_suspend_discon_work(struct work_struct *work) { struct dwc_otg2 *otg = dwc3_get_otg(); unsigned long flags; otg_dbg(otg, "start suspend_disconn work\n"); spin_lock_irqsave(&otg->lock, flags); otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT; otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT; dwc3_wakeup_otg_thread(otg); spin_unlock_irqrestore(&otg->lock, flags); }
static int dwc3_intel_handle_notification(struct notifier_block *nb, unsigned long event, void *data) { int state; unsigned long flags, valid_chrg_type; struct dwc_otg2 *otg = dwc3_get_otg(); struct power_supply_cable_props *cap; if (!otg) return NOTIFY_BAD; valid_chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP | POWER_SUPPLY_CHARGER_TYPE_USB_CDP | POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK; spin_lock_irqsave(&otg->lock, flags); switch (event) { case USB_EVENT_ID: otg->otg_events |= OEVT_CONN_ID_STS_CHNG_EVNT; state = NOTIFY_OK; break; case USB_EVENT_VBUS: /* WA for EM driver which should not sent VBUS event * if UTMI PHY selected. */ if (!charger_detect_enable(otg)) { state = NOTIFY_OK; goto done; } if (*(int *)data) { otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT; otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT; } else { otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT; otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT; } state = NOTIFY_OK; break; case USB_EVENT_CHARGER: if (charger_detect_enable(otg)) { state = NOTIFY_DONE; goto done; } cap = (struct power_supply_cable_props *)data; if (!(cap->chrg_type & valid_chrg_type)) { otg_err(otg, "Ignore invalid charger type!\n"); state = NOTIFY_DONE; goto done; } /* Ignore the events which send by USB driver itself. */ if (cap->chrg_evt == POWER_SUPPLY_CHARGER_EVENT_CONNECT) if (cap_record.chrg_type == POWER_SUPPLY_CHARGER_TYPE_USB_SDP) { state = NOTIFY_DONE; goto done; } if (cap->chrg_evt == POWER_SUPPLY_CHARGER_EVENT_CONNECT) { otg->otg_events |= OEVT_B_DEV_SES_VLD_DET_EVNT; otg->otg_events &= ~OEVT_A_DEV_SESS_END_DET_EVNT; cap_record.chrg_type = cap->chrg_type; cap_record.ma = cap->ma; cap_record.chrg_evt = cap->chrg_evt; } else if (cap->chrg_evt == POWER_SUPPLY_CHARGER_EVENT_DISCONNECT) { otg->otg_events |= OEVT_A_DEV_SESS_END_DET_EVNT; otg->otg_events &= ~OEVT_B_DEV_SES_VLD_DET_EVNT; cap_record.chrg_type = POWER_SUPPLY_CHARGER_TYPE_NONE; cap_record.ma = 0; cap_record.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT; } if (cap->chrg_type == POWER_SUPPLY_CHARGER_TYPE_ACA_DOCK) otg->otg_events |= OEVT_CONN_ID_STS_CHNG_EVNT; state = NOTIFY_OK; break; default: otg_dbg(otg, "DWC OTG Notify unknow notify message\n"); state = NOTIFY_DONE; } dwc3_wakeup_otg_thread(otg); done: spin_unlock_irqrestore(&otg->lock, flags); return state; }