aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHao Wu <hao.wu@intel.com>2010-12-09 10:37:46 +0000
committerAlan Cox <alan@linux.intel.com>2010-12-09 10:37:46 +0000
commite99b058b1a76a860c6ac544bec45806349c2bf52 (patch)
tree6fafb180f8776fb9cbbe79350bfe51da599a49f8
parentbd0e50951679bf66135f6758c8d7ff975b1f5a9f (diff)
downloadmrst-s0i3-test-e99b058b1a76a860c6ac544bec45806349c2bf52.tar.gz
mrst-s0i3-test-e99b058b1a76a860c6ac544bec45806349c2bf52.tar.xz
mrst-s0i3-test-e99b058b1a76a860c6ac544bec45806349c2bf52.zip
usb: langwell_udc: add runtime pm support for otg
This patch contains update on transceiver driver interfaces. Mainly to support runtime pm for OTG. Signed-off-by: Hao Wu <hao.wu@intel.com>
-rw-r--r--drivers/usb/gadget/langwell_udc.c116
1 files changed, 98 insertions, 18 deletions
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index 81d1ec9d71d..bf23704bd85 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>
@@ -3516,18 +3517,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);
@@ -3535,24 +3592,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);
@@ -3560,7 +3637,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)