Re: [PATCH v2 1/2] iio: adc: driver for texas instruments ads7142

From: József Horváth
Date: Wed May 19 2021 - 12:51:45 EST


On Mon, May 17, 2021 at 10:28:04AM +0100, Jonathan Cameron wrote:
> On Sun, 16 May 2021 19:07:55 +0000
> József Horváth <info@xxxxxxxxxxx> wrote:
>
> > On Sun, May 16, 2021 at 12:28:40PM +0100, Jonathan Cameron wrote:
> > > On Sun, 16 May 2021 07:30:35 +0000
> > > Jozsef Horvath <info@xxxxxxxxxxx> wrote:
> > >
> > > > This is an iio driver for
> > > > Texas Instruments ADS7142 dual-channel, programmable sensor monitor.
> > >
> > > Hi,
> > >
> > > Note I review in reverse, so it's possible my comments will make more
> > > sense read in that direction!
> > >
> > > Various comments inline, but mostly this seems to be coming together nicely!
> > >
> > > Jonathan
> > > >
> > > > All of the data buffer modes, supported by the device are selectable
> > > > over sysfs:
> > > > /sys/bus/iio/devices/iio:deviceX/buffer_mode
> > > >
> > > > Data buffer operation modes:
> > > > - start_burst:
> > >
> > > I'd like to see a lot of this info in the ABI docs. Not the internals
> > > part but the 'what needs to be configured' element.
> > >
> > > Some of the flow related stuff should go in the driver itself.
> > > It's non obvious and no one reads patch descriptions after the code has
> > > merged!
> > >
> >
> > Ok, I'll write a more detailed description with configuration
> > requirements
> >
> > >
> > > > In triggered buffer preenable hook: not relevant.
> > > > In trigger handler: the driver selects the autonomous monitoring
> > > > (see chapter 7.4.3 in datasheet) operation mode,
> > > > configures the channels in sequencer as specified by
> > > > sysfs(scan_elements/in_voltageY_en),
> > > > sets the data buffer mode to "Start Burst Mode",
> > > > then starts the conversion.
> > > > In irq handler: the driver pushes the conversion results received
> > > > from the device to the buffer,
> > > > then restarts the conversion like in trigger handler.
> > > > Both IRQ and trigger are required to support this mode.
> > > > See chapter 7.4.3.2.1 "Autonomous Mode with Start Burst"
> > > > in datasheet.
> > >
> > > > - stop_burst:
> > > > In triggered buffer preenable hook: the driver selects the
> > > > autonomous monitoring (see chapter 7.4.3 in datasheet)
> > > > operation mode,
> > > > configures the channels in sequencer as
> > > > specified by sysfs(scan_elements/in_voltageY_en),
> > > > sets the data buffer mode to "Stop Burst Mode",
> > > > then starts the conversion.
> > > > In trigger handler: the driver pushes the conversion results received
> > > > from the device to the buffer,
> > > > then restarts the conversion like in preenable hook.
> > > > In irq handler: not relevant.
> > > > Trigger is required to support this mode.
> > > > See chapter 7.4.3.2.2 "Autonomous Mode with Stop Burst"
> > > > in datasheet.
> > >
> > > > - pre_alert:
> > > > In triggered buffer preenable hook: the driver selects the autonomous
> > > > monitoring (see chapter 7.4.3 in datasheet) operation mode,
> > > > configures the channels in sequencer
> > > > as specified by sysfs(scan_elements/in_voltageY_en),
> > > > configures the digital window comparator and alert flags,
> > > > sets the data buffer mode to "Pre Alert Data Mode",
> > > > then starts the conversion.
> > > > In trigger handler: not relevant.
> > > > In irq handler: the driver pushes the conversion results received
> > > > from the device to the buffer,
> > > > then restarts the conversion like in preenable hook.
> > > > IRQ is required to support this mode.
> > > > See chapter 7.4.3.1.1 "Autonomous Mode with Pre Alert Data"
> > > > in datasheet
> > > > - post_alert:
> > > > The operations are same like in pre_alert mode,
> > > > except the data buffer mode selection, the selected mode is
> > > > "Post Alert Data Mode".
> > > > See chapter 7.4.3.1.2 "Autonomous Mode with Post Alert Data"
> > > > in datasheet
> > >
> > > Impressive you got all these to work reasonably cleanly. My only
> > > remaining question on this stuff is whether we can do anything that
> > > looks 'more standard' to enable the use of these with general purpose
> > > code.
> > >
> > > The last two could be implemented as a trigger, be it one that can only
> > > be used by this device. So you would select the mode by picking the
> > > relevant trigger.
> > >
> > > However I can't see any similar way of supporting the start and stop burst
> > > modes. So for now at least perhaps this is the best we can do (and it
> > > won't be too painful to support this as a legacy interface if we do later
> > > figure out a nice generic interface).
> > >
> > >
> > > I would like to think longer term about whether we can come up with
> > > some standard ABI for these 'burst' capture devices. We have another one
> > > in staging (adis16240) that has been there a long time as we never
> > > managed to make progress on the interface.
> > >
> > > Looking briefly at that device, I do note that it supports somewhere
> > > between your pre_alert and post_alert (X samples before event, so
> > > many samples after). Maybe we want to think about an alert mode
> > > and use a separate control to set the 'where' part relative to
> > > the alert mode?
> > >
> > > It is hard to define general ABI with 2 devices however, so perhaps
> > > we should stick with what you have and can always add an "alert"
> > > buffer mode as needed for a new device.
> > >
> >
> > I think we can say that, all of general purpose ADCs, pressure, light, accel etc.
> > sensors supports "virtual" start_burst mode with at least 1 element FIFO per channel.
> > Flow:
> > 1. in trigger, the host issues a start conversion request to device,
> > then polls or "wait" IRQ/conv rdy signal
> > 2. device do the job, then report the state of end of operation, somehow...
> > 3. the completion handler moves the conversion result to buffer
> >
> > Here is some device with real start_burst like support (not complete list):
> > accel/adxl345
> > datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
> > see: Table 22. FIFO Mode: FIFO collects up to 32 values...
> > accel/bmc150-accel
> > datasheet: https://hu.mouser.com/datasheet/2/783/BST-BMC150-DS000-1509560.pdf
> > see: 5.1 FIFO Operating Modes: FIFO Mode
> > note: obsolate
> > accel/bmi088-accel
> > datasheet: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
> > see: 4.9.1 FIFO operating modes: FIFO or stop-at-full mode
> > gyro/bmg160
> > datasheet: https://hu.mouser.com/datasheet/2/783/BST-BMG160-DS000-1509613.pdf
> > see: 5.1 FIFO Operating Modes: FIFO Mode
> > note: obsolete
> > health/max30100
> > datasheet: https://datasheets.maximintegrated.com/en/ds/MAX30100.pdf
> > see: FIFO (0x02–0x05)
> > note: this mode is very close to start_burst mode of ti-ads7141
> >
> > The current generalized triggered_buffer API covers this mode completely.
>
> Not quite. The triggered buffer API covers the one scan mode only (fifo depth 1).
> It doesn't in general cover using a trigger to start fifo capture. We have talked about
> adding this layered trigger approach before (conceptually it is one trigger starting
> a hardware trigger that we can't see), but not done it yet. The reason
> for this restriction is that most triggers can also be used to drive additional
> sensors (so capture from N devices at roughly the same time + at the same
> frequency). We do have a few devices which provide their own triggers limited
> to local use as a means of selecting modes like this (often complex ADCs like
> the stm32 ones where a bunch of other signals in the SoC can be used to
> autonomously start capture of a scan).
>
> Mostly the fifo mode on the above devices is implemented without a trigger.
> Triggers being attached makes them fall back into a 1 entry fifo so it is
> one trigger per scan.
>
> It might be possible to safely adapt the semantics of this mode to support
> such capture using existing interfaces, but we need to be very careful not
> to break existing ABI assumptions.
>

It's clear now, for me.
The problem we are facing is how can we represent a more than one element FIFO
scan collection, we can call this "capture".
You are right, the industrialio-buffer is not covers this requirement, we dontt
know, where the received scan line came from.
The "item" definition in the capture context:
One item in the capture is one or multiple lines of scans.

This problem is very similar to capturing images from a video device.
The solution what I'm thinking for, is close to videobuf2 queued buffer
mechanism(videobuf2-v4l2.c).

I think this kind of operation and the required configuration can be managed via sysfs,
but there is some useful IOCTL's for video buffer configuration/allocation
(VIDIOC_QBUF, VIDIOC_DQBUF), and pointer exchange between user and system
is faster and better for the high speed capture devices than copying from kernel to user,
and we can define/make similar IOCTL's over iio char device.

The new ABI name could be: industrialio-capture.

> >
> > Some of sensors under iio supports stop_burst mode with FIFO.
> > Flow could be:
> > 1. in somewhere(probably buffer_{pre,post} enable), the host configures the FIFO
> > then starts conversion
> > 2. in trigger, the host reads FIFO content,
> > then push the result to buffer,
> > then restart the conversion or not, it depends of application/device etc.
> >
> > Here is some device with stop_burst like support (not complete list):
> > accel/adxl345
> > datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
> > see: Table 22. Stream Mode: FIFO holds the last 32 data values...
> > accel/bmc150-accel
> > datasheet: https://hu.mouser.com/datasheet/2/783/BST-BMC150-DS000-1509560.pdf
> > see: 5.1 FIFO Operating Modes: Stream Mode
> > note: obsolate
> > accel/bmi088-accel
> > datasheet: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi088-ds001.pdf
> > see: 4.9.1 FIFO operating modes: STREAM mode
> > gyro/bmg160
> > datasheet: https://hu.mouser.com/datasheet/2/783/BST-BMG160-DS000-1509613.pdf
> > see: 5.1 FIFO Operating Modes: STREAM mode
> > note: obsolete
>
> Agreed this could be done, though I'm not convinced it makes that much sense. The main
> operating mode for these sensors in that mode is likely to be using a fifo watermark
> - the aim being to never drop data. The biggest exception to this would be very high
> speed devices where there is no hope of reading the data out without dropping, so
> you are looking for a very high frequency dataset of a short time period.
>
> So could do it, but I'm not sure many driver authors would implement it.
>
> From a proposal point of view, you are suggesting implementing in the drivers anyway
> so we can definitely support it for devices that care.
>
> >
> > Some of sensors under iio supports {pre,post}_alert or we can call near_{event,trigger}
> > or {before,after,around}_{event,trigger} with FIFO.
> > Flow could be:
> > 1. in configure_fifo hook(see below), the host configures the device FIFO mode/size
> > 2. in {pre,post}enable hook, the host starts conversion
> > 3. in IRQ handler, the host reads FIFO content,
> > then push the result to buffer, and reports events to user,
> > then restart the conversion or not, it depends of application/device etc.
> >
> > Here is some device (not complete list):
> > accel/adxl345
> > datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
> > see: Table 22. Trigger Mode: When triggered by the trigger bit...
> > note: as I understand the datasheet, this mode can be pre or post alert too,
> > it depends of the value of FIFO_CTL[4:0](Samples Bits)
> > staging/accel/adis16240
> > adc/ti-ads7142
> >
> > Overall, not only 2 devices, but many devices are affected under iio,
> > and I think in addition to "buffer_mode", the FIFO configuration should
> > also be included this ABI. And here, I think, the fifo_mode is a better name than buffer_mode.
> >
> > Here is my suggestion:
> >
> > This should be configured with buffered mode.
> >
> > enum iio_chan_info_enum {
> > ...
> > IIO_CHAN_INFO_CALIBAMBIENT,
> > + IIO_CHAN_INFO_FIFOSIZE,
> > };
> >
> > IIO_CHAN_INFO_FIFOSIZE: a new sysfs entry comes up under /sys/bus/iio/devices/iio:deviceX/
> > with "fifosize" postfix. This will be per device property mostly.
>
> Add this to the hwfifo_ attributes that are already defined.
> This is going to be per buffer rather than per channel so should
> be something like bufferX/hwfifo_length
>
>
> >
> > +enum iio_fifo_mode {
> > + IIO_FIFO_MODE_START_BURST,
> > + IIO_FIFO_MODE_STOP_BURST,
> > + IIO_FIFO_MODE_BEFORE_EVENT,
> > + IIO_FIFO_MODE_AFTER_EVENT,
> > + IIO_FIFO_MODE_AROUND_EVENT,
> > +};
>
> Can we collapse the 3 event cases to
> IIO_FIFO_MODE_EVENT then
> provide separate controls around
> hfifo_event_prescans
> hfifo_event_postscans
> (not sure on that naming!)
> and use normal rules that any IIO write may effect other attributes
> + _available attributes to specify what range these can take.
>
> Obviously would make the internals of drivers a little more complex
> but would avoid an odd corner case where a device supports a fully
> flexible AROUND_EVENT that can also == BEFORE_EVENT or AFTER_EVENT
> depending on the settings.
>
> >
> > struct iio_buffer_setup_ops {
> > int (*preenable)(struct iio_dev *);
> > int (*postenable)(struct iio_dev *);
> > int (*predisable)(struct iio_dev *);
> > int (*postdisable)(struct iio_dev *);
> > bool (*validate_scan_mask)(struct iio_dev *indio_dev,
> > const unsigned long *scan_mask);
> > + int fifo_mode_mask;
> > + int (*configure_fifo)(struct iio_dev*);
> > };
> >
> > If the device supports any of iio_fifo_mode, it can be configured with fifo_mode_mask.
> > If fifo_mode_mask have any flags, two new sysfs entry comes up
> > /sys/bus/iio/devices/iio:deviceX/buffer/fifo_mode
> > /sys/bus/iio/devices/iio:deviceX/buffer/fifo_mode_available
>
> bufferY/hwfifo_mode* but otherwise agreed..
>
> > I dont think, different fifo modes will be configurable by channel in the future,
> > but in that case, fifo_mode_mask_separate, etc can be added.
>
> No chance of it by definition. A buffer is a set of scans run together, if
> individual channels can have different options for this, they are in different
> buffers.
>
> >
> > The new configure_fifo hook could be called before preenable hook.
>
> Hmm. Maybe, or perhaps for now we leave it as a job for preenable/postenable
> and see how a number of drivers end up looking. I'm not 100% sure we need
> an additional callback for this. There is a reasonable argument
> we should think about pulling the sysfs stuff for hwfifo_ setup
> into the core, but there is no rush to do that either.
>
> >
> > I think this can cover the requirements for a while.
>
> Nice explanation and I agree it should work.
>
>
> >
> > >
> > > >
> > > > The in_voltageY_raw can be used, if the buffering mode is not enabled
> > > > in sysfs(buffer/enable).
> > > > The driver initiates a single conversion in the device for each
> > > > read request(in_voltageY_raw).
> > > > This is a one-shot conversion.
> > > > See chapter 7.4.2.2 "Manual Mode with AUTO Sequence" in datasheet.
> > > >
> > > > Datasheet: https://www.ti.com/lit/ds/symlink/ads7142.pdf
> > > >
> > > > Signed-off-by: Jozsef Horvath <info@xxxxxxxxxxx>
> > >
> > > > ---
> > > >
> > > > changes v1
> > > > - All of the buffer opertaion modes
> > > > (pre_alert, post_alert, start_burst, stop_burst)
> > > > are added
> > > > - Added triggered buffer
> > > > - Added buffer operation mode selection sysfs support
> > > > - Redundant parameters (ti,threshold-rising, etc.)
> > > > are removed
> > > > - Supply name changed(vref -> avdd)
> > > > - Added dvdd supply
> > > > - Added device sampling rate calculation
> > > > - Use device-managed functions for regulator, iio device register
> > > > and triggered buffer
> > > >
> > > > changes v2
> > > > - Unreachable statements removed
> > > > - ti_ads7142_buffered_setup_and_start returns without error when
> > > > pre/post alert mode is selected, but no thresh_{rising/falling}
> > > > enabled on any channel. Fixed with return -EINVAL in the case above.
> > > > - Stylistical changes
> > > > - devm_regulator_get return value error/NULL handling.
> > > > - "ti,prealert-count" parameter added, just for completeness.
> > > > ---
> > > > .../ABI/testing/sysfs-bus-iio-adc-ti-ads7142 | 11 +
> > > > MAINTAINERS | 7 +
> > > > drivers/iio/adc/Kconfig | 13 +
> > > > drivers/iio/adc/Makefile | 1 +
> > > > drivers/iio/adc/ti-ads7142.c | 1461 +++++++++++++++++
> > > > 5 files changed, 1493 insertions(+)
> > > > create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-adc-ti-ads7142
> > > > create mode 100644 drivers/iio/adc/ti-ads7142.c
> > > >
> > > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-ti-ads7142 b/Documentation/ABI/testing/sysfs-bus-iio-adc-ti-ads7142
> > > > new file mode 100644
> > > > index 000000000000..485017235f4a
> > > > --- /dev/null
> > > > +++ b/Documentation/ABI/testing/sysfs-bus-iio-adc-ti-ads7142
> > > > @@ -0,0 +1,11 @@
> > > > +What: /sys/bus/iio/devices/iio:deviceX/buffer_mode_available
> > > > +Date: May 2021
> > > > +KernelVersion: 5.13
> > > > +Contact: info@xxxxxxxxxxx
> > > > +Description: List all available buffer_mode settings.
> > >
> > > List them out with detailed explanation of what each one does + how it interacts
> > > with the trigger etc.
> > >
> >
> > Ok, I'll do that.
> >
> > > > +
> > > > +What: /sys/bus/iio/devices/iio:deviceX/buffer_mode
> > > > +Date: May 2021
> > > > +KernelVersion: 5.13
> > > > +Contact: info@xxxxxxxxxxx
> > > > +Description: Sets up the device data buffer mode.
>
> ...
>
> > > > +#include <linux/iio/triggered_buffer.h>
> > > > +
> > > > +#define TI_ADS7142_NAME "ads7142"
> > > > +
> > > > +#define TI_ADS7142_DATA_VALID_TIMEOUT 100
> > > > +
> > > > +/* Opcodes for commands */
> > > > +/* General */
> > > > +#define TI_ADS7142_OC_GENERAL 0x00
> > >
> > > the names of the defines are fairly self explanatory. I'd drop the comments
> > > unless you think they add a lot. (Keep the Opcodes for commands line though
> > > as OC isn't obvious).
> > >
> >
> > I tried to follow the structure and names like in datasheet
>
> Sure, just saying you don't need the comments for most of this
> /* Single Register Read */ is obviously from SINGLE_REG_READ
>
> All comments like this end up doing is bit rotting so only use
> them if they add significant value.
>
> >
> > > > +/* Single Register Read */
> > > > +#define TI_ADS7142_OC_SINGLE_REG_READ 0x10
> > > > +/* Single Register Write */
> > > > +#define TI_ADS7142_OC_SINGLE_REG_WRITE 0x08
> > > > +/* Single Bit Set */
> > > > +#define TI_ADS7142_OC_SET_BIT 0x18
> > > > +/* Single Bit Clear */
> > > > +#define TI_ADS7142_OC_CLEAR_BIT 0x20
> > > > +/* Block Register Read */
> > > > +#define TI_ADS7142_OC_BLOCK_READ 0x30
> > > > +/* Block Register Write */
> > > > +#define TI_ADS7142_OC_BLOCK_WRITE 0x28
> > > > +
>
> ...
>
> ...
>
> > > > +
> > > > +static int ti_ads7142_hys_set(struct iio_dev *indio_dev, int channel,
> > > > + int hysteresis)
> > > > +{
> > > > + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
> > > > + int ret;
> > > > +
> > > > + if (hysteresis < 0 || hysteresis > TI_ADS7142_HYSTERESIS_MSK)
> > > > + return -EINVAL;
> > > > +
> > > > + ret = ti_ads7142_reg_write(client, TI_ADS7142_DWC_HYS_CH0 + channel,
> > > > + hysteresis & TI_ADS7142_HYSTERESIS_MSK);
> > >
> > > I'd suggest either a cache of current value, or even better think about using
> > > regmap to handle all the caching for you.
> > >
> >
> > I'll use regmap.
>
> I'm not sure how it will interact with the fact not everything on this
> device is register based, but good to give it a quick go and see what
> it looks like.
>

As I see, I have to use dvm_regmap_init with custom regmap_bus and config.
I'll try and, we will see it. I see some devices(ads7924, ads7138, ads7128,
tla2528, ...) with similar I2C protocol, maybe worth it to do.

> >
>
> > > > + goto seq_start;
> > > > +
> > > > + /*
> > > > + * Pre and post alert settings
> > > > + */
> > > > + ret = ti_ads7142_reg_write(client, TI_ADS7142_PRE_ALT_EVT_CNT,
> > > > + priv->config.prealert_count &
> > > > + TI_ADS7142_PRE_ALT_EVT_CNT_MSK);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + ret = ti_ads7142_reg_write(client, TI_ADS7142_ALT_LOW_FLAGS,
> > > > + TI_ADS7142_ALT_LOW_FLAGS_CH0
> > > > + | TI_ADS7142_ALT_LOW_FLAGS_CH1);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + ret = ti_ads7142_reg_write(client, TI_ADS7142_ALT_HIGH_FLAGS,
> > > > + TI_ADS7142_ALT_HIGH_FLAGS_CH0
> > > > + | TI_ADS7142_ALT_HIGH_FLAGS_CH1);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + for_each_set_bit(i, indio_dev->active_scan_mask,
> > > > + indio_dev->masklength) {
> > > > + channel = ti_ads7142_address2channel(indio_dev, i);
> > > > + if (!channel)
> > > > + return -ENODEV;
> > > > +
> > > > + ret = ti_ads7142_hth_set(indio_dev, channel->channel,
> > > > + channel->config.high_threshold);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + ret = ti_ads7142_lth_set(indio_dev, channel->channel,
> > > > + channel->config.low_threshold);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + ret = ti_ads7142_hys_set(indio_dev, channel->channel,
> > > > + channel->config.hysteresis);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + if (channel->config.alert_low ||
> > > > + channel->config.alert_high) {
> > > > + alert_ch |= 1 << channel->channel;
> > > > + }
> > >
> > > It's unusual to only have events enable if the buffer is also enabled.
> > > Is there any way we can allow an events only configuration?
> > > If not, fair enough but we may need to think about whether we need some
> > > extra documentation around that.
> > >
> >
> > I think, without threshold value/enable, the pre/post alert is pointless.
> > I'll explain it in docs
>
> Ah. So these basically exist to give control over the events.
> Definitely needs documentation.
>
> We also need some way of linking the buffer back to the particular
> event. That may need some thought. If we have a device that supports
> N events but only one is used to trigger pre / post alert, then we need
> to be able to specify which. Could do that by providing triggers to
> represent the different available events (only useable by this driver)
>

Could we extend the buffer items with meta info? (timestamp is now exists).

> > > > +static int ti_ads7142_buffered_collect(struct iio_dev *indio_dev,
> > > > + int *channel_collected)
> > > > +{
> > > > + struct ti_ads7142_priv *priv = iio_priv(indio_dev);
> > > > + struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
> > > > + int scan_channel_count;
> > > > + int have_valid_data;
> > > > + int data_valid;
> > > > + u16 data_buffer;
> > > > + u16 buffer[TI_ADS7142_CHANNEL_COUNT];
> > > > + u8 seq_channels = 0;
> > > > + int channel_address;
> > > > + int value;
> > > > + int i, j;
> > > > + int ret;
> > > > +
> > > > + scan_channel_count = bitmap_weight(indio_dev->active_scan_mask,
> > > > + indio_dev->masklength);
> > > > + if (!scan_channel_count)
> > > > + return -EINVAL;
> > > > +
> > > > + for_each_set_bit(i, indio_dev->active_scan_mask,
> > > > + indio_dev->masklength) {
> > > > + seq_channels |= 1 << i;
> > > > + }
> > >
> > > Kernel style is no brackets around a single line statement like this.
> > > Also, isn't this duplicating the active_scan_mask?
> > >
> >
> > You are right, this is redundancy
> >
> > > > +
> > > > + do {
> > > > + memset(priv->scan_data, 0x00, indio_dev->scan_bytes);
> > >
> > > This should be unnecessary as the priv data is kzalloc'd in the first place, so
> > > all we can do here is leak old timestamps or channel values (actually timestamps
> > > can't leak anyway because either we write it or it never goes in the buffer, but
> > > that's harder to explain ;)
> > >
> >
> > Ok, I'll remove it
> >
> > >
> > > > + have_valid_data = 0;
> > > > + for (i = 0; i < scan_channel_count; i++) {
> > > > + ret = ti_ads7142_data_buffer_read(client,
> > > > + sizeof(data_buffer),
> > > > + &data_buffer);
> > > > + if (ret)
> > > > + return ret;
> > > > + data_buffer = be16_to_cpu(data_buffer);
> > >
> > > Definitely preferred to have two local variables when doing endian conversions
> > > Lets use track what endian a particular one is. Not to mention you'll get
> > > static checker warnings on this as it stands.
> > >
> >
> > I'll correct this. Thank you for explanation
> >
> > >
> > > > + data_valid = data_buffer & 1;
> > > > + if (!data_valid) {
> > > > + ret = -ENOENT;
> > > > + break;
> > > > + }
> > > > +
> > > > + channel_address = (data_buffer >> 1) & 0x7;
> > >
> > > FIELD_GET() perhaps?
> > >
> > > > + if (!(seq_channels & 1 << channel_address)) {
> > >
> > > test_bit()
> >
> > Ok, I'll do that
> >
> > >
> > > > + dev_err(indio_dev->dev.parent,
> > > > + "%s: invalid channel address(%d)",
> > > > + __func__, channel_address);
> > > > + return -EIO;
> > > > + }
> > > > +
> > > > + value = data_buffer >> 4;
> > > > + buffer[channel_address] = value;
> > > > + have_valid_data = 1;
> > > > + if (channel_collected)
> > > > + *channel_collected |= 1 << channel_address;
> > > > + }
> > > > +
> > > > + if (!have_valid_data)
> > > > + continue;
> > > > +
> > > > + j = 0;
> > > > + for_each_set_bit(i, indio_dev->active_scan_mask,
> > > > + indio_dev->masklength) {
> > >
> > > This confuses me somewhat. The code above appears to suggest that you will only
> > > be reading the entries you want anyway, so why can you not just fill scan_data
> > > directly in that loop?
> > >
> >
> > This is because the buffer[] indexed with channel_address value, reported by the device
> > for the conversion result, and if only the AIN1 selected for scanning, the conversion
> > result goes to buffer[1], but scan_bytes in this case is 2, so the
> > iio_push_to_buffers_with_timestamp will shows the priv->scan_data[0] to the user.
>
> But the choice to put the channel into the location referenced by channel_address
> is made in this code. You could store it directly into priv->scan_data[0] where
> you currently put it into buffer[1], just need to use a similar j++ type pattern
> to what you have here in the above loop rather than this one.

You are right.

>
> >
> > > > + priv->scan_data[j] = buffer[i];
> > > > + j++;
> > > > + }
> > > > + iio_push_to_buffers_with_timestamp(indio_dev, priv->scan_data,
> > > > + iio_get_time_ns(indio_dev));
> > > > + } while (data_valid);
> > > > +
> > > > + return ret;
> > > > +}
> ...
>
> > > > + if (priv->config.buffer_mode == TI_ADS7142_BUFFM_START_BURST ||
> > > > + priv->config.buffer_mode == TI_ADS7142_BUFFM_STOP_BURST) {
> > > > + ret = ti_ads7142_buffered_setup_and_start(indio_dev);
> > > > + if (ret) {
> > > > + dev_err(indio_dev->dev.parent,
> > > > + "%s: error(%d) when starting %s mode",
> > > > + __func__, ret,
> > > > + ti_ads7142_buffer_modes[priv->config.buffer_mode]);
> > > > + goto err_unlock;
> > >
> > > What code to return when you get an error in an interrupt handler is always
> > > an interesting question. However, in this case we've handled the interrupt, but
> > > not restarted capture. Returning IRQ_NONE doesn't feel right.
> > >
> >
> > You are right, but who knows what happends with the device.
> > In this case, what about iio_trigger_notify_done? It reenables the pollfunc.
>
> Yup. Though in that case we will just end up stuck rather than potentially
> triggering misleading spurious interrupt messages in the log.
>
> There isn't really a right answer for this though.
>

Ok, I'll change dev_err's to dev_dbg, and skip iio_trigger_notify_done
in case of error.

> >
> > > > + }
> > > > + }
> > > > +
> > > > + mutex_unlock(&priv->lock);
> > > > + iio_trigger_notify_done(indio_dev->trig);
> > > > +
> > > > + return IRQ_HANDLED;
> > > > +
> > > > +err_unlock:
> > > > + mutex_unlock(&priv->lock);
> > > > + return IRQ_NONE;
> > > > +}
> > > > +
>
> Fun device and interesting driver :)
>

It seems, it raised more questions than I thought. I started this driver because
I needed a super mini, low-power ADC and I developed the pre_alert mode support
just for fun.
The problems we are facing are very interesting for me.

My plan:
1. I would complete this driver as is.
2. I would start working on industrialio-capture
- I'll add capture support to ti-ads7142 driver
- I'll add capture(DMA) support to ti_am335x_adc driver
(I have an am3359 devkit on my shelf.)
These two example will show, how simple is to add capture support :)
3. I would extend the industrialio-buffer with event metadata

> Jonathan


Thank you

Best regards
József