static int mv_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
{
	struct mv_otg *mvotg = container_of(otg_p, struct mv_otg, otg);

	if (host) {
		if ((otg_p->state == OTG_STATE_A_HOST) || (otg_p->state == OTG_STATE_A_WAIT_BCON)) {
			/* stop old host first */
			if (otg_p->host) {
				mv_otg_start_host(mvotg, 0);
			}

			/* start the new host right away*/
			otg_p->host = host;
			mv_otg_set_vbus(&mvotg->otg, 1);
			mv_otg_start_host(mvotg, 1);
		}
	} else {
		if (otg_p->host) {
			mv_otg_set_vbus(&mvotg->otg, 0);
			mv_otg_start_host(mvotg, 0);
		}
	}
	otg_p->host = host;
	return 0;
}
예제 #2
0
static void mv_otg_work(struct work_struct *work)
{
	struct mv_otg *mvotg;
	struct usb_phy *phy;
	struct usb_otg *otg;
	int old_state;

	mvotg = container_of(to_delayed_work(work), struct mv_otg, work);

run:
	/* work queue is single thread, or we need spin_lock to protect */
	phy = &mvotg->phy;
	otg = phy->otg;
	old_state = phy->state;

	if (!mvotg->active)
		return;

	mv_otg_update_inputs(mvotg);
	mv_otg_update_state(mvotg);

	if (old_state != phy->state) {
		dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
			 state_string[old_state],
			 state_string[phy->state]);

		switch (phy->state) {
		case OTG_STATE_B_IDLE:
			otg->default_a = 0;
			if (old_state == OTG_STATE_B_PERIPHERAL)
				mv_otg_start_periphrals(mvotg, 0);
			mv_otg_reset(mvotg);
			mv_otg_disable(mvotg);
			break;
		case OTG_STATE_B_PERIPHERAL:
			mv_otg_enable(mvotg);
			mv_otg_start_periphrals(mvotg, 1);
			break;
		case OTG_STATE_A_IDLE:
			otg->default_a = 1;
			mv_otg_enable(mvotg);
			if (old_state == OTG_STATE_A_WAIT_VFALL)
				mv_otg_start_host(mvotg, 0);
			mv_otg_reset(mvotg);
			break;
		case OTG_STATE_A_WAIT_VRISE:
			mv_otg_set_vbus(otg, 1);
			break;
		case OTG_STATE_A_WAIT_BCON:
			if (old_state != OTG_STATE_A_HOST)
				mv_otg_start_host(mvotg, 1);
			mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER,
					 T_A_WAIT_BCON,
					 mv_otg_timer_await_bcon);
			/*
			 * Now, we directly enter A_HOST. So set b_conn = 1
			 * here. In fact, it need host driver to notify us.
			 */
			mvotg->otg_ctrl.b_conn = 1;
			break;
		case OTG_STATE_A_HOST:
			break;
		case OTG_STATE_A_WAIT_VFALL:
			/*
			 * Now, we has exited A_HOST. So set b_conn = 0
			 * here. In fact, it need host driver to notify us.
			 */
			mvotg->otg_ctrl.b_conn = 0;
			mv_otg_set_vbus(otg, 0);
			break;
		case OTG_STATE_A_VBUS_ERR:
			break;
		default:
			break;
		}
		goto run;
	}
}