Re: [PATCH v3 6/6] iio: pressure: Add triggered buffer support for BMP280 driver

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

 



On Sun, Mar 24, 2024 at 12:14:18PM +0000, Jonathan Cameron wrote:
> On Tue, 19 Mar 2024 01:29:25 +0100
> Vasileios Amoiridis <vassilisamir@xxxxxxxxx> wrote:
> 
> > BMP2xx, BMP3xx, and BMP5xx use consecutive buffers for their
> > temperature, pressure and humidity readings. This facilitates
> > the use of burst reads in order to acquire data much faster
> > and in a different way from the one used in oneshot captures.
> > 
> > BMP085 and BMP180 use a completely different measurement
> > process that is well defined and is used in their buffer_handler().
> > 
> > Suggested-by: Angel Iglesias <ang.iglesiasg@xxxxxxxxx>
> > Signed-off-by: Vasileios Amoiridis <vassilisamir@xxxxxxxxx>
> 
> Various comments inline,
> 
> Thanks,
> Jonathan
> 
> > ---
> >  drivers/iio/pressure/Kconfig       |   2 +
> >  drivers/iio/pressure/bmp280-core.c | 231 +++++++++++++++++++++++++++--
> >  drivers/iio/pressure/bmp280-spi.c  |   8 +-
> >  drivers/iio/pressure/bmp280.h      |  14 +-
> >  4 files changed, 241 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
> > index 79adfd059c3a..5145b94b4679 100644
> > --- a/drivers/iio/pressure/Kconfig
> > +++ b/drivers/iio/pressure/Kconfig
> > @@ -31,6 +31,8 @@ config BMP280
> >  	select REGMAP
> >  	select BMP280_I2C if (I2C)
> >  	select BMP280_SPI if (SPI_MASTER)
> > +	select IIO_BUFFER
> > +	select IIO_TRIGGERED_BUFFER
> >  	help
> >  	  Say yes here to build support for Bosch Sensortec BMP180, BMP280, BMP380
> >  	  and BMP580 pressure and temperature sensors. Also supports the BME280 with
> > diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> > index ddfcd23f29a0..ffcd17807cf5 100644
> > --- a/drivers/iio/pressure/bmp280-core.c
> > +++ b/drivers/iio/pressure/bmp280-core.c
> > @@ -40,7 +40,10 @@
> >  #include <linux/regmap.h>
> >  #include <linux/regulator/consumer.h>
> >  
> > +#include <linux/iio/buffer.h>
> >  #include <linux/iio/iio.h>
> > +#include <linux/iio/trigger_consumer.h>
> > +#include <linux/iio/triggered_buffer.h>
> >  
> >  #include <asm/unaligned.h>
> >  
> > @@ -454,7 +457,7 @@ static int bmp280_read_temp(struct bmp280_data *data, s32 *comp_temp)
> >  	int ret;
> >  
> >  	ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
> > -			       data->buf, sizeof(data->buf));
> > +			       data->buf, BMP280_NUM_TEMP_BYTES);
> >  	if (ret < 0) {
> >  		dev_err(data->dev, "failed to read temperature\n");
> >  		return ret;
> > @@ -484,7 +487,7 @@ static int bmp280_read_press(struct bmp280_data *data, u32 *comp_press)
> >  		return ret;
> >  
> >  	ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
> > -			       data->buf, sizeof(data->buf));
> > +			       data->buf, BMP280_NUM_PRESS_BYTES);
> >  	if (ret < 0) {
> >  		dev_err(data->dev, "failed to read pressure\n");
> >  		return ret;
> > @@ -513,13 +516,13 @@ static int bmp280_read_humid(struct bmp280_data *data, u32 *comp_humidity)
> >  		return ret;
> >  
> >  	ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB,
> > -			       &data->be16, sizeof(data->be16));
> > +			       &data->be16, BME280_NUM_HUMIDITY_BYTES);
> >  	if (ret < 0) {
> >  		dev_err(data->dev, "failed to read humidity\n");
> >  		return ret;
> >  	}
> >  
> > -	adc_humidity = be16_to_cpu(data->be16);
> > +	adc_humidity = get_unaligned_be16(&data->be16);
> 
> If it's a be16, how did it become unaligned?
> 
> >  	if (adc_humidity == BMP280_HUMIDITY_SKIPPED) {
> >  		/* reading was skipped */
> >  		dev_err(data->dev, "reading humidity skipped\n");
> > @@ -931,6 +934,73 @@ static int bmp280_chip_config(struct bmp280_data *data)
> >  	return ret;
> >  }
> >  
> > +static irqreturn_t bmp280_buffer_handler(int irq, void *p)
> > +{
> > +	struct iio_poll_func *pf = p;
> > +	struct iio_dev *indio_dev = pf->indio_dev;
> > +	struct bmp280_data *data = iio_priv(indio_dev);
> > +	s32 adc_temp, adc_press, adc_humidity;
> > +	u8 size_of_burst_read;
> > +	int ret, chan_value;
> > +
> > +	guard(mutex)(&data->lock);
> > +
> > +	if (test_bit(BME280_HUMID, indio_dev->active_scan_mask))
> 
> This confuses me a little. Is it allowing reuse of this function for
> multiple devices or aiming to optimise the read in the case of
> the humidity channel being disabled (in which case I don't think
> it works because you aren't providing that combination in avail_scan_masks.)
> 
> Add a comment to explain.
> 

Hi Jonathan,

It is aimed to reuse the function both for BMP280 and BME280 so that's why is
there, it's not in case humidity channel is disabled. I can add a comment it
is definitely not obvious. Thanks for pointing this out.

By applying the changes that you pointed out + by implementing the changes
that you proposed in a previous patch to split the t_fine calculation this
patch will become much cleaner, thanks a lot!

Cheers,
Vasilis
> > +		size_of_burst_read = 8;
> > +	else
> > +		size_of_burst_read = 6;
> > +
> > +	/* Burst read data registers */
> > +	ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
> > +			       data->buf, 8);
> > +	if (ret) {
> > +		dev_err(data->dev, "failed to read sensor data\n");
> > +		return ret;
> > +	}
> > +
> > +	/* Temperature calculations */
> > +	memcpy(&chan_value, &data->buf[3], 3);
> > +
> > +	adc_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&chan_value));
> > +	if (adc_temp == BMP280_TEMP_SKIPPED) {
> > +		/* reading was skipped */
> Similar comments on this to below (I read backwards as normally code makes
> more sense that way :)
> > +		dev_err(data->dev, "reading temperature skipped\n");
> > +		return -EIO;
> > +	}
> > +	data->iio_buf.sensor_data[0] = bmp280_compensate_temp(data, adc_temp);
> > +
> > +	/* Pressure calculations */
> > +	memcpy(&chan_value, &data->buf[0], 3);
> > +
> > +	adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&chan_value));
> > +	if (adc_press == BMP280_PRESS_SKIPPED) {
> > +		/* reading was skipped */
> > +		dev_err(data->dev, "reading pressure skipped\n");
> > +		return -EIO;
> > +	}
> > +	data->iio_buf.sensor_data[1] = bmp280_compensate_press(data, adc_press);
> > +
> > +	/* Humidity calculations */
> > +	if (test_bit(BME280_HUMID, indio_dev->active_scan_mask)) {
> > +		memcpy(&chan_value, &data->buf[6], 2);
> > +
> > +		adc_humidity = get_unaligned_be16(&chan_value);
> > +		if (adc_humidity == BMP280_HUMIDITY_SKIPPED) {
> > +			/* reading was skipped */
> > +			dev_err(data->dev, "reading humidity skipped\n");
> > +			return -EIO;
> > +		}
> > +	data->iio_buf.sensor_data[2] = bmp280_compensate_humidity(data, adc_humidity);
> Alignment of code looks wrong.
> 
> > +	}
> > +
> > +	iio_push_to_buffers_with_timestamp(indio_dev, &data->iio_buf,
> > +					   iio_get_time_ns(indio_dev));
> > +
> > +	iio_trigger_notify_done(indio_dev->trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> 
> > +static irqreturn_t bmp380_buffer_handler(int irq, void *p)
> > +{
> > +	struct iio_poll_func *pf = p;
> > +	struct iio_dev *indio_dev = pf->indio_dev;
> > +	struct bmp280_data *data = iio_priv(indio_dev);
> > +	s32 adc_temp, adc_press;
> > +	int ret, chan_value;
> > +
> > +	guard(mutex)(&data->lock);
> > +
> > +	/* Burst read data registers */
> > +	ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB,
> > +			       data->buf, 6);
> > +	if (ret) {
> > +		dev_err(data->dev, "failed to read sensor data\n");
> > +		return ret;
> > +	}
> > +
> > +	/* Temperature calculations */
> > +	memcpy(&chan_value, &data->buf[3], 3);
> > +
> > +	adc_temp = get_unaligned_le24(&chan_value);
> 
> Same comments as below.
> 
> > +	if (adc_temp == BMP380_TEMP_SKIPPED) {
> > +		/* reading was skipped */
> > +		dev_err(data->dev, "reading temperature skipped\n");
> > +		return -EIO;
> > +	}
> > +	data->iio_buf.sensor_data[0] = bmp380_compensate_temp(data, adc_temp);
> > +
> > +	/* Pressure calculations */
> > +	memcpy(&chan_value, &data->buf[0], 3);
> > +
> > +	adc_press = get_unaligned_le24(&chan_value);
> > +	if (adc_press == BMP380_PRESS_SKIPPED) {
> > +		/* reading was skipped */
> > +		dev_err(data->dev, "reading pressure skipped\n");
> > +		return -EIO;
> > +	}
> > +	data->iio_buf.sensor_data[1] = bmp380_compensate_press(data, adc_press);
> > +
> > +	iio_push_to_buffers_with_timestamp(indio_dev, &data->iio_buf,
> > +					   iio_get_time_ns(indio_dev));
> > +
> > +	iio_trigger_notify_done(indio_dev->trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> 
> > +static irqreturn_t bmp580_buffer_handler(int irq, void *p)
> > +{
> > +	struct iio_poll_func *pf = p;
> > +	struct iio_dev *indio_dev = pf->indio_dev;
> > +	struct bmp280_data *data = iio_priv(indio_dev);
> > +	s32 adc_temp, adc_press;
> > +	int ret, chan_value;
> > +
> > +	guard(mutex)(&data->lock);
> > +
> > +	/* Burst read data registers */
> > +	ret = regmap_bulk_read(data->regmap, BMP580_REG_TEMP_XLSB,
> > +			       data->buf, 6);
> > +	if (ret) {
> > +		dev_err(data->dev, "failed to read sensor data\n");
> > +		return ret;
> > +	}
> > +
> > +	/* Temperature calculations */
> > +	memcpy(&chan_value, &data->buf[3], 3);
> > +
> > +	adc_temp = get_unaligned_le24(&chan_value);
> 
> As in other thread branch, get it directly from &data->buf[3]
> rather than bouncing it via another buffer.
> 
> > +	if (adc_temp == BMP580_TEMP_SKIPPED) {
> > +		/* reading was skipped */
> > +		dev_err(data->dev, "reading temperature skipped\n");
> > +		return -EIO;
> -EIO isn't irqreturn_t 
> 
> There isn't a good way to return errors from interrupt handlers,
> so just return IRQ_HANDLED after printing the error message.
> 
> > +	}
> > +	data->iio_buf.sensor_data[0] = adc_temp;
> > +
> > +	/* Pressure calculations */
> > +	memcpy(&chan_value, &data->buf[0], 3);
> > +
> > +	adc_press = get_unaligned_le24(&chan_value);
> As above, get it directly.
> 
> > +	if (adc_press == BMP580_PRESS_SKIPPED) {
> > +		/* reading was skipped */
> > +		dev_err(data->dev, "reading pressure skipped\n");
> > +		return -EIO;
> return IRQ_HANDLED;
> 
> > +	}
> > +	data->iio_buf.sensor_data[1] =  adc_press;
> Extra space.
> 
> > +
> > +	iio_push_to_buffers_with_timestamp(indio_dev, &data->iio_buf,
> > +					   iio_get_time_ns(indio_dev));
> > +
> > +	iio_trigger_notify_done(indio_dev->trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> >  static const int bmp580_oversampling_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
> >  static const u8 bmp580_chip_ids[] = { BMP580_CHIP_ID, BMP580_CHIP_ID_ALT };
> >  static const int bmp580_temp_coeffs[] = { 1000, 16 };
> > @@ -1903,6 +2075,8 @@ const struct bmp280_chip_info bmp580_chip_info = {
> >  	.read_temp = bmp580_read_temp,
> >  	.read_press = bmp580_read_press,
> >  	.preinit = bmp580_preinit,
> > +
> > +	.buffer_handler = bmp580_buffer_handler
> >  };
> >  EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280);
> >  
> > @@ -2054,7 +2228,7 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val)
> >  		return ret;
> >  
> >  	ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB,
> > -			       data->buf, sizeof(data->buf));
> > +			       data->buf, BMP280_NUM_PRESS_BYTES);
> >  	if (ret)
> >  		return ret;
> >  
> > @@ -2122,6 +2296,35 @@ static int bmp180_chip_config(struct bmp280_data *data)
> >  	return 0;
> >  }
> >  
> > +static irqreturn_t bmp180_buffer_handler(int irq, void *p)
> > +{
> > +	struct iio_poll_func *pf = p;
> > +	struct iio_dev *indio_dev = pf->indio_dev;
> > +	struct bmp280_data *data = iio_priv(indio_dev);
> > +	int ret, chan_value;
> > +
> > +	guard(mutex)(&data->lock);
> > +
> > +	ret = data->chip_info->read_temp(data, &chan_value);
> > +	if (ret)
> > +		return ret;
> > +
> > +	data->iio_buf.sensor_data[0] = chan_value;
> > +
> > +	ret = data->chip_info->read_press(data, &chan_value);
> 
> Given my earlier suggestion to stop hiding t_fine in the
> structure, these callbacks will need to bring it all the way out
> here (from the temperature read) and pass it back into the
> pressure read.
> 
> That will have the pleasing side effect of making it obvious why
> we aren't handling subsets of channels (as they aren't
> independent)
> 
> 
> > +	if (ret)
> > +		return ret;
> > +
> > +	data->iio_buf.sensor_data[1] = chan_value;
> > +
> > +	iio_push_to_buffers_with_timestamp(indio_dev, &data->iio_buf,
> > +					   iio_get_time_ns(indio_dev));
> > +
> > +	iio_trigger_notify_done(indio_dev->trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> 
> > diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
> > index a444d4b2978b..dc297583cac1 100644
> > --- a/drivers/iio/pressure/bmp280-spi.c
> > +++ b/drivers/iio/pressure/bmp280-spi.c
> > @@ -40,14 +40,14 @@ static int bmp380_regmap_spi_read(void *context, const void *reg,
> >  				  size_t reg_size, void *val, size_t val_size)
> >  {
> >  	struct spi_device *spi = to_spi_device(context);
> > -	u8 rx_buf[4];
> > +	u8 rx_buf[9];
> >  	ssize_t status;
> >  
> >  	/*
> > -	 * Maximum number of consecutive bytes read for a temperature or
> > -	 * pressure measurement is 3.
> > +	 * Maximum number of a burst read for temperature, pressure, humidity
> > +	 * is 8 bytes.
> 
> Once this 8 is expressed as the sum of the 3 types, you can drop the comment
> as it will add nothing useful.
> 
> >  	 */
> > -	if (val_size > 3)
> > +	if (val_size > 8)
> >  		return -EINVAL;
> >  
> >  	/*
> > diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
> > index 8cc3eed70c18..32155567faf6 100644
> > --- a/drivers/iio/pressure/bmp280.h
> > +++ b/drivers/iio/pressure/bmp280.h
> > @@ -301,6 +301,10 @@
> >  #define BMP280_PRESS_SKIPPED		0x80000
> >  #define BMP280_HUMIDITY_SKIPPED		0x8000
> >  
> > +#define BMP280_NUM_TEMP_BYTES		3
> > +#define BMP280_NUM_PRESS_BYTES		3
> > +#define BME280_NUM_HUMIDITY_BYTES	2
> > +
> >  /* Core exported structs */
> >  
> >  static const char *const bmp280_supply_names[] = {
> > @@ -400,13 +404,19 @@ struct bmp280_data {
> >  	 */
> >  	s32 t_fine;
> >  
> > +	/* Data to push to userspace */
> > +	struct {
> > +		s32 sensor_data[3];
> 
> This doesn't work (as explanation of data) for all cases.
>  If you only have 2 channels, the packing needs to be.
> 
> 		s32 sensor_data[2];
> //no padding
> 		s64 timestamp __aligned(8);
> > +		s64 timestamp __aligned(8);
> > +	} iio_buf;
> > +
> So using a structure for this definition isn't a bug as such as the core
> doesn't care that you provide a bigger buffer than needed, but it is misleading.
> Use something along lines of
> 
> 	/* Up to 3 channels and aligned s64 timestamp */
> 	s32 sensor_data[6] __aligned(8);
> 
> or use a union of two structures to cover the two layouts making
> sure to write and read from the correct one in each callback.
> 
> >  	/*
> >  	 * DMA (thus cache coherency maintenance) may require the
> >  	 * transfer buffers to live in their own cache lines.
> >  	 */
> >  	union {
> >  		/* Sensor data buffer */
> > -		u8 buf[3];
> > +		u8 buf[8];
> As in previous discussion - build this up as a sum of what can go in it.
> Maybe via a define for BMP280_BURST_READ_MAX 
> 




[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