Re: [PATCHv2 00/15] Get MUSB PM runtime working again

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

 



Hi,

* Bin Liu <b-liu@xxxxxx> [160518 11:12]:
> On Wed, May 18, 2016 at 11:07:37AM -0700, Tony Lindgren wrote:
> > 
> > Is this with or without the $subject series?
> 
> Without.

OK sounds like you have a fix coming for that issue.

> > > I tried to enable some dynamic-debug log, but was unable to see any
> > > glue. I will try to enable musb reg access log tomorrow to see if I can
> > > find anything.
> > 
> > OK, I'm looking at implementing proper PM runtime for dsps.

And here's something to play with for PM runtime on top of the
$subject series.

Currently it only works in PIO mode and relies on keeping the
polling going.. See notes below about the GPIO mode.

BTW, looks like we can then just also remove try_idle also for
dsps glue layer.

Regards,

Tony

8< ----------------
From: Tony Lindgren <tony@xxxxxxxxxxx>
Date: Wed, 18 May 2016 08:22:31 -0700
Subject: [PATCH] usb: musb: Add PM runtime support for dsps glue for PIO mode

This gets basic PM runtime working for dsps glue layer uwing
PIO mode.

For now, we must keep polling enabled as typically at least
one of the controllers has ID pin tied down. Later on we can
add support for remuxing USB data lines to GPIO mode to leave
out the polling where possible.

Note that this shuts down the device currently only with
CONFIG_MUSB_PIO_ONLY=y as cppi41 is a child of musb_am335x.c
and needs PM runtime fixed up first.

Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx>

--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -144,6 +144,7 @@ struct dsps_glue {
 	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
 	struct timer_list timer;	/* otg_workaround timer */
 	unsigned long last_timer;    /* last timer data for each instance */
+	bool powered;
 	bool sw_babble_enabled;
 
 	struct dsps_context context;
@@ -250,6 +251,35 @@ static void dsps_musb_disable(struct musb *musb)
 	dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
 }
 
+static void dsps_musb_set_power(struct musb *musb, bool enabled)
+{
+	struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent);
+	int err;
+
+	if (enabled == glue->powered) {
+		dev_warn(musb->controller, "Power already %i\n",
+			 glue->powered);
+		return;
+	}
+
+	if (glue->powered) {
+		dev_dbg(musb->controller, "Disabling power\n");
+		pm_runtime_mark_last_busy(musb->controller);
+		pm_runtime_put_autosuspend(musb->controller);
+		glue->powered = false;
+	} else {
+		dev_dbg(musb->controller, "Enabling power\n");
+		err = pm_runtime_get_sync(musb->controller);
+		if (err < 0) {
+			dev_err(musb->controller,
+				"Could not pm_runtime_get: %i\n",
+				err);
+			return;
+		}
+		glue->powered = true;
+	}
+}
+
 static void otg_timer(unsigned long _musb)
 {
 	struct musb *musb = (void *)_musb;
@@ -260,6 +290,11 @@ static void otg_timer(unsigned long _musb)
 	u8 devctl;
 	unsigned long flags;
 	int skip_session = 0;
+	int err;
+
+	err = pm_runtime_get_sync(dev);
+	if (err < 0)
+		dev_err(dev, "Poll could not pm_runtime_get: %i\n", err);
 
 	/*
 	 * We poll because DSPS IP's won't expose several OTG-critical
@@ -287,6 +322,7 @@ static void otg_timer(unsigned long _musb)
 		}
 		if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session)
 			dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
+		dsps_musb_set_power(musb, false);
 		mod_timer(&glue->timer, jiffies +
 				msecs_to_jiffies(wrp->poll_timeout));
 		break;
@@ -294,11 +330,18 @@ static void otg_timer(unsigned long _musb)
 		musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
 		dsps_writel(musb->ctrl_base, wrp->coreintr_set,
 			    MUSB_INTR_VBUSERROR << wrp->usb_shift);
+		dsps_musb_set_power(musb, false);
+		break;
+	case OTG_STATE_UNDEFINED:
 		break;
 	default:
+		dsps_musb_set_power(musb, true);
 		break;
 	}
 	spin_unlock_irqrestore(&musb->lock, flags);
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 }
 
 static irqreturn_t dsps_interrupt(int irq, void *hci)
@@ -362,7 +405,6 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
 			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);
@@ -382,9 +424,10 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
 	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)
+	/* Poll for ID change and device connect */
+	if (musb->xceiv->otg->state == OTG_STATE_A_IDLE ||
+	    musb->xceiv->otg->state == OTG_STATE_A_WAIT_BCON ||
+	    musb->xceiv->otg->state == OTG_STATE_B_IDLE)
 		mod_timer(&glue->timer, jiffies +
 				msecs_to_jiffies(wrp->poll_timeout));
 out:
@@ -498,6 +541,7 @@ static int dsps_musb_exit(struct musb *musb)
 	phy_power_off(musb->phy);
 	phy_exit(musb->phy);
 	debugfs_remove_recursive(glue->dbgfs_root);
+	dsps_musb_set_power(musb, false);
 
 	return 0;
 }
@@ -808,6 +852,8 @@ static int dsps_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, glue);
 	pm_runtime_enable(&pdev->dev);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 500);
 
 	ret = pm_runtime_get_sync(&pdev->dev);
 	if (ret < 0) {
@@ -819,11 +865,15 @@ static int dsps_probe(struct platform_device *pdev)
 	if (ret)
 		goto err3;
 
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
+
 	return 0;
 
 err3:
-	pm_runtime_put(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
 err2:
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	return ret;
 }
@@ -835,7 +885,8 @@ static int dsps_remove(struct platform_device *pdev)
 	platform_device_unregister(glue->musb);
 
 	/* disable usbss clocks */
-	pm_runtime_put(&pdev->dev);
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 	return 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