diff options
Diffstat (limited to 'drivers/uio/uio_pdrv_genirq.c')
-rw-r--r-- | drivers/uio/uio_pdrv_genirq.c | 54 |
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 | ||
34 | static 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 | |||
43 | static 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 | |||
32 | static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info) | 52 | static 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 | ||
195 | static 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 | |||
212 | static 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 | |||
164 | static struct platform_driver uio_pdrv_genirq = { | 217 | static 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 | ||