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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux