Commit fd2bb310 authored by Cristina Opriceana's avatar Cristina Opriceana Committed by Jonathan Cameron

Staging: iio: Move evgen interrupt generation to irq_work

Enhance interrupt generation in the dummy driver and expand its usage
by introducing the irq_work infrastructure to trigger an interrupt.

This way, the irq_work_queue() wrapper permits calling both of the top
half and threaded part from a hard irq context, unlike handle_nested_irq(),
which only calls the threaded part.

As an outcome, the driver succeeds in simulating real hardware
interrupts, while keeping the normal interrupt flow.
Signed-off-by: default avatarCristina Opriceana <cristina.opriceana@gmail.com>
Acked-by: default avatarDaniel Baluta <daniel.baluta@intel.com>
Signed-off-by: default avatarJonathan Cameron <jic23@kernel.org>
parent cd8d9777
...@@ -24,9 +24,21 @@ ...@@ -24,9 +24,21 @@
#include "iio_dummy_evgen.h" #include "iio_dummy_evgen.h"
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/irq_work.h>
/* Fiddly bit of faking and irq without hardware */ /* Fiddly bit of faking and irq without hardware */
#define IIO_EVENTGEN_NO 10 #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 * struct iio_dummy_evgen - evgen state
* @chip: irq chip we are faking * @chip: irq chip we are faking
...@@ -35,6 +47,7 @@ ...@@ -35,6 +47,7 @@
* @inuse: mask of which irqs are connected * @inuse: mask of which irqs are connected
* @regs: irq regs we are faking * @regs: irq regs we are faking
* @lock: protect the evgen state * @lock: protect the evgen state
* @handler: helper for a 'hardware-like' interrupt simulation
*/ */
struct iio_dummy_eventgen { struct iio_dummy_eventgen {
struct irq_chip chip; struct irq_chip chip;
...@@ -43,6 +56,7 @@ struct iio_dummy_eventgen { ...@@ -43,6 +56,7 @@ struct iio_dummy_eventgen {
bool inuse[IIO_EVENTGEN_NO]; bool inuse[IIO_EVENTGEN_NO];
struct iio_dummy_regs regs[IIO_EVENTGEN_NO]; struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
struct mutex lock; struct mutex lock;
struct iio_dummy_handle_irq handler;
}; };
/* We can only ever have one instance of this 'device' */ /* We can only ever have one instance of this 'device' */
...@@ -67,6 +81,14 @@ static void iio_dummy_event_irqunmask(struct irq_data *d) ...@@ -67,6 +81,14 @@ static void iio_dummy_event_irqunmask(struct irq_data *d)
evgen->enabled[d->irq - evgen->base] = true; 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_handler->irq, irq_to_desc(irq_handler->irq));
}
static int iio_dummy_evgen_create(void) static int iio_dummy_evgen_create(void)
{ {
int ret, i; int ret, i;
...@@ -91,6 +113,7 @@ static int iio_dummy_evgen_create(void) ...@@ -91,6 +113,7 @@ static int iio_dummy_evgen_create(void)
IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOREQUEST | IRQ_NOAUTOEN,
IRQ_NOPROBE); IRQ_NOPROBE);
} }
init_irq_work(&iio_evgen->handler.work, iio_dummy_work_handler);
mutex_init(&iio_evgen->lock); mutex_init(&iio_evgen->lock);
return 0; return 0;
} }
...@@ -169,8 +192,9 @@ static ssize_t iio_evgen_poke(struct device *dev, ...@@ -169,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_id = this_attr->address;
iio_evgen->regs[this_attr->address].reg_data = event; 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]) 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; return len;
} }
......
...@@ -46,6 +46,7 @@ struct iio_dummy_state { ...@@ -46,6 +46,7 @@ struct iio_dummy_state {
int event_irq; int event_irq;
int event_val; int event_val;
bool event_en; bool event_en;
s64 event_timestamp;
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */ #endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
}; };
......
...@@ -153,6 +153,15 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, ...@@ -153,6 +153,15 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
return 0; return 0;
} }
static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct iio_dummy_state *st = iio_priv(indio_dev);
st->event_timestamp = iio_get_time_ns();
return IRQ_HANDLED;
}
/** /**
* iio_simple_dummy_event_handler() - identify and pass on event * iio_simple_dummy_event_handler() - identify and pass on event
* @irq: irq of event line * @irq: irq of event line
...@@ -177,7 +186,7 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private) ...@@ -177,7 +186,7 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0, IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
IIO_EV_DIR_RISING, IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH, 0, 0, 0), IIO_EV_TYPE_THRESH, 0, 0, 0),
iio_get_time_ns()); st->event_timestamp);
break; break;
case 1: case 1:
if (st->activity_running > st->event_val) if (st->activity_running > st->event_val)
...@@ -187,7 +196,7 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private) ...@@ -187,7 +196,7 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
IIO_EV_DIR_RISING, IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH, IIO_EV_TYPE_THRESH,
0, 0, 0), 0, 0, 0),
iio_get_time_ns()); st->event_timestamp);
break; break;
case 2: case 2:
if (st->activity_walking < st->event_val) if (st->activity_walking < st->event_val)
...@@ -197,14 +206,14 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private) ...@@ -197,14 +206,14 @@ static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
IIO_EV_DIR_FALLING, IIO_EV_DIR_FALLING,
IIO_EV_TYPE_THRESH, IIO_EV_TYPE_THRESH,
0, 0, 0), 0, 0, 0),
iio_get_time_ns()); st->event_timestamp);
break; break;
case 3: case 3:
iio_push_event(indio_dev, iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD, IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
IIO_EV_DIR_NONE, IIO_EV_DIR_NONE,
IIO_EV_TYPE_CHANGE, 0, 0, 0), IIO_EV_TYPE_CHANGE, 0, 0, 0),
iio_get_time_ns()); st->event_timestamp);
break; break;
default: default:
break; break;
...@@ -238,7 +247,7 @@ int iio_simple_dummy_events_register(struct iio_dev *indio_dev) ...@@ -238,7 +247,7 @@ int iio_simple_dummy_events_register(struct iio_dev *indio_dev)
st->regs = iio_dummy_evgen_get_regs(st->event_irq); st->regs = iio_dummy_evgen_get_regs(st->event_irq);
ret = request_threaded_irq(st->event_irq, ret = request_threaded_irq(st->event_irq,
NULL, &iio_simple_dummy_get_timestamp,
&iio_simple_dummy_event_handler, &iio_simple_dummy_event_handler,
IRQF_ONESHOT, IRQF_ONESHOT,
"iio_simple_event", "iio_simple_event",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment