This adds a new mode INDIO_HW_BUFFER_TRIGGERED to the IIO subsystem. This mode is essentially the hardware version of INDIO_BUFFER_TRIGGERED where the trigger has the semantics of INDIO_HARDWARE_TRIGGERED and the buffer has the semantics of INDIO_BUFFER_HARDWARE. So basically INDIO_HW_BUFFER_TRIGGERED is the same as INDIO_BUFFER_HARDWARE except that it also enables the trigger when the buffer is enabled. Signed-off-by: David Lechner <dlechner@xxxxxxxxxxxx> --- drivers/iio/industrialio-buffer.c | 43 ++++++++++++++++++++++++++++++++++++--- include/linux/iio/iio.h | 16 ++++++++++++--- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 176d31d9f9d8..ffee3043c65a 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -27,6 +27,7 @@ #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> #include <linux/iio/buffer_impl.h> +#include <linux/iio/trigger.h> static const char * const iio_endian_prefix[] = { [IIO_BE] = "be", @@ -867,8 +868,17 @@ static int iio_verify_update(struct iio_dev *indio_dev, insert_buffer->watermark); } - /* Definitely possible for devices to support both of these. */ - if ((modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) { + /* Definitely possible for devices to support all of these. */ + if (modes & INDIO_HW_BUFFER_TRIGGERED) { + /* + * Keep things simple for now and only allow a single buffer to + * be connected in hardware mode. + */ + if (insert_buffer && !list_empty(&iio_dev_opaque->buffer_list)) + return -EINVAL; + config->mode = INDIO_HW_BUFFER_TRIGGERED; + strict_scanmask = true; + } else if ((modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) { config->mode = INDIO_BUFFER_TRIGGERED; } else if (modes & INDIO_BUFFER_HARDWARE) { /* @@ -1107,11 +1117,21 @@ static int iio_enable_buffers(struct iio_dev *indio_dev, } } + if (iio_dev_opaque->currentmode == INDIO_HW_BUFFER_TRIGGERED) { + struct iio_trigger *trig = indio_dev->trig; + + if (trig->ops && trig->ops->set_trigger_state) { + ret = trig->ops->set_trigger_state(trig, true); + if (ret) + goto err_disable_buffers; + } + } + if (iio_dev_opaque->currentmode == INDIO_BUFFER_TRIGGERED) { ret = iio_trigger_attach_poll_func(indio_dev->trig, indio_dev->pollfunc); if (ret) - goto err_disable_buffers; + goto err_disable_hw_trigger; } if (indio_dev->setup_ops->postenable) { @@ -1130,6 +1150,16 @@ static int iio_enable_buffers(struct iio_dev *indio_dev, iio_trigger_detach_poll_func(indio_dev->trig, indio_dev->pollfunc); } +err_disable_hw_trigger: + if (iio_dev_opaque->currentmode == INDIO_HW_BUFFER_TRIGGERED) { + struct iio_trigger *trig = indio_dev->trig; + + if (trig->ops && trig->ops->set_trigger_state) { + ret = trig->ops->set_trigger_state(trig, false); + if (ret) + return ret; + } + } err_disable_buffers: buffer = list_prepare_entry(tmp, &iio_dev_opaque->buffer_list, buffer_list); list_for_each_entry_continue_reverse(buffer, &iio_dev_opaque->buffer_list, @@ -1174,6 +1204,13 @@ static int iio_disable_buffers(struct iio_dev *indio_dev) indio_dev->pollfunc); } + if (iio_dev_opaque->currentmode == INDIO_HW_BUFFER_TRIGGERED) { + struct iio_trigger *trig = indio_dev->trig; + + if (trig->ops && trig->ops->set_trigger_state) + trig->ops->set_trigger_state(trig, false); + } + list_for_each_entry(buffer, &iio_dev_opaque->buffer_list, buffer_list) { ret2 = iio_buffer_disable(buffer, indio_dev); if (ret2 && !ret) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index d0ce3b71106a..16f62bd38041 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -366,6 +366,11 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev); * they must be managed by the core, but without the entire interrupts/poll * functions burden. Interrupts are irrelevant as the data flow is hardware * mediated and distributed. + * @INDIO_HW_BUFFER_TRIGGERED: Very unusual mode. + * This is similar to INDIO_BUFFER_TRIGGERED but everything is done in hardware + * therefore there are no poll functions attached. It also implies the semantics + * of both INDIO_HARDWARE_TRIGGERED for the trigger and INDIO_BUFFER_HARDWARE + * for the buffer. */ #define INDIO_DIRECT_MODE 0x01 #define INDIO_BUFFER_TRIGGERED 0x02 @@ -373,14 +378,19 @@ s64 iio_get_time_ns(const struct iio_dev *indio_dev); #define INDIO_BUFFER_HARDWARE 0x08 #define INDIO_EVENT_TRIGGERED 0x10 #define INDIO_HARDWARE_TRIGGERED 0x20 +#define INDIO_HW_BUFFER_TRIGGERED 0x40 -#define INDIO_ALL_BUFFER_MODES \ - (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE) +#define INDIO_ALL_BUFFER_MODES \ + (INDIO_BUFFER_TRIGGERED \ + | INDIO_BUFFER_HARDWARE \ + | INDIO_BUFFER_SOFTWARE \ + | INDIO_HW_BUFFER_TRIGGERED) #define INDIO_ALL_TRIGGERED_MODES \ (INDIO_BUFFER_TRIGGERED \ | INDIO_EVENT_TRIGGERED \ - | INDIO_HARDWARE_TRIGGERED) + | INDIO_HARDWARE_TRIGGERED \ + | INDIO_HW_BUFFER_TRIGGERED) #define INDIO_MAX_RAW_ELEMENTS 4 -- 2.43.0