示例#1
0
文件: tahvo-usb.c 项目: mozyg/kernel
static irqreturn_t omap_otg_irq(int irq, void *arg)
{
	struct platform_device *otg_dev = (struct platform_device *) arg;
	struct tahvo_usb *tu = (struct tahvo_usb *) otg_dev->dev.driver_data;
	u16 otg_irq;

	otg_irq = OTG_IRQ_SRC_REG;
	if (otg_irq & OPRT_CHG) {
		OTG_IRQ_SRC_REG = OPRT_CHG;
	} else if (otg_irq & B_SRP_TMROUT) {
		OTG_IRQ_SRC_REG = B_SRP_TMROUT;
	} else if (otg_irq & B_HNP_FAIL) {
		OTG_IRQ_SRC_REG = B_HNP_FAIL;
	} else if (otg_irq & A_SRP_DETECT) {
		OTG_IRQ_SRC_REG = A_SRP_DETECT;
	} else if (otg_irq & A_REQ_TMROUT) {
		OTG_IRQ_SRC_REG = A_REQ_TMROUT;
	} else if (otg_irq & A_VBUS_ERR) {
		OTG_IRQ_SRC_REG = A_VBUS_ERR;
	} else if (otg_irq & DRIVER_SWITCH) {
		if ((!(OTG_CTRL_REG & OTG_DRIVER_SEL)) &&
		   tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) {
			/* role is host */
			usb_bus_start_enum(tu->otg.host,
					   tu->otg.host->otg_port);
		}
		OTG_IRQ_SRC_REG = DRIVER_SWITCH;
	} else
		return IRQ_NONE;

	return IRQ_HANDLED;

}
示例#2
0
文件: tahvo-usb.c 项目: tmlind/linux
static irqreturn_t omap_otg_irq(int irq, void *arg)
{
	u16 otg_irq;

	otg_irq = omap_readw(OTG_IRQ_SRC);
	if (otg_irq & OPRT_CHG) {
		omap_writew(OPRT_CHG, OTG_IRQ_SRC);
	} else if (otg_irq & B_SRP_TMROUT) {
		omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
	} else if (otg_irq & B_HNP_FAIL) {
		omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
	} else if (otg_irq & A_SRP_DETECT) {
		omap_writew(A_SRP_DETECT, OTG_IRQ_SRC);
	} else if (otg_irq & A_REQ_TMROUT) {
		omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
	} else if (otg_irq & A_VBUS_ERR) {
		omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
	} else if (otg_irq & DRIVER_SWITCH) {
#ifdef CONFIG_USB_OTG
		if ((!(omap_readl(OTG_CTRL) & OTG_DRIVER_SEL)) &&
		   tu->otg.host && tu->otg.state == OTG_STATE_A_HOST) {
			/* role is host */
			usb_bus_start_enum(tu->otg.host,
					   tu->otg.host->otg_port);
		}
#endif
		omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC);
	} else
		return IRQ_NONE;

	return IRQ_HANDLED;

}
示例#3
0
/* Called when entering a state */
int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
	state_changed = 1;
	if (fsm->transceiver->state == new_state)
		return 0;

	VDBG("chg state to %s", state_string(new_state));

	otg_leave_state(fsm, fsm->transceiver->state);

	switch (new_state) {
	case OTG_STATE_B_IDLE:
		otg_drv_vbus(fsm, 0);
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_UNDEF);
		otg_add_timer(fsm, b_se0_srp_tmr);
		break;
	case OTG_STATE_B_SRP_INIT:
		otg_start_pulse(fsm);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_UNDEF);
		otg_add_timer(fsm, b_srp_fail_tmr);
		break;
	case OTG_STATE_B_PERIPHERAL:
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 1);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_GADGET);
		break;
	case OTG_STATE_B_WAIT_ACON:
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, b_ase0_brst_tmr);
		fsm->a_bus_suspend = 0;
		break;
	case OTG_STATE_B_HOST:
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 1);
		otg_set_protocol(fsm, PROTO_HOST);
		usb_bus_start_enum(fsm->transceiver->host,
				   fsm->transceiver->host->otg_port);
		break;
	case OTG_STATE_A_IDLE:
		otg_drv_vbus(fsm, 0);
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		break;
	case OTG_STATE_A_WAIT_VRISE:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, a_wait_vrise_tmr);
		break;
	case OTG_STATE_A_WAIT_BCON:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, a_wait_bcon_tmr);
		break;
	case OTG_STATE_A_HOST:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 1);
		otg_set_protocol(fsm, PROTO_HOST);
		/* When HNP is triggered while a_bus_req = 0, a_host will 
		 * suspend too fast to complete a_set_b_hnp_en
		 */
		if (!fsm->a_bus_req || fsm->a_suspend_req)
			otg_add_timer(fsm, a_wait_enum_tmr);
		break;
	case OTG_STATE_A_SUSPEND:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, a_aidl_bdis_tmr);

		break;
	case OTG_STATE_A_PERIPHERAL:
		otg_loc_conn(fsm, 1);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_GADGET);
		otg_drv_vbus(fsm, 1);
		break;
	case OTG_STATE_A_WAIT_VFALL:
		otg_drv_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		break;
	case OTG_STATE_A_VBUS_ERR:
		otg_drv_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_UNDEF);
		break;
	default:
		break;
	}

	fsm->transceiver->state = new_state;
	return 0;
}
static irqreturn_t omap_otg_irq(int irq, void *_isp)
{
	u16		otg_irq = omap_readw(OTG_IRQ_SRC);
	u32		otg_ctrl;
	int		ret = IRQ_NONE;
	struct isp1301	*isp = _isp;

	/* update ISP1301 transciever from OTG controller */
	if (otg_irq & OPRT_CHG) {
		omap_writew(OPRT_CHG, OTG_IRQ_SRC);
		isp1301_defer_work(isp, WORK_UPDATE_ISP);
		ret = IRQ_HANDLED;

	/* SRP to become b_peripheral failed */
	} else if (otg_irq & B_SRP_TMROUT) {
		pr_debug("otg: B_SRP_TIMEOUT, %06x\n", omap_readl(OTG_CTRL));
		notresponding(isp);

		/* gadget drivers that care should monitor all kinds of
		 * remote wakeup (SRP, normal) using their own timer
		 * to give "check cable and A-device" messages.
		 */
		if (isp->otg.state == OTG_STATE_B_SRP_INIT)
			b_idle(isp, "srp_timeout");

		omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
		ret = IRQ_HANDLED;

	/* HNP to become b_host failed */
	} else if (otg_irq & B_HNP_FAIL) {
		pr_debug("otg: %s B_HNP_FAIL, %06x\n",
				state_name(isp), omap_readl(OTG_CTRL));
		notresponding(isp);

		otg_ctrl = omap_readl(OTG_CTRL);
		otg_ctrl |= OTG_BUSDROP;
		otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
		omap_writel(otg_ctrl, OTG_CTRL);

		/* subset of b_peripheral()... */
		isp->otg.state = OTG_STATE_B_PERIPHERAL;
		pr_debug("  --> b_peripheral\n");

		omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
		ret = IRQ_HANDLED;

	/* detect SRP from B-device ... */
	} else if (otg_irq & A_SRP_DETECT) {
		pr_debug("otg: %s SRP_DETECT, %06x\n",
				state_name(isp), omap_readl(OTG_CTRL));

		isp1301_defer_work(isp, WORK_UPDATE_OTG);
		switch (isp->otg.state) {
		case OTG_STATE_A_IDLE:
			if (!isp->otg.host)
				break;
			isp1301_defer_work(isp, WORK_HOST_RESUME);
			otg_ctrl = omap_readl(OTG_CTRL);
			otg_ctrl |= OTG_A_BUSREQ;
			otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)
					& ~OTG_XCEIV_INPUTS
					& OTG_CTRL_MASK;
			omap_writel(otg_ctrl, OTG_CTRL);
			break;
		default:
			break;
		}

		omap_writew(A_SRP_DETECT, OTG_IRQ_SRC);
		ret = IRQ_HANDLED;

	/* timer expired:  T(a_wait_bcon) and maybe T(a_wait_vrise)
	 * we don't track them separately
	 */
	} else if (otg_irq & A_REQ_TMROUT) {
		otg_ctrl = omap_readl(OTG_CTRL);
		pr_info("otg: BCON_TMOUT from %s, %06x\n",
				state_name(isp), otg_ctrl);
		notresponding(isp);

		otg_ctrl |= OTG_BUSDROP;
		otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
		omap_writel(otg_ctrl, OTG_CTRL);
		isp->otg.state = OTG_STATE_A_WAIT_VFALL;

		omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
		ret = IRQ_HANDLED;

	/* A-supplied voltage fell too low; overcurrent */
	} else if (otg_irq & A_VBUS_ERR) {
		otg_ctrl = omap_readl(OTG_CTRL);
		printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n",
			state_name(isp), otg_irq, otg_ctrl);

		otg_ctrl |= OTG_BUSDROP;
		otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
		omap_writel(otg_ctrl, OTG_CTRL);
		isp->otg.state = OTG_STATE_A_VBUS_ERR;

		omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
		ret = IRQ_HANDLED;

	/* switch driver; the transciever code activates it,
	 * ungating the udc clock or resuming OHCI.
	 */
	} else if (otg_irq & DRIVER_SWITCH) {
		int	kick = 0;

		otg_ctrl = omap_readl(OTG_CTRL);
		printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n",
				state_name(isp),
				(otg_ctrl & OTG_DRIVER_SEL)
					? "gadget" : "host",
				otg_ctrl);
		isp1301_defer_work(isp, WORK_UPDATE_ISP);

		/* role is peripheral */
		if (otg_ctrl & OTG_DRIVER_SEL) {
			switch (isp->otg.state) {
			case OTG_STATE_A_IDLE:
				b_idle(isp, __func__);
				break;
			default:
				break;
			}
			isp1301_defer_work(isp, WORK_UPDATE_ISP);

		/* role is host */
		} else {
			if (!(otg_ctrl & OTG_ID)) {
				otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
				omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL);
			}

			if (isp->otg.host) {
				switch (isp->otg.state) {
				case OTG_STATE_B_WAIT_ACON:
					isp->otg.state = OTG_STATE_B_HOST;
					pr_debug("  --> b_host\n");
					kick = 1;
					break;
				case OTG_STATE_A_WAIT_BCON:
					isp->otg.state = OTG_STATE_A_HOST;
					pr_debug("  --> a_host\n");
					break;
				case OTG_STATE_A_PERIPHERAL:
					isp->otg.state = OTG_STATE_A_WAIT_BCON;
					pr_debug("  --> a_wait_bcon\n");
					break;
				default:
					break;
				}
				isp1301_defer_work(isp, WORK_HOST_RESUME);
			}
		}

		omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC);
		ret = IRQ_HANDLED;

		if (kick)
			usb_bus_start_enum(isp->otg.host,
						isp->otg.host->otg_port);
	}

	check_state(isp, __func__);
	return ret;
}
示例#5
0
/* Called when entering a state */
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
	state_changed = 1;
	if (fsm->otg->phy->state == new_state)
		return 0;
	VDBG("Set state: %s\n", usb_otg_state_string(new_state));
	otg_leave_state(fsm, fsm->otg->phy->state);
	switch (new_state) {
	case OTG_STATE_B_IDLE:
		otg_drv_vbus(fsm, 0);
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		/*
		 * Driver is responsible for starting ADP probing
		 * if ADP sensing times out.
		 */
		otg_start_adp_sns(fsm);
		otg_set_protocol(fsm, PROTO_UNDEF);
		otg_add_timer(fsm, B_SE0_SRP);
		break;
	case OTG_STATE_B_SRP_INIT:
		otg_start_pulse(fsm);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_UNDEF);
		otg_add_timer(fsm, B_SRP_FAIL);
		break;
	case OTG_STATE_B_PERIPHERAL:
		otg_chrg_vbus(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_GADGET);
		otg_loc_conn(fsm, 1);
		break;
	case OTG_STATE_B_WAIT_ACON:
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, B_ASE0_BRST);
		fsm->a_bus_suspend = 0;
		break;
	case OTG_STATE_B_HOST:
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 1);
		otg_set_protocol(fsm, PROTO_HOST);
		usb_bus_start_enum(fsm->otg->host,
				fsm->otg->host->otg_port);
		break;
	case OTG_STATE_A_IDLE:
		otg_drv_vbus(fsm, 0);
		otg_chrg_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_start_adp_prb(fsm);
		otg_set_protocol(fsm, PROTO_HOST);
		break;
	case OTG_STATE_A_WAIT_VRISE:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, A_WAIT_VRISE);
		break;
	case OTG_STATE_A_WAIT_BCON:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, A_WAIT_BCON);
		break;
	case OTG_STATE_A_HOST:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 1);
		otg_set_protocol(fsm, PROTO_HOST);
		/*
		 * When HNP is triggered while a_bus_req = 0, a_host will
		 * suspend too fast to complete a_set_b_hnp_en
		 */
		if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
			otg_add_timer(fsm, A_WAIT_ENUM);
		break;
	case OTG_STATE_A_SUSPEND:
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, A_AIDL_BDIS);

		break;
	case OTG_STATE_A_PERIPHERAL:
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_GADGET);
		otg_drv_vbus(fsm, 1);
		otg_loc_conn(fsm, 1);
		otg_add_timer(fsm, A_BIDL_ADIS);
		break;
	case OTG_STATE_A_WAIT_VFALL:
		otg_drv_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_HOST);
		otg_add_timer(fsm, A_WAIT_VFALL);
		break;
	case OTG_STATE_A_VBUS_ERR:
		otg_drv_vbus(fsm, 0);
		otg_loc_conn(fsm, 0);
		otg_loc_sof(fsm, 0);
		otg_set_protocol(fsm, PROTO_UNDEF);
		break;
	default:
		break;
	}

	fsm->otg->phy->state = new_state;
	return 0;
}