static void tahvo_usb_power_off(struct tahvo_usb *tu) { u32 l; int id; /* Disable gadget controller if any */ if (tu->otg.gadget) usb_gadget_vbus_disconnect(tu->otg.gadget); host_suspend(tu); /* Disable OTG and interrupts */ if (TAHVO_MODE(tu) == TAHVO_MODE_PERIPHERAL) id = OTG_ID; else id = 0; l = OTG_CTRL_REG; l &= ~(OTG_CTRL_XCVR_MASK | OTG_CTRL_SYS_MASK | OTG_BSESSVLD); l |= id | OTG_BSESSEND; OTG_CTRL_REG = l; OTG_IRQ_EN_REG = 0; OTG_SYSCON_2_REG &= ~OTG_EN; OTG_SYSCON_1_REG |= OTG_IDLE_EN; /* Power off transceiver */ tahvo_write_reg(TAHVO_REG_USBR, 0); tu->otg.state = OTG_STATE_UNDEFINED; }
/* add or disable the host device+driver */ static int isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host) { struct isp1301 *isp = container_of(otg, struct isp1301, otg); if (!otg || isp != the_transceiver) return -ENODEV; if (!host) { omap_writew(0, OTG_IRQ_EN); power_down(isp); isp->otg.host = NULL; return 0; } #ifdef CONFIG_USB_OTG isp->otg.host = host; dev_dbg(&isp->client->dev, "registered host\n"); host_suspend(isp); if (isp->otg.gadget) return isp1301_otg_enable(isp); return 0; #elif !defined(CONFIG_USB_GADGET_OMAP) // FIXME update its refcount isp->otg.host = host; power_up(isp); if (machine_is_omap_h2()) isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); dev_info(&isp->client->dev, "A-Host sessions ok\n"); isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, INTR_ID_GND); isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, INTR_ID_GND); /* If this has a Mini-AB connector, this mode is highly * nonstandard ... but can be handy for testing, especially with * the Mini-A end of an OTG cable. (Or something nonstandard * like MiniB-to-StandardB, maybe built with a gender mender.) */ isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); dump_regs(isp, __func__); return 0; #else dev_dbg(&isp->client->dev, "host sessions not allowed\n"); return -EINVAL; #endif }
/* called from irq handlers */ static void b_idle(struct isp1301 *isp, const char *tag) { if (isp->otg.state == OTG_STATE_B_IDLE) return; isp->otg.default_a = 0; if (isp->otg.host) { isp->otg.host->is_b_host = 1; host_suspend(isp); } if (isp->otg.gadget) { isp->otg.gadget->is_a_peripheral = 0; gadget_suspend(isp); } isp->otg.state = OTG_STATE_B_IDLE; isp->last_otg_ctrl = OTG_CTRL_REG = OTG_CTRL_REG & OTG_XCEIV_OUTPUTS; pr_debug(" --> %s/%s\n", state_name(isp), tag); }
static int tahvo_usb_set_host(struct otg_transceiver *otg, struct usb_bus *host) { struct tahvo_usb *tu = container_of(otg, struct tahvo_usb, otg); u32 l; dev_dbg(&tu->pt_dev->dev, "set_host %p\n", host); if (otg == NULL) return -ENODEV; #if defined(CONFIG_USB_OTG) || !defined(CONFIG_USB_GADGET_OMAP) mutex_lock(&tu->serialize); if (host == NULL) { if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) tahvo_usb_power_off(tu); tu->otg.host = NULL; mutex_unlock(&tu->serialize); return 0; } l = omap_readl(OTG_SYSCON_1); l &= ~(OTG_IDLE_EN | HST_IDLE_EN | DEV_IDLE_EN); omap_writel(l, OTG_SYSCON_1); if (TAHVO_MODE(tu) == TAHVO_MODE_HOST) { tu->otg.host = NULL; tahvo_usb_become_host(tu); } else host_suspend(tu); tu->otg.host = host; mutex_unlock(&tu->serialize); #else /* No host mode configured, so do not allow host controlled to be set */ return -EINVAL; #endif return 0; }
/* called from irq handlers */ static void a_idle(struct isp1301 *isp, const char *tag) { u32 l; if (isp->otg.state == OTG_STATE_A_IDLE) return; isp->otg.default_a = 1; if (isp->otg.host) { isp->otg.host->is_b_host = 0; host_suspend(isp); } if (isp->otg.gadget) { isp->otg.gadget->is_a_peripheral = 1; gadget_suspend(isp); } isp->otg.state = OTG_STATE_A_IDLE; l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; omap_writel(l, OTG_CTRL); isp->last_otg_ctrl = l; pr_debug(" --> %s/%s\n", state_name(isp), tag); }
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 { u32 l; /* 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; l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; l &= ~OTG_CTRL_BITS; omap_writel(l, OTG_CTRL); 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, __func__); #endif /* FALLTHROUGH */ case OTG_STATE_B_SRP_INIT: b_idle(isp, __func__); l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; omap_writel(l, OTG_CTRL); /* 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, __func__); #endif dump_regs(isp, "isp1301->otg"); }
static void tahvo_usb_stop_host(struct tahvo_usb *tu) { host_suspend(tu); tu->otg.state = OTG_STATE_A_IDLE; }