Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quellcode-Bibliothek bmp280-core.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
 * Copyright (c) 2012 Bosch Sensortec GmbH
 * Copyright (c) 2012 Unixphere AB
 * Copyright (c) 2014 Intel Corporation
 * Copyright (c) 2016 Linus Walleij <linus.walleij@linaro.org>
 *
 * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor.
 *
 * Datasheet:
 * https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf
 * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
 * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf
 * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf
 * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf
 * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf
 *
 * Sensor API:
 * https://github.com/boschsensortec/BME280_SensorAPI
 * https://github.com/boschsensortec/BMP3_SensorAPI
 * https://github.com/boschsensortec/BMP5_SensorAPI
 *
 * Notice:
 * The link to the bmp180 datasheet points to an outdated version missing these changes:
 * - Changed document referral from ANP015 to BST-MPS-AN004-00 on page 26
 * - Updated equation for B3 param on section 3.5 to ((((long)AC1 * 4 + X3) << oss) + 2) / 4
 * - Updated RoHS directive to 2011/65/EU effective 8 June 2011 on page 26
 */


#define pr_fmt(fmt) "bmp280: " fmt

#include <linux/bitops.h>
#include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h> /* For irq_get_irq_data() */
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/random.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>

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

#include <linux/unaligned.h>

#include "bmp280.h"

/*
 * These enums are used for indexing into the array of calibration
 * coefficients for BMP180.
 */

enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };

enum bmp380_odr {
 BMP380_ODR_200HZ,
 BMP380_ODR_100HZ,
 BMP380_ODR_50HZ,
 BMP380_ODR_25HZ,
 BMP380_ODR_12_5HZ,
 BMP380_ODR_6_25HZ,
 BMP380_ODR_3_125HZ,
 BMP380_ODR_1_5625HZ,
 BMP380_ODR_0_78HZ,
 BMP380_ODR_0_39HZ,
 BMP380_ODR_0_2HZ,
 BMP380_ODR_0_1HZ,
 BMP380_ODR_0_05HZ,
 BMP380_ODR_0_02HZ,
 BMP380_ODR_0_01HZ,
 BMP380_ODR_0_006HZ,
 BMP380_ODR_0_003HZ,
 BMP380_ODR_0_0015HZ,
};

enum bmp580_odr {
 BMP580_ODR_240HZ,
 BMP580_ODR_218HZ,
 BMP580_ODR_199HZ,
 BMP580_ODR_179HZ,
 BMP580_ODR_160HZ,
 BMP580_ODR_149HZ,
 BMP580_ODR_140HZ,
 BMP580_ODR_129HZ,
 BMP580_ODR_120HZ,
 BMP580_ODR_110HZ,
 BMP580_ODR_100HZ,
 BMP580_ODR_89HZ,
 BMP580_ODR_80HZ,
 BMP580_ODR_70HZ,
 BMP580_ODR_60HZ,
 BMP580_ODR_50HZ,
 BMP580_ODR_45HZ,
 BMP580_ODR_40HZ,
 BMP580_ODR_35HZ,
 BMP580_ODR_30HZ,
 BMP580_ODR_25HZ,
 BMP580_ODR_20HZ,
 BMP580_ODR_15HZ,
 BMP580_ODR_10HZ,
 BMP580_ODR_5HZ,
 BMP580_ODR_4HZ,
 BMP580_ODR_3HZ,
 BMP580_ODR_2HZ,
 BMP580_ODR_1HZ,
 BMP580_ODR_0_5HZ,
 BMP580_ODR_0_25HZ,
 BMP580_ODR_0_125HZ,
};

/*
 * These enums are used for indexing into the array of compensation
 * parameters for BMP280.
 */

enum { T1, T2, T3, P1, P2, P3, P4, P5, P6, P7, P8, P9 };

enum {
 /* Temperature calib indexes */
 BMP380_T1 = 0,
 BMP380_T2 = 2,
 BMP380_T3 = 4,
 /* Pressure calib indexes */
 BMP380_P1 = 5,
 BMP380_P2 = 7,
 BMP380_P3 = 9,
 BMP380_P4 = 10,
 BMP380_P5 = 11,
 BMP380_P6 = 13,
 BMP380_P7 = 15,
 BMP380_P8 = 16,
 BMP380_P9 = 17,
 BMP380_P10 = 19,
 BMP380_P11 = 20,
};

enum bmp280_scan {
 BMP280_PRESS,
 BMP280_TEMP,
 BME280_HUMID,
};

static const struct iio_chan_spec bmp280_channels[] = {
 {
  .type = IIO_PRESSURE,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .scan_index = 0,
  .scan_type = {
   .sign = 'u',
   .realbits = 32,
   .storagebits = 32,
   .endianness = IIO_CPU,
  },
 },
 {
  .type = IIO_TEMP,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .scan_index = 1,
  .scan_type = {
   .sign = 's',
   .realbits = 32,
   .storagebits = 32,
   .endianness = IIO_CPU,
  },
 },
 IIO_CHAN_SOFT_TIMESTAMP(2),
};

static const struct iio_chan_spec bme280_channels[] = {
 {
  .type = IIO_PRESSURE,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .scan_index = 0,
  .scan_type = {
   .sign = 'u',
   .realbits = 32,
   .storagebits = 32,
   .endianness = IIO_CPU,
  },
 },
 {
  .type = IIO_TEMP,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .scan_index = 1,
  .scan_type = {
   .sign = 's',
   .realbits = 32,
   .storagebits = 32,
   .endianness = IIO_CPU,
  },
 },
 {
  .type = IIO_HUMIDITYRELATIVE,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .scan_index = 2,
  .scan_type = {
   .sign = 'u',
   .realbits = 32,
   .storagebits = 32,
   .endianness = IIO_CPU,
  },
 },
 IIO_CHAN_SOFT_TIMESTAMP(3),
};

static const struct iio_chan_spec bmp380_channels[] = {
 {
  .type = IIO_PRESSURE,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
        BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
  .scan_index = 0,
  .scan_type = {
   .sign = 'u',
   .realbits = 32,
   .storagebits = 32,
   .endianness = IIO_CPU,
  },
 },
 {
  .type = IIO_TEMP,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
        BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
  .scan_index = 1,
  .scan_type = {
   .sign = 's',
   .realbits = 32,
   .storagebits = 32,
   .endianness = IIO_CPU,
  },
 },
 IIO_CHAN_SOFT_TIMESTAMP(2),
};

static const struct iio_chan_spec bmp580_channels[] = {
 {
  .type = IIO_PRESSURE,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
        BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
  .scan_index = 0,
  .scan_type = {
   .sign = 'u',
   .realbits = 24,
   .storagebits = 32,
   .endianness = IIO_LE,
  },
 },
 {
  .type = IIO_TEMP,
  /* PROCESSED maintained for ABI backwards compatibility */
  .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
          BIT(IIO_CHAN_INFO_RAW) |
          BIT(IIO_CHAN_INFO_SCALE) |
          BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
  .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
        BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
  .scan_index = 1,
  .scan_type = {
   .sign = 's',
   .realbits = 24,
   .storagebits = 32,
   .endianness = IIO_LE,
  },
 },
 IIO_CHAN_SOFT_TIMESTAMP(2),
};

static int bmp280_read_calib(struct bmp280_data *data)
{
 struct bmp280_calib *calib = &data->calib.bmp280;
 int ret;

 /* Read temperature and pressure calibration values. */
 ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
          data->bmp280_cal_buf,
          sizeof(data->bmp280_cal_buf));
 if (ret) {
  dev_err(data->dev,
   "failed to read calibration parameters\n");
  return ret;
 }

 /* Toss calibration data into the entropy pool */
 add_device_randomness(data->bmp280_cal_buf,
         sizeof(data->bmp280_cal_buf));

 /* Parse temperature calibration values. */
 calib->T1 = le16_to_cpu(data->bmp280_cal_buf[T1]);
 calib->T2 = le16_to_cpu(data->bmp280_cal_buf[T2]);
 calib->T3 = le16_to_cpu(data->bmp280_cal_buf[T3]);

 /* Parse pressure calibration values. */
 calib->P1 = le16_to_cpu(data->bmp280_cal_buf[P1]);
 calib->P2 = le16_to_cpu(data->bmp280_cal_buf[P2]);
 calib->P3 = le16_to_cpu(data->bmp280_cal_buf[P3]);
 calib->P4 = le16_to_cpu(data->bmp280_cal_buf[P4]);
 calib->P5 = le16_to_cpu(data->bmp280_cal_buf[P5]);
 calib->P6 = le16_to_cpu(data->bmp280_cal_buf[P6]);
 calib->P7 = le16_to_cpu(data->bmp280_cal_buf[P7]);
 calib->P8 = le16_to_cpu(data->bmp280_cal_buf[P8]);
 calib->P9 = le16_to_cpu(data->bmp280_cal_buf[P9]);

 return 0;
}

/*
 * These enums are used for indexing into the array of humidity parameters
 * for BME280. Due to some weird indexing, unaligned BE/LE accesses co-exist in
 * order to prepare the FIELD_{GET/PREP}() fields. Table 16 in Section 4.2.2 of
 * the datasheet.
 */

enum { H2 = 0, H3 = 2, H4 = 3, H5 = 4, H6 = 6 };

