Ejemplo n.º 1
0
static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
{
	unsigned long   flags;
	irqreturn_t     retval = IRQ_NONE;
	struct musb     *musb = __hci;

	spin_lock_irqsave(&musb->lock, flags);

	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);

	if (musb->int_usb || musb->int_tx || musb->int_rx)
		retval = musb_interrupt(musb);

	spin_unlock_irqrestore(&musb->lock, flags);

	return retval;
}
unsigned int musb_polling_ep0_interrupt(void){
    unsigned short intrtx;
    DBG(0,"polling ep0 interrupt\n");
    do{
        intrtx = musb_readw(mtk_musb->mregs,MUSB_INTRTX);
        mb();
        musb_writew(mtk_musb->mregs,MUSB_INTRTX,intrtx);
        if(intrtx&0x1){//ep0 interrupt happen
            DBG(0,"get ep0 interrupt,csr0=0x%x\n",musb_readw(mtk_musb->mregs, MUSB_OTG_CSR0));
            break;
            }
        else{
            DBG(0,"polling ep0 interrupt,csr0=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_OTG_CSR0));
            wait_for_completion_timeout (&stop_event,1);
            if(!g_exec) return TEST_IS_STOP;
            }
        }
    while(g_exec);
    return 0;
}
Ejemplo n.º 3
0
/**
 * funct_host_notify_timer() - Initialize the timer for USB host driver.
 * @data: usb host data.
 *
 * This function runs the timer for the USB host mode.
 */
static void funct_host_notify_timer(unsigned long data)
{
	if (!cpu_is_u5500()) {
		struct musb	*musb = (struct musb *)data;
		unsigned long	flags;
		u8	devctl;
		spin_lock_irqsave(&musb->lock, flags);

		stm_set_peripheral_clock(PERI5_CLK_ENABLE);

		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

		switch (musb->xceiv->state) {
		case OTG_STATE_A_WAIT_BCON:
			if (devctl & MUSB_DEVCTL_BDEVICE) {
				musb->xceiv->state = OTG_STATE_B_IDLE;
				MUSB_DEV_MODE(musb);
			} else {
				musb->xceiv->state = OTG_STATE_A_IDLE;
				MUSB_HST_MODE(musb);
			}

#ifdef CONFIG_PM
		if (!(devctl & MUSB_DEVCTL_SESSION))
			stm_musb_context(USB_DISABLE);
#endif


		break;
		case OTG_STATE_A_SUSPEND:
		default:
		break;
		}

		stm_set_peripheral_clock(PERI5_CLK_DISABLE);

		spin_unlock_irqrestore(&musb->lock, flags);
		DBG(1, "otg_state %s devctl %d\n", otg_state_string(musb),
			devctl);
	}
}
Ejemplo n.º 4
0
static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
{
	struct musb		*musb = __hci;
	irqreturn_t		retval = IRQ_NONE;

	/* read and flush interrupts */
	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
	if (musb->int_usb)
		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
	if (musb->int_tx)
		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
	if (musb->int_rx)
		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);

	if (musb->int_usb || musb->int_tx || musb->int_rx)
		retval |= musb_interrupt(musb);

	return retval;
}
Ejemplo n.º 5
0
/**
 * musb_platform_set_mode() - Set the mode for the USB driver.
 * @musb: struct musb pointer.
 * @musb_mode: usb mode.
 *
 * This function set the mode for the USB.
 */
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
{
	u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

	devctl |= MUSB_DEVCTL_SESSION;
	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);

	switch (musb_mode) {
	case MUSB_HOST:
		otg_set_host(musb->xceiv, musb->xceiv->host);
		break;
	case MUSB_PERIPHERAL:
		otg_set_peripheral(musb->xceiv, musb->xceiv->gadget);
		break;
	case MUSB_OTG:
		break;
	default:
		return -EINVAL;
	}
	return 0;
}
Ejemplo n.º 6
0
Archivo: da8xx.c Proyecto: 7799/linux
static int da8xx_musb_init(struct musb *musb)
{
	void __iomem *reg_base = musb->ctrl_base;
	u32 rev;
	int ret = -ENODEV;

	musb->mregs += DA8XX_MENTOR_CORE_OFFSET;

	/* Returns zero if e.g. not clocked */
	rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG);
	if (!rev)
		goto fail;

	usb_nop_xceiv_register();
	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
	if (IS_ERR_OR_NULL(musb->xceiv)) {
		ret = -EPROBE_DEFER;
		goto fail;
	}

	setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);

	/* Reset the controller */
	musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);

	/* Start the on-chip PHY and its PLL. */
	phy_on();

	msleep(5);

	/* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */
	pr_debug("DA8xx OTG revision %08x, PHY %03x, control %02x\n",
		 rev, __raw_readl(CFGCHIP2),
		 musb_readb(reg_base, DA8XX_USB_CTRL_REG));

	musb->isr = da8xx_musb_interrupt;
	return 0;
fail:
	return ret;
}
Ejemplo n.º 7
0
static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
{
	u8	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

	devctl |= MUSB_DEVCTL_SESSION;

	/* this bit only works in the b_peripheral state
	 * to start the transition to b_wait_aconn
	 * and would normally be set through as a response
	 * to a b_hnp_enable
	 */

	if (musb_mode == MUSB_HOST) {
		devctl |= MUSB_DEVCTL_HR;
		if (musb->g.is_otg)
			musb->g.b_hnp_enable = 1;
	} else if (musb_mode == MUSB_PERIPHERAL) {
		devctl &= (~MUSB_DEVCTL_HR);
	}
	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
	return 0;
}
Ejemplo n.º 8
0
int __init musb_platform_init(struct musb *musb)
{
    void __iomem	*tibase = musb->ctrl_base;
    u32		revision;

    musb->mregs += DAVINCI_BASE_OFFSET;

    clk_enable(musb->clock);

    /* returns zero if e.g. not clocked */
    revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
    if (revision == 0)
        return -ENODEV;

    if (is_host_enabled(musb))
        setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);

    musb->board_set_vbus = davinci_set_vbus;
    davinci_source_power(musb, 0, 1);

    /* reset the controller */
    musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);

    /* start the on-chip PHY and its PLL */
    phy_on();

    msleep(5);

    /* NOTE:  irqs are in mixed mode, not bypass to pure-musb */
    pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
             revision, __raw_readl((void __force __iomem *)
                                   IO_ADDRESS(USBPHY_CTL_PADDR)),
             musb_readb(tibase, DAVINCI_USB_CTRL_REG));

    musb->isr = davinci_interrupt;
    return 0;
}
Ejemplo n.º 9
0
/**
 * musb_set_session() - Start the USB session
 *
 * This function is used to start the USB sessios in USB host mode
 * once the A cable is plugged in
 */
void musb_set_session(int is_on)
{
	u8 val;
	void __iomem *regs;
	struct musb *musb;

	if (musb_status == NULL) {
		printk(KERN_ERR "Error: devctl session cannot be set\n");
		return;
	}
	musb = musb_status;
	regs = musb_status->mregs;
	val = musb_readb(regs, MUSB_DEVCTL);

	if (is_on)
		musb_writeb(regs, MUSB_DEVCTL, val | MUSB_DEVCTL_SESSION);
	else {
		val &= ~MUSB_DEVCTL_SESSION;
		musb_writeb(regs, MUSB_DEVCTL, val);
		musb->xceiv->state = OTG_STATE_B_IDLE;
		MUSB_DEV_MODE(musb);
	}

}
Ejemplo n.º 10
0
static int davinci_musb_exit(struct musb *musb)
{
	if (is_host_enabled(musb))
		del_timer_sync(&otg_workaround);

	/* force VBUS off */
	if (cpu_is_davinci_dm355()) {
		u32	deepsleep = __raw_readl(DM355_DEEPSLEEP);

		deepsleep &= ~DRVVBUS_FORCE;
		deepsleep |= DRVVBUS_OVERRIDE;
		__raw_writel(deepsleep, DM355_DEEPSLEEP);
	}

	davinci_musb_source_power(musb, 0 /*off*/, 1);

	/* delay, to avoid problems with module reload */
	if (is_host_enabled(musb) && musb->xceiv->default_a) {
		int	maxdelay = 30;
		u8	devctl, warn = 0;

		/* if there's no peripheral connected, this can take a
		 * long time to fall, especially on EVM with huge C133.
		 */
		do {
			devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
			if (!(devctl & MUSB_DEVCTL_VBUS))
				break;
			if ((devctl & MUSB_DEVCTL_VBUS) != warn) {
				warn = devctl & MUSB_DEVCTL_VBUS;
				DBG(1, "VBUS %d\n",
					warn >> MUSB_DEVCTL_VBUS_SHIFT);
			}
			msleep(1000);
			maxdelay--;
		} while (maxdelay > 0);
Ejemplo n.º 11
0
static void musb_port_reset(struct musb *musb, bool do_reset)
{
	u8		power;
	void __iomem	*mbase = musb->mregs;

	if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) {
		dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n");
		musb->port1_status &= ~USB_PORT_STAT_RESET;
		return;
	}

	if (!is_host_enabled(musb))
		return;

	/* NOTE:  caller guarantees it will turn off the reset when
	 * the appropriate amount of time has passed
	 */
	power = musb_readb(mbase, MUSB_POWER);
	if (do_reset) {

		/*
		 * If RESUME is set, we must make sure it stays minimum 20 ms.
		 * Then we must clear RESUME and wait a bit to let musb start
		 * generating SOFs. If we don't do this, OPT HS A 6.8 tests
		 * fail with "Error! Did not receive an SOF before suspend
		 * detected".
		 */
		if (power &  MUSB_POWER_RESUME) {
			while (time_before(jiffies, musb->rh_timer))
				msleep(1);
			musb_writeb(mbase, MUSB_POWER,
				power & ~MUSB_POWER_RESUME);
			msleep(1);
		}

		musb->ignore_disconnect = true;
		power &= 0xf0;
		musb_writeb(mbase, MUSB_POWER,
				power | MUSB_POWER_RESET);

		musb->port1_status |= USB_PORT_STAT_RESET;
		musb->port1_status &= ~USB_PORT_STAT_ENABLE;
		musb->rh_timer = jiffies + msecs_to_jiffies(50);
	} else {
		dev_dbg(musb->controller, "root port reset stopped\n");
		musb_writeb(mbase, MUSB_POWER,
				power & ~MUSB_POWER_RESET);

		musb->ignore_disconnect = false;

		power = musb_readb(mbase, MUSB_POWER);
		if (power & MUSB_POWER_HSMODE) {
			dev_dbg(musb->controller, "high-speed device connected\n");
			musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
		}

		musb->port1_status &= ~USB_PORT_STAT_RESET;
		musb->port1_status |= USB_PORT_STAT_ENABLE
					| (USB_PORT_STAT_C_RESET << 16)
					| (USB_PORT_STAT_C_ENABLE << 16);
		usb_hcd_poll_rh_status(musb_to_hcd(musb));

		musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
	}
}
Ejemplo n.º 12
0
static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
{
	unsigned long	flags;
	irqreturn_t	retval = IRQ_NONE;
	struct musb	*musb = __hci;
	struct usb_otg	*otg = musb->xceiv->otg;
	void __iomem	*tibase = musb->ctrl_base;
	struct cppi	*cppi;
	u32		tmp;

	spin_lock_irqsave(&musb->lock, flags);

	/* NOTE: DaVinci shadows the Mentor IRQs.  Don't manage them through
	 * the Mentor registers (except for setup), use the TI ones and EOI.
	 *
	 * Docs describe irq "vector" registers associated with the CPPI and
	 * USB EOI registers.  These hold a bitmask corresponding to the
	 * current IRQ, not an irq handler address.  Would using those bits
	 * resolve some of the races observed in this dispatch code??
	 */

	/* CPPI interrupts share the same IRQ line, but have their own
	 * mask, state, "vector", and EOI registers.
	 */
	cppi = container_of(musb->dma_controller, struct cppi, controller);
	if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
		retval = cppi_interrupt(irq, __hci);

	/* ack and handle non-CPPI interrupts */
	tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
	musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp);
	dev_dbg(musb->controller, "IRQ %08x\n", tmp);

	musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK)
			>> DAVINCI_USB_RXINT_SHIFT;
	musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK)
			>> DAVINCI_USB_TXINT_SHIFT;
	musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK)
			>> DAVINCI_USB_USBINT_SHIFT;

	/* DRVVBUS irqs are the only proxy we have (a very poor one!) for
	 * DaVinci's missing ID change IRQ.  We need an ID change IRQ to
	 * switch appropriately between halves of the OTG state machine.
	 * Managing DEVCTL.SESSION per Mentor docs requires we know its
	 * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...
	 */
	if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) {
		int	drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG);
		void __iomem *mregs = musb->mregs;
		u8	devctl = musb_readb(mregs, MUSB_DEVCTL);
		int	err = musb->int_usb & MUSB_INTR_VBUSERROR;

		err = musb->int_usb & MUSB_INTR_VBUSERROR;
		if (err) {
			/* The Mentor core doesn't debounce VBUS as needed
			 * to cope with device connect current spikes. This
			 * means it's not uncommon for bus-powered devices
			 * to get VBUS errors during enumeration.
			 *
			 * This is a workaround, but newer RTL from Mentor
			 * seems to allow a better one: "re"starting sessions
			 * without waiting (on EVM, a **long** time) for VBUS
			 * to stop registering in devctl.
			 */
			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
			musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
			WARNING("VBUS error workaround (delay coming)\n");
		} else if (drvvbus) {
			MUSB_HST_MODE(musb);
			otg->default_a = 1;
			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
			del_timer(&otg_workaround);
		} else {
			musb->is_active = 0;
			MUSB_DEV_MODE(musb);
			otg->default_a = 0;
			musb->xceiv->state = OTG_STATE_B_IDLE;
			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
		}

		/* NOTE:  this must complete poweron within 100 msec
		 * (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
		 */
		davinci_musb_source_power(musb, drvvbus, 0);
		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
				drvvbus ? "on" : "off",
				usb_otg_state_string(musb->xceiv->state),
				err ? " ERROR" : "",
				devctl);
		retval = IRQ_HANDLED;
	}

	if (musb->int_tx || musb->int_rx || musb->int_usb)
		retval |= musb_interrupt(musb);

	/* irq stays asserted until EOI is written */
	musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);

	/* poll for ID change */
	if (musb->xceiv->state == OTG_STATE_B_IDLE)
		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);

	spin_unlock_irqrestore(&musb->lock, flags);

	return retval;
}
Ejemplo n.º 13
0
static int davinci_musb_init(struct musb *musb)
{
	void __iomem	*tibase = musb->ctrl_base;
	u32		revision;
	int 		ret = -ENODEV;

	usb_nop_xceiv_register();
	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
	if (IS_ERR_OR_NULL(musb->xceiv)) {
		ret = -EPROBE_DEFER;
		goto unregister;
	}

	musb->mregs += DAVINCI_BASE_OFFSET;

	/* returns zero if e.g. not clocked */
	revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
	if (revision == 0)
		goto fail;

	setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);

	davinci_musb_source_power(musb, 0, 1);

	/* dm355 EVM swaps D+/D- for signal integrity, and
	 * is clocked from the main 24 MHz crystal.
	 */
	if (machine_is_davinci_dm355_evm()) {
		u32	phy_ctrl = __raw_readl(USB_PHY_CTRL);

		phy_ctrl &= ~(3 << 9);
		phy_ctrl |= USBPHY_DATAPOL;
		__raw_writel(phy_ctrl, USB_PHY_CTRL);
	}

	/* On dm355, the default-A state machine needs DRVVBUS control.
	 * If we won't be a host, there's no need to turn it on.
	 */
	if (cpu_is_davinci_dm355()) {
		u32	deepsleep = __raw_readl(DM355_DEEPSLEEP);

		deepsleep &= ~DRVVBUS_FORCE;
		__raw_writel(deepsleep, DM355_DEEPSLEEP);
	}

	/* reset the controller */
	musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);

	/* start the on-chip PHY and its PLL */
	phy_on();

	msleep(5);

	/* NOTE:  irqs are in mixed mode, not bypass to pure-musb */
	pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
		revision, __raw_readl(USB_PHY_CTRL),
		musb_readb(tibase, DAVINCI_USB_CTRL_REG));

	musb->isr = davinci_musb_interrupt;
	return 0;

fail:
	usb_put_phy(musb->xceiv);
unregister:
	usb_nop_xceiv_unregister();
	return ret;
}
Ejemplo n.º 14
0
int __init musb_platform_init(struct musb *musb)
{
	void __iomem	*tibase = musb->ctrl_base;
	u32		revision;

	usb_nop_xceiv_register();
	musb->xceiv = otg_get_transceiver();
	if (!musb->xceiv)
		return -ENODEV;

	musb->mregs += DAVINCI_BASE_OFFSET;

	clk_enable(musb->clock);

	/* returns zero if e.g. not clocked */
	revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
	if (revision == 0)
		goto fail;

	if (is_host_enabled(musb))
		setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);

	musb->board_set_vbus = davinci_set_vbus;
	davinci_source_power(musb, 0, 1);

	/* dm355 EVM swaps D+/D- for signal integrity, and
	 * is clocked from the main 24 MHz crystal.
	 */
	if (machine_is_davinci_dm355_evm()) {
		u32	phy_ctrl = __raw_readl(USB_PHY_CTRL);

		phy_ctrl &= ~(3 << 9);
		phy_ctrl |= USBPHY_DATAPOL;
		__raw_writel(phy_ctrl, USB_PHY_CTRL);
	}

	/* On dm355, the default-A state machine needs DRVVBUS control.
	 * If we won't be a host, there's no need to turn it on.
	 */
	if (cpu_is_davinci_dm355()) {
		u32	deepsleep = __raw_readl(DM355_DEEPSLEEP);

		if (is_host_enabled(musb)) {
			deepsleep &= ~DRVVBUS_OVERRIDE;
		} else {
			deepsleep &= ~DRVVBUS_FORCE;
			deepsleep |= DRVVBUS_OVERRIDE;
		}
		__raw_writel(deepsleep, DM355_DEEPSLEEP);
	}

	/* reset the controller */
	musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1);

	/* start the on-chip PHY and its PLL */
	phy_on();

	msleep(5);

	/* NOTE:  irqs are in mixed mode, not bypass to pure-musb */
	pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n",
		revision, __raw_readl(USB_PHY_CTRL),
		musb_readb(tibase, DAVINCI_USB_CTRL_REG));

	musb->isr = davinci_interrupt;
	return 0;

fail:
	usb_nop_xceiv_unregister();
	return -ENODEV;
}
int musb_otg_exec_cmd(unsigned int cmd){

    unsigned char devctl;
    unsigned char intrusb;
    unsigned short intrtx;
    unsigned char power;
    unsigned short csr0;
    unsigned int usb_l1intp;
    unsigned int usb_l1ints;

    unsigned int ret;
    unsigned long timeout;
    bool timeout_flag = false;

    if(!mtk_musb){
        DBG(0,"mtk_musb is NULL,error!\n");
        }

	switch(cmd){
		case HOST_CMD_ENV_INIT:
    		musb_otg_env_init();
			return 0;
		case HOST_CMD_ENV_EXIT:
			musb_otg_env_exit ();
			return 0;
		}

    //init
    musb_writeb(mtk_musb->mregs, MUSB_POWER, 0x21);
    musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0);
    msleep(300);

    #ifdef DX_DBG
    devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL);
    power = musb_readb (mtk_musb->mregs,MUSB_POWER);
    intrusb = musb_readb(mtk_musb->mregs,MUSB_INTRUSB);
    DBG(0,"1:cmd=%d,devctl=0x%x,power=0x%x,intrusb=0x%x\n",cmd,devctl,power,intrusb);
    #endif
    musb_writew(mtk_musb->mregs,MUSB_INTRRX,0xffff);
    musb_writew(mtk_musb->mregs,MUSB_INTRTX,0xffff);
    musb_writeb(mtk_musb->mregs,MUSB_INTRUSB,0xff);
    msleep(10);
    #ifdef DX_DBG
    devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL);
    power = musb_readb (mtk_musb->mregs,MUSB_POWER);
    intrusb = musb_readb(mtk_musb->mregs,MUSB_INTRUSB);
    DBG(0,"2:cmd=%d,devctl=0x%x,power=0x%x,intrusb=0x%x\n",cmd,devctl,power,intrusb);
    #endif
    high_speed = false;
    g_exec = 1;

	DBG(0,"before exec:cmd=%d\n",cmd);

    switch(cmd){
        //electrical
        case OTG_CMD_E_ENABLE_VBUS:
        		DBG(0,"musb::enable VBUS!\n");
            musb_otg_set_session (true);
	    #ifdef MTK_FAN5405_SUPPORT
	    fan5405_set_opa_mode(1);
	    fan5405_set_otg_pl(1);
	    fan5405_set_otg_en(1);
            #elif defined(MTK_BQ24158_SUPPORT) 
            bq24158_set_opa_mode(1);
	    bq24158_set_otg_pl(1);
	    bq24158_set_otg_en(1);
	    #endif
            while(g_exec)
                msleep(100);
            musb_otg_set_session (false);
	    #ifdef MTK_FAN5405_SUPPORT
	    fan5405_config_interface_liao(0x01,0x30);
	    fan5405_config_interface_liao(0x02,0x8e);
            #elif defined(MTK_BQ24158_SUPPORT)
            bq24158_config_interface_reg(0x01,0x30);
	    bq24158_config_interface_reg(0x02,0x8e);
	    #endif
            break;
        case OTG_CMD_E_ENABLE_SRP: //need to clear session?
            DBG(0,"musb::enable srp!\n");
            musb_otg_reset_usb();
            USBPHY_WRITE8 (0x6c, 0x1);
            USBPHY_WRITE8 (0x6d, 0x1);
            musb_writeb(mtk_musb->mregs,0x7B,1);
            musb_otg_set_session (true);
            while(g_exec){
                msleep(100);
                }
            musb_otg_set_session (false);
            break;
        case OTG_CMD_E_START_DET_SRP:
            //need as a A-device
            musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0);
            devctl = musb_readb (mtk_musb->mregs, MUSB_DEVCTL);
             while(g_exec&&(devctl & 0x18)){//VBUS[1:0] should be 0, it indicate below SessionEnd
                DBG(0,"musb::not below session end!\n");
                msleep(100);
                devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL);
                }
            while(g_exec&&(!(devctl & 0x10))){
                DBG(0,"musb::not above session end!\n");
                msleep(100);
                devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL);
                }
            devctl |= MUSB_DEVCTL_SESSION;
            musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, devctl);
            while(g_exec)
                msleep(100);
            musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0);
            break;
        case OTG_CMD_E_START_DET_VBUS:
            usb_l1intp = musb_readl(mtk_musb->mregs,USB_L1INTP);
            usb_l1intp &= ~(1<<10);
            musb_writel(mtk_musb->mregs,USB_L1INTP,usb_l1intp);
            usb_l1ints = musb_readl(mtk_musb->mregs,USB_L1INTS);
            while((usb_l1ints&(1<<8))==0){
                DBG(0,"musb::vbus is 0!\n");
                msleep(100);
                usb_l1ints = musb_readl(mtk_musb->mregs,USB_L1INTS);
                }
            DBG(0,"musb::vbus is detected!\n");
            power = musb_readb (mtk_musb->mregs,MUSB_POWER);
            power |= MUSB_POWER_SOFTCONN;
            musb_writeb(mtk_musb->mregs, MUSB_POWER, power);
            while(g_exec)
                 msleep(100);
            musb_writeb(mtk_musb->mregs, MUSB_POWER, 0x21);
            break;

		case OTG_CMD_P_B_UUT_TD59:
			is_td_59 = true;
			if(is_td_59) DBG(0, "TD5.9 will be tested!\n");
			break;

        //protocal
        case OTG_CMD_P_A_UUT:
			DBG(0,"A-UUT starts...\n");
            //polling the session req from B-OPT and start a new session
            device_enumed = false;
TD_4_6:
            musb_otg_reset_usb();
			DBG(0,"A-UUT reset success\n");
            timeout = jiffies + 5*HZ;
            musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0);
            devctl = musb_readb (mtk_musb->mregs, MUSB_DEVCTL);
            while(g_exec&&(devctl & 0x18)){//VBUS[1:0] should be 0, it indicate below SessionEnd
                DBG(0,"musb::not below session end!\n");
                msleep(100);
                if(time_after(jiffies,timeout)){
                    timeout_flag = true;
                    break;
                    }
                devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL);
                }
            if(timeout_flag){
                timeout_flag = false;
                musb_otg_reset_usb();
                DBG(0,"timeout for below session end, after reset usb, devctl=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_DEVCTL));
                }
            DBG(0,"polling session request,begin\n");
            ret = musb_polling_bus_interrupt(MUSB_INTR_SESSREQ);
            DBG(0,"polling session request,done,ret=0x%x\n",ret);
            if(TEST_IS_STOP == ret) break;
            musb_otg_set_session(true);//session is set and VBUS will be out.
            #if 1
            power = musb_readb(mtk_musb->mregs,MUSB_POWER);
            power &= ~MUSB_POWER_SOFTCONN;
            musb_writeb(mtk_musb->mregs,MUSB_POWER,power);
            #endif
            //polling the connect interrupt from B-OPT
            DBG(0,"polling connect interrupt,begin\n");
            ret = musb_polling_bus_interrupt(MUSB_INTR_CONNECT);
            DBG(0,"polling connect interrupt,done,ret=0x%x\n",ret);
            if(TEST_IS_STOP == ret) break;
            if(DEV_NOT_CONNECT == ret){
                DBG(0,"device is not connected in 15s\n");
                g_otg_message.msg = OTG_MSG_DEV_NOT_RESPONSE;
                break;
                }
            DBG(0,"musb::connect interrupt is detected!\n");
            msleep(100);//the test is fail beacuse the reset starts less than100 ms from the B-OPT connect. the IF test needs
            //reset the bus,check whether it is a hs device
            musb_h_reset();//should last for more than 50ms, TD.4.2
            musb_h_enumerate();
            //suspend the bus
            csr0 = musb_readw(mtk_musb->mregs, MUSB_OTG_CSR0);
            DBG(0,"after enum B-OPT,csr0=0x%x\n",csr0);
            musb_h_suspend();

            //polling the disconnect interrupt from B-OPT, and remote wakeup(TD.4.8)
            DBG(0,"polling disconnect or remote wakeup,begin\n");
            ret = musb_polling_bus_interrupt(MUSB_INTR_DISCONNECT|MUSB_INTR_RESUME);
            DBG(0,"polling disconnect or remote wakeup,done,ret=0x%x\n",ret);
            if(TEST_IS_STOP == ret) break;
            if(MUSB_INTR_RESUME == ret){
                //for TD4.8
                musb_h_remote_wakeup();
                //maybe need to access the B-OPT, get device descriptor
                if(g_exec)
                    wait_for_completion (&stop_event);
                break;
                }
            //polling the reset interrupt from B-OPT
            if(!(ret & MUSB_INTR_RESET)){
                DBG(0,"polling reset for B-OPT,begin\n");
                ret = musb_polling_bus_interrupt(MUSB_INTR_RESET);
                DBG(0,"polling reset for B-OPT,done,ret=0x%x\n",ret);
                if(TEST_IS_STOP == ret) break;
                if(DEV_NOT_RESET == ret){
                    if(g_exec)
                        wait_for_completion (&stop_event);
                    break;
                    }
                }

            DBG(0,"after receive reset,devctl=0x%x,csr0=0x%x\n",musb_readb(mtk_musb->mregs, MUSB_DEVCTL),musb_readw(mtk_musb->mregs, MUSB_OTG_CSR0));

            //enumerate and polling the suspend interrupt form B-OPT

            do{
                intrtx = musb_readw(mtk_musb->mregs, MUSB_INTRTX);
                mb();
                musb_writew(mtk_musb->mregs, MUSB_INTRTX, intrtx);
                intrusb = musb_readb(mtk_musb->mregs, MUSB_INTRUSB);
                mb();
                musb_writeb(mtk_musb->mregs, MUSB_INTRUSB,intrusb);
                if(intrtx || (intrusb&MUSB_INTR_SUSPEND)){
                    if(intrtx){
                        if(intrtx&0x1)
                            musb_d_enumerated();
                        }
                    if(intrusb){
                        if(intrusb&MUSB_INTR_SUSPEND){//maybe receive disconnect interrupt when the session is end
                            if(device_enumed){
                                break;//return form the while loop
                                }
                            else{//TD.4.6
                                musb_d_soft_connect (false);
                                goto TD_4_6;
                                }
                            }
                        }
                    }
                else
                    wait_for_completion_timeout(&stop_event,1);
                }
            while(g_exec);//the enum will be repeated for 5 times
            if(!g_exec){
                break;//return form the switch-case
                }
            DBG(0,"polling connect form B-OPT,begin\n");
            ret = musb_polling_bus_interrupt(MUSB_INTR_CONNECT);//B-OPT will connect again 100ms after A disconnect
            DBG(0,"polling connect form B-OPT,done,ret=0x%x\n",ret);
            if(TEST_IS_STOP == ret) break;
            musb_h_reset();//should reset bus again, TD.4.7
            wait_for_completion (&stop_event);
            DBG(0,"the test as A-UUT is done\n");
            break;

        case OTG_CMD_P_B_UUT:
            musb_otg_reset_usb();
            //The B-UUT issues an SRP to start a session with the A-OPT
            musb_otg_set_session (true);
            //100ms after VBUS begins to decay the A-OPT powers VBUS
            timeout = jiffies + 5 * HZ;
            devctl = musb_readb (mtk_musb->mregs, MUSB_DEVCTL);

            while(((devctl & MUSB_DEVCTL_VBUS)>>MUSB_DEVCTL_VBUS_SHIFT)<0x3){
                if(time_after(jiffies, timeout)){
                    timeout_flag = true;
                    break;
                    }
                msleep(100);
                devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL);
                }
            if(timeout_flag){
				DBG(0,"B-UUT set vbus timeout\n");
                g_otg_message.msg = OTG_MSG_DEV_NOT_RESPONSE;
                timeout_flag = false;
                break;
                }

            //After detecting the VBUS, B-UUT should connect to the A_OPT
            power = musb_readb(mtk_musb->mregs, MUSB_POWER);
            power |= MUSB_POWER_HSENAB;
            musb_writeb(mtk_musb->mregs, MUSB_POWER,power);
