aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uio
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-08-14 06:49:38 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-08-23 05:03:19 -0400
commitaf76756e6e8c268c684865d29b897a470de1f097 (patch)
treeab7d67edc7a74cc66251c8261e71ea709087bf6e /drivers/uio
parent6d1386c6b8db54ac8d94c01194e0c27cd538532b (diff)
uio: Runtime PM for UIO devices
This patch modifies the uio_pdrv_genirq driver to support Runtime PM. The power management implementation simply runtime resumes the device at open() time and runtime suspends it at release() time. The user space driver is responsible for re-initializing the hardware after open(). Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
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 @@
20#include <linux/bitops.h> 20#include <linux/bitops.h>
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/stringify.h> 22#include <linux/stringify.h>
23#include <linux/pm_runtime.h>
23 24
24#define DRIVER_NAME "uio_pdrv_genirq" 25#define DRIVER_NAME "uio_pdrv_genirq"
25 26
@@ -27,8 +28,27 @@ struct uio_pdrv_genirq_platdata {
27 struct uio_info *uioinfo; 28 struct uio_info *uioinfo;
28 spinlock_t lock; 29 spinlock_t lock;
29 unsigned long flags; 30 unsigned long flags;
31 struct platform_device *pdev;
30}; 32};
31 33
34static int uio_pdrv_genirq_open(struct uio_info *info, struct inode *inode)
35{
36 struct uio_pdrv_genirq_platdata *priv = info->priv;
37
38 /* Wait until the Runtime PM code has woken up the device */
39 pm_runtime_get_sync(&priv->pdev->dev);
40 return 0;
41}
42
43static int uio_pdrv_genirq_release(struct uio_info *info, struct inode *inode)
44{
45 struct uio_pdrv_genirq_platdata *priv = info->priv;
46
47 /* Tell the Runtime PM code that the device has become idle */
48 pm_runtime_put_sync(&priv->pdev->dev);
49 return 0;
50}
51
32static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info) 52static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info)
33{ 53{
34 struct uio_pdrv_genirq_platdata *priv = dev_info->priv; 54 struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
@@ -97,6 +117,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
97 priv->uioinfo = uioinfo; 117 priv->uioinfo = uioinfo;
98 spin_lock_init(&priv->lock); 118 spin_lock_init(&priv->lock);
99 priv->flags = 0; /* interrupt is enabled to begin with */ 119 priv->flags = 0; /* interrupt is enabled to begin with */
120 priv->pdev = pdev;
100 121
101 uiomem = &uioinfo->mem[0]; 122 uiomem = &uioinfo->mem[0];
102 123
@@ -136,8 +157,17 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
136 uioinfo->irq_flags |= IRQF_DISABLED; 157 uioinfo->irq_flags |= IRQF_DISABLED;
137 uioinfo->handler = uio_pdrv_genirq_handler; 158 uioinfo->handler = uio_pdrv_genirq_handler;
138 uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol; 159 uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol;
160 uioinfo->open = uio_pdrv_genirq_open;
161 uioinfo->release = uio_pdrv_genirq_release;
139 uioinfo->priv = priv; 162 uioinfo->priv = priv;
140 163
164 /* Enable Runtime PM for this device:
165 * The device starts in suspended state to allow the hardware to be
166 * turned off by default. The Runtime PM bus code should power on the
167 * hardware and enable clocks at open().
168 */
169 pm_runtime_enable(&pdev->dev);
170
141 ret = uio_register_device(&pdev->dev, priv->uioinfo); 171 ret = uio_register_device(&pdev->dev, priv->uioinfo);
142 if (ret) { 172 if (ret) {
143 dev_err(&pdev->dev, "unable to register uio device\n"); 173 dev_err(&pdev->dev, "unable to register uio device\n");
@@ -157,16 +187,40 @@ static int uio_pdrv_genirq_remove(struct platform_device *pdev)
157 struct uio_pdrv_genirq_platdata *priv = platform_get_drvdata(pdev); 187 struct uio_pdrv_genirq_platdata *priv = platform_get_drvdata(pdev);
158 188
159 uio_unregister_device(priv->uioinfo); 189 uio_unregister_device(priv->uioinfo);
190 pm_runtime_disable(&pdev->dev);
160 kfree(priv); 191 kfree(priv);
161 return 0; 192 return 0;
162} 193}
163 194
195static int uio_pdrv_genirq_runtime_nop(struct device *dev)
196{
197 /* Runtime PM callback shared between ->runtime_suspend()
198 * and ->runtime_resume(). Simply returns success.
199 *
200 * In this driver pm_runtime_get_sync() and pm_runtime_put_sync()
201 * are used at open() and release() time. This allows the
202 * Runtime PM code to turn off power to the device while the
203 * device is unused, ie before open() and after release().
204 *
205 * This Runtime PM callback does not need to save or restore
206 * any registers since user space is responsbile for hardware
207 * register reinitialization after open().
208 */
209 return 0;
210}
211
212static struct dev_pm_ops uio_pdrv_genirq_dev_pm_ops = {
213 .runtime_suspend = uio_pdrv_genirq_runtime_nop,
214 .runtime_resume = uio_pdrv_genirq_runtime_nop,
215};
216
164static struct platform_driver uio_pdrv_genirq = { 217static struct platform_driver uio_pdrv_genirq = {
165 .probe = uio_pdrv_genirq_probe, 218 .probe = uio_pdrv_genirq_probe,
166 .remove = uio_pdrv_genirq_remove, 219 .remove = uio_pdrv_genirq_remove,
167 .driver = { 220 .driver = {
168 .name = DRIVER_NAME, 221 .name = DRIVER_NAME,
169 .owner = THIS_MODULE, 222 .owner = THIS_MODULE,
223 .pm = &uio_pdrv_genirq_dev_pm_ops,
170 }, 224 },
171}; 225};
172 226