static int bme280_read_calib(struct bmp280_data *data)
{
 struct bmp280_calib *calib = &data->calib.bmp280;
 struct device *dev = data->dev;
 s16 h4_upper, h4_lower, tmp_1, tmp_2, tmp_3;
 unsigned int tmp;
 int ret;

 /* Load shared calibration params with bmp280 first */
 ret = bmp280_read_calib(data);
 if (ret)
  return ret;

 ret = regmap_read(data->regmap, BME280_REG_COMP_H1, &tmp);
 if (ret) {
  dev_err(dev, "failed to read H1 comp value\n");
  return ret;
 }
 calib->H1 = tmp;

 ret = regmap_bulk_read(data->regmap, BME280_REG_COMP_H2,
          data->bme280_humid_cal_buf,
          sizeof(data->bme280_humid_cal_buf));
 if (ret) {
  dev_err(dev, "failed to read humidity calibration values\n");
  return ret;
 }

 calib->H2 = get_unaligned_le16(&data->bme280_humid_cal_buf[H2]);
 calib->H3 = data->bme280_humid_cal_buf[H3];
 tmp_1 = get_unaligned_be16(&data->bme280_humid_cal_buf[H4]);
 tmp_2 = FIELD_GET(BME280_COMP_H4_GET_MASK_UP, tmp_1);
 h4_upper = FIELD_PREP(BME280_COMP_H4_PREP_MASK_UP, tmp_2);
 h4_lower = FIELD_GET(BME280_COMP_H4_MASK_LOW, tmp_1);
 calib->H4 = sign_extend32(h4_upper | h4_lower, 11);
 tmp_3 = get_unaligned_le16(&data->bme280_humid_cal_buf[H5]);
 calib->H5 = sign_extend32(FIELD_GET(BME280_COMP_H5_MASK, tmp_3), 11);
 calib->H6 = data->bme280_humid_cal_buf[H6];

 return 0;
}

static int bme280_read_humid_adc(struct bmp280_data *data, u16 *adc_humidity)
{
 u16 value_humidity;
 int ret;

 ret = regmap_bulk_read(data->regmap, BME280_REG_HUMIDITY_MSB,
          &data->be16, BME280_NUM_HUMIDITY_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to read humidity\n");
  return ret;
 }

 value_humidity = be16_to_cpu(data->be16);
 if (value_humidity == BMP280_HUMIDITY_SKIPPED) {
  dev_err(data->dev, "reading humidity skipped\n");
  return -EIO;
 }
 *adc_humidity = value_humidity;

 return 0;
}

/*
 * Returns humidity in percent, resolution is 0.01 percent. Output value of
 * "47445" represents 47445/1024 = 46.333 %RH.
 *
 * Taken from BME280 datasheet, Section 4.2.3, "Compensation formula".
 */

static u32 bme280_compensate_humidity(struct bmp280_data *data,
          u16 adc_humidity, s32 t_fine)
{
 struct bmp280_calib *calib = &data->calib.bmp280;
 s32 var;

 var = t_fine - (s32)76800;
 var = (((((s32)adc_humidity << 14) - (calib->H4 << 20) - (calib->H5 * var))
  + (s32)16384) >> 15) * (((((((var * calib->H6) >> 10)
  * (((var * (s32)calib->H3) >> 11) + (s32)32768)) >> 10)
  + (s32)2097152) * calib->H2 + 8192) >> 14);
 var -= ((((var >> 15) * (var >> 15)) >> 7) * (s32)calib->H1) >> 4;

 var = clamp_val(var, 0, 419430400);

 return var >> 12;
}

static int bmp280_read_temp_adc(struct bmp280_data *data, u32 *adc_temp)
{
 u32 value_temp;
 int ret;

 ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
          data->buf, BMP280_NUM_TEMP_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to read temperature\n");
  return ret;
 }

 value_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf));
 if (value_temp == BMP280_TEMP_SKIPPED) {
  dev_err(data->dev, "reading temperature skipped\n");
  return -EIO;
 }
 *adc_temp = value_temp;

 return 0;
}

/*
 * Returns temperature in DegC, resolution is 0.01 DegC.  Output value of
 * "5123" equals 51.23 DegC.  t_fine carries fine temperature as global
 * value.
 *
 * Taken from datasheet, Section 3.11.3, "Compensation formula".
 */

static s32 bmp280_calc_t_fine(struct bmp280_data *data, u32 adc_temp)
{
 struct bmp280_calib *calib = &data->calib.bmp280;
 s32 var1, var2;

 var1 = (((((s32)adc_temp) >> 3) - ((s32)calib->T1 << 1)) *
  ((s32)calib->T2)) >> 11;
 var2 = (((((((s32)adc_temp) >> 4) - ((s32)calib->T1)) *
    ((((s32)adc_temp >> 4) - ((s32)calib->T1))) >> 12) *
  ((s32)calib->T3))) >> 14;
 return var1 + var2; /* t_fine = var1 + var2 */
}

static int bmp280_get_t_fine(struct bmp280_data *data, s32 *t_fine)
{
 u32 adc_temp;
 int ret;

 ret = bmp280_read_temp_adc(data, &adc_temp);
 if (ret)
  return ret;

 *t_fine = bmp280_calc_t_fine(data, adc_temp);

 return 0;
}

static s32 bmp280_compensate_temp(struct bmp280_data *data, u32 adc_temp)
{
 return (bmp280_calc_t_fine(data, adc_temp) * 5 + 128) / 256;
}

static int bmp280_read_press_adc(struct bmp280_data *data, u32 *adc_press)
{
 u32 value_press;
 int ret;

 ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
          data->buf, BMP280_NUM_PRESS_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to read pressure\n");
  return ret;
 }

 value_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf));
 if (value_press == BMP280_PRESS_SKIPPED) {
  dev_err(data->dev, "reading pressure skipped\n");
  return -EIO;
 }
 *adc_press = value_press;

 return 0;
}

/*
 * Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24
 * integer bits and 8 fractional bits).  Output value of "24674867"
 * represents 24674867/256 = 96386.2 Pa = 963.862 hPa
 *
 * Taken from datasheet, Section 3.11.3, "Compensation formula".
 */

static u32 bmp280_compensate_press(struct bmp280_data *data,
       u32 adc_press, s32 t_fine)
{
 struct bmp280_calib *calib = &data->calib.bmp280;
 s64 var1, var2, p;

 var1 = ((s64)t_fine) - 128000;
 var2 = var1 * var1 * (s64)calib->P6;
 var2 += (var1 * (s64)calib->P5) << 17;
 var2 += ((s64)calib->P4) << 35;
 var1 = ((var1 * var1 * (s64)calib->P3) >> 8) +
  ((var1 * (s64)calib->P2) << 12);
 var1 = ((((s64)1) << 47) + var1) * ((s64)calib->P1) >> 33;

 if (var1 == 0)
  return 0;

 p = ((((s64)1048576 - (s32)adc_press) << 31) - var2) * 3125;
 p = div64_s64(p, var1);
 var1 = (((s64)calib->P9) * (p >> 13) * (p >> 13)) >> 25;
 var2 = ((s64)(calib->P8) * p) >> 19;
 p = ((p + var1 + var2) >> 8) + (((s64)calib->P7) << 4);

 return (u32)p;
}

static int bmp280_read_temp(struct bmp280_data *data, s32 *comp_temp)
{
 u32 adc_temp;
 int ret;

 ret = bmp280_read_temp_adc(data, &adc_temp);
 if (ret)
  return ret;

 *comp_temp = bmp280_compensate_temp(data, adc_temp);

 return 0;
}

static int bmp280_read_press(struct bmp280_data *data, u32 *comp_press)
{
 u32 adc_press;
 s32 t_fine;
 int ret;

 ret = bmp280_get_t_fine(data, &t_fine);
 if (ret)
  return ret;

 ret = bmp280_read_press_adc(data, &adc_press);
 if (ret)
  return ret;

 *comp_press = bmp280_compensate_press(data, adc_press, t_fine);

 return 0;
}

static int bme280_read_humid(struct bmp280_data *data, u32 *comp_humidity)
{
 u16 adc_humidity;
 s32 t_fine;
 int ret;

 ret = bmp280_get_t_fine(data, &t_fine);
 if (ret)
  return ret;

 ret = bme280_read_humid_adc(data, &adc_humidity);
 if (ret)
  return ret;

 *comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine);

 return 0;
}

static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
    struct iio_chan_spec const *chan,
    int *val, int *val2, long mask)
{
 struct bmp280_data *data = iio_priv(indio_dev);
 int chan_value;
 int ret;

 guard(mutex)(&data->lock);

 switch (mask) {
 case IIO_CHAN_INFO_PROCESSED:
  ret = data->chip_info->set_mode(data, BMP280_FORCED);
  if (ret)
   return ret;

  ret = data->chip_info->wait_conv(data);
  if (ret)
   return ret;

  switch (chan->type) {
  case IIO_HUMIDITYRELATIVE:
   ret = data->chip_info->read_humid(data, &chan_value);
   if (ret)
    return ret;

   *val = data->chip_info->humid_coeffs[0] * chan_value;
   *val2 = data->chip_info->humid_coeffs[1];
   return data->chip_info->humid_coeffs_type;
  case IIO_PRESSURE:
   ret = data->chip_info->read_press(data, &chan_value);
   if (ret)
    return ret;

   *val = data->chip_info->press_coeffs[0] * chan_value;
   *val2 = data->chip_info->press_coeffs[1];
   return data->chip_info->press_coeffs_type;
  case IIO_TEMP:
   ret = data->chip_info->read_temp(data, &chan_value);
   if (ret)
    return ret;

   *val = data->chip_info->temp_coeffs[0] * chan_value;
   *val2 = data->chip_info->temp_coeffs[1];
   return data->chip_info->temp_coeffs_type;
  default:
   return -EINVAL;
  }
 case IIO_CHAN_INFO_RAW:
  ret = data->chip_info->set_mode(data, BMP280_FORCED);
  if (ret)
   return ret;

  ret = data->chip_info->wait_conv(data);
  if (ret)
   return ret;

  switch (chan->type) {
  case IIO_HUMIDITYRELATIVE:
   ret = data->chip_info->read_humid(data, &chan_value);
   if (ret)
    return ret;

   *val = chan_value;
   return IIO_VAL_INT;
  case IIO_PRESSURE:
   ret = data->chip_info->read_press(data, &chan_value);
   if (ret)
    return ret;

   *val = chan_value;
   return IIO_VAL_INT;
  case IIO_TEMP:
   ret = data->chip_info->read_temp(data, &chan_value);
   if (ret)
    return ret;

   *val = chan_value;
   return IIO_VAL_INT;
  default:
   return -EINVAL;
  }
 case IIO_CHAN_INFO_SCALE:
  switch (chan->type) {
  case IIO_HUMIDITYRELATIVE:
   *val = data->chip_info->humid_coeffs[0];
   *val2 = data->chip_info->humid_coeffs[1];
   return data->chip_info->humid_coeffs_type;
  case IIO_PRESSURE:
   *val = data->chip_info->press_coeffs[0];
   *val2 = data->chip_info->press_coeffs[1];
   return data->chip_info->press_coeffs_type;
  case IIO_TEMP:
   *val = data->chip_info->temp_coeffs[0];
   *val2 = data->chip_info->temp_coeffs[1];
   return data->chip_info->temp_coeffs_type;
  default:
   return -EINVAL;
  }
 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
  switch (chan->type) {
  case IIO_HUMIDITYRELATIVE:
   *val = 1 << data->oversampling_humid;
   return IIO_VAL_INT;
  case IIO_PRESSURE:
   *val = 1 << data->oversampling_press;
   return IIO_VAL_INT;
  case IIO_TEMP:
   *val = 1 << data->oversampling_temp;
   return IIO_VAL_INT;
  default:
   return -EINVAL;
  }
 case IIO_CHAN_INFO_SAMP_FREQ:
  if (!data->chip_info->sampling_freq_avail)
   return -EINVAL;

  *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
  *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
  return IIO_VAL_INT_PLUS_MICRO;
 case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
  if (!data->chip_info->iir_filter_coeffs_avail)
   return -EINVAL;

  *val = (1 << data->iir_filter_coeff) - 1;
  return IIO_VAL_INT;
 default:
  return -EINVAL;
 }
}

static int bmp280_read_raw(struct iio_dev *indio_dev,
      struct iio_chan_spec const *chan,
      int *val, int *val2, long mask)
{
 struct bmp280_data *data = iio_priv(indio_dev);
 int ret;

 pm_runtime_get_sync(data->dev);
 ret = bmp280_read_raw_impl(indio_dev, chan, val, val2, mask);
 pm_runtime_mark_last_busy(data->dev);
 pm_runtime_put_autosuspend(data->dev);

 return ret;
}

static int bme280_write_oversampling_ratio_humid(struct bmp280_data *data,
       int val)
{
 const int *avail = data->chip_info->oversampling_humid_avail;
 const int n = data->chip_info->num_oversampling_humid_avail;
 int ret, prev;
 int i;

 for (i = 0; i < n; i++) {
  if (avail[i] == val) {
   prev = data->oversampling_humid;
   data->oversampling_humid = ilog2(val);

   ret = data->chip_info->chip_config(data);
   if (ret) {
    data->oversampling_humid = prev;
    data->chip_info->chip_config(data);
    return ret;
   }
   return 0;
  }
 }
 return -EINVAL;
}

static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data,
      int val)
{
 const int *avail = data->chip_info->oversampling_temp_avail;
 const int n = data->chip_info->num_oversampling_temp_avail;
 int ret, prev;
 int i;

 for (i = 0; i < n; i++) {
  if (avail[i] == val) {
   prev = data->oversampling_temp;
   data->oversampling_temp = ilog2(val);

   ret = data->chip_info->chip_config(data);
   if (ret) {
    data->oversampling_temp = prev;
    data->chip_info->chip_config(data);
    return ret;
   }
   return 0;
  }
 }
 return -EINVAL;
}

static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data,
       int val)
{
 const int *avail = data->chip_info->oversampling_press_avail;
 const int n = data->chip_info->num_oversampling_press_avail;
 int ret, prev;
 int i;

 for (i = 0; i < n; i++) {
  if (avail[i] == val) {
   prev = data->oversampling_press;
   data->oversampling_press = ilog2(val);

   ret = data->chip_info->chip_config(data);
   if (ret) {
    data->oversampling_press = prev;
    data->chip_info->chip_config(data);
    return ret;
   }
   return 0;
  }
 }
 return -EINVAL;
}

static int bmp280_write_sampling_frequency(struct bmp280_data *data,
        int val, int val2)
{
 const int (*avail)[2] = data->chip_info->sampling_freq_avail;
 const int n = data->chip_info->num_sampling_freq_avail;
 int ret, prev;
 int i;

 for (i = 0; i < n; i++) {
  if (avail[i][0] == val && avail[i][1] == val2) {
   prev = data->sampling_freq;
   data->sampling_freq = i;

   ret = data->chip_info->chip_config(data);
   if (ret) {
    data->sampling_freq = prev;
    data->chip_info->chip_config(data);
    return ret;
   }
   return 0;
  }
 }
 return -EINVAL;
}

static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val)
{
 const int *avail = data->chip_info->iir_filter_coeffs_avail;
 const int n = data->chip_info->num_iir_filter_coeffs_avail;
 int ret, prev;
 int i;

 for (i = 0; i < n; i++) {
  if (avail[i] - 1  == val) {
   prev = data->iir_filter_coeff;
   data->iir_filter_coeff = i;

   ret = data->chip_info->chip_config(data);
   if (ret) {
    data->iir_filter_coeff = prev;
    data->chip_info->chip_config(data);
    return ret;

   }
   return 0;
  }
 }
 return -EINVAL;
}

static int bmp280_write_raw_impl(struct iio_dev *indio_dev,
     struct iio_chan_spec const *chan,
     int val, int val2, long mask)
{
 struct bmp280_data *data = iio_priv(indio_dev);

 guard(mutex)(&data->lock);

 /*
 * Helper functions to update sensor running configuration.
 * If an error happens applying new settings, will try restore
 * previous parameters to ensure the sensor is left in a known
 * working configuration.
 */

 switch (mask) {
 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
  switch (chan->type) {
  case IIO_HUMIDITYRELATIVE:
   return bme280_write_oversampling_ratio_humid(data, val);
  case IIO_PRESSURE:
   return bmp280_write_oversampling_ratio_press(data, val);
  case IIO_TEMP:
   return bmp280_write_oversampling_ratio_temp(data, val);
  default:
   return -EINVAL;
  }
 case IIO_CHAN_INFO_SAMP_FREQ:
  return bmp280_write_sampling_frequency(data, val, val2);
 case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
  return bmp280_write_iir_filter_coeffs(data, val);
 default:
  return -EINVAL;
 }
}

static int bmp280_write_raw(struct iio_dev *indio_dev,
       struct iio_chan_spec const *chan,
       int val, int val2, long mask)
{
 struct bmp280_data *data = iio_priv(indio_dev);
 int ret;

 pm_runtime_get_sync(data->dev);
 ret = bmp280_write_raw_impl(indio_dev, chan, val, val2, mask);
 pm_runtime_mark_last_busy(data->dev);
 pm_runtime_put_autosuspend(data->dev);

 return ret;
}

static int bmp280_read_avail(struct iio_dev *indio_dev,
        struct iio_chan_spec const *chan,
        const int **vals, int *type, int *length,
        long mask)
{
 struct bmp280_data *data = iio_priv(indio_dev);

 switch (mask) {
 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
  switch (chan->type) {
  case IIO_PRESSURE:
   *vals = data->chip_info->oversampling_press_avail;
   *length = data->chip_info->num_oversampling_press_avail;
   break;
  case IIO_TEMP:
   *vals = data->chip_info->oversampling_temp_avail;
   *length = data->chip_info->num_oversampling_temp_avail;
   break;
  default:
   return -EINVAL;
  }
  *type = IIO_VAL_INT;
  return IIO_AVAIL_LIST;
 case IIO_CHAN_INFO_SAMP_FREQ:
  *vals = (const int *)data->chip_info->sampling_freq_avail;
  *type = IIO_VAL_INT_PLUS_MICRO;
  /* Values are stored in a 2D matrix */
  *length = data->chip_info->num_sampling_freq_avail;
  return IIO_AVAIL_LIST;
 case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
  *vals = data->chip_info->iir_filter_coeffs_avail;
  *type = IIO_VAL_INT;
  *length = data->chip_info->num_iir_filter_coeffs_avail;
  return IIO_AVAIL_LIST;
 default:
  return -EINVAL;
 }
}

static const struct iio_info bmp280_info = {
 .read_raw = &bmp280_read_raw,
 .read_avail = &bmp280_read_avail,
 .write_raw = &bmp280_write_raw,
};

static const unsigned long bmp280_avail_scan_masks[] = {
 BIT(BMP280_TEMP) | BIT(BMP280_PRESS),
 0
};

static const unsigned long bme280_avail_scan_masks[] = {
 BIT(BME280_HUMID) | BIT(BMP280_TEMP) | BIT(BMP280_PRESS),
 0
};

static int bmp280_preinit(struct bmp280_data *data)
{
 struct device *dev = data->dev;
 unsigned int reg;
 int ret;

 ret = regmap_write(data->regmap, BMP280_REG_RESET, BMP280_RST_SOFT_CMD);
 if (ret)
  return dev_err_probe(dev, ret, "Failed to reset device.\n");

 /*
 * According to the datasheet in Chapter 1: Specification, Table 2,
 * after resetting, the device uses the complete power-on sequence so
 * it needs to wait for the defined start-up time.
 */

 fsleep(data->start_up_time_us);

 ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
 if (ret)
  return dev_err_probe(dev, ret, "Failed to read status register.\n");

 if (reg & BMP280_REG_STATUS_IM_UPDATE)
  return dev_err_probe(dev, -EIO, "Failed to copy NVM contents.\n");

 return 0;
}

static const u8 bmp280_operation_mode[] = {
 [BMP280_SLEEP] = BMP280_MODE_SLEEP,
 [BMP280_FORCED] = BMP280_MODE_FORCED,
 [BMP280_NORMAL] = BMP280_MODE_NORMAL,
};

static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
{
 int ret;

 ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
    BMP280_MODE_MASK, bmp280_operation_mode[mode]);
 if (ret) {
  dev_err(data->dev, "failed to write ctrl_meas register.\n");
  return ret;
 }

 data->op_mode = mode;

 return 0;
}

static int bmp280_wait_conv(struct bmp280_data *data)
{
 unsigned int reg, meas_time_us;
 int ret;

 /* Check if we are using a BME280 device */
 if (data->oversampling_humid)
  meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
    BIT(data->oversampling_humid) * BMP280_MEAS_DUR;

 else
  meas_time_us = 0;

 /* Pressure measurement time */
 meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
   BIT(data->oversampling_press) * BMP280_MEAS_DUR;

 /* Temperature measurement time */
 meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;

 /* Waiting time according to the BM(P/E)2 Sensor API */
 fsleep(meas_time_us);

 ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
 if (ret) {
  dev_err(data->dev, "failed to read status register.\n");
  return ret;
 }

 if (reg & BMP280_REG_STATUS_MEAS_BIT) {
  dev_err(data->dev, "Measurement cycle didn't complete.\n");
  return -EBUSY;
 }

 return 0;
}

static int bmp280_chip_config(struct bmp280_data *data)
{
 u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
    FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
 int ret;

 ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
    BMP280_OSRS_TEMP_MASK |
    BMP280_OSRS_PRESS_MASK |
    BMP280_MODE_MASK,
    osrs | BMP280_MODE_SLEEP);
 if (ret) {
  dev_err(data->dev, "failed to write ctrl_meas register\n");
  return ret;
 }

 ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
     BMP280_FILTER_MASK,
     BMP280_FILTER_4X);
 if (ret) {
  dev_err(data->dev, "failed to write config register\n");
  return ret;
 }

 return ret;
}

static irqreturn_t bmp280_trigger_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);
 u32 adc_temp, adc_press;
 s32 t_fine;
 struct {
  u32 comp_press;
  s32 comp_temp;
  aligned_s64 timestamp;
 } buffer;
 int ret;

 guard(mutex)(&data->lock);

 /* Burst read data registers */
 ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
          data->buf, BMP280_BURST_READ_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to burst read sensor data\n");
  goto out;
 }

 /* Temperature calculations */
 adc_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[3]));
 if (adc_temp == BMP280_TEMP_SKIPPED) {
  dev_err(data->dev, "reading temperature skipped\n");
  goto out;
 }

 buffer.comp_temp = bmp280_compensate_temp(data, adc_temp);

 /* Pressure calculations */
 adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0]));
 if (adc_press == BMP280_PRESS_SKIPPED) {
  dev_err(data->dev, "reading pressure skipped\n");
  goto out;
 }

 t_fine = bmp280_calc_t_fine(data, adc_temp);
 buffer.comp_press = bmp280_compensate_press(data, adc_press, t_fine);

 iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
        iio_get_time_ns(indio_dev));

out:
 iio_trigger_notify_done(indio_dev->trig);

 return IRQ_HANDLED;
}

static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static const u8 bmp280_chip_ids[] = { BMP280_CHIP_ID };
static const int bmp280_temp_coeffs[] = { 10, 1 };
static const int bmp280_press_coeffs[] = { 1, 256000 };

const struct bmp280_chip_info bmp280_chip_info = {
 .id_reg = BMP280_REG_ID,
 .chip_id = bmp280_chip_ids,
 .num_chip_id = ARRAY_SIZE(bmp280_chip_ids),
 .regmap_config = &bmp280_regmap_config,
 .start_up_time_us = 2000,
 .channels = bmp280_channels,
 .num_channels = ARRAY_SIZE(bmp280_channels),
 .avail_scan_masks = bmp280_avail_scan_masks,

 .oversampling_temp_avail = bmp280_oversampling_avail,
 .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail),
 /*
 * Oversampling config values on BMx280 have one additional setting
 * that other generations of the family don't:
 * The value 0 means the measurement is bypassed instead of
 * oversampling set to x1.
 *
 * To account for this difference, and preserve the same common
 * config logic, this is handled later on chip_config callback
 * incrementing one unit the oversampling setting.
 */

 .oversampling_temp_default = BMP280_OSRS_TEMP_2X - 1,

 .oversampling_press_avail = bmp280_oversampling_avail,
 .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
 .oversampling_press_default = BMP280_OSRS_PRESS_16X - 1,

 .temp_coeffs = bmp280_temp_coeffs,
 .temp_coeffs_type = IIO_VAL_FRACTIONAL,
 .press_coeffs = bmp280_press_coeffs,
 .press_coeffs_type = IIO_VAL_FRACTIONAL,

 .chip_config = bmp280_chip_config,
 .read_temp = bmp280_read_temp,
 .read_press = bmp280_read_press,
 .read_calib = bmp280_read_calib,
 .set_mode = bmp280_set_mode,
 .wait_conv = bmp280_wait_conv,
 .preinit = bmp280_preinit,

 .trigger_handler = bmp280_trigger_handler,
};
EXPORT_SYMBOL_NS(bmp280_chip_info, "IIO_BMP280");

static int bme280_chip_config(struct bmp280_data *data)
{
 u8 osrs = FIELD_PREP(BME280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1);
 int ret;

 /*
 * Oversampling of humidity must be set before oversampling of
 * temperature/pressure is set to become effective.
 */

 ret = regmap_update_bits(data->regmap, BME280_REG_CTRL_HUMIDITY,
     BME280_OSRS_HUMIDITY_MASK, osrs);
 if (ret) {
  dev_err(data->dev, "failed to set humidity oversampling");
  return ret;
 }

 return bmp280_chip_config(data);
}

static irqreturn_t bme280_trigger_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);
 u32 adc_temp, adc_press, adc_humidity;
 s32 t_fine;
 struct {
  u32 comp_press;
  s32 comp_temp;
  u32 comp_humidity;
  aligned_s64 timestamp;
 } buffer = { }; /* Don't leak uninitialized stack to userspace. */
 int ret;

 guard(mutex)(&data->lock);

 /* Burst read data registers */
 ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
          data->buf, BME280_BURST_READ_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to burst read sensor data\n");
  goto out;
 }

 /* Temperature calculations */
 adc_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[3]));
 if (adc_temp == BMP280_TEMP_SKIPPED) {
  dev_err(data->dev, "reading temperature skipped\n");
  goto out;
 }

 buffer.comp_temp = bmp280_compensate_temp(data, adc_temp);

 /* Pressure calculations */
 adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(&data->buf[0]));
 if (adc_press == BMP280_PRESS_SKIPPED) {
  dev_err(data->dev, "reading pressure skipped\n");
  goto out;
 }

 t_fine = bmp280_calc_t_fine(data, adc_temp);
 buffer.comp_press = bmp280_compensate_press(data, adc_press, t_fine);

 /* Humidity calculations */
 adc_humidity = get_unaligned_be16(&data->buf[6]);

 if (adc_humidity == BMP280_HUMIDITY_SKIPPED) {
  dev_err(data->dev, "reading humidity skipped\n");
  goto out;
 }

 buffer.comp_humidity = bme280_compensate_humidity(data, adc_humidity,
         t_fine);

 iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
        iio_get_time_ns(indio_dev));

out:
 iio_trigger_notify_done(indio_dev->trig);

 return IRQ_HANDLED;
}

static int __bmp280_trigger_probe(struct iio_dev *indio_dev,
      const struct iio_trigger_ops *trigger_ops,
      int (*int_pin_config)(struct bmp280_data *data),
      irq_handler_t irq_thread_handler)
{
 struct bmp280_data *data = iio_priv(indio_dev);
 struct device *dev = data->dev;
 u32 irq_type;
 int ret, irq;

 irq = fwnode_irq_get(dev_fwnode(dev), 0);
 if (irq < 0)
  return dev_err_probe(dev, irq, "No interrupt found.\n");

 irq_type = irq_get_trigger_type(irq);
 switch (irq_type) {
 case IRQF_TRIGGER_RISING:
  data->trig_active_high = true;
  break;
 case IRQF_TRIGGER_FALLING:
  data->trig_active_high = false;
  break;
 default:
  return dev_err_probe(dev, -EINVAL, "Invalid interrupt type specified.\n");
 }

 data->trig_open_drain =
  fwnode_property_read_bool(dev_fwnode(dev), "int-open-drain");

 ret = int_pin_config(data);
 if (ret)
  return ret;

 data->trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d",
         indio_dev->name,
         iio_device_id(indio_dev));
 if (!data->trig)
  return -ENOMEM;

 data->trig->ops = trigger_ops;
 iio_trigger_set_drvdata(data->trig, data);

 ret = devm_request_threaded_irq(data->dev, irq, NULL,
     irq_thread_handler, IRQF_ONESHOT,
     indio_dev->name, indio_dev);
 if (ret)
  return dev_err_probe(dev, ret, "request IRQ failed.\n");

 ret = devm_iio_trigger_register(data->dev, data->trig);
 if (ret)
  return dev_err_probe(dev, ret, "iio trigger register failed.\n");

 indio_dev->trig = iio_trigger_get(data->trig);

 return 0;
}

static const u8 bme280_chip_ids[] = { BME280_CHIP_ID };
static const int bme280_humid_coeffs[] = { 1000, 1024 };

const struct bmp280_chip_info bme280_chip_info = {
 .id_reg = BMP280_REG_ID,
 .chip_id = bme280_chip_ids,
 .num_chip_id = ARRAY_SIZE(bme280_chip_ids),
 .regmap_config = &bme280_regmap_config,
 .start_up_time_us = 2000,
 .channels = bme280_channels,
 .num_channels = ARRAY_SIZE(bme280_channels),
 .avail_scan_masks = bme280_avail_scan_masks,

 .oversampling_temp_avail = bmp280_oversampling_avail,
 .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail),
 .oversampling_temp_default = BMP280_OSRS_TEMP_2X - 1,

 .oversampling_press_avail = bmp280_oversampling_avail,
 .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
 .oversampling_press_default = BMP280_OSRS_PRESS_16X - 1,

 .oversampling_humid_avail = bmp280_oversampling_avail,
 .num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
 .oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1,

 .temp_coeffs = bmp280_temp_coeffs,
 .temp_coeffs_type = IIO_VAL_FRACTIONAL,
 .press_coeffs = bmp280_press_coeffs,
 .press_coeffs_type = IIO_VAL_FRACTIONAL,
 .humid_coeffs = bme280_humid_coeffs,
 .humid_coeffs_type = IIO_VAL_FRACTIONAL,

 .chip_config = bme280_chip_config,
 .read_temp = bmp280_read_temp,
 .read_press = bmp280_read_press,
 .read_humid = bme280_read_humid,
 .read_calib = bme280_read_calib,
 .set_mode = bmp280_set_mode,
 .wait_conv = bmp280_wait_conv,
 .preinit = bmp280_preinit,

 .trigger_handler = bme280_trigger_handler,
};
EXPORT_SYMBOL_NS(bme280_chip_info, "IIO_BMP280");

/*
 * Helper function to send a command to BMP3XX sensors.
 *
 * Sensor processes commands written to the CMD register and signals
 * execution result through "cmd_rdy" and "cmd_error" flags available on
 * STATUS and ERROR registers.
 */

static int bmp380_cmd(struct bmp280_data *data, u8 cmd)
{
 unsigned int reg;
 int ret;

 /* Check if device is ready to process a command */
 ret = regmap_read(data->regmap, BMP380_REG_STATUS, ®);
 if (ret) {
  dev_err(data->dev, "failed to read error register\n");
  return ret;
 }
 if (!(reg & BMP380_STATUS_CMD_RDY_MASK)) {
  dev_err(data->dev, "device is not ready to accept commands\n");
  return -EBUSY;
 }

 /* Send command to process */
 ret = regmap_write(data->regmap, BMP380_REG_CMD, cmd);
 if (ret) {
  dev_err(data->dev, "failed to send command to device\n");
  return ret;
 }
 /* Wait for 2ms for command to be processed */
 fsleep(data->start_up_time_us);
 /* Check for command processing error */
 ret = regmap_read(data->regmap, BMP380_REG_ERROR, ®);
 if (ret) {
  dev_err(data->dev, "error reading ERROR reg\n");
  return ret;
 }
 if (reg & BMP380_ERR_CMD_MASK) {
  dev_err(data->dev, "error processing command 0x%X\n", cmd);
  return -EINVAL;
 }

 return 0;
}

static int bmp380_read_temp_adc(struct bmp280_data *data, u32 *adc_temp)
{
 u32 value_temp;
 int ret;

 ret = regmap_bulk_read(data->regmap, BMP380_REG_TEMP_XLSB,
          data->buf, BMP280_NUM_TEMP_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to read temperature\n");
  return ret;
 }

 value_temp = get_unaligned_le24(data->buf);
 if (value_temp == BMP380_TEMP_SKIPPED) {
  dev_err(data->dev, "reading temperature skipped\n");
  return -EIO;
 }
 *adc_temp = value_temp;

 return 0;
}

/*
 * Returns temperature in Celsius degrees, resolution is 0.01º C. Output value
 * of "5123" equals 51.2º C. t_fine carries fine temperature as global value.
 *
 * Taken from datasheet, Section Appendix 9, "Compensation formula" and repo
 * https://github.com/BoschSensortec/BMP3-Sensor-API.
 */

static s32 bmp380_calc_t_fine(struct bmp280_data *data, u32 adc_temp)
{
 s64 var1, var2, var3, var4, var5, var6;
 struct bmp380_calib *calib = &data->calib.bmp380;

 var1 = ((s64) adc_temp) - (((s64) calib->T1) << 8);
 var2 = var1 * ((s64) calib->T2);
 var3 = var1 * var1;
 var4 = var3 * ((s64) calib->T3);
 var5 = (var2 << 18) + var4;
 var6 = var5 >> 32;
 return (s32)var6; /* t_fine = var6 */
}

static int bmp380_get_t_fine(struct bmp280_data *data, s32 *t_fine)
{
 s32 adc_temp;
 int ret;

 ret = bmp380_read_temp_adc(data, &adc_temp);
 if (ret)
  return ret;

 *t_fine = bmp380_calc_t_fine(data, adc_temp);

 return 0;
}

static int bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp)
{
 s64 comp_temp;
 s32 var6;

 var6 = bmp380_calc_t_fine(data, adc_temp);
 comp_temp = (var6 * 25) >> 14;

 comp_temp = clamp_val(comp_temp, BMP380_MIN_TEMP, BMP380_MAX_TEMP);
 return (s32) comp_temp;
}

static int bmp380_read_press_adc(struct bmp280_data *data, u32 *adc_press)
{
 u32 value_press;
 int ret;

 ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB,
          data->buf, BMP280_NUM_PRESS_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to read pressure\n");
  return ret;
 }

 value_press = get_unaligned_le24(data->buf);
 if (value_press == BMP380_PRESS_SKIPPED) {
  dev_err(data->dev, "reading pressure skipped\n");
  return -EIO;
 }
 *adc_press = value_press;

 return 0;
}

/*
 * Returns pressure in Pa as an unsigned 32 bit integer in fractional Pascal.
 * Output value of "9528709" represents 9528709/100 = 95287.09 Pa = 952.8709 hPa.
 *
 * Taken from datasheet, Section 9.3. "Pressure compensation" and repository
 * https://github.com/BoschSensortec/BMP3-Sensor-API.
 */

static u32 bmp380_compensate_press(struct bmp280_data *data,
       u32 adc_press, s32 t_fine)
{
 s64 var1, var2, var3, var4, var5, var6, offset, sensitivity;
 struct bmp380_calib *calib = &data->calib.bmp380;
 u32 comp_press;

 var1 = (s64)t_fine * (s64)t_fine;
 var2 = var1 >> 6;
 var3 = (var2 * ((s64)t_fine)) >> 8;
 var4 = ((s64)calib->P8 * var3) >> 5;
 var5 = ((s64)calib->P7 * var1) << 4;
 var6 = ((s64)calib->P6 * (s64)t_fine) << 22;
 offset = ((s64)calib->P5 << 47) + var4 + var5 + var6;
 var2 = ((s64)calib->P4 * var3) >> 5;
 var4 = ((s64)calib->P3 * var1) << 2;
 var5 = ((s64)calib->P2 - ((s64)1 << 14)) *
        ((s64)t_fine << 21);
 sensitivity = (((s64) calib->P1 - ((s64) 1 << 14)) << 46) +
   var2 + var4 + var5;
 var1 = (sensitivity >> 24) * (s64)adc_press;
 var2 = (s64)calib->P10 * (s64)t_fine;
 var3 = var2 + ((s64)calib->P9 << 16);
 var4 = (var3 * (s64)adc_press) >> 13;

 /*
 * Dividing by 10 followed by multiplying by 10 to avoid
 * possible overflow caused by (uncomp_data->pressure * partial_data4).
 */

 var5 = ((s64)adc_press * div_s64(var4, 10)) >> 9;
 var5 *= 10;
 var6 = (s64)adc_press * (s64)adc_press;
 var2 = ((s64)calib->P11 * var6) >> 16;
 var3 = (var2 * (s64)adc_press) >> 7;
 var4 = (offset >> 2) + var1 + var5 + var3;
 comp_press = ((u64)var4 * 25) >> 40;

 comp_press = clamp_val(comp_press, BMP380_MIN_PRES, BMP380_MAX_PRES);
 return comp_press;
}

static int bmp380_read_temp(struct bmp280_data *data, s32 *comp_temp)
{
 u32 adc_temp;
 int ret;

 ret = bmp380_read_temp_adc(data, &adc_temp);
 if (ret)
  return ret;

 *comp_temp = bmp380_compensate_temp(data, adc_temp);

 return 0;
}

static int bmp380_read_press(struct bmp280_data *data, u32 *comp_press)
{
 u32 adc_press, t_fine;
 int ret;

 ret = bmp380_get_t_fine(data, &t_fine);
 if (ret)
  return ret;

 ret = bmp380_read_press_adc(data, &adc_press);
 if (ret)
  return ret;

 *comp_press = bmp380_compensate_press(data, adc_press, t_fine);

 return 0;
}

static int bmp380_read_calib(struct bmp280_data *data)
{
 struct bmp380_calib *calib = &data->calib.bmp380;
 int ret;

 /* Read temperature and pressure calibration data */
 ret = regmap_bulk_read(data->regmap, BMP380_REG_CALIB_TEMP_START,
          data->bmp380_cal_buf,
          sizeof(data->bmp380_cal_buf));
 if (ret) {
  dev_err(data->dev,
   "failed to read calibration parameters\n");
  return ret;
 }

 /* Toss the temperature calibration data into the entropy pool */
 add_device_randomness(data->bmp380_cal_buf,
         sizeof(data->bmp380_cal_buf));

 /* Parse calibration values */
 calib->T1 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_T1]);
 calib->T2 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_T2]);
 calib->T3 = data->bmp380_cal_buf[BMP380_T3];
 calib->P1 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P1]);
 calib->P2 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P2]);
 calib->P3 = data->bmp380_cal_buf[BMP380_P3];
 calib->P4 = data->bmp380_cal_buf[BMP380_P4];
 calib->P5 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P5]);
 calib->P6 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P6]);
 calib->P7 = data->bmp380_cal_buf[BMP380_P7];
 calib->P8 = data->bmp380_cal_buf[BMP380_P8];
 calib->P9 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P9]);
 calib->P10 = data->bmp380_cal_buf[BMP380_P10];
 calib->P11 = data->bmp380_cal_buf[BMP380_P11];

 return 0;
}

static const int bmp380_odr_table[][2] = {
 [BMP380_ODR_200HZ] = {200, 0},
 [BMP380_ODR_100HZ] = {100, 0},
 [BMP380_ODR_50HZ] = {50, 0},
 [BMP380_ODR_25HZ] = {25, 0},
 [BMP380_ODR_12_5HZ] = {12, 500000},
 [BMP380_ODR_6_25HZ] = {6, 250000},
 [BMP380_ODR_3_125HZ] = {3, 125000},
 [BMP380_ODR_1_5625HZ] = {1, 562500},
 [BMP380_ODR_0_78HZ] = {0, 781250},
 [BMP380_ODR_0_39HZ] = {0, 390625},
 [BMP380_ODR_0_2HZ] = {0, 195313},
 [BMP380_ODR_0_1HZ] = {0, 97656},
 [BMP380_ODR_0_05HZ] = {0, 48828},
 [BMP380_ODR_0_02HZ] = {0, 24414},
 [BMP380_ODR_0_01HZ] = {0, 12207},
 [BMP380_ODR_0_006HZ] = {0, 6104},
 [BMP380_ODR_0_003HZ] = {0, 3052},
 [BMP380_ODR_0_0015HZ] = {0, 1526},
};

static int bmp380_preinit(struct bmp280_data *data)
{
 /* BMP3xx requires soft-reset as part of initialization */
 return bmp380_cmd(data, BMP380_CMD_SOFT_RESET);
}

static const u8 bmp380_operation_mode[] = {
 [BMP280_SLEEP] = BMP380_MODE_SLEEP,
 [BMP280_FORCED] = BMP380_MODE_FORCED,
 [BMP280_NORMAL] = BMP380_MODE_NORMAL,
};

static int bmp380_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
{
 int ret;

 ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL,
    BMP380_MODE_MASK,
    FIELD_PREP(BMP380_MODE_MASK,
        bmp380_operation_mode[mode]));
 if (ret) {
  dev_err(data->dev, "failed to write power control register.\n");
  return ret;
 }

 data->op_mode = mode;

 return 0;
}

static int bmp380_wait_conv(struct bmp280_data *data)
{
 unsigned int reg;
 int ret, meas_time_us;

 /* Offset measurement time */
 meas_time_us = BMP380_MEAS_OFFSET;

 /* Pressure measurement time */
 meas_time_us += BMP380_PRESS_MEAS_OFFSET +
       BIT(data->oversampling_press) * BMP380_MEAS_DUR;

 /* Temperature measurement time */
 meas_time_us += BMP380_TEMP_MEAS_OFFSET +
       BIT(data->oversampling_temp) * BMP380_MEAS_DUR;

 /* Measurement time defined in Datasheet Section 3.9.2 */
 fsleep(meas_time_us);

 ret = regmap_read(data->regmap, BMP380_REG_STATUS, ®);
 if (ret) {
  dev_err(data->dev, "failed to read status register.\n");
  return ret;
 }

 if (!((reg & BMP380_STATUS_DRDY_PRESS_MASK) &&
       (reg & BMP380_STATUS_DRDY_TEMP_MASK))) {
  dev_err(data->dev, "Measurement cycle didn't complete.\n");
  return -EBUSY;
 }

 return 0;
}

static int bmp380_chip_config(struct bmp280_data *data)
{
 bool change = false, aux;
 unsigned int tmp;
 u8 osrs;
 int ret;

 /* Configure power control register */
 ret = regmap_update_bits(data->regmap, BMP380_REG_POWER_CONTROL,
     BMP380_CTRL_SENSORS_MASK,
     BMP380_CTRL_SENSORS_PRESS_EN |
     BMP380_CTRL_SENSORS_TEMP_EN);
 if (ret) {
  dev_err(data->dev,
   "failed to write operation control register\n");
  return ret;
 }

 /* Configure oversampling */
 osrs = FIELD_PREP(BMP380_OSRS_TEMP_MASK, data->oversampling_temp) |
        FIELD_PREP(BMP380_OSRS_PRESS_MASK, data->oversampling_press);

 ret = regmap_update_bits_check(data->regmap, BMP380_REG_OSR,
           BMP380_OSRS_TEMP_MASK |
           BMP380_OSRS_PRESS_MASK,
           osrs, &aux);
 if (ret) {
  dev_err(data->dev, "failed to write oversampling register\n");
  return ret;
 }
 change = change || aux;

 /* Configure output data rate */
 ret = regmap_update_bits_check(data->regmap, BMP380_REG_ODR,
           BMP380_ODRS_MASK, data->sampling_freq,
           &aux);
 if (ret) {
  dev_err(data->dev, "failed to write ODR selection register\n");
  return ret;
 }
 change = change || aux;

 /* Set filter data */
 ret = regmap_update_bits(data->regmap, BMP380_REG_CONFIG, BMP380_FILTER_MASK,
     FIELD_PREP(BMP380_FILTER_MASK, data->iir_filter_coeff));
 if (ret) {
  dev_err(data->dev, "failed to write config register\n");
  return ret;
 }

 if (change) {
  /*
 * The configurations errors are detected on the fly during a
 * measurement cycle. If the sampling frequency is too low, it's
 * faster to reset the measurement loop than wait until the next
 * measurement is due.
 *
 * Resets sensor measurement loop toggling between sleep and
 * normal operating modes.
 */

  ret = bmp380_set_mode(data, BMP280_SLEEP);
  if (ret) {
   dev_err(data->dev, "failed to set sleep mode\n");
   return ret;
  }

  /*
 * According to the BMP3 Sensor API, the sensor needs 5ms
 * in order to go to the sleep mode.
 */

  fsleep(5 * USEC_PER_MSEC);

  ret = bmp380_set_mode(data, BMP280_NORMAL);
  if (ret) {
   dev_err(data->dev, "failed to set normal mode\n");
   return ret;
  }
  /*
 * Waits for measurement before checking configuration error
 * flag. Selected longest measurement time, calculated from
 * formula in datasheet section 3.9.2 with an offset of ~+15%
 * as it seen as well in table 3.9.1.
 */

  fsleep(150 * USEC_PER_MSEC);

  /* Check config error flag */
  ret = regmap_read(data->regmap, BMP380_REG_ERROR, &tmp);
  if (ret) {
   dev_err(data->dev, "failed to read error register\n");
   return ret;
  }
  if (tmp & BMP380_ERR_CONF_MASK) {
   dev_warn(data->dev,
     "sensor flagged configuration as incompatible\n");
   return -EINVAL;
  }
 }

 /* Dummy read to empty data registers. */
 ret = bmp380_read_press(data, &tmp);
 if (ret)
  return ret;

 ret = bmp380_set_mode(data, BMP280_SLEEP);
 if (ret)
  dev_err(data->dev, "failed to set sleep mode.\n");

 return ret;
}

static int bmp380_data_rdy_trigger_set_state(struct iio_trigger *trig,
          bool state)
{
 struct bmp280_data *data = iio_trigger_get_drvdata(trig);
 int ret;

 guard(mutex)(&data->lock);

 ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL,
     BMP380_INT_CTRL_DRDY_EN,
     FIELD_PREP(BMP380_INT_CTRL_DRDY_EN, !!state));
 if (ret)
  dev_err(data->dev,
   "Could not %s interrupt.\n", str_enable_disable(state));
 return ret;
}

static const struct iio_trigger_ops bmp380_trigger_ops = {
 .set_trigger_state = &bmp380_data_rdy_trigger_set_state,
};

static int bmp380_int_pin_config(struct bmp280_data *data)
{
 int pin_drive_cfg = FIELD_PREP(BMP380_INT_CTRL_OPEN_DRAIN,
           data->trig_open_drain);
 int pin_level_cfg = FIELD_PREP(BMP380_INT_CTRL_LEVEL,
           data->trig_active_high);
 int ret, int_pin_cfg = pin_drive_cfg | pin_level_cfg;

 ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL,
     BMP380_INT_CTRL_SETTINGS_MASK, int_pin_cfg);
 if (ret)
  dev_err(data->dev, "Could not set interrupt settings.\n");

 return ret;
}

static irqreturn_t bmp380_irq_thread_handler(int irq, void *p)
{
 struct iio_dev *indio_dev = p;
 struct bmp280_data *data = iio_priv(indio_dev);
 unsigned int int_ctrl;
 int ret;

 ret = regmap_read(data->regmap, BMP380_REG_INT_STATUS, &int_ctrl);
 if (ret)
  return IRQ_NONE;

 if (FIELD_GET(BMP380_INT_STATUS_DRDY, int_ctrl))
  iio_trigger_poll_nested(data->trig);

 return IRQ_HANDLED;
}

static int bmp380_trigger_probe(struct iio_dev *indio_dev)
{
 return __bmp280_trigger_probe(indio_dev, &bmp380_trigger_ops,
          bmp380_int_pin_config,
          bmp380_irq_thread_handler);
}

static irqreturn_t bmp380_trigger_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);
 u32 adc_temp, adc_press;
 s32 t_fine;
 struct {
  u32 comp_press;
  s32 comp_temp;
  aligned_s64 timestamp;
 } buffer;
 int ret;

 guard(mutex)(&data->lock);

 /* Burst read data registers */
 ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB,
          data->buf, BMP280_BURST_READ_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to burst read sensor data\n");
  goto out;
 }

 /* Temperature calculations */
 adc_temp = get_unaligned_le24(&data->buf[3]);
 if (adc_temp == BMP380_TEMP_SKIPPED) {
  dev_err(data->dev, "reading temperature skipped\n");
  goto out;
 }

 buffer.comp_temp = bmp380_compensate_temp(data, adc_temp);

 /* Pressure calculations */
 adc_press = get_unaligned_le24(&data->buf[0]);
 if (adc_press == BMP380_PRESS_SKIPPED) {
  dev_err(data->dev, "reading pressure skipped\n");
  goto out;
 }

 t_fine = bmp380_calc_t_fine(data, adc_temp);
 buffer.comp_press = bmp380_compensate_press(data, adc_press, t_fine);

 iio_push_to_buffers_with_ts(indio_dev, &buffer, sizeof(buffer),
        iio_get_time_ns(indio_dev));

out:
 iio_trigger_notify_done(indio_dev->trig);

 return IRQ_HANDLED;
}

static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 };
static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128};
static const u8 bmp380_chip_ids[] = { BMP380_CHIP_ID, BMP390_CHIP_ID };
static const int bmp380_temp_coeffs[] = { 10, 1 };
static const int bmp380_press_coeffs[] = { 1, 100000 };

const struct bmp280_chip_info bmp380_chip_info = {
 .id_reg = BMP380_REG_ID,
 .chip_id = bmp380_chip_ids,
 .num_chip_id = ARRAY_SIZE(bmp380_chip_ids),
 .regmap_config = &bmp380_regmap_config,
 .spi_read_extra_byte = true,
 .start_up_time_us = 2000,
 .channels = bmp380_channels,
 .num_channels = ARRAY_SIZE(bmp380_channels),
 .avail_scan_masks = bmp280_avail_scan_masks,

 .oversampling_temp_avail = bmp380_oversampling_avail,
 .num_oversampling_temp_avail = ARRAY_SIZE(bmp380_oversampling_avail),
 .oversampling_temp_default = ilog2(1),

 .oversampling_press_avail = bmp380_oversampling_avail,
 .num_oversampling_press_avail = ARRAY_SIZE(bmp380_oversampling_avail),
 .oversampling_press_default = ilog2(4),

 .sampling_freq_avail = bmp380_odr_table,
 .num_sampling_freq_avail = ARRAY_SIZE(bmp380_odr_table) * 2,
 .sampling_freq_default = BMP380_ODR_50HZ,

 .iir_filter_coeffs_avail = bmp380_iir_filter_coeffs_avail,
 .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp380_iir_filter_coeffs_avail),
 .iir_filter_coeff_default = 2,

 .temp_coeffs = bmp380_temp_coeffs,
 .temp_coeffs_type = IIO_VAL_FRACTIONAL,
 .press_coeffs = bmp380_press_coeffs,
 .press_coeffs_type = IIO_VAL_FRACTIONAL,

 .chip_config = bmp380_chip_config,
 .read_temp = bmp380_read_temp,
 .read_press = bmp380_read_press,
 .read_calib = bmp380_read_calib,
 .set_mode = bmp380_set_mode,
 .wait_conv = bmp380_wait_conv,
 .preinit = bmp380_preinit,

 .trigger_probe = bmp380_trigger_probe,
 .trigger_handler = bmp380_trigger_handler,
};
EXPORT_SYMBOL_NS(bmp380_chip_info, "IIO_BMP280");

static int bmp580_soft_reset(struct bmp280_data *data)
{
 unsigned int reg;
 int ret;

 ret = regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_SOFT_RESET);
 if (ret) {
  dev_err(data->dev, "failed to send reset command to device\n");
  return ret;
 }
 /* From datasheet's table 4: electrical characteristics */
 fsleep(2000);

 /* Dummy read of chip_id */
 ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®);
 if (ret) {
  dev_err(data->dev, "failed to reestablish comms after reset\n");
  return ret;
 }

 ret = regmap_read(data->regmap, BMP580_REG_INT_STATUS, ®);
 if (ret) {
  dev_err(data->dev, "error reading interrupt status register\n");
  return ret;
 }
 if (!(reg & BMP580_INT_STATUS_POR_MASK)) {
  dev_err(data->dev, "error resetting sensor\n");
  return -EINVAL;
 }

 return 0;
}

/**
 * bmp580_nvm_operation() - Helper function to commit NVM memory operations
 * @data: sensor data struct
 * @is_write: flag to signal write operation
 */

static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write)
{
 unsigned long timeout, poll;
 unsigned int reg;
 int ret;

 /* Check NVM ready flag */
 ret = regmap_read(data->regmap, BMP580_REG_STATUS, ®);
 if (ret) {
  dev_err(data->dev, "failed to check nvm status\n");
  return ret;
 }
 if (!(reg & BMP580_STATUS_NVM_RDY_MASK)) {
  dev_err(data->dev, "sensor's nvm is not ready\n");
  return -EIO;
 }

 /* Start NVM operation sequence */
 ret = regmap_write(data->regmap, BMP580_REG_CMD,
      BMP580_CMD_NVM_OP_SEQ_0);
 if (ret) {
  dev_err(data->dev,
   "failed to send nvm operation's first sequence\n");
  return ret;
 }
 if (is_write) {
  /* Send NVM write sequence */
  ret = regmap_write(data->regmap, BMP580_REG_CMD,
       BMP580_CMD_NVM_WRITE_SEQ_1);
  if (ret) {
   dev_err(data->dev,
    "failed to send nvm write sequence\n");
   return ret;
  }
  /* Datasheet says on 4.8.1.2 it takes approximately 10ms */
  poll = 2000;
  timeout = 12000;
 } else {
  /* Send NVM read sequence */
  ret = regmap_write(data->regmap, BMP580_REG_CMD,
       BMP580_CMD_NVM_READ_SEQ_1);
  if (ret) {
   dev_err(data->dev,
    "failed to send nvm read sequence\n");
   return ret;
  }
  /* Datasheet says on 4.8.1.1 it takes approximately 200us */
  poll = 50;
  timeout = 400;
 }

 /* Wait until NVM is ready again */
 ret = regmap_read_poll_timeout(data->regmap, BMP580_REG_STATUS, reg,
           (reg & BMP580_STATUS_NVM_RDY_MASK),
           poll, timeout);
 if (ret) {
  dev_err(data->dev, "error checking nvm operation status\n");
  return ret;
 }

 /* Check NVM error flags */
 if ((reg & BMP580_STATUS_NVM_ERR_MASK) || (reg & BMP580_STATUS_NVM_CMD_ERR_MASK)) {
  dev_err(data->dev, "error processing nvm operation\n");
  return -EIO;
 }

 return 0;
}

/*
 * Contrary to previous sensors families, compensation algorithm is builtin.
 * We are only required to read the register raw data and adapt the ranges
 * for what is expected on IIO ABI.
 */


static int bmp580_read_temp(struct bmp280_data *data, s32 *raw_temp)
{
 s32 value_temp;
 int ret;

 ret = regmap_bulk_read(data->regmap, BMP580_REG_TEMP_XLSB,
          data->buf, BMP280_NUM_TEMP_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to read temperature\n");
  return ret;
 }

 value_temp = get_unaligned_le24(data->buf);
 if (value_temp == BMP580_TEMP_SKIPPED) {
  dev_err(data->dev, "reading temperature skipped\n");
  return -EIO;
 }
 *raw_temp = sign_extend32(value_temp, 23);

 return 0;
}

static int bmp580_read_press(struct bmp280_data *data, u32 *raw_press)
{
 u32 value_press;
 int ret;

 ret = regmap_bulk_read(data->regmap, BMP580_REG_PRESS_XLSB,
          data->buf, BMP280_NUM_PRESS_BYTES);
 if (ret) {
  dev_err(data->dev, "failed to read pressure\n");
  return ret;
 }

 value_press = get_unaligned_le24(data->buf);
 if (value_press == BMP580_PRESS_SKIPPED) {
  dev_err(data->dev, "reading pressure skipped\n");
  return -EIO;
 }
 *raw_press = value_press;

 return 0;
}