//TD5_5:
            musb_d_soft_connect(true);

            device_enumed = false;
            //polling the reset single form the A-OPT
            DBG(0,"polling reset form A-OPT,begin\n");
            ret = musb_polling_bus_interrupt(MUSB_INTR_RESET);
            DBG(0,"polling reset form A-OPT,done,ret=0x%x\n",ret);
            if(TEST_IS_STOP == ret) break;
            power = musb_readb(mtk_musb->mregs,MUSB_POWER);
            if(power & MUSB_POWER_HSMODE){
                high_speed = true;
            	}
            else
                high_speed = false;
            //The A-OPT enumerates the B-UUT
TD6_13:     do{
                intrtx = musb_readw(mtk_musb->mregs, MUSB_INTRTX);
                mb();
                musb_writew(mtk_musb->mregs, MUSB_INTRTX,intrtx);
                intrusb = musb_readb(mtk_musb->mregs, MUSB_INTRUSB);
                mb();
                musb_writeb(mtk_musb->mregs, MUSB_INTRUSB,intrusb);
                if(intrtx || (intrusb & 0xf7)){
                    if(intrtx){
                        //DBG(0,"B-enum,intrtx=0x%x\n",intrtx);
                        if(intrtx&0x1)
                            DBG(0,"ep0 interrupt\n");
                            musb_d_enumerated();
                        }
                    if(intrusb){
                        if(intrusb & 0xf7)
                            DBG(0,"B-enum,intrusb=0x%x,power=0x%x\n",intrusb,musb_readb(mtk_musb->mregs,MUSB_POWER));
                        if((device_enumed)&&(intrusb & MUSB_INTR_SUSPEND)){
                            DBG(0,"suspend interrupt is received,power=0x%x,devctl=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),musb_readb(mtk_musb->mregs,MUSB_DEVCTL));
                            break;
                            }
                        }
                    }
                else{
                    DBG(0,"power=0x%x,devctl=0x%x,intrtx=0x%x,intrusb=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),musb_readb(mtk_musb->mregs,MUSB_DEVCTL),musb_readw(mtk_musb->mregs,MUSB_INTRTX),musb_readb(mtk_musb->mregs,MUSB_INTRUSB));
                    wait_for_completion_timeout (&stop_event,1);
                    }
                }
            while(g_exec);
            if(!g_exec) break;
            DBG(0,"hnp start\n");
            if(intrusb & MUSB_INTR_RESUME)
                goto TD6_13;
            if(!(intrusb & MUSB_INTR_CONNECT)){
                //polling the connect from A-OPT, the UUT acts as host
                DBG(0,"polling connect or resume form A-OPT,begin\n");
                ret = musb_polling_bus_interrupt(MUSB_INTR_CONNECT|MUSB_INTR_RESUME);
                DBG(0,"polling connect or resume form A-OPT,done,ret=0x%x\n",ret);
                if(TEST_IS_STOP == ret) break;
                if(MUSB_INTR_RESUME == ret){
                    goto TD6_13;
                    }
                if(DEV_HNP_TIMEOUT == ret){
					DBG(0,"B-UUT HNP timeout\n");
                    devctl = musb_readb(mtk_musb->mregs,MUSB_DEVCTL);
                    //DBG(0,"hnp timeout,power=0x%x,devctl=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),devctl);
                    devctl &= ~MUSB_DEVCTL_HR;
                    musb_writeb(mtk_musb->mregs,MUSB_DEVCTL,devctl);
					if(is_td_59)
						g_otg_message.msg = OTG_MSG_DEV_NOT_RESPONSE;
                    break;
                    }
                }
            //reset the bus and check whether it is a hs device
            musb_h_reset();
            musb_h_enumerate();
            //suspend the bus
            musb_h_suspend();
            //polling the disconnect interrupt from A-OPT
            DBG(0,"polling disconnect form A-OPT,begin\n");
            ret = musb_polling_bus_interrupt(MUSB_INTR_DISCONNECT);
            DBG(0,"polling disconnect form A-OPT,done,ret=0x%x\n",ret);
            //DBG(0,"power=0x%x,devctl=0x%x,intrusb=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),musb_readb(mtk_musb->mregs,MUSB_DEVCTL),musb_readb(mtk_musb->mregs,MUSB_INTRUSB));
            if(TEST_IS_STOP == ret) break;
            DBG(0,"A-OPT is disconnected, UUT will be back to device\n");
            if(!(ret & MUSB_INTR_RESET)){
                musb_d_soft_connect(true);
                //polling the reset single form the A-OPT
                DBG(0,"polling reset form A-OPT,begin\n");
                ret = musb_polling_bus_interrupt(MUSB_INTR_RESET);
                //musb_d_reset ();
                DBG(0,"polling reset form A-OPT,done,ret=0x%x\n",ret);
                if(TEST_IS_STOP == ret) break;
                }
            device_enumed = false;
            if(g_exec)
                goto TD6_13;//TD5_5
            wait_for_completion(&stop_event);
            DBG(0,"test as B_UUT is done\n");
            break;

       	case HOST_CMD_TEST_SE0_NAK:
       	case HOST_CMD_TEST_J:
       	case HOST_CMD_TEST_K:
       	case HOST_CMD_TEST_PACKET:
       	case HOST_CMD_SUSPEND_RESUME:
       	case HOST_CMD_GET_DESCRIPTOR:
       	case HOST_CMD_SET_FEATURE:
       		musb_host_test_mode(cmd);
       		while(g_exec)
                msleep(100);
       		break;
        }
    DBG(0,"musb_otg_exec_cmd--\n");
    return 0;

}
Ejemplo n.º 16
0
void musb_port_reset(struct musb *musb, bool do_reset)
{
	u8		power;
	void __iomem	*mbase = musb->mregs;

	if (musb->xceiv->state == OTG_STATE_B_IDLE) {
		dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n");
		musb->port1_status &= ~USB_PORT_STAT_RESET;
		return;
	}

	if (!is_host_active(musb))
		return;

	/* NOTE:  caller guarantees it will turn off the reset when
	 * the appropriate amount of time has passed
	 */
	power = musb_readb(mbase, MUSB_POWER);
	if (do_reset) {
		/*
		 * If RESUME is set, we must make sure it stays minimum 20 ms.
		 * Then we must clear RESUME and wait a bit to let musb start
		 * generating SOFs. If we don't do this, OPT HS A 6.8 tests
		 * fail with "Error! Did not receive an SOF before suspend
		 * detected".
		 */
		if (power &  MUSB_POWER_RESUME) {
			long remain = (unsigned long) musb->rh_timer - jiffies;

			if (musb->rh_timer > 0 && remain > 0) {
				/* take into account the minimum delay after resume */
				schedule_delayed_work(
					&musb->deassert_reset_work, remain);
				return;
			}

			musb_writeb(mbase, MUSB_POWER,
				    power & ~MUSB_POWER_RESUME);

			/* Give the core 1 ms to clear MUSB_POWER_RESUME */
			schedule_delayed_work(&musb->deassert_reset_work,
					      msecs_to_jiffies(1));
			return;
		}

		power &= 0xf0;
		musb_writeb(mbase, MUSB_POWER,
				power | MUSB_POWER_RESET);

		musb->port1_status |= USB_PORT_STAT_RESET;
		musb->port1_status &= ~USB_PORT_STAT_ENABLE;
		schedule_delayed_work(&musb->deassert_reset_work,
				      msecs_to_jiffies(50));
	} else {
		dev_dbg(musb->controller, "root port reset stopped\n");
		musb_writeb(mbase, MUSB_POWER,
				power & ~MUSB_POWER_RESET);

		power = musb_readb(mbase, MUSB_POWER);
		if (power & MUSB_POWER_HSMODE) {
			dev_dbg(musb->controller, "high-speed device connected\n");
			musb->port1_status |= USB_PORT_STAT_HIGH_SPEED;
		}

		musb->port1_status &= ~USB_PORT_STAT_RESET;
		musb->port1_status |= USB_PORT_STAT_ENABLE
					| (USB_PORT_STAT_C_RESET << 16)
					| (USB_PORT_STAT_C_ENABLE << 16);
		usb_hcd_poll_rh_status(musb->hcd);

		musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
	}
}
Ejemplo n.º 17
0
static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
{
	struct musb		*musb = hci;
	void __iomem		*reg_base = musb->ctrl_base;
	struct usb_otg		*otg = musb->xceiv->otg;
	unsigned long		flags;
	irqreturn_t		ret = IRQ_NONE;
	u32			status;

	spin_lock_irqsave(&musb->lock, flags);

	/*
	 * NOTE: DA8XX shadows the Mentor IRQs.  Don't manage them through
	 * the Mentor registers (except for setup), use the TI ones and EOI.
	 */

	/* Acknowledge and handle non-CPPI interrupts */
	status = musb_readl(reg_base, DA8XX_USB_INTR_SRC_MASKED_REG);
	if (!status)
		goto eoi;

	musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status);
	dev_dbg(musb->controller, "USB IRQ %08x\n", status);

	musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT;
	musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT;
	musb->int_usb = (status & DA8XX_INTR_USB_MASK) >> DA8XX_INTR_USB_SHIFT;

	/*
	 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
	 * DA8xx's missing ID change IRQ.  We need an ID change IRQ to
	 * switch appropriately between halves of the OTG state machine.
	 * Managing DEVCTL.Session per Mentor docs requires that we know its
	 * value but DEVCTL.BDevice is invalid without DEVCTL.Session set.
	 * Also, DRVVBUS pulses for SRP (but not at 5 V)...
	 */
	if (status & (DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT)) {
		int drvvbus = musb_readl(reg_base, DA8XX_USB_STAT_REG);
		void __iomem *mregs = musb->mregs;
		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
		int err;

		err = musb->int_usb & MUSB_INTR_VBUSERROR;
		if (err) {
			/*
			 * The Mentor core doesn't debounce VBUS as needed
			 * to cope with device connect current spikes. This
			 * means it's not uncommon for bus-powered devices
			 * to get VBUS errors during enumeration.
			 *
			 * This is a workaround, but newer RTL from Mentor
			 * seems to allow a better one: "re"-starting sessions
			 * without waiting for VBUS to stop registering in
			 * devctl.
			 */
			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
			WARNING("VBUS error workaround (delay coming)\n");
		} else if (drvvbus) {
			MUSB_HST_MODE(musb);
			otg->default_a = 1;
			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
			portstate(musb->port1_status |= USB_PORT_STAT_POWER);
			del_timer(&otg_workaround);
		} else {
			musb->is_active = 0;
			MUSB_DEV_MODE(musb);
			otg->default_a = 0;
			musb->xceiv->otg->state = OTG_STATE_B_IDLE;
			portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
		}

		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
				drvvbus ? "on" : "off",
				usb_otg_state_string(musb->xceiv->otg->state),
				err ? " ERROR" : "",
				devctl);
		ret = IRQ_HANDLED;
	}

	if (musb->int_tx || musb->int_rx || musb->int_usb)
		ret |= musb_interrupt(musb);

 eoi:
	/* EOI needs to be written for the IRQ to be re-asserted. */
	if (ret == IRQ_HANDLED || status)
		musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);

	/* Poll for ID change */
	if (musb->xceiv->otg->state == OTG_STATE_B_IDLE)
		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);

	spin_unlock_irqrestore(&musb->lock, flags);

	return ret;
}
Ejemplo n.º 18
0
static irqreturn_t dsps_interrupt(int irq, void *hci)
{
	struct musb  *musb = hci;
	void __iomem *reg_base = musb->ctrl_base;
	struct device *dev = musb->controller;
	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
	const struct dsps_musb_wrapper *wrp = glue->wrp;
	unsigned long flags;
	irqreturn_t ret = IRQ_NONE;
	u32 epintr, usbintr;

	spin_lock_irqsave(&musb->lock, flags);

	/* Get endpoint interrupts */
	epintr = musb_readl(reg_base, wrp->epintr_status);
	musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
	musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;

	if (epintr)
		musb_writel(reg_base, wrp->epintr_status, epintr);

	/* Get usb core interrupts */
	usbintr = musb_readl(reg_base, wrp->coreintr_status);
	if (!usbintr && !epintr)
		goto out;

	musb->int_usb =	(usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
	if (usbintr)
		musb_writel(reg_base, wrp->coreintr_status, usbintr);

	dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
			usbintr, epintr);

	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
		int drvvbus = musb_readl(reg_base, wrp->status);
		void __iomem *mregs = musb->mregs;
		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
		int err;

		err = musb->int_usb & MUSB_INTR_VBUSERROR;
		if (err) {
			/*
			 * The Mentor core doesn't debounce VBUS as needed
			 * to cope with device connect current spikes. This
			 * means it's not uncommon for bus-powered devices
			 * to get VBUS errors during enumeration.
			 *
			 * This is a workaround, but newer RTL from Mentor
			 * seems to allow a better one: "re"-starting sessions
			 * without waiting for VBUS to stop registering in
			 * devctl.
			 */
			musb->int_usb &= ~MUSB_INTR_VBUSERROR;
			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL;
			dsps_mod_timer_optional(glue);
			WARNING("VBUS error workaround (delay coming)\n");
		} else if (drvvbus) {
			MUSB_HST_MODE(musb);
			musb->xceiv->otg->default_a = 1;
			musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
			dsps_mod_timer_optional(glue);
		} else {
			musb->is_active = 0;
			MUSB_DEV_MODE(musb);
			musb->xceiv->otg->default_a = 0;
			musb->xceiv->otg->state = OTG_STATE_B_IDLE;
		}

		/* NOTE: this must complete power-on within 100 ms. */
		dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
				drvvbus ? "on" : "off",
				usb_otg_state_string(musb->xceiv->otg->state),
				err ? " ERROR" : "",
				devctl);
		ret = IRQ_HANDLED;
	}

	if (musb->int_tx || musb->int_rx || musb->int_usb)
		ret |= musb_interrupt(musb);

	/* Poll for ID change and connect */
	switch (musb->xceiv->otg->state) {
	case OTG_STATE_B_IDLE:
	case OTG_STATE_A_WAIT_BCON:
		dsps_mod_timer_optional(glue);
		break;
	default:
		break;
	}

