diff mbox series

[v1,3/5] iio: accel: bma400: Add triggered buffer support

Message ID 20220319181023.8090-4-jagathjog1996@gmail.com (mailing list archive)
State Changes Requested
Headers show
Series iio: accel: bma400: Add support for buffer and step | expand

Commit Message

Jagath Jog J March 19, 2022, 6:10 p.m. UTC
Added trigger buffer support to read continuous acceleration
data from device with data ready interrupt which is mapped
to INT1 pin.

Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com>
---
 drivers/iio/accel/Kconfig       |   2 +
 drivers/iio/accel/bma400.h      |  10 +-
 drivers/iio/accel/bma400_core.c | 161 +++++++++++++++++++++++++++++++-
 drivers/iio/accel/bma400_i2c.c  |   2 +-
 drivers/iio/accel/bma400_spi.c  |   2 +-
 5 files changed, 169 insertions(+), 8 deletions(-)

Comments

kernel test robot March 20, 2022, 3:30 a.m. UTC | #1
Hi Jagath,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on v5.17-rc8]
[cannot apply to jic23-iio/togreg next-20220318]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jagath-Jog-J/iio-accel-bma400-Add-support-for-buffer-and-step/20220320-021114
base:    09688c0166e76ce2fb85e86b9d99be8b0084cdf9
config: i386-randconfig-s001 (https://download.01.org/0day-ci/archive/20220320/202203201124.OLMstZaW-lkp@intel.com/config)
compiler: gcc-9 (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.4-dirty
        # https://github.com/0day-ci/linux/commit/8dc9a46d5af9a53917108ce2b103b3d9a50986a5
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jagath-Jog-J/iio-accel-bma400-Add-support-for-buffer-and-step/20220320-021114
        git checkout 8dc9a46d5af9a53917108ce2b103b3d9a50986a5
        # save the config file to linux build tree
        mkdir build_dir
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=i386 SHELL=/bin/bash drivers/iio/accel/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
>> drivers/iio/accel/bma400_core.c:906:13: sparse: sparse: restricted __le16 degrades to integer

vim +906 drivers/iio/accel/bma400_core.c

   891	
   892	static irqreturn_t bma400_interrupt(int irq, void *private)
   893	{
   894		struct iio_dev *indio_dev = private;
   895		struct bma400_data *data = iio_priv(indio_dev);
   896		int ret;
   897		__le16 status;
   898	
   899		mutex_lock(&data->mutex);
   900		ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG, &status,
   901				       sizeof(status));
   902		mutex_unlock(&data->mutex);
   903		if (ret)
   904			goto out;
   905	
 > 906		if (status & BMA400_INT_DRDY_MSK)
   907			iio_trigger_poll_chained(data->trig);
   908	
   909	out:
   910		return IRQ_HANDLED;
   911	}
   912
Jonathan Cameron March 20, 2022, 5:26 p.m. UTC | #2
On Sat, 19 Mar 2022 23:40:21 +0530
Jagath Jog J <jagathjog1996@gmail.com> wrote:

> Added trigger buffer support to read continuous acceleration
> data from device with data ready interrupt which is mapped
> to INT1 pin.
> 
> Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com>
> ---
>  drivers/iio/accel/Kconfig       |   2 +
>  drivers/iio/accel/bma400.h      |  10 +-
>  drivers/iio/accel/bma400_core.c | 161 +++++++++++++++++++++++++++++++-
>  drivers/iio/accel/bma400_i2c.c  |   2 +-
>  drivers/iio/accel/bma400_spi.c  |   2 +-
>  5 files changed, 169 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
> index 49587c992a6d..0eb379578e00 100644
> --- a/drivers/iio/accel/Kconfig
> +++ b/drivers/iio/accel/Kconfig
> @@ -177,6 +177,8 @@ config BMA220
>  config BMA400
>  	tristate "Bosch BMA400 3-Axis Accelerometer Driver"
>  	select REGMAP
> +	select IIO_BUFFER
> +	select IIO_TRIGGERED_BUFFER
>  	select BMA400_I2C if I2C
>  	select BMA400_SPI if SPI
>  	help
> diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h
> index cfc2c9bacec8..b306a5ad513a 100644
> --- a/drivers/iio/accel/bma400.h
> +++ b/drivers/iio/accel/bma400.h
> @@ -62,6 +62,13 @@
>  #define BMA400_ACC_CONFIG2_REG      0x1b
>  #define BMA400_CMD_REG              0x7e
>  
> +/* Interrupt registers */
> +#define BMA400_INT_CONFIG0_REG      0x1f
> +#define BMA400_INT_CONFIG1_REG      0x20
> +#define BMA400_INT1_MAP_REG         0x21
> +#define BMA400_INT_IO_CTRL_REG      0x24
> +#define BMA400_INT_DRDY_MSK         BIT(7)
> +
>  /* Chip ID of BMA 400 devices found in the chip ID register. */
>  #define BMA400_ID_REG_VAL           0x90
>  
> @@ -92,6 +99,7 @@
>  
>  extern const struct regmap_config bma400_regmap_config;
>  
> -int bma400_probe(struct device *dev, struct regmap *regmap, const char *name);
> +int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
> +		 const char *name);
>  
>  #endif
> diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
> index dcc7549c7a0e..797403c7dd85 100644
> --- a/drivers/iio/accel/bma400_core.c
> +++ b/drivers/iio/accel/bma400_core.c
> @@ -20,6 +20,12 @@
>  #include <linux/mutex.h>
>  #include <linux/regmap.h>
>  #include <linux/regulator/consumer.h>
> +#include <linux/bits.h>
> +#include <linux/bitfield.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>
>  
>  #include "bma400.h"
>  
> @@ -61,6 +67,13 @@ struct bma400_data {
>  	struct bma400_sample_freq sample_freq;
>  	int oversampling_ratio;
>  	int scale;
> +	struct iio_trigger *trig;
> +	/* Correct time stamp alignment */
> +	struct {
> +		__be16 buff[3];
> +		u8 temperature;
> +		s64 ts __aligned(8);
> +	} buffer;
you are doing bulk reads from an spi device into here.
There is a long running discussion about what we can assume about need for DMA
safety when regmap is involved.  Current state is we can't assume we don't need
to be DMA safe.  As such this should be in a separate cacheline from anything
that might be touched concurrently with DMA.

Mark buffer ___cacheline_aligned; and we should be fine.

If curious, Wolfram Sang did a good talk on this at ELCE a few years back that
google should find for you. It's an interesting little corner of horribleness :)

>  };
>  
>  static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
> @@ -152,7 +165,7 @@ static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
>  	{ }
>  };
>  
> -#define BMA400_ACC_CHANNEL(_axis) { \
> +#define BMA400_ACC_CHANNEL(_index, _axis) { \
>  	.type = IIO_ACCEL, \
>  	.modified = 1, \
>  	.channel2 = IIO_MOD_##_axis, \
> @@ -164,17 +177,32 @@ static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
>  		BIT(IIO_CHAN_INFO_SCALE) | \
>  		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
>  	.ext_info = bma400_ext_info, \
> +	.scan_index = _index,	\
> +	.scan_type = {		\
> +		.sign = 's',	\
> +		.realbits = 12,		\
> +		.storagebits = 16,	\
> +		.endianness = IIO_LE,	\
> +	},				\
>  }
>  
>  static const struct iio_chan_spec bma400_channels[] = {
> -	BMA400_ACC_CHANNEL(X),
> -	BMA400_ACC_CHANNEL(Y),
> -	BMA400_ACC_CHANNEL(Z),
> +	BMA400_ACC_CHANNEL(0, X),
> +	BMA400_ACC_CHANNEL(1, Y),
> +	BMA400_ACC_CHANNEL(2, Z),
>  	{
>  		.type = IIO_TEMP,
>  		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
>  		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> +		.scan_index = 3,
> +		.scan_type = {
> +			.sign = 's',
> +			.realbits = 8,
> +			.storagebits = 8,
> +			.endianness = IIO_LE,
> +		},
>  	},
> +	IIO_CHAN_SOFT_TIMESTAMP(4),
>  };
>  
>  static int bma400_get_temp_reg(struct bma400_data *data, int *val, int *val2)
> @@ -632,6 +660,11 @@ static int bma400_init(struct bma400_data *data)
>  	if (ret)
>  		goto err_reg_disable;
>  
> +	/* Configure INT-1 pin to push pull */

Hmm. We should be getting the requirements for using this pin from DT, though
I can't immediately think how to do it.  If the interrupt controller
is happy with open drain, then we should do that as well. Ultimately I think
this code will be happy with shared interrupts so lets not make it harder
than we need to.

> +	ret = regmap_write(data->regmap, BMA400_INT_IO_CTRL_REG, 0x02);
> +	if (ret)
> +		goto err_reg_disable;
> +
>  	/*
>  	 * Once the interrupt engine is supported we might use the
>  	 * data_src_reg, but for now ensure this is set to the
> @@ -786,6 +819,33 @@ static int bma400_write_raw_get_fmt(struct iio_dev *indio_dev,
>  	}
>  }
>  
> +static int bma400_data_rdy_trigger_set_state(struct iio_trigger *trig,
> +					     bool state)
> +{
> +	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
> +	struct bma400_data *data = iio_priv(indio_dev);
> +	int ret;
> +
> +	ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG,
> +				 BMA400_INT_DRDY_MSK,
> +				 FIELD_PREP(BMA400_INT_DRDY_MSK, state));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG,
> +				 BMA400_INT_DRDY_MSK,
> +				 FIELD_PREP(BMA400_INT_DRDY_MSK, state));
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static const unsigned long bma400_avail_scan_masks[] = {
> +	GENMASK(3, 0),
> +	0,
> +};
> +
>  static const struct iio_info bma400_info = {
>  	.read_raw          = bma400_read_raw,
>  	.read_avail        = bma400_read_avail,
> @@ -793,6 +853,63 @@ static const struct iio_info bma400_info = {
>  	.write_raw_get_fmt = bma400_write_raw_get_fmt,
>  };
>  
> +static const struct iio_trigger_ops bma400_trigger_ops = {
> +	.set_trigger_state = &bma400_data_rdy_trigger_set_state,
> +	.validate_device = &iio_trigger_validate_own_device,
> +};
> +
> +static irqreturn_t bma400_trigger_handler(int irq, void *p)
> +{
> +	struct iio_poll_func *pf = p;
> +	struct iio_dev *indio_dev = pf->indio_dev;
> +	struct bma400_data *data = iio_priv(indio_dev);
> +	int ret, temp;
> +
> +	mutex_lock(&data->mutex);
> +
> +	/* bulk read six registers, with the base being the LSB register */
> +	ret = regmap_bulk_read(data->regmap, BMA400_X_AXIS_LSB_REG,
> +			       &data->buffer.buff, 3 * sizeof(__be16));
> +	mutex_unlock(&data->mutex);
> +	if (ret)
> +		goto out;
> +
> +	ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &temp);
> +	if (ret)
> +		goto out;
> +
> +	data->buffer.temperature = temp;
> +
> +	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
> +					   iio_get_time_ns(indio_dev));
> +
> +out:
> +	iio_trigger_notify_done(indio_dev->trig);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t bma400_interrupt(int irq, void *private)
> +{
> +	struct iio_dev *indio_dev = private;
> +	struct bma400_data *data = iio_priv(indio_dev);
> +	int ret;
> +	__le16 status;
> +
> +	mutex_lock(&data->mutex);
> +	ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG, &status,
> +			       sizeof(status));
> +	mutex_unlock(&data->mutex);
> +	if (ret)
> +		goto out;
> +
> +	if (status & BMA400_INT_DRDY_MSK)

