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 {  |