out:
	spin_unlock_irqrestore(&musb->lock, flags);

	return ret;
}
Ejemplo n.º 19
0
static int dsps_musb_init(struct musb *musb)
{
	struct device *dev = musb->controller;
	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
	struct platform_device *parent = to_platform_device(dev->parent);
	const struct dsps_musb_wrapper *wrp = glue->wrp;
	void __iomem *reg_base;
	struct resource *r;
	u32 rev, val;
	int ret;

	r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
	reg_base = devm_ioremap_resource(dev, r);
	if (IS_ERR(reg_base))
		return PTR_ERR(reg_base);
	musb->ctrl_base = reg_base;

	/* NOP driver needs change if supporting dual instance */
	musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "phys", 0);
	if (IS_ERR(musb->xceiv))
		return PTR_ERR(musb->xceiv);

	musb->phy = devm_phy_get(dev->parent, "usb2-phy");

	/* Returns zero if e.g. not clocked */
	rev = musb_readl(reg_base, wrp->revision);
	if (!rev)
		return -ENODEV;

	if (IS_ERR(musb->phy))  {
		musb->phy = NULL;
	} else {
		ret = phy_init(musb->phy);
		if (ret < 0)
			return ret;
		ret = phy_power_on(musb->phy);
		if (ret) {
			phy_exit(musb->phy);
			return ret;
		}
	}

	timer_setup(&musb->dev_timer, otg_timer, 0);

	/* Reset the musb */
	musb_writel(reg_base, wrp->control, (1 << wrp->reset));

	musb->isr = dsps_interrupt;

	/* reset the otgdisable bit, needed for host mode to work */
	val = musb_readl(reg_base, wrp->phy_utmi);
	val &= ~(1 << wrp->otg_disable);
	musb_writel(musb->ctrl_base, wrp->phy_utmi, val);

	/*
	 *  Check whether the dsps version has babble control enabled.
	 * In latest silicon revision the babble control logic is enabled.
	 * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control
	 * logic enabled.
	 */
	val = musb_readb(musb->mregs, MUSB_BABBLE_CTL);
	if (val & MUSB_BABBLE_RCV_DISABLE) {
		glue->sw_babble_enabled = true;
		val |= MUSB_BABBLE_SW_SESSION_CTRL;
		musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val);
	}

	dsps_mod_timer(glue, -1);

	return dsps_musb_dbg_init(musb, glue);
}
Ejemplo n.º 20
0
static void musb_port_suspend(struct musb *musb, bool do_suspend)
{
	u8		power;
	void __iomem	*mbase = musb->mregs;
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *plat = dev->platform_data;
	struct omap_musb_board_data *data = plat->board_data;

	if (!is_host_active(musb))
		return;

	/* NOTE:  this doesn't necessarily put PHY into low power mode,
	 * turning off its clock; that's a function of PHY integration and
	 * MUSB_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
	 * SE0 changing to connect (J) or wakeup (K) states.
	 */
	power = musb_readb(mbase, MUSB_POWER);
	if (do_suspend) {
		int retries = 10000;

		power &= ~MUSB_POWER_RESUME;
		power |= MUSB_POWER_SUSPENDM;
		if (data->interface_type == MUSB_INTERFACE_UTMI)
			power |= MUSB_POWER_ENSUSPEND;
		musb_writeb(mbase, MUSB_POWER, power);

		/* Needed for OPT A tests */
		power = musb_readb(mbase, MUSB_POWER);
		while (power & MUSB_POWER_SUSPENDM) {
			power = musb_readb(mbase, MUSB_POWER);
			if (retries-- < 1)
				break;
		}

		DBG(3, "Root port suspended, power %02x\n", power);

		musb->port1_status |= USB_PORT_STAT_SUSPEND;
		switch (musb->xceiv->state) {
		case OTG_STATE_A_HOST:
			musb->xceiv->state = OTG_STATE_A_SUSPEND;
			musb->is_active = is_otg_enabled(musb)
					&& musb->xceiv->host->b_hnp_enable;
			if (musb->is_active)
				mod_timer(&musb->otg_timer, jiffies
					+ msecs_to_jiffies(
						OTG_TIME_A_AIDL_BDIS));
			musb_platform_try_idle(musb, 0);
			/*
			 * disable the phy clock when the device is supended.
			 * this will allow the core retention
			 */
			otg_set_clk(musb->xceiv, 0);
			break;
#ifdef	CONFIG_USB_MUSB_OTG
		case OTG_STATE_B_HOST:
			musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
			musb->is_active = is_otg_enabled(musb)
					&& musb->xceiv->host->b_hnp_enable;
			musb_platform_try_idle(musb, 0);
			break;
#endif
		default:
			DBG(1, "bogus rh suspend? %s\n",
				otg_state_string(musb));
		}
	} else if (power & MUSB_POWER_SUSPENDM) {
		power &= ~MUSB_POWER_SUSPENDM;
		if (data->interface_type == MUSB_INTERFACE_UTMI)
			power &= ~MUSB_POWER_ENSUSPEND;
		power |= MUSB_POWER_RESUME;
		musb_writeb(mbase, MUSB_POWER, power);

		otg_set_clk(musb->xceiv, 1);
		DBG(3, "Root port resuming, power %02x\n", power);

		/* later, GetPortStatus will stop RESUME signaling */
		musb->port1_status |= MUSB_PORT_STAT_RESUME;
		musb->rh_timer = jiffies + msecs_to_jiffies(20);
	}
}
Ejemplo n.º 21
0
/* Caller must take musb->lock */
static int dsps_check_status(struct musb *musb, void *unused)
{
	void __iomem *mregs = musb->mregs;
	struct device *dev = musb->controller;
	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
	const struct dsps_musb_wrapper *wrp = glue->wrp;
	u8 devctl;
	int skip_session = 0;

	if (glue->vbus_irq)
		del_timer(&musb->dev_timer);

	/*
	 * We poll because DSPS IP's won't expose several OTG-critical
	 * status change events (from the transceiver) otherwise.
	 */
	devctl = musb_readb(mregs, MUSB_DEVCTL);
	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
				usb_otg_state_string(musb->xceiv->otg->state));

	switch (musb->xceiv->otg->state) {
	case OTG_STATE_A_WAIT_VRISE:
		dsps_mod_timer_optional(glue);
		break;
	case OTG_STATE_A_WAIT_BCON:
		/* keep VBUS on for host-only mode */
		if (musb->port_mode == MUSB_PORT_MODE_HOST) {
			dsps_mod_timer_optional(glue);
			break;
		}
		musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
		skip_session = 1;
		/* fall */

	case OTG_STATE_A_IDLE:
	case OTG_STATE_B_IDLE:
		if (!glue->vbus_irq) {
			if (devctl & MUSB_DEVCTL_BDEVICE) {
				musb->xceiv->otg->state = OTG_STATE_B_IDLE;
				MUSB_DEV_MODE(musb);
			} else {
				musb->xceiv->otg->state = OTG_STATE_A_IDLE;
				MUSB_HST_MODE(musb);
			}
			if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session)
				musb_writeb(mregs, MUSB_DEVCTL,
					    MUSB_DEVCTL_SESSION);
		}
		dsps_mod_timer_optional(glue);
		break;
	case OTG_STATE_A_WAIT_VFALL:
		musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
		musb_writel(musb->ctrl_base, wrp->coreintr_set,
			    MUSB_INTR_VBUSERROR << wrp->usb_shift);
		break;
	default:
		break;
	}

	return 0;
}
Ejemplo n.º 22
0
static irqreturn_t dma_controller_irq(int irq, void *private_data)
{
	struct musb_dma_controller *controller = private_data;
	struct musb *musb = controller->private_data;
	struct musb_dma_channel *musb_channel;
	struct dma_channel *channel;

	void __iomem *mbase = controller->base;

	irqreturn_t retval = IRQ_NONE;

	unsigned long flags;

	u8 bchannel;
	u8 int_hsdma;

	u32 addr;
	u16 csr, count;

	spin_lock_irqsave(&musb->lock, flags);

	int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
	if (!int_hsdma) {
		DBG(2, "spurious DMA irq\n");

		for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
			musb_channel = (struct musb_dma_channel *)
					&(controller->channel[bchannel]);
			channel = &musb_channel->channel;
			if (channel->status == MUSB_DMA_STATUS_BUSY) {
				count = musb_readw(mbase,
					MUSB_HSDMA_CHANNEL_OFFSET(bchannel,
							MUSB_HSDMA_COUNT));
				if (count == 0)
					int_hsdma |= (1 << bchannel);
			}
		}

		DBG(2, "int_hsdma = 0x%x\n", int_hsdma);

		if (!int_hsdma)
			goto done;
	}

	for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
		if (int_hsdma & (1 << bchannel)) {
			musb_channel = (struct musb_dma_channel *)
					&(controller->channel[bchannel]);
			channel = &musb_channel->channel;

			csr = musb_readw(mbase,
					MUSB_HSDMA_CHANNEL_OFFSET(bchannel,
							MUSB_HSDMA_CONTROL));

			if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) {
				musb_channel->channel.status =
					MUSB_DMA_STATUS_BUS_ABORT;
			} else {
				u8 devctl;

				addr = musb_read_hsdma_addr(mbase,
						bchannel);
				channel->actual_len = addr
					- musb_channel->start_addr;

				DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n",
					channel, musb_channel->start_addr,
					addr, channel->actual_len,
					musb_channel->len,
					(channel->actual_len
						< musb_channel->len) ?
					"=> reconfig 0" : "=> complete");

				devctl = musb_readb(mbase, MUSB_DEVCTL);

				channel->status = MUSB_DMA_STATUS_FREE;

				if (musb_channel->transmit)
					controller->tx_active &=
							~(1 << bchannel);
				else
					controller->rx_active &=
							~(1 << bchannel);

				/* completed */
				if ((devctl & MUSB_DEVCTL_HM)
					&& (musb_channel->transmit)
					&& ((channel->desired_mode == 0)
					    || (channel->actual_len &
					    (musb_channel->max_packet_sz - 1)))
				    ) {
					u8  epnum  = musb_channel->epnum;
					int offset = MUSB_EP_OFFSET(epnum,
								    MUSB_TXCSR);
					u16 txcsr;

					/*
					 * The programming guide says that we
					 * must clear DMAENAB before DMAMODE.
					 */
					musb_ep_select(mbase, epnum);
					txcsr = musb_readw(mbase, offset);
					txcsr &= ~(MUSB_TXCSR_DMAENAB
							| MUSB_TXCSR_AUTOSET);
					musb_writew(mbase, offset, txcsr);
					/* Send out the packet */
					txcsr &= ~MUSB_TXCSR_DMAMODE;
					txcsr |=  MUSB_TXCSR_TXPKTRDY;
					musb_writew(mbase, offset, txcsr);
				}
				musb_dma_completion(musb, musb_channel->epnum,
						    musb_channel->transmit);
			}
		}
	}

