diff options
| -rw-r--r-- | drivers/mfd/m4sensorhub-irq.c | 47 | ||||
| -rw-r--r-- | include/linux/m4sensorhub.h | 1 |
2 files changed, 38 insertions, 10 deletions
diff --git a/drivers/mfd/m4sensorhub-irq.c b/drivers/mfd/m4sensorhub-irq.c index 41c8378c142..139359cc73e 100644 --- a/drivers/mfd/m4sensorhub-irq.c +++ b/drivers/mfd/m4sensorhub-irq.c @@ -20,6 +20,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #include <linux/wakelock.h> #include <linux/i2c.h> #include <linux/slab.h> @@ -46,7 +47,7 @@ /* ------------ Local Function Prototypes ----------- */ static unsigned short get_enable_reg(enum m4sensorhub_irqs event); -static irqreturn_t event_threaded(int irq, void *devid); +static void irq_work_func(struct work_struct *work); #ifdef CONFIG_DEBUG_FS static int m4sensorhub_dbg_irq_open(struct inode *inode, struct file *file); #endif @@ -94,6 +95,8 @@ struct m4sensorhub_irq_info { struct m4sensorhub_irqdata { struct mutex lock; /* lock event handlers and data */ + struct work_struct work; + struct workqueue_struct *workqueue; struct m4sensorhub_data *m4sensorhub; struct m4sensorhub_event_handler event_handler[M4SH_IRQ__NUM]; struct m4sensorhub_irq_info irq_info[M4SH_IRQ__NUM]; @@ -123,11 +126,21 @@ static const struct { static irqreturn_t event_isr(int irq, void *data) { + /* Interrupts are left enabled; if multiple interrupts arrive, there + * will be multiple jobs in the workqueue. In this case, the first + * job in the workqueue may service multple interrupts and + * susbsequent jobs will have no interrupts left to service. + */ struct m4sensorhub_irqdata *irq_data = data; - + disable_irq_nosync(irq_data->m4sensorhub->i2c_client->irq); wake_lock(&irq_data->wake_lock); - return IRQ_WAKE_THREAD; + if (irq_data->m4sensorhub->irq_dbg.suspend == 1) + irq_data->m4sensorhub->irq_dbg.print_irqs = 1; + + queue_work(irq_data->workqueue, &irq_data->work); + + return IRQ_HANDLED; } #ifdef CONFIG_DEBUG_FS @@ -188,12 +201,20 @@ int m4sensorhub_irq_init(struct m4sensorhub_data *m4sensorhub) goto err_free; } + data->workqueue = create_workqueue("m4sensorhub_irq"); + if (data->workqueue == NULL) { + KDEBUG(M4SH_ERROR, "%s: IRQ Workqueue init failure\n", + __func__); + retval = -ENOMEM; + goto err_free; + } + INIT_WORK(&data->work, irq_work_func); + wake_lock_init(&data->wake_lock, WAKE_LOCK_SUSPEND, "m4sensorhub-irq"); wake_lock_init(&data->tm_wake_lock, WAKE_LOCK_SUSPEND, "m4sensorhub-timed-irq"); - retval = request_threaded_irq(i2c->irq, event_isr, event_threaded, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + retval = request_irq(i2c->irq, event_isr, IRQF_TRIGGER_HIGH, "m4sensorhub-irq", data); if (retval) { KDEBUG(M4SH_ERROR, "%s: Failed requesting irq.\n", __func__); @@ -231,6 +252,7 @@ err_free_irq: err_destroy_wq: wake_lock_destroy(&data->wake_lock); wake_lock_destroy(&data->tm_wake_lock); + destroy_workqueue(data->workqueue); err_free: mutex_destroy(&data->lock); m4sensorhub->irqdata = NULL; @@ -293,6 +315,9 @@ void m4sensorhub_irq_shutdown(struct m4sensorhub_data *m4sensorhub) mutex_unlock(&data->lock); mutex_destroy(&data->lock); + cancel_work_sync(&data->work); + destroy_workqueue(data->workqueue); + kfree(data); } EXPORT_SYMBOL_GPL(m4sensorhub_irq_shutdown); @@ -706,15 +731,16 @@ error: return; } -static irqreturn_t event_threaded(int irq, void *devid) +static void irq_work_func(struct work_struct *work) { unsigned short en_ints[NUM_INT_REGS] = { 0 }; int i; - struct m4sensorhub_irqdata *data = devid; + struct m4sensorhub_irqdata *data; struct m4sensorhub_data *m4sensorhub; struct i2c_client *i2c; unsigned char value, is_irq_set = 0; + data = container_of(work, struct m4sensorhub_irqdata, work); m4sensorhub = data->m4sensorhub; i2c = m4sensorhub->i2c_client; @@ -736,8 +762,10 @@ static irqreturn_t event_threaded(int irq, void *devid) goto error; } - if (m4sensorhub->irq_dbg.suspend == 1) + if (m4sensorhub->irq_dbg.print_irqs == 1) { m4sensorhub_print_irq_sources(en_ints); + m4sensorhub->irq_dbg.print_irqs = 0; + } for (i = 0; i < NUM_INT_REGS; ++i) { unsigned char index; @@ -782,8 +810,7 @@ static irqreturn_t event_threaded(int irq, void *devid) } error: wake_unlock(&data->wake_lock); - - return IRQ_HANDLED; + enable_irq(m4sensorhub->i2c_client->irq); } #ifdef CONFIG_DEBUG_FS diff --git a/include/linux/m4sensorhub.h b/include/linux/m4sensorhub.h index 5bc54f0885b..ae3645d5d99 100644 --- a/include/linux/m4sensorhub.h +++ b/include/linux/m4sensorhub.h @@ -95,6 +95,7 @@ struct m4sensorhub_hwconfig { struct m4sensorhub_irq_dbg { unsigned char suspend; /* 1 - Suspended, 0 - Normal */ + unsigned char print_irqs; /* 1 - IRQs to print, 0 - None */ }; struct m4sensorhub_data { |