⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isp1301_omap.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 3 页
字号:
			& OTG_CTRL_MASK			& ~OTG_XCEIV_INPUTS			& ~(OTG_BSESSVLD|OTG_BSESSEND);	if (otg_status & OTG_B_SESS_VLD)		otg_ctrl |= OTG_BSESSVLD;	else if (otg_status & OTG_B_SESS_END)		otg_ctrl |= OTG_BSESSEND;	OTG_CTRL_REG = otg_ctrl;}/* inputs going to ISP1301 */static void otg_update_isp(struct isp1301 *isp){	u32	otg_ctrl, otg_change;	u8	set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP;	otg_ctrl = OTG_CTRL_REG;	otg_change = otg_ctrl ^ isp->last_otg_ctrl;	isp->last_otg_ctrl = otg_ctrl;	otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS;	switch (isp->otg.state) {	case OTG_STATE_B_IDLE:	case OTG_STATE_B_PERIPHERAL:	case OTG_STATE_B_SRP_INIT:		if (!(otg_ctrl & OTG_PULLUP)) {			// if (otg_ctrl & OTG_B_HNPEN) {			if (isp->otg.gadget->b_hnp_enable) {				isp->otg.state = OTG_STATE_B_WAIT_ACON;				pr_debug("  --> b_wait_acon\n");			}			goto pulldown;		}pullup:		set |= OTG1_DP_PULLUP;		clr |= OTG1_DP_PULLDOWN;		break;	case OTG_STATE_A_SUSPEND:	case OTG_STATE_A_PERIPHERAL:		if (otg_ctrl & OTG_PULLUP)			goto pullup;		/* FALLTHROUGH */	// case OTG_STATE_B_WAIT_ACON:	default:pulldown:		set |= OTG1_DP_PULLDOWN;		clr |= OTG1_DP_PULLUP;		break;	}#	define toggle(OTG,ISP) do { \		if (otg_ctrl & OTG) set |= ISP; \		else clr |= ISP; \		} while (0)	if (!(isp->otg.host))		otg_ctrl &= ~OTG_DRV_VBUS;	switch (isp->otg.state) {	case OTG_STATE_A_SUSPEND:		if (otg_ctrl & OTG_DRV_VBUS) {			set |= OTG1_VBUS_DRV;			break;		}		/* HNP failed for some reason (A_AIDL_BDIS timeout) */		notresponding(isp);		/* FALLTHROUGH */	case OTG_STATE_A_VBUS_ERR:		isp->otg.state = OTG_STATE_A_WAIT_VFALL;		pr_debug("  --> a_wait_vfall\n");		/* FALLTHROUGH */	case OTG_STATE_A_WAIT_VFALL:		/* FIXME usbcore thinks port power is still on ... */		clr |= OTG1_VBUS_DRV;		break;	case OTG_STATE_A_IDLE:		if (otg_ctrl & OTG_DRV_VBUS) {			isp->otg.state = OTG_STATE_A_WAIT_VRISE;			pr_debug("  --> a_wait_vrise\n");		}		/* FALLTHROUGH */	default:		toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV);	}	toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG);	toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG);#	undef toggle	isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set);	isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr);	/* HNP switch to host or peripheral; and SRP */	if (otg_change & OTG_PULLUP) {		switch (isp->otg.state) {		case OTG_STATE_B_IDLE:			if (clr & OTG1_DP_PULLUP)				break;			isp->otg.state = OTG_STATE_B_PERIPHERAL;			pr_debug("  --> b_peripheral\n");			break;		case OTG_STATE_A_SUSPEND:			if (clr & OTG1_DP_PULLUP)				break;			isp->otg.state = OTG_STATE_A_PERIPHERAL;			pr_debug("  --> a_peripheral\n");			break;		default:			break;		}		OTG_CTRL_REG |= OTG_PULLUP;	}	check_state(isp, __FUNCTION__);	dump_regs(isp, "otg->isp1301");}static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs){	u16		otg_irq = OTG_IRQ_SRC_REG;	u32		otg_ctrl;	int		ret = IRQ_NONE;	struct isp1301	*isp = _isp;	/* update ISP1301 transciever from OTG controller */	if (otg_irq & OPRT_CHG) {		OTG_IRQ_SRC_REG = OPRT_CHG;		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", OTG_CTRL_REG);		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");		OTG_IRQ_SRC_REG = B_SRP_TMROUT;		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), OTG_CTRL_REG);		notresponding(isp);		otg_ctrl = OTG_CTRL_REG;		otg_ctrl |= OTG_BUSDROP;		otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;		OTG_CTRL_REG = otg_ctrl;		/* subset of b_peripheral()... */		isp->otg.state = OTG_STATE_B_PERIPHERAL;		pr_debug("  --> b_peripheral\n");		OTG_IRQ_SRC_REG = B_HNP_FAIL;		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), OTG_CTRL_REG);		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 = OTG_CTRL_REG;			otg_ctrl |= OTG_A_BUSREQ;			otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ)					& ~OTG_XCEIV_INPUTS					& OTG_CTRL_MASK;			OTG_CTRL_REG = otg_ctrl;			break;		default:			break;		}		OTG_IRQ_SRC_REG = A_SRP_DETECT;		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 = OTG_CTRL_REG;		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;		OTG_CTRL_REG = otg_ctrl;		isp->otg.state = OTG_STATE_A_WAIT_VFALL;		OTG_IRQ_SRC_REG = A_REQ_TMROUT;		ret = IRQ_HANDLED;	/* A-supplied voltage fell too low; overcurrent */	} else if (otg_irq & A_VBUS_ERR) {		otg_ctrl = OTG_CTRL_REG;		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;		OTG_CTRL_REG = otg_ctrl;		isp->otg.state = OTG_STATE_A_VBUS_ERR;		OTG_IRQ_SRC_REG = A_VBUS_ERR;		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 = OTG_CTRL_REG;		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, __FUNCTION__);				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;				OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ;			}			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);			}		}		OTG_IRQ_SRC_REG = DRIVER_SWITCH;		ret = IRQ_HANDLED;		if (kick)			usb_bus_start_enum(isp->otg.host,						isp->otg.host->otg_port);	}	check_state(isp, __FUNCTION__);	return ret;}static struct platform_device *otg_dev;static int otg_init(struct isp1301 *isp){	if (!otg_dev)		return -ENODEV;	dump_regs(isp, __FUNCTION__);	/* some of these values are board-specific... */	OTG_SYSCON_2_REG |= OTG_EN		/* for B-device: */		| SRP_GPDATA		/* 9msec Bdev D+ pulse */		| SRP_GPDVBUS		/* discharge after VBUS pulse */		// | (3 << 24)		/* 2msec VBUS pulse */		/* for A-device: */		| (0 << 20)		/* 200ms nominal A_WAIT_VRISE timer */		| SRP_DPW		/* detect 167+ns SRP pulses */		| SRP_DATA | SRP_VBUS	/* accept both kinds of SRP pulse */		;	update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));	update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));	check_state(isp, __FUNCTION__);	pr_debug("otg: %s, %s %06x\n",			state_name(isp), __FUNCTION__, OTG_CTRL_REG);	OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG			| B_SRP_TMROUT | B_HNP_FAIL			| A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT;	OTG_SYSCON_2_REG |= OTG_EN;	return 0;}static int otg_probe(struct device *dev){	// struct omap_usb_config *config = dev->platform_data;	otg_dev = to_platform_device(dev);	return 0;}static int otg_remove(struct device *dev){	otg_dev = 0;	return 0;}struct device_driver omap_otg_driver = {	.name		= "omap_otg",	.bus		= &platform_bus_type,	.probe		= otg_probe,	.remove		= otg_remove,	};static int otg_bind(struct isp1301 *isp){	int	status;	if (otg_dev)		return -EBUSY;	status = driver_register(&omap_otg_driver);	if (status < 0)		return status;	if (otg_dev)		status = request_irq(otg_dev->resource[1].start, omap_otg_irq,				SA_INTERRUPT, DRIVER_NAME, isp);	else		status = -ENODEV;	if (status < 0)		driver_unregister(&omap_otg_driver);	return status;}static void otg_unbind(struct isp1301 *isp){	if (!otg_dev)		return;	free_irq(otg_dev->resource[1].start, isp);}#else/* OTG controller isn't clocked */#endif	/* CONFIG_USB_OTG *//*-------------------------------------------------------------------------*/static void b_peripheral(struct isp1301 *isp){	OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;	usb_gadget_vbus_connect(isp->otg.gadget);#ifdef	CONFIG_USB_OTG	enable_vbus_draw(isp, 8);	otg_update_isp(isp);#else	enable_vbus_draw(isp, 100);	/* UDC driver just set OTG_BSESSVLD */	isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP);	isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN);	isp->otg.state = OTG_STATE_B_PERIPHERAL;	pr_debug("  --> b_peripheral\n");	dump_regs(isp, "2periph");#endif}static void isp_update_otg(struct isp1301 *isp, u8 stat){	u8			isp_stat, isp_bstat;	enum usb_otg_state	state = isp->otg.state;	if (stat & INTR_BDIS_ACON)		pr_debug("OTG:  BDIS_ACON, %s\n", state_name(isp));	/* start certain state transitions right away */	isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);	if (isp_stat & INTR_ID_GND) {		if (isp->otg.default_a) {			switch (state) {			case OTG_STATE_B_IDLE:				a_idle(isp, "idle");				/* FALLTHROUGH */			case OTG_STATE_A_IDLE:				enable_vbus_source(isp);				/* FALLTHROUGH */			case OTG_STATE_A_WAIT_VRISE:				/* we skip over OTG_STATE_A_WAIT_BCON, since				 * the HC will transition to A_HOST (or				 * A_SUSPEND!) without our noticing except				 * when HNP is used.				 */				if (isp_stat & INTR_VBUS_VLD)					isp->otg.state = OTG_STATE_A_HOST;				break;			case OTG_STATE_A_WAIT_VFALL:				if (!(isp_stat & INTR_SESS_VLD))					a_idle(isp, "vfell");				break;			default:				if (!(isp_stat & INTR_VBUS_VLD))					isp->otg.state = OTG_STATE_A_VBUS_ERR;				break;			}			isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);		} else {			switch (state) {			case OTG_STATE_B_PERIPHERAL:			case OTG_STATE_B_HOST:			case OTG_STATE_B_WAIT_ACON:				usb_gadget_vbus_disconnect(isp->otg.gadget);				break;			default:				break;			}			if (state != OTG_STATE_A_IDLE)				a_idle(isp, "id");			if (isp->otg.host && state == OTG_STATE_A_IDLE)				isp1301_defer_work(isp, WORK_HOST_RESUME);			isp_bstat = 0;		}	} else {		/* if user unplugged mini-A end of cable,		 * don't bypass A_WAIT_VFALL.		 */		if (isp->otg.default_a) {			switch (state) {			default:				isp->otg.state = OTG_STATE_A_WAIT_VFALL;				break;			case OTG_STATE_A_WAIT_VFALL:				state = OTG_STATE_A_IDLE;				/* khubd may take a while to notice and				 * handle this disconnect, so don't go				 * to B_IDLE quite yet.				 */				break;			case OTG_STATE_A_IDLE:				host_suspend(isp);				isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1,						MC1_BDIS_ACON_EN);				isp->otg.state = OTG_STATE_B_IDLE;				OTG_CTRL_REG &= OTG_CTRL_REG & OTG_CTRL_MASK						& ~OTG_CTRL_BITS;				break;			case OTG_STATE_B_IDLE:				break;			}		}		isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);		switch (isp->otg.state) {		case OTG_STATE_B_PERIPHERAL:		case OTG_STATE_B_WAIT_ACON:		case OTG_STATE_B_HOST:			if (likely(isp_bstat & OTG_B_SESS_VLD))				break;			enable_vbus_draw(isp, 0);#ifndef	CONFIG_USB_OTG			/* UDC driver will clear OTG_BSESSVLD */			isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,						OTG1_DP_PULLDOWN);			isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,						OTG1_DP_PULLUP);			dump_regs(isp, __FUNCTION__);#endif			/* FALLTHROUGH */		case OTG_STATE_B_SRP_INIT:			b_idle(isp, __FUNCTION__);			OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;			/* FALLTHROUGH */		case OTG_STATE_B_IDLE:			if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) {#ifdef	CONFIG_USB_OTG				update_otg1(isp, isp_stat);				update_otg2(isp, isp_bstat);#endif				b_peripheral(isp);			} else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD)))				isp_bstat |= OTG_B_SESS_END;			break;		case OTG_STATE_A_WAIT_VFALL:			break;		default:			pr_debug("otg: unsupported b-device %s\n",				state_name(isp));			break;		}	}	if (state != isp->otg.state)		pr_debug("  isp, %s -> %s\n",				state_string(state), state_name(isp));#ifdef	CONFIG_USB_OTG	/* update the OTG controller state to match the isp1301; may	 * trigger OPRT_CHG irqs for changes going to the isp1301.	 */	update_otg1(isp, isp_stat);	update_otg2(isp, isp_bstat);	check_state(isp, __FUNCTION__);#endif	dump_regs(isp, "isp1301->otg");}/*-------------------------------------------------------------------------*/static u8 isp1301_clear_latch(struct isp1301 *isp){	u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH);	isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch);	return latch;}static voidisp1301_work(void *data){	struct isp1301	*isp = data;	int		stop;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -