Re: [PATCH v8 3/3] iio: pressure: bmp280: Add triggered buffer support

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

 



On Sat, Jun 22, 2024 at 10:40:39AM +0100, Jonathan Cameron wrote:
> On Tue, 18 Jun 2024 01:05:40 +0200
> Vasileios Amoiridis <vassilisamir@xxxxxxxxx> wrote:
> 
> > BMP2xx, BME280, BMP3xx, and BMP5xx use continuous buffers for their
> > temperature, pressure and humidity readings. This facilitates the
> > use of burst/bulk reads in order to acquire data faster. The
> > approach is different from the one used in oneshot captures.
> > 
> > BMP085 & BMP1xx devices 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>
> > Link: https://lore.kernel.org/r/20240512230524.53990-6-vassilisamir@xxxxxxxxx
> > ---
> The sign extend in buffered path doesn't make much sense as we should be
> advertising the correct bit depth for the channel and making that a userspace
> problem.
> 
> I'd failed to notice you are doing endian conversions just to check
> the skipped values. Ideally we'd leave the channels little endian
> and include that in the channel spec.
> 
> Hmm. I guess this works and if we have to do the endian conversion
> anyway isn't too bad.  It does provide slightly wrong information
> to userspace though.
> 
> So even with this in place I think these channels should be real_bits 24.
> 
> 
> 
> > +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;
> > +
> > +	guard(mutex)(&data->lock);
> > +
> > +	/* Burst read data registers */
> > +	ret = regmap_bulk_read(data->regmap, BMP580_REG_TEMP_XLSB,
> > +			       data->buf, BMP280_BURST_READ_BYTES);

With the bulk read here, we have 24 bits of temperature and 24 bits 
of pressure, so in total 6 bytes. The only way I can see to not do
the endian conversion is that I memcpy the first 3 bytes to the
data->sensor_data[1], and the last 3 bytes to the data->sensor_data[0].

If you can see any other better way please let me know, otherwise the
other solution is to use get_unaligned_24(). Still, we won't do the
skipping part.
 