0-day pointed this out. You need an le16_to_cpu()

> +		iio_trigger_poll_chained(data->trig);
> +
> +out:
> +	return IRQ_HANDLED;
> +}
> +
>  static void bma400_disable(void *data_ptr)
>  {
>  	struct bma400_data *data = data_ptr;
> @@ -806,7 +923,8 @@ static void bma400_disable(void *data_ptr)
>  	regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
>  }
>  
> -int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
> +int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
> +		 const char *name)
>  {
>  	struct iio_dev *indio_dev;
>  	struct bma400_data *data;
> @@ -833,12 +951,45 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
>  	indio_dev->info = &bma400_info;
>  	indio_dev->channels = bma400_channels;
>  	indio_dev->num_channels = ARRAY_SIZE(bma400_channels);
> +	indio_dev->available_scan_masks = bma400_avail_scan_masks;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  
>  	ret = devm_add_action_or_reset(dev, bma400_disable, data);
>  	if (ret)
>  		return ret;
>  
> +	if (irq > 0) {
> +		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
> +						    indio_dev->name,
> +						    iio_device_id(indio_dev));
> +		if (!data->trig)
> +			return -ENOMEM;
> +
> +		data->trig->ops = &bma400_trigger_ops;
> +		iio_trigger_set_drvdata(data->trig, indio_dev);
> +
> +		ret = devm_iio_trigger_register(data->dev, data->trig);
> +		if (ret) {
> +			dev_err(dev, "iio trigger register failed\n");
> +			return ret;
> +		}
> +		indio_dev->trig = iio_trigger_get(data->trig);
> +		ret = devm_request_threaded_irq(dev, irq, NULL,
> +						&bma400_interrupt,
> +						IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +						indio_dev->name, indio_dev);
> +		if (ret) {
> +			dev_err(dev, "request irq %d failed\n", irq);
> +			return ret;
> +		}
> +	}
> +
> +	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
> +					      &bma400_trigger_handler, NULL);
> +	if (ret) {
> +		dev_err(dev, "iio triggered buffer setup failed\n");
> +		return ret;
> +	}
>  	return devm_iio_device_register(dev, indio_dev);
>  }
Andy Shevchenko March 21, 2022, 8:39 a.m. UTC | #3
On Sat, Mar 19, 2022 at 8:10 PM Jagath Jog J <jagathjog1996@gmail.com> wrote:
>
> Added trigger buffer support to read continuous acceleration
> data from device with data ready interrupt which is mapped
> to INT1 pin.

...

>  #include <linux/mutex.h>
>  #include <linux/regmap.h>
>  #include <linux/regulator/consumer.h>
> +#include <linux/bits.h>
> +#include <linux/bitfield.h>

It would be nice to keep the above in order.

> +#include <linux/iio/buffer.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_buffer.h>
> +#include <linux/iio/trigger_consumer.h>

These ones, possibly including iio headers from the above piece, are
good to be grouped together here with a blank line in between the
above part and iio/*.

...

> +static const unsigned long bma400_avail_scan_masks[] = {
> +       GENMASK(3, 0),

> +       0,

No need to have a comma in terminator entry.

> +};

...

> +       ret = regmap_bulk_read(data->regmap, BMA400_X_AXIS_LSB_REG,
> +                              &data->buffer.buff, 3 * sizeof(__be16));

sizeof(buff)

...

> +out:

A useless label. Moreover this raises a question: why is it okay to
always mark IRQ as handled?

> +       return IRQ_HANDLED;

...

> +                       dev_err(dev, "iio trigger register failed\n");
> +                       return ret;

return dev_err_probe();

...

> +                       dev_err(dev, "request irq %d failed\n", irq);
> +                       return ret;

Ditto.

...

> +               dev_err(dev, "iio triggered buffer setup failed\n");
> +               return ret;

Ditto.
Jagath Jog J March 21, 2022, 10:21 p.m. UTC | #4
Hello Andy,

On Mon, Mar 21, 2022 at 10:39:22AM +0200, Andy Shevchenko wrote:
> On Sat, Mar 19, 2022 at 8:10 PM Jagath Jog J <jagathjog1996@gmail.com> wrote:
> >
> > Added trigger buffer support to read continuous acceleration
> > data from device with data ready interrupt which is mapped
> > to INT1 pin.
> 
> ...
> 
> >  #include <linux/mutex.h>
> >  #include <linux/regmap.h>
> >  #include <linux/regulator/consumer.h>
> > +#include <linux/bits.h>
> > +#include <linux/bitfield.h>
> 
> It would be nice to keep the above in order.
> 
> > +#include <linux/iio/buffer.h>
> > +#include <linux/iio/trigger.h>
> > +#include <linux/iio/triggered_buffer.h>
> > +#include <linux/iio/trigger_consumer.h>
> 
> These ones, possibly including iio headers from the above piece, are
> good to be grouped together here with a blank line in between the
> above part and iio/*.
> 
> ...
> 
> > +static const unsigned long bma400_avail_scan_masks[] = {
> > +       GENMASK(3, 0),
> 
> > +       0,
> 
> No need to have a comma in terminator entry.
> 
> > +};
> 
> ...
> 
> > +       ret = regmap_bulk_read(data->regmap, BMA400_X_AXIS_LSB_REG,
> > +                              &data->buffer.buff, 3 * sizeof(__be16));
> 
> sizeof(buff)
> 
> ...
> 
> > +out:

Just to skip the below "if()" if error occurs in previous regmap read,
I used this label.
       if (status & BMA400_INT_DRDY_MSK)
             iio_trigger_poll_chained(data->trig);

I will remove the label in next patch
> 
> A useless label. Moreover this raises a question: why is it okay to
> always mark IRQ as handled?
> 
> > +       return IRQ_HANDLED;

Since I was not using top-half of the interrupt so I marked IRQ as handled
even for error case in the handler.

> 
> ...
> 
> > +                       dev_err(dev, "iio trigger register failed\n");
> > +                       return ret;
> 
> return dev_err_probe();
> 
> ...
> 
> > +                       dev_err(dev, "request irq %d failed\n", irq);
> > +                       return ret;
> 
> Ditto.
> 
> ...
> 
> > +               dev_err(dev, "iio triggered buffer setup failed\n");
> > +               return ret;
> 
> Ditto.

I will change this in the next patch version.
> 
> -- 
> With Best Regards,
> Andy Shevchenko
Andy Shevchenko March 22, 2022, 8:54 a.m. UTC | #5
On Tue, Mar 22, 2022 at 12:21 AM Jagath Jog J <jagathjog1996@gmail.com> wrote:
> On Mon, Mar 21, 2022 at 10:39:22AM +0200, Andy Shevchenko wrote:
> > On Sat, Mar 19, 2022 at 8:10 PM Jagath Jog J <jagathjog1996@gmail.com> wrote:

First of all, you left many uncommented comments. I assume you agree
with my comments and are going to address them. If it's not the case,
please elaborate.

...

> > > +out:
>
> Just to skip the below "if()" if error occurs in previous regmap read,
> I used this label.
>        if (status & BMA400_INT_DRDY_MSK)
>              iio_trigger_poll_chained(data->trig);
>
> I will remove the label in next patch

Just return directly.

...

> > A useless label. Moreover this raises a question: why is it okay to
> > always mark IRQ as handled?
> >
> > > +       return IRQ_HANDLED;
>
> Since I was not using top-half of the interrupt so I marked IRQ as handled
> even for error case in the handler.

Yes, but why? Isn't it an erroneous state? Does it mean spurious
interrupt? Does it mean interrupt is unserviced?
Jagath Jog J March 22, 2022, 3:40 p.m. UTC | #6
Hello Andy,

On Tue, Mar 22, 2022 at 10:54:53AM +0200, Andy Shevchenko wrote:
> On Tue, Mar 22, 2022 at 12:21 AM Jagath Jog J <jagathjog1996@gmail.com> wrote:
> > On Mon, Mar 21, 2022 at 10:39:22AM +0200, Andy Shevchenko wrote:
> > > On Sat, Mar 19, 2022 at 8:10 PM Jagath Jog J <jagathjog1996@gmail.com> wrote:
> 
> First of all, you left many uncommented comments. I assume you agree
> with my comments and are going to address them. If it's not the case,
> please elaborate.

Yes Andy, I agree with your comments and I will address them in the next v2 series.

> 
> ...
> 
> > > > +out:
> >
> > Just to skip the below "if()" if error occurs in previous regmap read,
> > I used this label.
> >        if (status & BMA400_INT_DRDY_MSK)
> >              iio_trigger_poll_chained(data->trig);
> >
> > I will remove the label in next patch
> 
> Just return directly.
> 
> ...
> 
> > > A useless label. Moreover this raises a question: why is it okay to
> > > always mark IRQ as handled?
> > >
> > > > +       return IRQ_HANDLED;
> >
> > Since I was not using top-half of the interrupt so I marked IRQ as handled
> > even for error case in the handler.
> 
> Yes, but why? Isn't it an erroneous state? Does it mean spurious
> interrupt? Does it mean interrupt is unserviced?

Sorry, even for erroneous state I was returning IRQ_HANDLED.
As shown below, now for erroneous state and spurious interrupt I will return
IRQ_NONE and for valid interrupt IRQ_HANDLED will be returned.

Is below method is correct?

static irqreturn_t bma400_interrupt(int irq, void *private)
{
       struct iio_dev *indio_dev = private;
       struct bma400_data *data = iio_priv(indio_dev);
       int ret;
       __le16 status;

       mutex_lock(&data->mutex);
       ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG, &status,
                              sizeof(status));
       mutex_unlock(&data->mutex);
       if (ret)
               return IRQ_NONE;

       if (le16_to_cpu(status) & BMA400_INT_DRDY_MSK) {
               iio_trigger_poll_chained(data->trig);
	       return IRQ_HANDLED;
	}

        return IRQ_NONE;
}

> 
> -- 
> With Best Regards,
> Andy Shevchenko
Andy Shevchenko March 22, 2022, 4:12 p.m. UTC | #7
On Tue, Mar 22, 2022 at 5:40 PM Jagath Jog J <jagathjog1996@gmail.com> wrote:
> On Tue, Mar 22, 2022 at 10:54:53AM +0200, Andy Shevchenko wrote:
> > On Tue, Mar 22, 2022 at 12:21 AM Jagath Jog J <jagathjog1996@gmail.com> wrote:
> > > On Mon, Mar 21, 2022 at 10:39:22AM +0200, Andy Shevchenko wrote:
> > > > On Sat, Mar 19, 2022 at 8:10 PM Jagath Jog J <jagathjog1996@gmail.com> wrote:

...

> > > > A useless label. Moreover this raises a question: why is it okay to
> > > > always mark IRQ as handled?
> > > >
> > > > > +       return IRQ_HANDLED;
> > >
> > > Since I was not using top-half of the interrupt so I marked IRQ as handled
> > > even for error case in the handler.
> >
> > Yes, but why? Isn't it an erroneous state? Does it mean spurious
> > interrupt? Does it mean interrupt is unserviced?
>
> Sorry, even for erroneous state I was returning IRQ_HANDLED.
> As shown below, now for erroneous state and spurious interrupt I will return
> IRQ_NONE and for valid interrupt IRQ_HANDLED will be returned.
>
> Is below method is correct?

The thing is that I don't know. I am not familiar with this hardware.
So, you have to investigate and decide.

> static irqreturn_t bma400_interrupt(int irq, void *private)
> {
>        struct iio_dev *indio_dev = private;
>        struct bma400_data *data = iio_priv(indio_dev);
>        int ret;
>        __le16 status;
>
>        mutex_lock(&data->mutex);
>        ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG, &status,
>                               sizeof(status));
>        mutex_unlock(&data->mutex);
>        if (ret)
>                return IRQ_NONE;

>        if (le16_to_cpu(status) & BMA400_INT_DRDY_MSK) {
>                iio_trigger_poll_chained(data->trig);
>                return IRQ_HANDLED;
>         }
>
>         return IRQ_NONE;

If you are going with this approach, try to handle errors first, i.e.

    if (...)
        return IRQ_NONE;
    ...
    return IRQ_HANDLED;

> }
diff mbox series

Patch

diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 49587c992a6d..0eb379578e00 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -177,6 +177,8 @@  config BMA220
 config BMA400
 	tristate "Bosch BMA400 3-Axis Accelerometer Driver"
 	select REGMAP
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
 	select BMA400_I2C if I2C
 	select BMA400_SPI if SPI
 	help
diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h
index cfc2c9bacec8..b306a5ad513a 100644
--- a/drivers/iio/accel/bma400.h
+++ b/drivers/iio/accel/bma400.h
@@ -62,6 +62,13 @@ 
 #define BMA400_ACC_CONFIG2_REG      0x1b
 #define BMA400_CMD_REG              0x7e
 
+/* Interrupt registers */
+#define BMA400_INT_CONFIG0_REG      0x1f
+#define BMA400_INT_CONFIG1_REG      0x20
+#define BMA400_INT1_MAP_REG         0x21
+#define BMA400_INT_IO_CTRL_REG      0x24
+#define BMA400_INT_DRDY_MSK         BIT(7)
+
 /* Chip ID of BMA 400 devices found in the chip ID register. */
 #define BMA400_ID_REG_VAL           0x90
 
@@ -92,6 +99,7 @@ 
 
 extern const struct regmap_config bma400_regmap_config;
 
-int bma400_probe(struct device *dev, struct regmap *regmap, const char *name);
+int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
+		 const char *name);
 
 #endif
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index dcc7549c7a0e..797403c7dd85 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -20,6 +20,12 @@ 
 #include <linux/mutex.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
 
 #include "bma400.h"
 
@@ -61,6 +67,13 @@  struct bma400_data {
 	struct bma400_sample_freq sample_freq;
 	int oversampling_ratio;
 	int scale;
+	struct iio_trigger *trig;
+	/* Correct time stamp alignment */
+	struct {
+		__be16 buff[3];
+		u8 temperature;
+		s64 ts __aligned(8);
+	} buffer;
 };
 
 static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
@@ -152,7 +165,7 @@  static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
 	{ }
 };
 
-#define BMA400_ACC_CHANNEL(_axis) { \
+#define BMA400_ACC_CHANNEL(_index, _axis) { \
 	.type = IIO_ACCEL, \
 	.modified = 1, \
 	.channel2 = IIO_MOD_##_axis, \
@@ -164,17 +177,32 @@  static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
 		BIT(IIO_CHAN_INFO_SCALE) | \
 		BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
 	.ext_info = bma400_ext_info, \
+	.scan_index = _index,	\
+	.scan_type = {		\
+		.sign = 's',	\
+		.realbits = 12,		\
+		.storagebits = 16,	\
+		.endianness = IIO_LE,	\
+	},				\
 }
 
 static const struct iio_chan_spec bma400_channels[] = {
-	BMA400_ACC_CHANNEL(X),
-	BMA400_ACC_CHANNEL(Y),
-	BMA400_ACC_CHANNEL(Z),
+	BMA400_ACC_CHANNEL(0, X),
+	BMA400_ACC_CHANNEL(1, Y),
+	BMA400_ACC_CHANNEL(2, Z),
 	{
 		.type = IIO_TEMP,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
 		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+		.scan_index = 3,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 8,
+			.storagebits = 8,
+			.endianness = IIO_LE,
+		},
 	},
+	IIO_CHAN_SOFT_TIMESTAMP(4),
 };
 
 static int bma400_get_temp_reg(struct bma400_data *data, int *val, int *val2)
@@ -632,6 +660,11 @@  static int bma400_init(struct bma400_data *data)
 	if (ret)
 		goto err_reg_disable;
 
+	/* Configure INT-1 pin to push pull */
+	ret = regmap_write(data->regmap, BMA400_INT_IO_CTRL_REG, 0x02);
+	if (ret)
+		goto err_reg_disable;
+
 	/*
 	 * Once the interrupt engine is supported we might use the
 	 * data_src_reg, but for now ensure this is set to the
@@ -786,6 +819,33 @@  static int bma400_write_raw_get_fmt(struct iio_dev *indio_dev,
 	}
 }
 
+static int bma400_data_rdy_trigger_set_state(struct iio_trigger *trig,
+					     bool state)
+{
+	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+	struct bma400_data *data = iio_priv(indio_dev);
+	int ret;
+
+	ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG,
+				 BMA400_INT_DRDY_MSK,
+				 FIELD_PREP(BMA400_INT_DRDY_MSK, state));
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG,
+				 BMA400_INT_DRDY_MSK,
+				 FIELD_PREP(BMA400_INT_DRDY_MSK, state));
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const unsigned long bma400_avail_scan_masks[] = {
+	GENMASK(3, 0),
+	0,
+};
+
 static const struct iio_info bma400_info = {
 	.read_raw          = bma400_read_raw,
 	.read_avail        = bma400_read_avail,
@@ -793,6 +853,63 @@  static const struct iio_info bma400_info = {
 	.write_raw_get_fmt = bma400_write_raw_get_fmt,
 };
 
+static const struct iio_trigger_ops bma400_trigger_ops = {
+	.set_trigger_state = &bma400_data_rdy_trigger_set_state,
+	.validate_device = &iio_trigger_validate_own_device,
+};
+
+static irqreturn_t bma400_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct bma400_data *data = iio_priv(indio_dev);
+	int ret, temp;
+
+	mutex_lock(&data->mutex);
+
+	/* bulk read six registers, with the base being the LSB register */
+	ret = regmap_bulk_read(data->regmap, BMA400_X_AXIS_LSB_REG,
+			       &data->buffer.buff, 3 * sizeof(__be16));
+	mutex_unlock(&data->mutex);
+	if (ret)
+		goto out;
+
+	ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &temp);
+	if (ret)
+		goto out;
+
+	data->buffer.temperature = temp;
+
+	iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
+					   iio_get_time_ns(indio_dev));
+
+out:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bma400_interrupt(int irq, void *private)
+{
+	struct iio_dev *indio_dev = private;
+	struct bma400_data *data = iio_priv(indio_dev);
+	int ret;
+	__le16 status;
+
+	mutex_lock(&data->mutex);
+	ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG, &status,
+			       sizeof(status));
+	mutex_unlock(&data->mutex);
+	if (ret)
+		goto out;
+
+	if (status & BMA400_INT_DRDY_MSK)
+		iio_trigger_poll_chained(data->trig);
+
+out:
+	return IRQ_HANDLED;
+}
+
 static void bma400_disable(void *data_ptr)
 {
 	struct bma400_data *data = data_ptr;
@@ -806,7 +923,8 @@  static void bma400_disable(void *data_ptr)
 	regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
 }
 
-int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
+int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
+		 const char *name)
 {
 	struct iio_dev *indio_dev;
 	struct bma400_data *data;
@@ -833,12 +951,45 @@  int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
 	indio_dev->info = &bma400_info;
 	indio_dev->channels = bma400_channels;
 	indio_dev->num_channels = ARRAY_SIZE(bma400_channels);
+	indio_dev->available_scan_masks = bma400_avail_scan_masks;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 
 	ret = devm_add_action_or_reset(dev, bma400_disable, data);
 	if (ret)
 		return ret;
 
+	if (irq > 0) {
+		data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+						    indio_dev->name,
+						    iio_device_id(indio_dev));
+		if (!data->trig)
+			return -ENOMEM;
+
+		data->trig->ops = &bma400_trigger_ops;
+		iio_trigger_set_drvdata(data->trig, indio_dev);
+
+		ret = devm_iio_trigger_register(data->dev, data->trig);
+		if (ret) {
+			dev_err(dev, "iio trigger register failed\n");
+			return ret;
+		}
+		indio_dev->trig = iio_trigger_get(data->trig);
+		ret = devm_request_threaded_irq(dev, irq, NULL,
+						&bma400_interrupt,
+						IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+						indio_dev->name, indio_dev);
+		if (ret) {
+			dev_err(dev, "request irq %d failed\n", irq);
+			return ret;
+		}
+	}
+
+	ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+					      &bma400_trigger_handler, NULL);
+	if (ret) {
+		dev_err(dev, "iio triggered buffer setup failed\n");
+		return ret;
+	}
 	return devm_iio_device_register(dev, indio_dev);
 }
 EXPORT_SYMBOL(bma400_probe);
diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c
index 56da06537562..49b0ae13fdc8 100644
--- a/drivers/iio/accel/bma400_i2c.c
+++ b/drivers/iio/accel/bma400_i2c.c
@@ -24,7 +24,7 @@  static int bma400_i2c_probe(struct i2c_client *client,
 		return PTR_ERR(regmap);
 	}
 
-	return bma400_probe(&client->dev, regmap, id->name);
+	return bma400_probe(&client->dev, regmap, client->irq, id->name);
 }
 
 static const struct i2c_device_id bma400_i2c_ids[] = {
diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c
index 96dc9c215401..2957ebc51543 100644
--- a/drivers/iio/accel/bma400_spi.c
+++ b/drivers/iio/accel/bma400_spi.c
@@ -84,7 +84,7 @@  static int bma400_spi_probe(struct spi_device *spi)
 	if (ret)
 		dev_err(&spi->dev, "Failed to read chip id register\n");
 
-	return bma400_probe(&spi->dev, regmap, id->name);
+	return bma400_probe(&spi->dev, regmap, spi->irq, id->name);
 }
 
 static const struct spi_device_id bma400_spi_ids[] = {