#ifdef CONFIG_BLACKFIN
	/* Clear DMA interrup flags */
	musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
#endif

	retval = IRQ_HANDLED;
done:
	spin_unlock_irqrestore(&musb->lock, flags);
	return retval;
}
Ejemplo n.º 23
0
int __init musb_platform_init(struct musb *musb)
{
	u32 l;
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *plat = dev->platform_data;
	struct omap_musb_board_data *data = plat->board_data;
	int status;
	u32 val;
	u8 devctl;

	/* We require some kind of external transceiver, hooked
	 * up through ULPI.  TWL4030-family PMICs include one,
	 * which needs a driver, drivers aren't always needed.
	 */
	musb->xceiv = otg_get_transceiver();
	if (!musb->xceiv) {
		pr_err("HS USB OTG: no transceiver configured\n");
		return -ENODEV;
	}

	/* Fixme this can be enabled when load the gadget driver also*/
	musb_platform_resume(musb);

	/*powerup the phy as romcode would have put the phy in some state
	* which is impacting the core retention if the gadget driver is not
	* loaded.
	*/
	l = musb_readl(musb->mregs, OTG_INTERFSEL);

	if (data->interface_type == MUSB_INTERFACE_UTMI) {
		/* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
		l &= ~ULPI_12PIN;       /* Disable ULPI */
		l |= UTMI_8BIT;         /* Enable UTMI  */
	} else {
		l |= ULPI_12PIN;
	}

	musb_writel(musb->mregs, OTG_INTERFSEL, l);

	pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
			"sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
			musb_readl(musb->mregs, OTG_REVISION),
			musb_readl(musb->mregs, OTG_SYSCONFIG),
			musb_readl(musb->mregs, OTG_SYSSTATUS),
			musb_readl(musb->mregs, OTG_INTERFSEL),
			musb_readl(musb->mregs, OTG_SIMENABLE));

	if (is_host_enabled(musb))
		musb->board_set_vbus = omap_set_vbus;

	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
	plat->is_usb_active = is_musb_active;

	wake_lock_init(&plat->musb_lock, WAKE_LOCK_SUSPEND, "musb_wake_lock");
	if (cpu_is_omap44xx()) {
		phymux_base = ioremap(0x4A100000, SZ_1K);

	 if (!phymux_base) {
                     			 dev_err(dev, "ioremap failed\n");
			wake_lock_destroy(&plat->musb_lock);
                       			return -ENOMEM;
		}
		ctrl_base = ioremap(0x4A002000, SZ_1K);
		if (!ctrl_base) {
			dev_err(dev, "ioremap failed\n");
                         wake_lock_destroy(&plat->musb_lock);
			return -ENOMEM;
		}
	}
       /* register for transciever notification */
       status = otg_register_notifier(musb->xceiv, &musb->nb);
       if (status) {
               DBG(1, "notification register failed\n");
               wake_lock_destroy(&plat->musb_lock);
       }

       /* Keep the old initalization code for revisions < 1.2
        * since the new code seem to crash the older boards
        * when coming out of power off mode
        */
       if (omap_rev() < OMAP3630_REV_ES1_2) {
	/* configure in force idle/ standby */
	musb_writel(musb->mregs, OTG_FORCESTDBY, 1);
	val = musb_readl(musb->mregs, OTG_SYSCONFIG);
	val &= ~(SMARTIDLEWKUP | NOSTDBY | ENABLEWAKEUP);
	val |= FORCEIDLE | FORCESTDBY;
	musb_writel(musb->mregs, OTG_SYSCONFIG,	val);
       } else {
               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
               if ((devctl & MUSB_DEVCTL_VBUS) !=
                                       (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
                       /* configure in force idle/ standby */
                       musb_writel(musb->mregs, OTG_FORCESTDBY, 1);
                       val = FORCEIDLE | FORCESTDBY;
                       musb_writel(musb->mregs, OTG_SYSCONFIG, val);
               } else {
                       /* configure smart idle when usb cable inserted at *
                        * startup*/
                       val =  SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP;
                       musb_writel(musb->mregs, OTG_SYSCONFIG, val);
               }
       }




//	l = musb_readl(musb->mregs, OTG_FORCESTDBY);
//	l &= ~ENABLEFORCE;	/* disable MSTANDBY */
//	musb_writel(musb->mregs, OTG_FORCESTDBY, l);
	
	return 0;
}
Ejemplo n.º 24
0
static void musb_port_suspend(struct musb *musb, bool do_suspend)
{
	u8		power;
	void __iomem	*mbase = musb->mregs;

	if (!is_host_active(musb))
		return;

	/* NOTE:  this doesn't necessarily put PHY into low power mode,
	 * turning off its clock; that's a function of PHY integration and
	 * MUSB_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
	 * SE0 changing to connect (J) or wakeup (K) states.
	 */
	power = musb_readb(mbase, MUSB_POWER);
	if (do_suspend) {
		int retries = 10000;

		power &= ~MUSB_POWER_RESUME;
		power |= MUSB_POWER_SUSPENDM;
		musb_writeb(mbase, MUSB_POWER, power);

		/* Needed for OPT A tests */
		power = musb_readb(mbase, MUSB_POWER);
		while (power & MUSB_POWER_SUSPENDM) {
			power = musb_readb(mbase, MUSB_POWER);
			if (retries-- < 1)
				break;
		}

		DBG(3, "Root port suspended, power %02x\n", power);

		musb->port1_status |= USB_PORT_STAT_SUSPEND;
		switch (musb->xceiv->state) {
		case OTG_STATE_A_HOST:
			musb->xceiv->state = OTG_STATE_A_SUSPEND;
			musb->is_active = is_otg_enabled(musb)
					&& musb->xceiv->host->b_hnp_enable;
			if (musb->is_active)
				mod_timer(&musb->otg_timer, jiffies
					+ msecs_to_jiffies((
						OTG_TIME_A_AIDL_BDIS +
						USB_SUSP_DET_DURATION)));
			musb_platform_try_idle(musb, 0);
			break;
#ifdef	CONFIG_USB_MUSB_OTG
		case OTG_STATE_B_HOST:
			musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
			musb->is_active = is_otg_enabled(musb)
					&& musb->xceiv->host->b_hnp_enable;
			musb_platform_try_idle(musb, 0);
			break;
#endif
		default:
			DBG(1, "bogus rh suspend? %s\n",
				otg_state_string(musb));
		}
	} else if (power & MUSB_POWER_SUSPENDM) {
		power &= ~MUSB_POWER_SUSPENDM;
		power |= MUSB_POWER_RESUME;
		musb_writeb(mbase, MUSB_POWER, power);

		DBG(3, "Root port resuming, power %02x\n", power);

		/* later, GetPortStatus will stop RESUME signaling */
		musb->port1_status |= MUSB_PORT_STAT_RESUME;
		musb->rh_timer = jiffies + msecs_to_jiffies(20);
	}
}
Ejemplo n.º 25
0
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(!HCD_HW_ACCESSIBLE(hcd))) {
		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_platform_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;
		}
		dev_dbg(musb->controller, "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->u.hs.DeviceRemovable[0] = 0x02;	/* port 1 */
		desc->u.hs.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;
			dev_dbg(musb->controller, "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 */
		dev_dbg(musb->controller, "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:
			if (unlikely(is_host_enabled(musb)))
				goto error;

			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);
			if (wIndex == 4) {
				musb_writew(musb->endpoints[0].regs,
					MUSB_CSR0, MUSB_CSR0_TXPKTRDY);
			}
			break;
		default:
			goto error;
		}
		dev_dbg(musb->controller, "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;
}
void host_test_mode(struct musb *musb, unsigned int wIndex){
            unsigned char temp;
            unsigned char power;
            struct usb_ctrlrequest setup_packet;
            struct usb_device_descriptor device_descriptor;

            setup_packet.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
            setup_packet.bRequest = USB_REQ_GET_DESCRIPTOR;
            setup_packet.wIndex = 0;
            setup_packet.wValue = 0x0100;
            setup_packet.wLength = 0x40;
            musb_otg_set_session (true);
            msleep(200);
            DBG(0,"devctl = 0x%x\n",musb_readb(musb->mregs,MUSB_DEVCTL));
			switch (wIndex) {
            case HOST_CMD_TEST_SE0_NAK:
							DBG(0,"TEST_SE0_NAK\n");
							temp = MUSB_TEST_SE0_NAK;
			        musb_writeb(musb->mregs, MUSB_TESTMODE, temp);

						break;
			case HOST_CMD_TEST_J:
				DBG(0,"TEST_J\n");
				temp = MUSB_TEST_J;
                musb_writeb(musb->mregs, MUSB_TESTMODE, temp);

				break;
			case HOST_CMD_TEST_K:
				DBG(0,"TEST_K\n");
				temp = MUSB_TEST_K;
                musb_writeb(musb->mregs, MUSB_TESTMODE, temp);

				break;
			case HOST_CMD_TEST_PACKET:
				DBG(0,"TEST_PACKET\n");
				temp = MUSB_TEST_PACKET;
				musb_host_load_testpacket(musb);
                musb_writeb(musb->mregs, MUSB_TESTMODE, temp);
                musb_writew(musb->mregs, 0x102, MUSB_CSR0_TXPKTRDY);
				break;

			case HOST_CMD_SUSPEND_RESUME://HS_HOST_PORT_SUSPEND_RESUME
			    DBG(0,"HS_HOST_PORT_SUSPEND_RESUME\n");
					msleep(5000);//the host must continue sending SOFs for 15s
					DBG(0,"please begin to trigger suspend!\n");
					msleep(10000);
					power = musb_readb(musb->mregs,MUSB_POWER);
                power |= MUSB_POWER_SUSPENDM | MUSB_POWER_ENSUSPEND;
                musb_writeb(musb->mregs,MUSB_POWER,power);
                msleep(5000);
                DBG(0,"please begin to trigger resume!\n");
                msleep(10000);
                power &= ~MUSB_POWER_SUSPENDM;
                power |= MUSB_POWER_RESUME;
                musb_writeb(musb->mregs,MUSB_POWER,power);
					mdelay(25);
                power &= ~MUSB_POWER_RESUME;
                musb_writeb(musb->mregs,MUSB_POWER,power);
                //SOF continue
                musb_h_setup(&setup_packet);
				break;
			case HOST_CMD_GET_DESCRIPTOR://SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup
			    DBG(0,"SINGLE_STEP_GET_DEVICE_DESCRIPTOR\n");
			    msleep(15000);//the host issues SOFs for 15s allowing the test engineer to raise the scope trigger just above the SOF voltage level.
			    musb_h_setup(&setup_packet);
			    break;
			case HOST_CMD_SET_FEATURE://SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute
			    DBG(0,"SINGLE_STEP_GET_DEVICE_DESCRIPTOR\n");
			    //get device descriptor
			    musb_h_setup(&setup_packet);
			    msleep(15000);
			    musb_h_in_data((char*)&device_descriptor,sizeof(struct usb_device_descriptor));
			    musb_h_out_status();
			    break;
			default:
                break;

             }
            //while(1);
}
Ejemplo n.º 27
0
static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
{
	struct usb_otg	*otg = musb->xceiv->otg;
	u8		devctl;
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	/* HDRC controls CPEN, but beware current surges during device
	 * connect.  They can trigger transient overcurrent conditions
	 * that must be ignored.
	 */

	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

	if (is_on) {
		if (musb->xceiv->state == OTG_STATE_A_IDLE) {
			int loops = 100;
			/* start the session */
			devctl |= MUSB_DEVCTL_SESSION;
			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
			/*
			 * Wait for the musb to set as A device to enable the
			 * VBUS
			 */
			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {

				mdelay(5);
				cpu_relax();

				if (time_after(jiffies, timeout)
				    || loops-- <= 0) {
					dev_err(musb->controller,
					"configured as A device timeout");
					break;
				}
			}

			otg_set_vbus(otg, 1);
		} else {
			musb->is_active = 1;
			otg->default_a = 1;
			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
			devctl |= MUSB_DEVCTL_SESSION;
			MUSB_HST_MODE(musb);
		}
	} else {
		musb->is_active = 0;

		/* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
		 * jumping right to B_IDLE...
		 */

		otg->default_a = 0;
		musb->xceiv->state = OTG_STATE_B_IDLE;
		devctl &= ~MUSB_DEVCTL_SESSION;

		MUSB_DEV_MODE(musb);
	}
	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);

	dev_dbg(musb->controller, "VBUS %s, devctl %02x "
		/* otg %3x conf %08x prcm %08x */ "\n",
		usb_otg_state_string(musb->xceiv->state),
		musb_readb(musb->mregs, MUSB_DEVCTL));
}
int musb_otg_env_init(void){
    u8 power;
    //u8 intrusb;
    //step1: mask the PMU/PMIC EINT
    mtk_musb->usb_if = true;
    mtk_musb->is_host = true;//workaround for PMIC charger detection
    //mt65xx_eint_mask(EINT_CHR_DET_NUM);

    upmu_interrupt_chrdet_int_en(0);

    #ifndef MTK_FAN5405_SUPPORT
    #ifndef MTK_NCP1851_SUPPORT
    #ifndef MTK_BQ24196_SUPPORT
    #ifndef MTK_BQ24158_SUPPORT
    //set the drvvbus mode as drvvbus(mode 6)
#if !(defined(CONFIG_MT6585_FPGA) || defined(CONFIG_MT6577_FPGA) || defined(CONFIG_MT6589_FPGA) || defined(CONFIG_MT6582_FPGA))
#if defined(GPIO_OTG_DRVVBUS_PIN)
    mt_set_gpio_mode(GPIO_OTG_DRVVBUS_PIN,6);
    #endif
    #endif
    #endif
    #endif
    #endif
    #endif
    //step5: make sure to power on the USB module
    if(mtk_musb->power)
        mtk_musb->power = FALSE;
    musb_platform_enable(mtk_musb);
    //step6: clear session bit
    musb_writeb(mtk_musb->mregs,MUSB_DEVCTL,0);
    //step7: disable and enable usb interrupt
    usb_l1intm_store = musb_readl(mtk_musb->mregs,USB_L1INTM);
    usb_intrrxe_store = musb_readw(mtk_musb->mregs,MUSB_INTRRXE);
    usb_intrtxe_store = musb_readw(mtk_musb->mregs,MUSB_INTRTXE);
    usb_intrusbe_store = musb_readb(mtk_musb->mregs,MUSB_INTRUSBE);

    musb_writel(mtk_musb->mregs,USB_L1INTM,0);
    musb_writew(mtk_musb->mregs,MUSB_INTRRXE,0);
    musb_writew(mtk_musb->mregs,MUSB_INTRTXE,0);
    musb_writeb(mtk_musb->mregs,MUSB_INTRUSBE,0);
    musb_writew(mtk_musb->mregs,MUSB_INTRRX,0xffff);
    musb_writew(mtk_musb->mregs,MUSB_INTRTX,0xffff);
    musb_writeb(mtk_musb->mregs,MUSB_INTRUSB,0xff);
    free_irq (mtk_musb->nIrq, mtk_musb);
    musb_writel(mtk_musb->mregs,USB_L1INTM,0x105);
    musb_writew(mtk_musb->mregs,MUSB_INTRTXE,1);
    musb_writeb(mtk_musb->mregs,MUSB_INTRUSBE,0xf7);
    //setp8: set the index to 0 for ep0, maybe no need. Designers said it is better not to use the index register.
    musb_writeb(mtk_musb->mregs, MUSB_INDEX, 0);
    //setp9: init message
    g_otg_message.msg = 0;
    spin_lock_init(&g_otg_message.lock);

    init_completion(&stop_event);
    #ifdef DX_DBG
    power = musb_readb(mtk_musb->mregs,MUSB_POWER);
    DBG(0,"start the USB-IF test in EM,power=0x%x!\n",power);
    #endif

    return 0;
}
Ejemplo n.º 29
0
void musb_port_suspend(struct musb *musb, bool do_suspend)
{
	struct usb_otg	*otg = musb->xceiv->otg;
	u8		power;
	void __iomem	*mbase = musb->mregs;

	if (!is_host_active(musb))
		return;

	/* NOTE:  this doesn't necessarily put PHY into low power mode,
	 * turning off its clock; that's a function of PHY integration and
	 * MUSB_POWER_ENSUSPEND.  PHY may need a clock (sigh) to detect
	 * SE0 changing to connect (J) or wakeup (K) states.
	 */
	power = musb_readb(mbase, MUSB_POWER);
	if (do_suspend) {
		int retries = 10000;

		power &= ~MUSB_POWER_RESUME;
		power |= MUSB_POWER_SUSPENDM;
		musb_writeb(mbase, MUSB_POWER, power);

		/* Needed for OPT A tests */
		power = musb_readb(mbase, MUSB_POWER);
		while (power & MUSB_POWER_SUSPENDM) {
			power = musb_readb(mbase, MUSB_POWER);
			if (retries-- < 1)
				break;
		}

		dev_dbg(musb->controller, "Root port suspended, power %02x\n", power);

		musb->port1_status |= USB_PORT_STAT_SUSPEND;
		switch (musb->xceiv->state) {
		case OTG_STATE_A_HOST:
			musb->xceiv->state = OTG_STATE_A_SUSPEND;
			musb->is_active = otg->host->b_hnp_enable;
			if (musb->is_active)
				mod_timer(&musb->otg_timer, jiffies
					+ msecs_to_jiffies(
						OTG_TIME_A_AIDL_BDIS));
			musb_platform_try_idle(musb, 0);
			break;
		case OTG_STATE_B_HOST:
			musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
			musb->is_active = otg->host->b_hnp_enable;
			musb_platform_try_idle(musb, 0);
			break;
		default:
			dev_dbg(musb->controller, "bogus rh suspend? %s\n",
				usb_otg_state_string(musb->xceiv->state));
		}
	} else if (power & MUSB_POWER_SUSPENDM) {
		power &= ~MUSB_POWER_SUSPENDM;
		power |= MUSB_POWER_RESUME;
		musb_writeb(mbase, MUSB_POWER, power);

		dev_dbg(musb->controller, "Root port resuming, power %02x\n", power);

		/* later, GetPortStatus will stop RESUME signaling */
		musb->port1_status |= MUSB_PORT_STAT_RESUME;
		schedule_delayed_work(&musb->finish_resume_work,
				      msecs_to_jiffies(USB_RESUME_TIMEOUT));
	}
}
Ejemplo n.º 30
0
static void otg_timer(unsigned long _musb)
{
	struct musb		*musb = (void *)_musb;
	void __iomem		*mregs = musb->mregs;
	u8			devctl;
	unsigned long		flags;

	/*
	 * We poll because DaVinci's won't expose several OTG-critical
	 * status change events (from the transceiver) otherwise.
	 */
	devctl = musb_readb(mregs, MUSB_DEVCTL);
	dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
		usb_otg_state_string(musb->xceiv->otg->state));

	spin_lock_irqsave(&musb->lock, flags);
	switch (musb->xceiv->otg->state) {
	case OTG_STATE_A_WAIT_BCON:
		devctl &= ~MUSB_DEVCTL_SESSION;
		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);

		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
		if (devctl & MUSB_DEVCTL_BDEVICE) {
			musb->xceiv->otg->state = OTG_STATE_B_IDLE;
			MUSB_DEV_MODE(musb);
		} else {
			musb->xceiv->otg->state = OTG_STATE_A_IDLE;
			MUSB_HST_MODE(musb);
		}
		break;
	case OTG_STATE_A_WAIT_VFALL:
		/*
		 * Wait till VBUS falls below SessionEnd (~0.2 V); the 1.3
		 * RTL seems to mis-handle session "start" otherwise (or in
		 * our case "recover"), in routine "VBUS was valid by the time
		 * VBUSERR got reported during enumeration" cases.
		 */
		if (devctl & MUSB_DEVCTL_VBUS) {
			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
			break;
		}
		musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
		musb_writel(musb->ctrl_base, DA8XX_USB_INTR_SRC_SET_REG,
			    MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT);
		break;
	case OTG_STATE_B_IDLE:
		/*
		 * There's no ID-changed IRQ, so we have no good way to tell
		 * when to switch to the A-Default state machine (by setting
		 * the DEVCTL.Session bit).
		 *
		 * Workaround:  whenever we're in B_IDLE, try setting the
		 * session flag every few seconds.  If it works, ID was
		 * grounded and we're now in the A-Default state machine.
		 *
		 * NOTE: setting the session flag is _supposed_ to trigger
		 * SRP but clearly it doesn't.
		 */
		musb_writeb(mregs, MUSB_DEVCTL, devctl | MUSB_DEVCTL_SESSION);
		devctl = musb_readb(mregs, MUSB_DEVCTL);
		if (devctl & MUSB_DEVCTL_BDEVICE)
			mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
		else
			musb->xceiv->otg->state = OTG_STATE_A_IDLE;
		break;
	default:
		break;
	}
	spin_unlock_irqrestore(&musb->lock, flags);
}