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;

}
예제 #3
0
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;
}
예제 #5
0
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);
}
예제 #7
0
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;

}