Hello, Thanks for the review, Jonathan. Comments inline... On Sat, Aug 29, 2020 at 10:16 PM Jonathan Cameron <jic23@xxxxxxxxxx> wrote: > > On Tue, 25 Aug 2020 18:17:09 +0530 > Nishant Malpani <nish.malpani25@xxxxxxxxx> wrote: > > > Provide a way for continuous data capture by setting up buffer support. The > > data ready signal exposed at the SYNC pin of the ADXRS290 is exploited as > > a hardware interrupt which triggers to fill the buffer. > > > > Triggered buffer setup was tested with both hardware trigger (DATA_RDY) and > > software triggers (sysfs-trig & hrtimer). > > > > Signed-off-by: Nishant Malpani <nish.malpani25@xxxxxxxxx> > > I've tried not to overlap with Andy's comments but might have hit on a few. > Anyhow, comments inline. > > Jonathan > > > > --- > > drivers/iio/gyro/Kconfig | 2 + > > drivers/iio/gyro/adxrs290.c | 272 ++++++++++++++++++++++++++++++++++-- > > 2 files changed, 260 insertions(+), 14 deletions(-) > > > > diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig > > index 024a34139875..5824f2edf975 100644 > > --- a/drivers/iio/gyro/Kconfig > > +++ b/drivers/iio/gyro/Kconfig > > @@ -44,6 +44,8 @@ config ADIS16260 > > config ADXRS290 > > tristate "Analog Devices ADXRS290 Dual-Axis MEMS Gyroscope SPI driver" > > depends on SPI > > + select IIO_BUFFER > > + select IIO_TRIGGERED_BUFFER > > help > > Say yes here to build support for Analog Devices ADXRS290 programmable > > digital output gyroscope. > > diff --git a/drivers/iio/gyro/adxrs290.c b/drivers/iio/gyro/adxrs290.c > > index ff989536d2fb..25046590761e 100644 > > --- a/drivers/iio/gyro/adxrs290.c > > +++ b/drivers/iio/gyro/adxrs290.c > > @@ -13,8 +13,12 @@ > > #include <linux/module.h> > > #include <linux/spi/spi.h> > > > > +#include <linux/iio/buffer.h> > > #include <linux/iio/iio.h> > > #include <linux/iio/sysfs.h> > > +#include <linux/iio/trigger.h> > > +#include <linux/iio/triggered_buffer.h> > > +#include <linux/iio/trigger_consumer.h> > > > > #define ADXRS290_ADI_ID 0xAD > > #define ADXRS290_MEMS_ID 0x1D > > @@ -35,7 +39,9 @@ > > #define ADXRS290_READ BIT(7) > > #define ADXRS290_TSM BIT(0) > > #define ADXRS290_MEASUREMENT BIT(1) > > -#define ADXRS290_SYNC GENMASK(1, 0) > > +#define ADXRS290_DATA_RDY_OUT BIT(0) > > +#define ADXRS290_SYNC_MASK GENMASK(1, 0) > > +#define ADXRS290_SYNC(x) FIELD_PREP(ADXRS290_SYNC_MASK, x) > > #define ADXRS290_LPF_MASK GENMASK(2, 0) > > #define ADXRS290_LPF(x) FIELD_PREP(ADXRS290_LPF_MASK, x) > > #define ADXRS290_HPF_MASK GENMASK(7, 4) > > @@ -50,6 +56,13 @@ enum adxrs290_mode { > > ADXRS290_MODE_MEASUREMENT, > > }; > > > > +enum adxrs290_scan_index { > > + ADXRS290_IDX_X, > > + ADXRS290_IDX_Y, > > + ADXRS290_IDX_TEMP, > > + ADXRS290_IDX_TS, > > +}; > > + > > struct adxrs290_state { > > struct spi_device *spi; > > /* Serialize reads and their subsequent processing */ > > @@ -57,6 +70,12 @@ struct adxrs290_state { > > enum adxrs290_mode mode; > > unsigned int lpf_3db_freq_idx; > > unsigned int hpf_3db_freq_idx; > > + struct iio_trigger *dready_trig; > > + /* Ensure correct alignment of timestamp when present */ > > + struct { > > + s16 channels[3]; > > + s64 ts __aligned(8); > > + } buffer; > } buffer; > > I can see why you did the alignment like you have, but it looks really odd > in this case. > I thought so too. Will fix it in v2. > > }; > > > > ... > > > > > +static void adxrs290_chip_off_action(void *data) > > +{ > > + struct iio_dev *indio_dev = data; > > + > > + adxrs290_set_mode(indio_dev, ADXRS290_MODE_STANDBY); > > +} > > + > > static int adxrs290_read_raw(struct iio_dev *indio_dev, > > struct iio_chan_spec const *chan, > > int *val, > > @@ -215,24 +287,34 @@ static int adxrs290_read_raw(struct iio_dev *indio_dev, > > > > switch (mask) { > > case IIO_CHAN_INFO_RAW: > > + ret = iio_device_claim_direct_mode(indio_dev); > > + if (ret) > > + return ret; > > + > > switch (chan->type) { > > case IIO_ANGL_VEL: > > ret = adxrs290_get_rate_data(indio_dev, > > ADXRS290_READ_REG(chan->address), > > val); > > if (ret < 0) > > - return ret; > > + goto err_release; > > > > - return IIO_VAL_INT; > > + ret = IIO_VAL_INT; > > + break; > > case IIO_TEMP: > > ret = adxrs290_get_temp_data(indio_dev, val); > > if (ret < 0) > > - return ret; > > + goto err_release; > > > > - return IIO_VAL_INT; > > + ret = IIO_VAL_INT; > > + break; > > default: > > - return -EINVAL; > > + ret = -EINVAL; > > + break; > > } > > +err_release: > > + iio_device_release_direct_mode(indio_dev); > > + return ret; > > case IIO_CHAN_INFO_SCALE: > > switch (chan->type) { > > case IIO_ANGL_VEL: > > @@ -279,34 +361,53 @@ static int adxrs290_write_raw(struct iio_dev *indio_dev, > > long mask) > > { > > struct adxrs290_state *st = iio_priv(indio_dev); > > - int lpf_idx, hpf_idx; > > + int ret, lpf_idx, hpf_idx; > > + > > + ret = iio_device_claim_direct_mode(indio_dev); > > Is there anything in the datasheet that says we can't change the filters > whilst doing captures? Might get crazy data but if the datasheet doesn't > want against a particular action, then we tend not to try and prevent it. > The datasheet, to my knowledge, explicitly doesn't mention any restriction on changing the filter settings during a capture. Quoting the datasheet, "The group delay of the wideband filter option is less than 0.5ms" (pg. 11) - during an ongoing capture if one re-configures the filter, how do we address this? > > + if (ret) > > + return ret; > > > > switch (mask) { > > case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: > > lpf_idx = adxrs290_find_match(adxrs290_lpf_3db_freq_hz_table, > > ARRAY_SIZE(adxrs290_lpf_3db_freq_hz_table), > > val, val2); > > - if (lpf_idx < 0) > > - return -EINVAL; > > + if (lpf_idx < 0) { > > + ret = -EINVAL; > > + goto err_release; > > + } > > + > > /* caching the updated state of the low-pass filter */ > > st->lpf_3db_freq_idx = lpf_idx; > > /* retrieving the current state of the high-pass filter */ > > hpf_idx = st->hpf_3db_freq_idx; > > - return adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx); > > + ret = adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx); > > + break; > > + > > case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: > > hpf_idx = adxrs290_find_match(adxrs290_hpf_3db_freq_hz_table, > > ARRAY_SIZE(adxrs290_hpf_3db_freq_hz_table), > > val, val2); > > - if (hpf_idx < 0) > > - return -EINVAL; > > + if (hpf_idx < 0) { > > + ret = -EINVAL; > > + goto err_release; > > + } > > + > > /* caching the updated state of the high-pass filter */ > > st->hpf_3db_freq_idx = hpf_idx; > > /* retrieving the current state of the low-pass filter */ > > lpf_idx = st->lpf_3db_freq_idx; > > - return adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx); > > + ret = adxrs290_set_filter_freq(indio_dev, lpf_idx, hpf_idx); > > + break; > > + > > + default: > > + ret = -EINVAL; > > + break; > > } > > > > - return -EINVAL; > > +err_release: > I think Andy may have mentioned this, but a break would work just as well > to get you here > Agreed. Will refactor accordingly in v2. > > + iio_device_release_direct_mode(indio_dev); > > + return ret; > > } > > > > static int adxrs290_read_avail(struct iio_dev *indio_dev, > > @@ -334,6 +435,68 @@ static int adxrs290_read_avail(struct iio_dev *indio_dev, > > } > > } > > > > +static int adxrs290_data_rdy_trigger_set_state(struct iio_trigger *trig, bool state) > > +{ > > + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > > + struct adxrs290_state *st = iio_priv(indio_dev); > > + int ret; > > + u8 val; > > + > > + val = (state ? ADXRS290_SYNC(ADXRS290_DATA_RDY_OUT) : 0); > > Why the outer set of brackets? > I now realize those are unnecessary and probably violate the kernel coding-style. Will remove those in v2. > > + > > + ret = adxrs290_spi_write_reg(st->spi, ADXRS290_REG_DATA_RDY, val); > > + if (ret < 0) > > + dev_err(&st->spi->dev, "failed to start data ready interrupt\n"); > > + > > + return ret; > > +} > > + > > +static int adxrs290_reset_trig(struct iio_trigger *trig) > > +{ > > + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); > > + int val; > > + > > + /* > > + * Data ready interrupt is reset after a read of the data registers. > > + * Here, we only read the 16b DATAY registers as that marks the end of > > + * a read of the data registers and initiates a reset for the interrupt line. > > + */ > > + return adxrs290_get_rate_data(indio_dev, ADXRS290_READ_REG(ADXRS290_REG_DATAY0), &val); > > We have a bug around this at the moment btw. > > A try_reenable callback shouldn't return an error. The return value is > meant to indicate that we need to go round again or not > (though that's broken currently anwyay). Hence safer to just not > return errors. > > return 0; > Right, I forgot about the recent conversations on the mailing list about this; thanks for pointing out again. Will fix this in v2. > > +} > > + > > +static const struct iio_trigger_ops adxrs290_trigger_ops = { > > + .set_trigger_state = &adxrs290_data_rdy_trigger_set_state, > > + .validate_device = &iio_trigger_validate_own_device, > > + .try_reenable = &adxrs290_reset_trig, > > +}; > > + > > +static irqreturn_t adxrs290_trigger_handler(int irq, void *p) > > +{ > > + struct iio_poll_func *pf = p; > > + struct iio_dev *indio_dev = pf->indio_dev; > > + struct adxrs290_state *st = iio_priv(indio_dev); > > + struct spi_device *spi = st->spi; > > As you only use spi once, I'd just use st->spi inline. > Okay. > > + u8 tx = ADXRS290_READ_REG(ADXRS290_REG_DATAX0); > > + int ret; > > + > > + mutex_lock(&st->lock); > > + > > + /* exercise a bulk data capture starting from reg DATAX0... */ > > + ret = spi_write_then_read(spi, &tx, sizeof(tx), st->buffer.channels, > > + sizeof(st->buffer.channels)); > > + if (ret < 0) > > + goto done; > > + > > + iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer, > > + pf->timestamp); > > + > > +done: > > + mutex_unlock(&st->lock); > > + iio_trigger_notify_done(indio_dev->trig); > > + > > + return IRQ_HANDLED; > > +} > > + > > #define ADXRS290_ANGL_VEL_CHANNEL(reg, axis) { \ > > .type = IIO_ANGL_VEL, \ > > .address = reg, \ > > @@ -346,6 +509,13 @@ static int adxrs290_read_avail(struct iio_dev *indio_dev, > > .info_mask_shared_by_type_available = \ > > BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \ > > BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ > > + .scan_index = ADXRS290_IDX_##axis, \ > > + .scan_type = { \ > > + .sign = 's', \ > > + .realbits = 16, \ > > + .storagebits = 16, \ > > + .endianness = IIO_LE, \ > > + }, \ > > } > > > > static const struct iio_chan_spec adxrs290_channels[] = { > > @@ -356,7 +526,21 @@ static const struct iio_chan_spec adxrs290_channels[] = { > > .address = ADXRS290_REG_TEMP0, > > .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | > > BIT(IIO_CHAN_INFO_SCALE), > > + .scan_index = ADXRS290_IDX_TEMP, > > + .scan_type = { > > + .sign = 's', > > + .realbits = 12, > > + .storagebits = 16, > > + .shift = 0, > > No need to specify shift if it is 0 as that's the obvious default. > Got it. > > + .endianness = IIO_LE, > > + }, > > }, > > + IIO_CHAN_SOFT_TIMESTAMP(ADXRS290_IDX_TS), > > +}; > > + > > +static const unsigned long adxrs290_avail_scan_masks[] = { > > + BIT(ADXRS290_IDX_X) | BIT(ADXRS290_IDX_Y) | BIT(ADXRS290_IDX_TEMP), > > + 0 > > }; > > > > static const struct iio_info adxrs290_info = { > > @@ -365,6 +549,47 @@ static const struct iio_info adxrs290_info = { > > .read_avail = &adxrs290_read_avail, > > }; > > > > +static int adxrs290_probe_trigger(struct iio_dev *indio_dev) > > +{ > > + struct adxrs290_state *st = iio_priv(indio_dev); > > + int ret; > > + > > + if (!st->spi->irq) { > > + dev_info(&st->spi->dev, "no irq, using polling\n"); > > + return 0; > > + } > > + > > + st->dready_trig = devm_iio_trigger_alloc(&st->spi->dev, > > + "%s-dev%d", > > + indio_dev->name, > > + indio_dev->id); > > As below, this could be sensibly done on fewer lines without any real loss > of readability (staying under advised 80 chars) > Sure, will re-align in v2. > > + if (!st->dready_trig) > > + return -ENOMEM; > > + > > + st->dready_trig->dev.parent = &st->spi->dev; > > + st->dready_trig->ops = &adxrs290_trigger_ops; > > + iio_trigger_set_drvdata(st->dready_trig, indio_dev); > > + > > + ret = devm_request_irq(&st->spi->dev, st->spi->irq, > > + &iio_trigger_generic_data_rdy_poll, > > + IRQF_ONESHOT, > > + "adxrs290_irq", st->dready_trig); > > + if (ret < 0) { > > + dev_err(&st->spi->dev, "request irq %d failed\n", st->spi->irq); > > + return ret; > > + } > > + > > + ret = devm_iio_trigger_register(&st->spi->dev, st->dready_trig); > > + if (ret) { > > + dev_err(&st->spi->dev, "iio trigger register failed\n"); > > + return ret; > > + } > > + > > + indio_dev->trig = iio_trigger_get(st->dready_trig); > > + > > + return 0; > > +} > > + > > static int adxrs290_probe(struct spi_device *spi) > > { > > struct iio_dev *indio_dev; > > @@ -384,6 +609,7 @@ static int adxrs290_probe(struct spi_device *spi) > > indio_dev->channels = adxrs290_channels; > > indio_dev->num_channels = ARRAY_SIZE(adxrs290_channels); > > indio_dev->info = &adxrs290_info; > > + indio_dev->available_scan_masks = adxrs290_avail_scan_masks; > > > > mutex_init(&st->lock); > > > > @@ -416,6 +642,12 @@ static int adxrs290_probe(struct spi_device *spi) > > /* max transition time to measurement mode */ > > msleep(ADXRS290_MAX_TRANSITION_TIME_MS); > > > > + ret = devm_add_action_or_reset(&spi->dev, > > + adxrs290_chip_off_action, > > + indio_dev); > > What is this unwinding? We should only be using devm to undo things > that have been 'done' in probe and the association should be clear. > This unwinding is for placing the device **back** to its default 'STANDBY' mode. The device, during the probe, was put to 'MEASUREMENT' mode during 'adxrs290_initial_setup()' a few lines back. How else do you suggest I highlight the association? > You have been a bit in consistent with wrapping. Personally I would > go for as many parameters as fit on each line under 80 chars as possible. > The only exception being when there is some clear 'pairing' of parameters > or similar. > Yes, I realize that, sorry. Will fix wherever necessary in v2. With regards, Nishant Malpani > > + if (ret < 0) > > + return ret; > > + > > ret = adxrs290_get_3db_freq(indio_dev, &val, &val2); > > if (ret < 0) > > return ret; > > @@ -423,6 +655,18 @@ static int adxrs290_probe(struct spi_device *spi) > > st->lpf_3db_freq_idx = val; > > st->hpf_3db_freq_idx = val2; > > > > + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, > > + &iio_pollfunc_store_time, > > + &adxrs290_trigger_handler, NULL); > > + if (ret < 0) { > > + dev_err(&spi->dev, "iio triggered buffer setup failed\n"); > > + return ret; > > + } > > + > > + ret = adxrs290_probe_trigger(indio_dev); > > + if (ret < 0) > > + return ret; > > + > > return devm_iio_device_register(&spi->dev, indio_dev); > > } > > >