summaryrefslogtreecommitdiff
path: root/drivers/mxc/vpu
diff options
context:
space:
mode:
authorSammy He <r62914@freescale.com>2010-11-16 22:12:14 +0800
committerAlan Tull <alan.tull@freescale.com>2011-02-03 16:30:48 -0600
commit804a4cf530c96fe10f52f2daff30a6822cffb224 (patch)
treeb0bd9ba84f2c98df5ff0e3a14a3c5aa30cf790ee /drivers/mxc/vpu
parent11d7db4f8885fe2ea756a51ce4493314fcc47e1e (diff)
ENGR00133726 vpu: make clk_disable() be called only in process context
Voltage scaling is done using the Regulator API, which talks to PMIC using SPI. SPI code can sleep and hence clk_[en|dis]able() cannot be called in an ISR/tasklet etc contexts. Signed-off-by: Sammy He <r62914@freescale.com>
Diffstat (limited to 'drivers/mxc/vpu')
-rw-r--r--drivers/mxc/vpu/mxc_vpu.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/drivers/mxc/vpu/mxc_vpu.c b/drivers/mxc/vpu/mxc_vpu.c
index e4ba1e10f43d..67b9ebbdca42 100644
--- a/drivers/mxc/vpu/mxc_vpu.c
+++ b/drivers/mxc/vpu/mxc_vpu.c
@@ -36,6 +36,7 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <asm/sizes.h>
#include <mach/clock.h>
@@ -45,6 +46,8 @@
struct vpu_priv {
struct fasync_struct *async_queue;
+ struct work_struct work;
+ struct workqueue_struct *workqueue;
};
/* To track the allocated memory buffer */
@@ -190,27 +193,35 @@ static int vpu_free_buffers(void)
return 0;
}
-/*!
- * @brief vpu interrupt handler
- */
-static irqreturn_t vpu_irq_handler(int irq, void *dev_id)
+static inline void vpu_worker_callback(struct work_struct *w)
{
- struct vpu_priv *dev = dev_id;
-
- READ_REG(BIT_INT_STATUS);
- WRITE_REG(0x1, BIT_INT_CLEAR);
+ struct vpu_priv *dev = container_of(w, struct vpu_priv,
+ work);
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
+ codec_done = 1;
+ wake_up_interruptible(&vpu_queue);
+
/*
* Clock is gated on when dec/enc started, gate it off when
* interrupt is received.
*/
clk_disable(vpu_clk);
+}
- codec_done = 1;
- wake_up_interruptible(&vpu_queue);
+/*!
+ * @brief vpu interrupt handler
+ */
+static irqreturn_t vpu_irq_handler(int irq, void *dev_id)
+{
+ struct vpu_priv *dev = dev_id;
+
+ READ_REG(BIT_INT_STATUS);
+ WRITE_REG(0x1, BIT_INT_CLEAR);
+
+ queue_work(dev->workqueue, &dev->work);
return IRQ_HANDLED;
}
@@ -644,6 +655,8 @@ static int vpu_dev_probe(struct platform_device *pdev)
if (err)
goto err_out_class;
+ vpu_data.workqueue = create_workqueue("vpu_wq");
+ INIT_WORK(&vpu_data.work, vpu_worker_callback);
printk(KERN_INFO "VPU initialized\n");
goto out;
@@ -664,6 +677,10 @@ static int vpu_dev_probe(struct platform_device *pdev)
static int vpu_dev_remove(struct platform_device *pdev)
{
free_irq(vpu_irq, &vpu_data);
+ cancel_work_sync(&vpu_data.work);
+ flush_workqueue(vpu_data.workqueue);
+ destroy_workqueue(vpu_data.workqueue);
+
iounmap(vpu_base);
if (VPU_IRAM_SIZE)
iram_free(iram.start, VPU_IRAM_SIZE);