[PATCH v2 17/25] usb: langwell_udc: add runtime pm support for otg

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

 



This patch contains update on transceiver driver interfaces.
Mainly to support runtime pm for OTG.

Signed-off-by: Hao Wu <hao.wu@xxxxxxxxx>
---
 drivers/usb/gadget/langwell_udc.c |  116 +++++++++++++++++++++++++++++++------
 1 files changed, 98 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index df2b82b..2c56faf 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -45,6 +45,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <asm/system.h>
@@ -3505,18 +3506,74 @@ static struct pci_driver langwell_pci_driver = {
 static int intel_mid_start_peripheral(struct intel_mid_otg_xceiv *iotg)
 {
 	struct langwell_udc	*dev = the_controller;
-	struct pci_dev		*pdev;
+	size_t			size;
 	unsigned long		flags;
-	int			retval;
 
-	if (iotg == NULL)
-		return -EINVAL;
+	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
-	pdev = to_pci_dev(iotg->otg.dev);
+	pm_runtime_get(&dev->pdev->dev);
 
-	retval = langwell_udc_resume(pdev);
-	if (retval)
-		dev_dbg(&pdev->dev, "Failed to start peripheral driver\n");
+	/* exit PHY low power suspend */
+	langwell_phy_low_power(dev, 0);
+
+	/* enable SRAM caching if detected */
+	if (dev->has_sram && !dev->got_sram)
+		sram_init(dev);
+
+	/* allocate device dQH memory */
+	size = dev->ep_max * sizeof(struct langwell_dqh);
+	dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size);
+	if (size < DQH_ALIGNMENT)
+		size = DQH_ALIGNMENT;
+	else if ((size % DQH_ALIGNMENT) != 0) {
+		size += DQH_ALIGNMENT + 1;
+		size &= ~(DQH_ALIGNMENT - 1);
+	}
+	dev->ep_dqh = dma_alloc_coherent(&dev->pdev->dev, size,
+					&dev->ep_dqh_dma, GFP_KERNEL);
+	if (!dev->ep_dqh) {
+		dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
+		return -ENOMEM;
+	}
+	dev->ep_dqh_size = size;
+	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size);
+
+	/* create dTD dma_pool resource */
+	dev->dtd_pool = dma_pool_create("langwell_dtd",
+			&dev->pdev->dev,
+			sizeof(struct langwell_dtd),
+			DTD_ALIGNMENT,
+			DMA_BOUNDARY);
+
+	if (!dev->dtd_pool)
+		return -ENOMEM;
+
+	/* enable IRQ handler */
+	if (request_irq(dev->pdev->irq, langwell_irq, IRQF_SHARED,
+				driver_name, dev) != 0) {
+		dev_err(&dev->pdev->dev, "request interrupt %d failed\n",
+				dev->pdev->irq);
+		return -EBUSY;
+	}
+	dev->got_irq = 1;
+
+	/* reset and start controller to run state */
+	if (dev->stopped) {
+		/* reset device controller */
+		langwell_udc_reset(dev);
+
+		/* reset ep0 dQH and endptctrl */
+		ep0_reset(dev);
+
+		/* start device if gadget is loaded */
+		if (dev->driver)
+			langwell_udc_start(dev);
+	}
+
+	/* reset USB status */
+	dev->usb_state = USB_STATE_ATTACHED;
+	dev->ep0_state = WAIT_FOR_SETUP;
+	dev->ep0_dir = USB_DIR_OUT;
 
 	if (dev) {
 		spin_lock_irqsave(&dev->lock, flags);
@@ -3524,24 +3581,44 @@ static int intel_mid_start_peripheral(struct intel_mid_otg_xceiv *iotg)
 		spin_unlock_irqrestore(&dev->lock, flags);
 	}
 
-	return retval;
+	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+	return 0;
 }
 
 static int intel_mid_stop_peripheral(struct intel_mid_otg_xceiv *iotg)
 {
 	struct langwell_udc	*dev = the_controller;
-	struct pci_dev		*pdev;
 	unsigned long		flags;
-	int			retval;
 
-	if (iotg == NULL)
-		return -EINVAL;
+	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
-	pdev = to_pci_dev(iotg->otg.dev);
+	/* disable interrupt and set controller to stop state */
+	langwell_udc_stop(dev);
 
-	retval = langwell_udc_suspend(pdev, PMSG_FREEZE);
-	if (retval)
-		dev_dbg(&pdev->dev, "Failed to stop peripheral driver\n");
+	/* diable IRQ handler */
+	if (dev->got_irq)
+		free_irq(dev->pdev->irq, dev);
+	dev->got_irq = 0;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	/* stop all usb activities */
+	stop_activity(dev, dev->driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	/* free dTD dma_pool and dQH */
+	if (dev->dtd_pool)
+		dma_pool_destroy(dev->dtd_pool);
+
+	if (dev->ep_dqh)
+		dma_free_coherent(&dev->pdev->dev, dev->ep_dqh_size,
+			dev->ep_dqh, dev->ep_dqh_dma);
+
+	/* release SRAM caching */
+	if (dev->has_sram && dev->got_sram)
+		sram_deinit(dev);
+
+	/* enter PHY low power suspend */
+	langwell_phy_low_power(dev, 1);
 
 	if (dev) {
 		spin_lock_irqsave(&dev->lock, flags);
@@ -3549,7 +3626,10 @@ static int intel_mid_stop_peripheral(struct intel_mid_otg_xceiv *iotg)
 		spin_unlock_irqrestore(&dev->lock, flags);
 	}
 
-	return retval;
+	pm_runtime_put(&dev->pdev->dev);
+
+	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+	return 0;
 }
 
 static int intel_mid_register_peripheral(struct pci_driver *peripheral_driver)
-- 
1.6.0.6

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux