summary refs log tree commit diff
path: root/drivers/uio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-18 09:43:09 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-18 09:43:09 -0700
commit515b696b282f856c3ad1679ccd658120faa387d0 (patch)
treed9d7c1185c396617f128ca23463062308d11393b /drivers/uio
parentfa877c71e2136bd682b45022c96d5e073ced9f58 (diff)
parent064a16dc41be879d12bd5de5d2f9d38d890e0ee7 (diff)
downloadlinux-515b696b282f856c3ad1679ccd658120faa387d0.tar.gz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6: (262 commits)
  sh: mach-ecovec24: Add user debug switch support
  sh: Kill off unused se_skipped in alignment trap notification code.
  sh: Wire up HAVE_SYSCALL_TRACEPOINTS.
  video: sh_mobile_lcdcfb: use both register sets for display panning
  video: sh_mobile_lcdcfb: implement display panning
  sh: Fix up sh7705 flush_dcache_page() build.
  sh: kfr2r09: document the PLL/FLL <-> RF relationship.
  sh: mach-ecovec24: need asm/clock.h.
  sh: mach-ecovec24: deassert usb irq on boot.
  sh: Add KEYSC support for EcoVec24
  sh: add kycr2_delay for sh_keysc
  sh: cpufreq: Include CPU id in info messages.
  sh: multi-evt support for SH-X3 proto CPU.
  sh: clkfwk: remove bogus set_bus_parent() from SH7709.
  sh: Fix the indication point of the liquid crystal of AP-325RXA(AP3300)
  sh: Add EcoVec24 romImage defconfig
  sh: USB disable process is needed if romImage boot for EcoVec24
  sh: EcoVec24: add HIZA setting for LED
  sh: EcoVec24: write MAC address in boot
  sh: Add romImage support for EcoVec24
  ...
Diffstat (limited to 'drivers/uio')
-rw-r--r--drivers/uio/uio_pdrv_genirq.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index 3f06818cf9fa..02347c57357d 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -20,6 +20,7 @@
 #include <linux/bitops.h>
 #include <linux/interrupt.h>
 #include <linux/stringify.h>
+#include <linux/pm_runtime.h>
 
 #define DRIVER_NAME "uio_pdrv_genirq"
 
@@ -27,8 +28,27 @@ struct uio_pdrv_genirq_platdata {
 	struct uio_info *uioinfo;
 	spinlock_t lock;
 	unsigned long flags;
+	struct platform_device *pdev;
 };
 
+static int uio_pdrv_genirq_open(struct uio_info *info, struct inode *inode)
+{
+	struct uio_pdrv_genirq_platdata *priv = info->priv;
+
+	/* Wait until the Runtime PM code has woken up the device */
+	pm_runtime_get_sync(&priv->pdev->dev);
+	return 0;
+}
+
+static int uio_pdrv_genirq_release(struct uio_info *info, struct inode *inode)
+{
+	struct uio_pdrv_genirq_platdata *priv = info->priv;
+
+	/* Tell the Runtime PM code that the device has become idle */
+	pm_runtime_put_sync(&priv->pdev->dev);
+	return 0;
+}
+
 static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info)
 {
 	struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
@@ -97,6 +117,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
 	priv->uioinfo = uioinfo;
 	spin_lock_init(&priv->lock);
 	priv->flags = 0; /* interrupt is enabled to begin with */
+	priv->pdev = pdev;
 
 	uiomem = &uioinfo->mem[0];
 
@@ -136,8 +157,17 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
 	uioinfo->irq_flags |= IRQF_DISABLED;
 	uioinfo->handler = uio_pdrv_genirq_handler;
 	uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol;
+	uioinfo->open = uio_pdrv_genirq_open;
+	uioinfo->release = uio_pdrv_genirq_release;
 	uioinfo->priv = priv;
 
+	/* Enable Runtime PM for this device:
+	 * The device starts in suspended state to allow the hardware to be
+	 * turned off by default. The Runtime PM bus code should power on the
+	 * hardware and enable clocks at open().
+	 */
+	pm_runtime_enable(&pdev->dev);
+
 	ret = uio_register_device(&pdev->dev, priv->uioinfo);
 	if (ret) {
 		dev_err(&pdev->dev, "unable to register uio device\n");
@@ -157,16 +187,40 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev)
 	struct uio_pdrv_genirq_platdata *priv = platform_get_drvdata(pdev);
 
 	uio_unregister_device(priv->uioinfo);
+	pm_runtime_disable(&pdev->dev);
 	kfree(priv);
 	return 0;
 }
 
+static int uio_pdrv_genirq_runtime_nop(struct device *dev)
+{
+	/* Runtime PM callback shared between ->runtime_suspend()
+	 * and ->runtime_resume(). Simply returns success.
+	 *
+	 * In this driver pm_runtime_get_sync() and pm_runtime_put_sync()
+	 * are used at open() and release() time. This allows the
+	 * Runtime PM code to turn off power to the device while the
+	 * device is unused, ie before open() and after release().
+	 *
+	 * This Runtime PM callback does not need to save or restore
+	 * any registers since user space is responsbile for hardware
+	 * register reinitialization after open().
+	 */
+	return 0;
+}
+
+static struct dev_pm_ops uio_pdrv_genirq_dev_pm_ops = {
+	.runtime_suspend = uio_pdrv_genirq_runtime_nop,
+	.runtime_resume = uio_pdrv_genirq_runtime_nop,
+};
+
 static struct platform_driver uio_pdrv_genirq = {
 	.probe = uio_pdrv_genirq_probe,
 	.remove = uio_pdrv_genirq_remove,
 	.driver = {
 		.name = DRIVER_NAME,
 		.owner = THIS_MODULE,
+		.pm = &uio_pdrv_genirq_dev_pm_ops,
 	},
 };