summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/staging/iio/iio_dummy_evgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/staging/iio/iio_dummy_evgen.c')
-rw-r--r--kernel/drivers/staging/iio/iio_dummy_evgen.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/kernel/drivers/staging/iio/iio_dummy_evgen.c b/kernel/drivers/staging/iio/iio_dummy_evgen.c
index 0c9c86d7b..9e83f348d 100644
--- a/kernel/drivers/staging/iio/iio_dummy_evgen.c
+++ b/kernel/drivers/staging/iio/iio_dummy_evgen.c
@@ -24,9 +24,21 @@
#include "iio_dummy_evgen.h"
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/irq_work.h>
/* Fiddly bit of faking and irq without hardware */
#define IIO_EVENTGEN_NO 10
+
+/**
+ * struct iio_dummy_handle_irq - helper struct to simulate interrupt generation
+ * @work: irq_work used to run handlers from hardirq context
+ * @irq: fake irq line number to trigger an interrupt
+ */
+struct iio_dummy_handle_irq {
+ struct irq_work work;
+ int irq;
+};
+
/**
* struct iio_dummy_evgen - evgen state
* @chip: irq chip we are faking
@@ -35,6 +47,7 @@
* @inuse: mask of which irqs are connected
* @regs: irq regs we are faking
* @lock: protect the evgen state
+ * @handler: helper for a 'hardware-like' interrupt simulation
*/
struct iio_dummy_eventgen {
struct irq_chip chip;
@@ -43,6 +56,7 @@ struct iio_dummy_eventgen {
bool inuse[IIO_EVENTGEN_NO];
struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
struct mutex lock;
+ struct iio_dummy_handle_irq handler;
};
/* We can only ever have one instance of this 'device' */
@@ -67,6 +81,14 @@ static void iio_dummy_event_irqunmask(struct irq_data *d)
evgen->enabled[d->irq - evgen->base] = true;
}
+static void iio_dummy_work_handler(struct irq_work *work)
+{
+ struct iio_dummy_handle_irq *irq_handler;
+
+ irq_handler = container_of(work, struct iio_dummy_handle_irq, work);
+ handle_simple_irq(irq_to_desc(irq_handler->irq));
+}
+
static int iio_dummy_evgen_create(void)
{
int ret, i;
@@ -91,6 +113,7 @@ static int iio_dummy_evgen_create(void)
IRQ_NOREQUEST | IRQ_NOAUTOEN,
IRQ_NOPROBE);
}
+ init_irq_work(&iio_evgen->handler.work, iio_dummy_work_handler);
mutex_init(&iio_evgen->lock);
return 0;
}
@@ -128,13 +151,11 @@ EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq);
*
* Used by client driver instances to give the irqs back when they disconnect
*/
-int iio_dummy_evgen_release_irq(int irq)
+void iio_dummy_evgen_release_irq(int irq)
{
mutex_lock(&iio_evgen->lock);
iio_evgen->inuse[irq - iio_evgen->base] = false;
mutex_unlock(&iio_evgen->lock);
-
- return 0;
}
EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
@@ -171,8 +192,9 @@ static ssize_t iio_evgen_poke(struct device *dev,
iio_evgen->regs[this_attr->address].reg_id = this_attr->address;
iio_evgen->regs[this_attr->address].reg_data = event;
+ iio_evgen->handler.irq = iio_evgen->base + this_attr->address;
if (iio_evgen->enabled[this_attr->address])
- handle_nested_irq(iio_evgen->base + this_attr->address);
+ irq_work_queue(&iio_evgen->handler.work);
return len;
}
@@ -216,6 +238,7 @@ static struct device iio_evgen_dev = {
.groups = iio_evgen_groups,
.release = &iio_evgen_release,
};
+
static __init int iio_dummy_evgen_init(void)
{
int ret = iio_dummy_evgen_create();