static void musb_id_pin_work(struct work_struct *data) { //bool is_ready = mtk_musb->is_ready; //u8 opstate = 0; down(&mtk_musb->musb_lock); DBG(0, "work start, is_host=%d\n", mtk_musb->is_host); if(mtk_musb->in_ipo_off) { DBG(0, "do nothing due to in_ipo_off\n"); goto out; } //mtk_musb->is_ready = FALSE; mtk_musb ->is_host = musb_is_host(); DBG(0,"musb is as %s\n",mtk_musb->is_host?"host":"device"); switch_set_state((struct switch_dev *)&otg_state,mtk_musb->is_host); if(mtk_musb ->is_host) { //setup fifo for host mode ep_config_from_table_for_host(mtk_musb); wake_lock(&mtk_musb->usb_lock); ignore_vbuserr = false; musb_set_vbus(mtk_musb,true); musb_start(mtk_musb); switch_int_to_device(); } else { DBG(0,"devctl is %x\n",musb_readb(mtk_musb->mregs,MUSB_DEVCTL)); dumpTime(funcWriteb, 0); musb_writeb(mtk_musb->mregs,MUSB_DEVCTL,0); wake_unlock(&mtk_musb->usb_lock); musb_set_vbus(mtk_musb,FALSE); /* opstate = musb_readb(mtk_musb->mregs,MUSB_OPSTATE); while(opstate != OTG_IDLE) { msleep(10); DBG(1,"wait OTG enter IDLE,opstate is %d\n",opstate); opstate = musb_readb(mtk_musb->mregs,MUSB_OPSTATE); } */ DBG(0,"musb_stop is called\n"); //switch_int_to_host(); // move to musb_stop musb_stop(mtk_musb); } //mtk_musb->is_ready = is_ready; out: DBG(0, "work end, is_host=%d\n", mtk_musb->is_host); up(&mtk_musb->musb_lock); }
int musb_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct musb *musb = hcd_to_musb(hcd); u32 temp; int retval = 0; unsigned long flags; spin_lock_irqsave(&musb->lock, flags); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { spin_unlock_irqrestore(&musb->lock, flags); return -ESHUTDOWN; } /* hub features: always zero, setting is a NOP * port features: reported, sometimes updated when host is active * no indicators */ switch (typeReq) { case ClearHubFeature: case SetHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: break; default: goto error; } break; case ClearPortFeature: if ((wIndex & 0xff) != 1) goto error; switch (wValue) { case USB_PORT_FEAT_ENABLE: break; case USB_PORT_FEAT_SUSPEND: musb_port_suspend(musb, false); break; case USB_PORT_FEAT_POWER: if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) musb_set_vbus(musb, 0); break; case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_SUSPEND: break; default: goto error; } DBG(5, "clear feature %d\n", wValue); musb->port1_status &= ~(1 << wValue); break; case GetHubDescriptor: { struct usb_hub_descriptor *desc = (void *)buf; desc->bDescLength = 9; desc->bDescriptorType = 0x29; desc->bNbrPorts = 1; desc->wHubCharacteristics = cpu_to_le16( 0x0001 /* per-port power switching */ | 0x0010 /* no overcurrent reporting */ ); desc->bPwrOn2PwrGood = 5; /* msec/2 */ desc->bHubContrCurrent = 0; /* workaround bogus struct definition */ desc->DeviceRemovable[0] = 0x02; /* port 1 */ desc->DeviceRemovable[1] = 0xff; } break; case GetHubStatus: temp = 0; *(__le32 *) buf = cpu_to_le32(temp); break; case GetPortStatus: if (wIndex != 1) goto error; /* finish RESET signaling? */ if ((musb->port1_status & USB_PORT_STAT_RESET) && time_after_eq(jiffies, musb->rh_timer)) musb_port_reset(musb, false); /* finish RESUME signaling? */ if ((musb->port1_status & MUSB_PORT_STAT_RESUME) && time_after_eq(jiffies, musb->rh_timer)) { u8 power; power = musb_readb(musb->mregs, MUSB_POWER); power &= ~MUSB_POWER_RESUME; DBG(4, "root port resume stopped, power %02x\n", power); musb_writeb(musb->mregs, MUSB_POWER, power); /* ISSUE: DaVinci (RTL 1.300) disconnects after * resume of high speed peripherals (but not full * speed ones). */ musb->is_active = 1; musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME); musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; usb_hcd_poll_rh_status(musb_to_hcd(musb)); /* NOTE: it might really be A_WAIT_BCON ... */ musb->xceiv->state = OTG_STATE_A_HOST; } put_unaligned(cpu_to_le32(musb->port1_status & ~MUSB_PORT_STAT_RESUME), (__le32 *) buf); /* port change status is more interesting */ DBG(get_unaligned((u16 *)(buf+2)) ? 2 : 5, "port status %08x\n", musb->port1_status); break; case SetPortFeature: if ((wIndex & 0xff) != 1) goto error; switch (wValue) { case USB_PORT_FEAT_POWER: /* NOTE: this controller has a strange state machine * that involves "requesting sessions" according to * magic side effects from incompletely-described * rules about startup... * * This call is what really starts the host mode; be * very careful about side effects if you reorder any * initialization logic, e.g. for OTG, or change any * logic relating to VBUS power-up. */ if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) musb_start(musb); break; case USB_PORT_FEAT_RESET: musb_port_reset(musb, true); break; case USB_PORT_FEAT_SUSPEND: musb_port_suspend(musb, true); break; case USB_PORT_FEAT_TEST: wIndex >>= 8; switch (wIndex) { case 1: pr_debug("TEST_J\n"); temp = MUSB_TEST_J; break; case 2: pr_debug("TEST_K\n"); temp = MUSB_TEST_K; break; case 3: pr_debug("TEST_SE0_NAK\n"); temp = MUSB_TEST_SE0_NAK; break; case 4: pr_debug("TEST_PACKET\n"); temp = MUSB_TEST_PACKET; musb_load_testpacket(musb); break; case 5: pr_debug("TEST_FORCE_ENABLE\n"); temp = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS; musb_writeb(musb->mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); break; case 6: pr_debug("TEST_FIFO_ACCESS\n"); temp = MUSB_TEST_FIFO_ACCESS; break; default: goto error; } musb_writeb(musb->mregs, MUSB_TESTMODE, temp); break; default: goto error; } DBG(5, "set feature %d\n", wValue); musb->port1_status |= 1 << wValue; break; default: error: /* "protocol stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&musb->lock, flags); return retval; }
/* blocking notifier support */ void cpcap_musb_notifier_call(unsigned long event) { struct musb *musb = g_musb; struct device *dev = musb->controller; struct musb_hdrc_platform_data *pdata = dev->platform_data; struct omap_musb_board_data *data = pdata->board_data; static int hostmode; u32 val; u8 power; switch (event) { case USB_EVENT_ID: DBG(1, "ID GND\n"); /* configure musb into smartidle with wakeup enabled * smart standby mode. */ omap_pm_set_max_mpu_wakeup_lat(&pdata->musb_qos_request, 4000); musb_writel(musb->mregs, OTG_FORCESTDBY, 0); val = musb_readl(musb->mregs, OTG_SYSCONFIG); if (cpu_is_omap44xx()) val |= SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP; else val |= SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP; musb_writel(musb->mregs, OTG_SYSCONFIG, val); if (data->interface_type == MUSB_INTERFACE_UTMI) { phy_init(); otg_init(musb->xceiv); /* enable VBUS valid, id groung*/ __raw_writel(AVALID | VBUSVALID, ctrl_base + USBOTGHS_CONTROL); val = __raw_readl(phymux_base + USBA0_OTG_CE_PAD1_USBA0_OTG_DP); val |= DP_WAKEUPENABLE; __raw_writel(val, phymux_base + USBA0_OTG_CE_PAD1_USBA0_OTG_DP); } hostmode = 1; musb_start(musb); musb_set_vbus(musb, 1); break; case USB_EVENT_VBUS: DBG(1, "VBUS Connect\n"); /* configure musb into smartidle with wakeup enabled * smart standby mode. */ musb_writel(musb->mregs, OTG_FORCESTDBY, 0); val = musb_readl(musb->mregs, OTG_SYSCONFIG); if (cpu_is_omap44xx()) val |= SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP; else val |= SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP; musb_writel(musb->mregs, OTG_SYSCONFIG, val); power = musb_readb(musb->mregs, MUSB_POWER); power &= ~MUSB_POWER_SOFTCONN; musb_writeb(musb->mregs, MUSB_POWER, power); if (data->interface_type == MUSB_INTERFACE_UTMI) { phy_init(); otg_init(musb->xceiv); if (!hostmode) { /* Enable VBUS Valid, AValid. Clear SESSEND.*/ __raw_writel(IDDIG | AVALID | VBUSVALID, ctrl_base + USBOTGHS_CONTROL); } } break; case USB_EVENT_NONE: DBG(1, "VBUS Disconnect\n"); if (data->interface_type == MUSB_INTERFACE_UTMI) { /* enable this clock because in suspend interrupt * handler phy clocks are disabled. If phy clocks are * not enabled then DISCONNECT interrupt will not be * reached to mentor */ otg_set_clk(musb->xceiv, 1); __raw_writel(SESSEND | IDDIG, ctrl_base + USBOTGHS_CONTROL); if (musb->xceiv->set_vbus) otg_set_vbus(musb->xceiv, 0); otg_shutdown(musb->xceiv); phy_shutdown(); } /* configure in force idle/ standby */ musb_writel(musb->mregs, OTG_FORCESTDBY, 1); val = musb_readl(musb->mregs, OTG_SYSCONFIG); val &= ~(SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP); val |= FORCEIDLE | FORCESTDBY; musb_writel(musb->mregs, OTG_SYSCONFIG, val); omap_pm_set_max_mpu_wakeup_lat(&pdata->musb_qos_request, -1); if (data->interface_type == MUSB_INTERFACE_UTMI) { val = __raw_readl(phymux_base + USBA0_OTG_CE_PAD1_USBA0_OTG_DP); val &= ~DP_WAKEUPENABLE; __raw_writel(val, phymux_base + USBA0_OTG_CE_PAD1_USBA0_OTG_DP); } if (hostmode) { musb_stop(musb); musb_set_vbus(musb, 0); } hostmode = 0; break; default: DBG(1, "ID float\n"); } }