diff mbox series

[06/13] iio: buffer: add hardware triggered buffer support

Message ID 20240109-axi-spi-engine-series-3-v1-6-e42c6a986580@baylibre.com (mailing list archive)
State Changes Requested
Headers show
Series spi: axi-spi-engine: add offload support | expand

Commit Message

David Lechner Jan. 10, 2024, 7:49 p.m. UTC
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@baylibre.com>
---
 drivers/iio/industrialio-buffer.c | 43 ++++++++++++++++++++++++++++++++++++---
 include/linux/iio/iio.h           | 16 ++++++++++++---
 2 files changed, 53 insertions(+), 6 deletions(-)

Comments

Jonathan Cameron Jan. 12, 2024, 12:37 p.m. UTC | #1
On Wed, 10 Jan 2024 13:49:47 -0600
David Lechner <dlechner@baylibre.com> wrote:

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

If the trigger isn't routeable to multiple devices we normally don't
make it visible at all.

I'm not yet understanding what a trigger actually means in this case.
Why do you need it to be userspace configurable?

J
David Lechner Jan. 12, 2024, 3:42 p.m. UTC | #2
On Fri, Jan 12, 2024 at 6:37 AM Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
>
> On Wed, 10 Jan 2024 13:49:47 -0600
> David Lechner <dlechner@baylibre.com> wrote:
>
> > 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.
>
> If the trigger isn't routeable to multiple devices we normally don't
> make it visible at all.
>
> I'm not yet understanding what a trigger actually means in this case.
> Why do you need it to be userspace configurable?
>
> J
>

It looks like this question was answered in another thread (we need to
configure the sampling frequency from userspace). But there you
mentioned that adding a trigger for that seemed overkill. So you would
you suggest to add the sampling_frequency sysfs attribute to the
iio:deviceX instead and just forget about the trigger part? It seems a
bit odd to me to have an attribute that may or may not be there
depending other hardware external to the ADC chip. But if that is a
normal acceptable thing to do, then it does seem like the simpler
thing to do.
Nuno Sá Jan. 12, 2024, 4:50 p.m. UTC | #3
On Fri, 2024-01-12 at 09:42 -0600, David Lechner wrote:
> On Fri, Jan 12, 2024 at 6:37 AM Jonathan Cameron
> <Jonathan.Cameron@huawei.com> wrote:
> > 
> > On Wed, 10 Jan 2024 13:49:47 -0600
> > David Lechner <dlechner@baylibre.com> wrote:
> > 
> > > 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.
> > 
> > If the trigger isn't routeable to multiple devices we normally don't
> > make it visible at all.
> > 
> > I'm not yet understanding what a trigger actually means in this case.
> > Why do you need it to be userspace configurable?
> > 
> > J
> > 
> 
> It looks like this question was answered in another thread (we need to
> configure the sampling frequency from userspace). But there you
> mentioned that adding a trigger for that seemed overkill. So you would
> you suggest to add the sampling_frequency sysfs attribute to the
> iio:deviceX instead and just forget about the trigger part? It seems a
> bit odd to me to have an attribute that may or may not be there
> depending other hardware external to the ADC chip. But if that is a
> normal acceptable thing to do, then it does seem like the simpler
> thing to do.

Well, for these converters you usually always need some sort of trigger to tell the
engine to fetch the data. But if not, you could make it optional in the driver (I
guess a trigger will always be a pwm, gpio, clk, etc...) and only expose the
interface if needed. Yes, if we start having tons of devices with optional triggers
(which is not the case so far) I agree we would be duplicating logic all over the
place.

But let's see where all this discussion leads us. AFAIU, having the triggers somehow
directly in the spi framework is also an option. If we can make that generic enough
and with a nice interface I think that would make the most sense as this trigger
affects the offload engine which is a spi controller thing. Let's see where we end up
:)

- Nuno Sá
diff mbox series

Patch

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