> > +	if (ret) {
> > +		dev_err(data->dev, "failed to burst read sensor data\n");
> > +		goto out;
> > +	}
> > +
> > +	/* Temperature calculations */
> > +	adc_temp = get_unaligned_le24(&data->buf[0]);
> > +	if (adc_temp == BMP580_TEMP_SKIPPED) {
> > +		dev_err(data->dev, "reading temperature skipped\n");
> > +		goto out;
> > +	}
> > +
> > +	data->sensor_data[1] = sign_extend32(adc_temp, 23);
> 
> the channel type should indicate that it's a 24 bit value. Not our
> problem to sign extend.  Leave that to userspace.
> 
> > +
> > +	/* Pressure calculations */
> > +	adc_press = get_unaligned_le24(&data->buf[3]);
> > +	if (adc_press == BMP380_PRESS_SKIPPED) {
> > +		dev_err(data->dev, "reading pressure skipped\n");
> > +		goto out;
> > +	}
> > +
> > +	data->sensor_data[0] = adc_press;
> > +
> > +	iio_push_to_buffers_with_timestamp(indio_dev, &data->sensor_data,
> > +					   iio_get_time_ns(indio_dev));
> > +
> > +out:
> > +	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 };
> > @@ -1929,6 +2204,7 @@ const struct bmp280_chip_info bmp580_chip_info = {
> >  	.start_up_time = 2000,
> >  	.channels = bmp380_channels,
> >  	.num_channels = ARRAY_SIZE(bmp380_channels),
> > +	.avail_scan_masks = bmp280_avail_scan_masks,
> >  
> >  	.oversampling_temp_avail = bmp580_oversampling_avail,
> >  	.num_oversampling_temp_avail = ARRAY_SIZE(bmp580_oversampling_avail),
> > @@ -1955,6 +2231,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);
> >  
> > @@ -2133,7 +2411,7 @@ static int bmp180_read_press_adc(struct bmp280_data *data, u32 *adc_press)
> >  		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) {
> >  		dev_err(data->dev, "failed to read pressure\n");
> >  		return ret;
> > @@ -2204,6 +2482,36 @@ 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 = bmp180_read_temp(data, &chan_value);
> > +	if (ret)
> > +		goto out;
> > +
> > +	data->sensor_data[1] = chan_value;
> > +
> > +	ret = bmp180_read_press(data, &chan_value);
> > +	if (ret)
> > +		goto out;
> > +
> > +	data->sensor_data[0] = chan_value;
> > +
> > +	iio_push_to_buffers_with_timestamp(indio_dev, &data->sensor_data,
> > +					   iio_get_time_ns(indio_dev));
> > +
> > +out:
> > +	iio_trigger_notify_done(indio_dev->trig);
> > +
> > +	return IRQ_HANDLED;
> > +}
> > +
> >  static const int bmp180_oversampling_temp_avail[] = { 1 };
> >  static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 };
> >  static const u8 bmp180_chip_ids[] = { BMP180_CHIP_ID };
> > @@ -2218,6 +2526,7 @@ const struct bmp280_chip_info bmp180_chip_info = {
> >  	.start_up_time = 2000,
> >  	.channels = bmp280_channels,
> >  	.num_channels = ARRAY_SIZE(bmp280_channels),
> > +	.avail_scan_masks = bmp280_avail_scan_masks,
> >  
> >  	.oversampling_temp_avail = bmp180_oversampling_temp_avail,
> >  	.num_oversampling_temp_avail =
> > @@ -2238,6 +2547,8 @@ const struct bmp280_chip_info bmp180_chip_info = {
> >  	.read_temp = bmp180_read_temp,
> >  	.read_press = bmp180_read_press,
> >  	.read_calib = bmp180_read_calib,
> > +
> > +	.buffer_handler = bmp180_buffer_handler,
> >  };
> >  EXPORT_SYMBOL_NS(bmp180_chip_info, IIO_BMP280);
> >  
> > @@ -2283,6 +2594,30 @@ static int bmp085_fetch_eoc_irq(struct device *dev,
> >  	return 0;
> >  }
> >  
> > +static int bmp280_buffer_preenable(struct iio_dev *indio_dev)
> > +{
> > +	struct bmp280_data *data = iio_priv(indio_dev);
> > +
> > +	pm_runtime_get_sync(data->dev);
> > +
> > +	return 0;
> > +}
> > +
> > +static int bmp280_buffer_postdisable(struct iio_dev *indio_dev)
> > +{
> > +	struct bmp280_data *data = iio_priv(indio_dev);
> > +
> > +	pm_runtime_mark_last_busy(data->dev);
> > +	pm_runtime_put_autosuspend(data->dev);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct iio_buffer_setup_ops bmp280_buffer_setup_ops = {
> > +	.preenable = bmp280_buffer_preenable,
> > +	.postdisable = bmp280_buffer_postdisable,
> > +};
> > +
> >  static void bmp280_pm_disable(void *data)
> >  {
> >  	struct device *dev = data;
> > @@ -2329,6 +2664,7 @@ int bmp280_common_probe(struct device *dev,
> >  	/* Apply initial values from chip info structure */
> >  	indio_dev->channels = chip_info->channels;
> >  	indio_dev->num_channels = chip_info->num_channels;
> > +	indio_dev->available_scan_masks = chip_info->avail_scan_masks;
> >  	data->oversampling_press = chip_info->oversampling_press_default;
> >  	data->oversampling_humid = chip_info->oversampling_humid_default;
> >  	data->oversampling_temp = chip_info->oversampling_temp_default;
> > @@ -2414,6 +2750,14 @@ int bmp280_common_probe(struct device *dev,
> >  					     "failed to read calibration coefficients\n");
> >  	}
> >  
> > +	ret = devm_iio_triggered_buffer_setup(data->dev, indio_dev,
> > +					      iio_pollfunc_store_time,
> > +					      data->chip_info->buffer_handler,
> > +					      &bmp280_buffer_setup_ops);
> > +	if (ret)
> > +		return dev_err_probe(data->dev, ret,
> > +				     "iio triggered buffer setup failed\n");
> > +
> >  	/*
> >  	 * Attempt to grab an optional EOC IRQ - only the BMP085 has this
> >  	 * however as it happens, the BMP085 shares the chip ID of BMP180
> > diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
> > index 62b4e58104cf..e5abee15950e 100644
> > --- a/drivers/iio/pressure/bmp280-spi.c
> > +++ b/drivers/iio/pressure/bmp280-spi.c
> > @@ -40,14 +40,10 @@ 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[BME280_BURST_READ_BYTES + 1];
> >  	ssize_t status;
> >  
> > -	/*
> > -	 * Maximum number of consecutive bytes read for a temperature or
> > -	 * pressure measurement is 3.
> > -	 */
> > -	if (val_size > 3)
> > +	if (val_size > BME280_BURST_READ_BYTES)
> >  		return -EINVAL;
> >  
> >  	/*
> > diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
> > index a3d2cd722760..756c644354c2 100644
> > --- a/drivers/iio/pressure/bmp280.h
> > +++ b/drivers/iio/pressure/bmp280.h
> > @@ -304,6 +304,16 @@
> >  #define BMP280_PRESS_SKIPPED		0x80000
> >  #define BMP280_HUMIDITY_SKIPPED		0x8000
> >  
> > +/* Number of bytes for each value */
> > +#define BMP280_NUM_PRESS_BYTES		3
> > +#define BMP280_NUM_TEMP_BYTES		3
> > +#define BME280_NUM_HUMIDITY_BYTES	2
> > +#define BMP280_BURST_READ_BYTES		(BMP280_NUM_PRESS_BYTES + \
> > +					 BMP280_NUM_TEMP_BYTES)
> > +#define BME280_BURST_READ_BYTES		(BMP280_NUM_PRESS_BYTES + \
> > +					 BMP280_NUM_TEMP_BYTES + \
> > +					 BME280_NUM_HUMIDITY_BYTES)
> > +
> >  /* Core exported structs */
> >  
> >  static const char *const bmp280_supply_names[] = {
> > @@ -397,13 +407,19 @@ struct bmp280_data {
> >  	 */
> >  	int sampling_freq;
> >  
> > +	/*
> > +	 * Data to push to userspace triggered buffer. Up to 3 channels and
> > +	 * s64 timestamp, aligned.
> > +	 */
> > +	s32 sensor_data[6] __aligned(8);
> > +
> >  	/*
> >  	 * 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[BME280_BURST_READ_BYTES];
> >  		/* Calibration data buffers */
> >  		__le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS / 2];
> >  		__be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT / 2];
> > @@ -425,6 +441,7 @@ struct bmp280_chip_info {
> >  	const struct iio_chan_spec *channels;
> >  	int num_channels;
> >  	unsigned int start_up_time;
> > +	const unsigned long *avail_scan_masks;
> >  
> >  	const int *oversampling_temp_avail;
> >  	int num_oversampling_temp_avail;
> > @@ -459,6 +476,8 @@ struct bmp280_chip_info {
> >  	int (*read_humid)(struct bmp280_data *data, u32 *adc_humidity);
> >  	int (*read_calib)(struct bmp280_data *data);
> >  	int (*preinit)(struct bmp280_data *data);
> > +
> > +	irqreturn_t (*buffer_handler)(int irq, void *p);
> >  };
> >  
> >  /* Chip infos for each variant */
> 




[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