static const int bmp580_odr_table[][2] = {
 [BMP580_ODR_240HZ] = {240, 0},
 [BMP580_ODR_218HZ] = {218, 0},
 [BMP580_ODR_199HZ] = {199, 0},
 [BMP580_ODR_179HZ] = {179, 0},
 [BMP580_ODR_160HZ] = {160, 0},
 [BMP580_ODR_149HZ] = {149, 0},
 [BMP580_ODR_140HZ] = {140, 0},
 [BMP580_ODR_129HZ] = {129, 0},
 [BMP580_ODR_120HZ] = {120, 0},
 [BMP580_ODR_110HZ] = {110, 0},
 [BMP580_ODR_100HZ] = {100, 0},
 [BMP580_ODR_89HZ] = {89, 0},
 [BMP580_ODR_80HZ] = {80, 0},
 [BMP580_ODR_70HZ] = {70, 0},
 [BMP580_ODR_60HZ] = {60, 0},
 [BMP580_ODR_50HZ] = {50, 0},
 [BMP580_ODR_45HZ] = {45, 0},
 [BMP580_ODR_40HZ] = {40, 0},
 [BMP580_ODR_35HZ] = {35, 0},
 [BMP580_ODR_30HZ] = {30, 0},
 [BMP580_ODR_25HZ] = {25, 0},
 [BMP580_ODR_20HZ] = {20, 0},
 [BMP580_ODR_15HZ] = {15, 0},
 [BMP580_ODR_10HZ] = {10, 0},
 [BMP580_ODR_5HZ] = {5, 0},
 [BMP580_ODR_4HZ] = {4, 0},
 [BMP580_ODR_3HZ] = {3, 0},
 [BMP580_ODR_2HZ] = {2, 0},
 [BMP580_ODR_1HZ] = {1, 0},
 [BMP580_ODR_0_5HZ] = {0, 500000},
 [BMP580_ODR_0_25HZ] = {0, 250000},
 [BMP580_ODR_0_125HZ] = {0, 125000},
};

static const int bmp580_nvmem_addrs[] = { 0x20, 0x21, 0x22 };

static int bmp580_nvmem_read_impl(void *priv, unsigned int offset, void *val,
      size_t bytes)
{
 struct bmp280_data *data = priv;
 u16 *dst = val;
 int ret, addr;

 guard(mutex)(&data->lock);

 /* Set sensor in standby mode */
 ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG,
     BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS,
     BMP580_ODR_DEEPSLEEP_DIS |
     FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP));
 if (ret) {
  dev_err(data->dev, "failed to change sensor to standby mode\n");
  goto exit;
 }
 /* Wait standby transition time */
 fsleep(2500);

 while (bytes >= sizeof(*dst)) {
  addr = bmp580_nvmem_addrs[offset / sizeof(*dst)];

  ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR,
       FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr));
  if (ret) {
   dev_err(data->dev, "error writing nvm address\n");
   goto exit;
  }

  ret = bmp580_nvm_operation(data, false);
  if (ret)
   goto exit;

  ret = regmap_bulk_read(data->regmap, BMP580_REG_NVM_DATA_LSB,
           &data->le16, sizeof(data->le16));
  if (ret) {
   dev_err(data->dev, "error reading nvm data regs\n");
   goto exit;
  }

  *dst++ = le16_to_cpu(data->le16);
  bytes -= sizeof(*dst);
  offset += sizeof(*dst);
 }
exit:
 /* Restore chip config */
 data->chip_info->chip_config(data);
 return ret;
}

static int bmp580_nvmem_read(void *priv, unsigned int offset, void *val,
        size_t bytes)
{
 struct bmp280_data *data = priv;
 int ret;

 pm_runtime_get_sync(data->dev);
 ret = bmp580_nvmem_read_impl(priv, offset, val, bytes);
 pm_runtime_mark_last_busy(data->dev);
 pm_runtime_put_autosuspend(data->dev);

 return ret;
}

static int bmp580_nvmem_write_impl(void *priv, unsigned int offset, void *val,
       size_t bytes)
{
 struct bmp280_data *data = priv;
 u16 *buf = val;
 int ret, addr;

 guard(mutex)(&data->lock);

 /* Set sensor in standby mode */
 ret = regmap_update_bits(data->regmap, BMP580_REG_ODR_CONFIG,
     BMP580_MODE_MASK | BMP580_ODR_DEEPSLEEP_DIS,
     BMP580_ODR_DEEPSLEEP_DIS |
     FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_SLEEP));
 if (ret) {
  dev_err(data->dev, "failed to change sensor to standby mode\n");
  goto exit;
 }
 /* Wait standby transition time */
 fsleep(2500);

 while (bytes >= sizeof(*buf)) {
  addr = bmp580_nvmem_addrs[offset / sizeof(*buf)];

  ret = regmap_write(data->regmap, BMP580_REG_NVM_ADDR,
       BMP580_NVM_PROG_EN |
       FIELD_PREP(BMP580_NVM_ROW_ADDR_MASK, addr));
  if (ret) {
   dev_err(data->dev, "error writing nvm address\n");
   goto exit;
  }
  data->le16 = cpu_to_le16(*buf++);

  ret = regmap_bulk_write(data->regmap, BMP580_REG_NVM_DATA_LSB,
     &data->le16, sizeof(data->le16));
  if (ret) {
   dev_err(data->dev, "error writing LSB NVM data regs\n");
   goto exit;
  }

  ret = bmp580_nvm_operation(data, true);
  if (ret)
   goto exit;

  /* Disable programming mode bit */
  ret = regmap_clear_bits(data->regmap, BMP580_REG_NVM_ADDR,
     BMP580_NVM_PROG_EN);
  if (ret) {
   dev_err(data->dev, "error resetting nvm write\n");
   goto exit;
  }

  bytes -= sizeof(*buf);
  offset += sizeof(*buf);
 }
exit:
 /* Restore chip config */
 data->chip_info->chip_config(data);
 return ret;
}

static int bmp580_nvmem_write(void *priv, unsigned int offset, void *val,
         size_t bytes)
{
 struct bmp280_data *data = priv;
 int ret;

 pm_runtime_get_sync(data->dev);
 ret = bmp580_nvmem_write_impl(priv, offset, val, bytes);
 pm_runtime_mark_last_busy(data->dev);
 pm_runtime_put_autosuspend(data->dev);

 return ret;
}

static int bmp580_preinit(struct bmp280_data *data)
{
 struct nvmem_config config = {
  .dev = data->dev,
  .priv = data,
  .name = "bmp580_nvmem",
  .word_size = sizeof(u16),
  .stride = sizeof(u16),
  .size = 3 * sizeof(u16),
  .reg_read = bmp580_nvmem_read,
  .reg_write = bmp580_nvmem_write,
 };
 unsigned int reg;
 int ret;

 /* Issue soft-reset command */
 ret = bmp580_soft_reset(data);
 if (ret)
  return ret;

 /* Post powerup sequence */
 ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®);
 if (ret) {
  dev_err(data->dev, "failed to establish comms with the chip\n");
  return ret;
 }

 /* Print warn message if we don't know the chip id */
 if (reg != BMP580_CHIP_ID && reg != BMP580_CHIP_ID_ALT)
  dev_warn(data->dev, "unexpected chip_id\n");

 ret = regmap_read(data->regmap, BMP580_REG_STATUS, ®);
 if (ret) {
  dev_err(data->dev, "failed to read nvm status\n");
  return ret;
 }

 /* Check nvm status */
 if (!(reg & BMP580_STATUS_NVM_RDY_MASK) || (reg & BMP580_STATUS_NVM_ERR_MASK)) {
  dev_err(data->dev, "nvm error on powerup sequence\n");
  return -EIO;
 }

 /* Register nvmem device */
 return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config));
}

static const u8 bmp580_operation_mode[] = {
 [BMP280_SLEEP] = BMP580_MODE_SLEEP,
 [BMP280_FORCED] = BMP580_MODE_FORCED,
 [BMP280_NORMAL] = BMP580_MODE_NORMAL,
};

static int bmp580_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
{
 struct device *dev = data->dev;
 int ret;

 if (mode == BMP280_FORCED) {
  ret = regmap_set_bits(data->regmap, BMP580_REG_DSP_CONFIG,
          BMP580_DSP_IIR_FORCED_FLUSH);
  if (ret) {
   dev_err(dev, "Could not flush IIR filter constants.\n");
   return ret;
  }
 }

 ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG,
    BMP580_MODE_MASK,
    FIELD_PREP(BMP580_MODE_MASK,
        bmp580_operation_mode[mode]));
 if (ret) {
  dev_err(dev, "failed to write power control register.\n");
  return ret;
 }

 data->op_mode = mode;

 return 0;
}

static int bmp580_wait_conv(struct bmp280_data *data)
{
 /*
 * Taken from datasheet, Section 2 "Specification, Table 3 "Electrical
 * characteristics.
 */

 static const int time_conv_press[] = {
  0, 1050, 1785, 3045, 5670, 10920, 21420, 42420,
  84420,
 };
 static const int time_conv_temp[] = {
  0, 1050, 1105, 1575, 2205, 3465, 6090, 11340,
  21840,
 };
 int meas_time_us;

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=92 G=92

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.35Bemerkung:  (vorverarbeitet)  ¤

*Bot Zugriff






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge