Re: [PATCHv2] usb: musb: Add support for optional VBUS irq to dsps glue layer

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jan 12, 2017 at 01:40:46PM -0800, Tony Lindgren wrote:
> We can now configure the PMIC interrupt to provide us VBUS
> events. In that case we don't need to constantly poll the
> status and can make it optional. This is only wired up
> for the mini-B interface on beaglebone.
> 
> Note that eventually we should get also the connect status
> for the host interface when the am335x internal PM coprocessor
> provides us with an IRQ chip. For now, we still need to poll
> for the host mode status.
> 
> Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx>

Applied. Thanks.
-Bin.

> ---
> 
> Changes since v1:
> 
> - Updated based on comments from Bin mostly to limit to peripheral
>   mode only
> 
> ---
>  drivers/usb/musb/musb_dsps.c | 117 ++++++++++++++++++++++++++++++++++---------
>  1 file changed, 93 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
> --- a/drivers/usb/musb/musb_dsps.c
> +++ b/drivers/usb/musb/musb_dsps.c
> @@ -118,6 +118,7 @@ struct dsps_glue {
>  	struct device *dev;
>  	struct platform_device *musb;	/* child musb pdev */
>  	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
> +	int vbus_irq;			/* optional vbus irq */
>  	struct timer_list timer;	/* otg_workaround timer */
>  	unsigned long last_timer;    /* last timer data for each instance */
>  	bool sw_babble_enabled;
> @@ -145,6 +146,29 @@ static const struct debugfs_reg32 dsps_musb_regs[] = {
>  	{ "mode",		0xe8 },
>  };
>  
> +static void dsps_mod_timer(struct dsps_glue *glue, int wait_ms)
> +{
> +	int wait;
> +
> +	if (wait_ms < 0)
> +		wait = msecs_to_jiffies(glue->wrp->poll_timeout);
> +	else
> +		wait = msecs_to_jiffies(wait_ms);
> +
> +	mod_timer(&glue->timer, jiffies + wait);
> +}
> +
> +/*
> + * If no vbus irq from the PMIC is configured, we need to poll VBUS status.
> + */
> +static void dsps_mod_timer_optional(struct dsps_glue *glue)
> +{
> +	if (glue->vbus_irq)
> +		return;
> +
> +	dsps_mod_timer(glue, -1);
> +}
> +
>  /**
>   * dsps_musb_enable - enable interrupts
>   */
> @@ -167,8 +191,7 @@ static void dsps_musb_enable(struct musb *musb)
>  	/* start polling for ID change in dual-role idle 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));
> +		dsps_mod_timer(glue, -1);
>  }
>  
>  /**
> @@ -199,6 +222,9 @@ static int dsps_check_status(struct musb *musb, void *unused)
>  	u8 devctl;
>  	int skip_session = 0;
>  
> +	if (glue->vbus_irq)
> +		del_timer(&glue->timer);
> +
>  	/*
>  	 * We poll because DSPS IP's won't expose several OTG-critical
>  	 * status change events (from the transceiver) otherwise.
> @@ -209,8 +235,7 @@ static int dsps_check_status(struct musb *musb, void *unused)
>  
>  	switch (musb->xceiv->otg->state) {
>  	case OTG_STATE_A_WAIT_VRISE:
> -		mod_timer(&glue->timer, jiffies +
> -				msecs_to_jiffies(wrp->poll_timeout));
> +		dsps_mod_timer_optional(glue);
>  		break;
>  	case OTG_STATE_A_WAIT_BCON:
>  		musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
> @@ -219,17 +244,19 @@ static int dsps_check_status(struct musb *musb, void *unused)
>  
>  	case OTG_STATE_A_IDLE:
>  	case OTG_STATE_B_IDLE:
> -		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 (!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);
>  		}
> -		if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session)
> -			musb_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
> -		mod_timer(&glue->timer, jiffies +
> -				msecs_to_jiffies(wrp->poll_timeout));
> +		dsps_mod_timer_optional(glue);
>  		break;
>  	case OTG_STATE_A_WAIT_VFALL:
>  		musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
> @@ -332,15 +359,13 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
>  			 */
>  			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));
> +			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;
> -			mod_timer(&glue->timer, jiffies +
> -				  msecs_to_jiffies(wrp->poll_timeout));
> +			dsps_mod_timer_optional(glue);
>  		} else {
>  			musb->is_active = 0;
>  			MUSB_DEV_MODE(musb);
> @@ -364,8 +389,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
>  	switch (musb->xceiv->otg->state) {
>  	case OTG_STATE_B_IDLE:
>  	case OTG_STATE_A_WAIT_BCON:
> -		mod_timer(&glue->timer, jiffies +
> -				msecs_to_jiffies(wrp->poll_timeout));
> +		dsps_mod_timer_optional(glue);
>  		break;
>  	default:
>  		break;
> @@ -469,8 +493,7 @@ static int dsps_musb_init(struct musb *musb)
>  		musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val);
>  	}
>  
> -	mod_timer(&glue->timer, jiffies +
> -		  msecs_to_jiffies(glue->wrp->poll_timeout));
> +	dsps_mod_timer(glue, -1);
>  
>  	return dsps_musb_dbg_init(musb, glue);
>  }
> @@ -765,6 +788,47 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,
>  	return ret;
>  }
>  
> +static irqreturn_t dsps_vbus_threaded_irq(int irq, void *priv)
> +{
> +	struct dsps_glue *glue = priv;
> +	struct musb *musb = platform_get_drvdata(glue->musb);
> +
> +	if (!musb)
> +		return IRQ_NONE;
> +
> +	dev_dbg(glue->dev, "VBUS interrupt\n");
> +	dsps_mod_timer(glue, 0);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int dsps_setup_optional_vbus_irq(struct platform_device *pdev,
> +					struct dsps_glue *glue)
> +{
> +	int error;
> +
> +	glue->vbus_irq = platform_get_irq_byname(pdev, "vbus");
> +	if (glue->vbus_irq == -EPROBE_DEFER)
> +		return -EPROBE_DEFER;
> +
> +	if (glue->vbus_irq <= 0) {
> +		glue->vbus_irq = 0;
> +		return 0;
> +	}
> +
> +	error = devm_request_threaded_irq(glue->dev, glue->vbus_irq,
> +					  NULL, dsps_vbus_threaded_irq,
> +					  IRQF_ONESHOT,
> +					  "vbus", glue);
> +	if (error) {
> +		glue->vbus_irq = 0;
> +		return error;
> +	}
> +	dev_dbg(glue->dev, "VBUS irq %i configured\n", glue->vbus_irq);
> +
> +	return 0;
> +}
> +
>  static int dsps_probe(struct platform_device *pdev)
>  {
>  	const struct of_device_id *match;
> @@ -793,6 +857,12 @@ static int dsps_probe(struct platform_device *pdev)
>  	glue->dev = &pdev->dev;
>  	glue->wrp = wrp;
>  
> +	if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) {
> +		ret = dsps_setup_optional_vbus_irq(pdev, glue);
> +		if (ret)
> +			return ret;
> +	}
> +
>  	platform_set_drvdata(pdev, glue);
>  	pm_runtime_enable(&pdev->dev);
>  	ret = dsps_create_musb_pdev(glue, pdev);
> @@ -903,8 +973,7 @@ static int dsps_resume(struct device *dev)
>  	musb_writel(mbase, wrp->rx_mode, glue->context.rx_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));
> +		dsps_mod_timer(glue, -1);
>  
>  	return 0;
>  }
> -- 
> 2.11.0
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux