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; }
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; }
/* 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; }
/* 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; }