Example #1
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 = dsps_readl(reg_base, wrp->revision);
	if (!rev)
		return -ENODEV;

	usb_phy_init(musb->xceiv);
	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;
		}
	}

	setup_timer(&glue->timer, otg_timer, (unsigned long) musb);

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

	musb->isr = dsps_interrupt;

	/* reset the otgdisable bit, needed for host mode to work */
	val = dsps_readl(reg_base, wrp->phy_utmi);
	val &= ~(1 << wrp->otg_disable);
	dsps_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 = dsps_readb(musb->mregs, MUSB_BABBLE_CTL);
	if (val & MUSB_BABBLE_RCV_DISABLE) {
		glue->sw_babble_enabled = true;
		val |= MUSB_BABBLE_SW_SESSION_CTRL;
		dsps_writeb(musb->mregs, MUSB_BABBLE_CTL, val);
	}

	ret = dsps_musb_dbg_init(musb, glue);
	if (ret)
		return ret;

	return 0;
}
Example #2
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 = dsps_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)
        dsps_writel(reg_base, wrp->epintr_status, epintr);

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

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

    dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
            usbintr, epintr);
    /*
     * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
     * DSPS IP'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 5V) ...
     */
    if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) {
        pr_info("CAUTION: musb: Babble Interrupt Occurred\n");

        /*
         * When a babble condition occurs, the musb controller removes
         * the session and is no longer in host mode. Hence, all
         * devices connected to its root hub get disconnected.
         *
         * Hand this error down to the musb core isr, so it can
         * recover.
         */
        musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT;
        musb->int_tx = musb->int_rx = 0;
    }

    if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
        int drvvbus = dsps_readl(reg_base, wrp->status);
        void __iomem *mregs = musb->mregs;
        u8 devctl = dsps_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->state = OTG_STATE_A_WAIT_VFALL;
            mod_timer(&glue->timer,
                      jiffies + wrp->poll_seconds * HZ);
            WARNING("VBUS error workaround (delay coming)\n");
        } else if (drvvbus) {
            MUSB_HST_MODE(musb);
            musb->xceiv->otg->default_a = 1;
            musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
            del_timer(&glue->timer);
        } else {
            musb->is_active = 0;
            MUSB_DEV_MODE(musb);
            musb->xceiv->otg->default_a = 0;
            musb->xceiv->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->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 in OTG port mode */
    if (musb->xceiv->state == OTG_STATE_B_IDLE &&
            musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
        mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
out:
    spin_unlock_irqrestore(&musb->lock, flags);

    return ret;
}
Example #3
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 = dsps_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)
		dsps_writel(reg_base, wrp->epintr_status, epintr);

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

	musb->int_usb =	(usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
	if (usbintr)
		dsps_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 = dsps_readl(reg_base, wrp->status);
		void __iomem *mregs = musb->mregs;
		u8 devctl = dsps_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(&glue->timer, jiffies +
					msecs_to_jiffies(wrp->poll_timeout));
			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;
			del_timer(&glue->timer);
		} 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 in OTG port mode */
	if (musb->xceiv->otg->state == OTG_STATE_B_IDLE &&
			musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
		mod_timer(&glue->timer, jiffies +
				msecs_to_jiffies(wrp->poll_timeout));
out:
	spin_unlock_irqrestore(&musb->lock, flags);

	return ret;
}
static int dsps_musb_init(struct musb *musb)
{
	struct device *dev = musb->controller;
	struct platform_device *pdev = to_platform_device(dev);
	struct dsps_glue *glue = dev_get_drvdata(dev->parent);
	const struct dsps_musb_wrapper *wrp = glue->wrp;
	void __iomem *reg_base = musb->ctrl_base;
	u32 rev, val;
	int status;

	/* mentor core register starts at offset of 0x400 from musb base */
	musb->mregs += wrp->musb_core_offset;

#if 1
	/* NOP driver needs change if supporting dual instance */
	if(!pdev->id) {
		usb_nop_xceiv_register();
	}
	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
#else
	/* Get the NOP PHY */
	sprintf(name, "usb%d-phy", pdev->id);
	musb->xceiv = devm_usb_get_phy_by_phandle(&parent_pdev->dev, name);
#endif
	if (IS_ERR_OR_NULL(musb->xceiv)) {
		dev_err(dev, "%s:%d %s: FAIL\n", __FILE__, __LINE__, __func__);
		return -EPROBE_DEFER;
	}

	/* Returns zero if e.g. not clocked */
	rev = dsps_readl(reg_base, wrp->revision);
	if (!rev) {
		dev_err(dev, "%s:%d %s: FAIL\n", __FILE__, __LINE__, __func__);
		status = -ENODEV;
		goto err0;
	}

	dev_info(dev, "pdev->id = %d\n", pdev->id);

	setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);

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

	/* Start the on-chip PHY and its PLL. */
	musb_dsps_phy_control(glue, pdev->id, 1);

	musb->isr = dsps_interrupt;

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

	/* clear level interrupt */
	dsps_writel(reg_base, wrp->eoi, 0);

	dev_info(dev, "%s:%d %s: OK\n", __FILE__, __LINE__, __func__);

	return 0;
err0:
	usb_put_phy(musb->xceiv);
	if(!pdev->id) {
		usb_nop_xceiv_unregister();
	}
	return status;
}