Commit 10b40ffb authored by Angel Iglesias's avatar Angel Iglesias Committed by Jonathan Cameron
Browse files

iio: pressure: bmp280: Add more tunable config parameters for BMP380



Allows sampling frequency and IIR filter coefficients configuration
using sysfs ABI.

The IIR filter coefficient is configurable using the sysfs attribute
"filter_low_pass_3db_frequency".

Signed-off-by: default avatarAngel Iglesias <ang.iglesiasg@gmail.com>
Link: https://lore.kernel.org/r/876f8a2277f71672488e99aa02aae4239d530f51.1663025017.git.ang.iglesiasg@gmail.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 2a332dcd
Loading
Loading
Loading
Loading
+238 −9
Original line number Diff line number Diff line
@@ -109,6 +109,27 @@ static const char *const bmp280_supply_names[] = {

#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names)

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,
};

struct bmp280_data {
	struct device *dev;
	struct mutex lock;
@@ -128,6 +149,17 @@ struct bmp280_data {
	u8 oversampling_press;
	u8 oversampling_temp;
	u8 oversampling_humid;
	u8 iir_filter_coeff;

	/*
	 * BMP380 devices introduce sampling frequency configuration. See
	 * datasheet sections 3.3.3. and 4.3.19 for more details.
	 *
	 * BMx280 devices allowed indirect configuration of sampling frequency
	 * changing the t_standby duration between measurements, as detailed on
	 * section 3.6.3 of the datasheet.
	 */
	int sampling_freq;

	/*
	 * Carryover value from temperature conversion, used in pressure
@@ -155,6 +187,7 @@ struct bmp280_data {
struct bmp280_chip_info {
	unsigned int id_reg;

	const struct iio_chan_spec *channels;
	int num_channels;
	unsigned int start_up_time;

@@ -170,6 +203,14 @@ struct bmp280_chip_info {
	int num_oversampling_humid_avail;
	int oversampling_humid_default;

	const int *iir_filter_coeffs_avail;
	int num_iir_filter_coeffs_avail;
	int iir_filter_coeff_default;

	const int (*sampling_freq_avail)[2];
	int num_sampling_freq_avail;
	int sampling_freq_default;

	int (*chip_config)(struct bmp280_data *);
	int (*read_temp)(struct bmp280_data *, int *);
	int (*read_press)(struct bmp280_data *, int *, int *);
@@ -220,6 +261,30 @@ static const struct iio_chan_spec bmp280_channels[] = {
	},
};

static const struct iio_chan_spec bmp380_channels[] = {
	{
		.type = IIO_PRESSURE,
		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
				      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),
	},
	{
		.type = IIO_TEMP,
		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
				      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),
	},
	{
		.type = IIO_HUMIDITYRELATIVE,
		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
				      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),
	},
};

static int bmp280_read_calib(struct bmp280_data *data)
{
	struct bmp280_calib *calib = &data->calib.bmp280;
@@ -550,6 +615,25 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
			break;
		}
		break;
	case IIO_CHAN_INFO_SAMP_FREQ:
		if (!data->chip_info->sampling_freq_avail) {
			ret = -EINVAL;
			break;
		}

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

		*val = (1 << data->iir_filter_coeff) - 1;
		ret = IIO_VAL_INT;
		break;
	default:
		ret = -EINVAL;
		break;
@@ -567,13 +651,21 @@ static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data,
{
	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);

			return data->chip_info->chip_config(data);
			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;
@@ -584,13 +676,21 @@ static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data,
{
	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);

			return data->chip_info->chip_config(data);
			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;
@@ -601,13 +701,71 @@ static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data,
{
	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);

			return data->chip_info->chip_config(data);
			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;
@@ -620,6 +778,12 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
	struct bmp280_data *data = iio_priv(indio_dev);
	int ret = 0;

	/*
	 * 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:
		pm_runtime_get_sync(data->dev);
@@ -642,6 +806,22 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
		pm_runtime_mark_last_busy(data->dev);
		pm_runtime_put_autosuspend(data->dev);
		break;
	case IIO_CHAN_INFO_SAMP_FREQ:
		pm_runtime_get_sync(data->dev);
		mutex_lock(&data->lock);
		ret = bmp280_write_sampling_frequency(data, val, val2);
		mutex_unlock(&data->lock);
		pm_runtime_mark_last_busy(data->dev);
		pm_runtime_put_autosuspend(data->dev);
		break;
	case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
		pm_runtime_get_sync(data->dev);
		mutex_lock(&data->lock);
		ret = bmp280_write_iir_filter_coeffs(data, val);
		mutex_unlock(&data->lock);
		pm_runtime_mark_last_busy(data->dev);
		pm_runtime_put_autosuspend(data->dev);
		break;
	default:
		return -EINVAL;
	}
@@ -672,6 +852,17 @@ static int bmp280_read_avail(struct iio_dev *indio_dev,
		}
		*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;
	}
@@ -717,6 +908,7 @@ static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static const struct bmp280_chip_info bmp280_chip_info = {
	.id_reg = BMP280_REG_ID,
	.start_up_time = 2000,
	.channels = bmp280_channels,
	.num_channels = 2,

	.oversampling_temp_avail = bmp280_oversampling_avail,
@@ -764,6 +956,7 @@ static int bme280_chip_config(struct bmp280_data *data)
static const struct bmp280_chip_info bme280_chip_info = {
	.id_reg = BMP280_REG_ID,
	.start_up_time = 2000,
	.channels = bmp280_channels,
	.num_channels = 3,

	.oversampling_temp_avail = bmp280_oversampling_avail,
@@ -1003,6 +1196,27 @@ static int bmp380_read_calib(struct bmp280_data *data)
	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_chip_config(struct bmp280_data *data)
{
	bool change = false, aux;
@@ -1036,21 +1250,23 @@ static int bmp380_chip_config(struct bmp280_data *data)
	change = change || aux;

	/* Configure output data rate */
	ret = regmap_update_bits(data->regmap, BMP380_REG_ODR,
				 BMP380_ODRS_MASK, BMP380_ODRS_50HZ);
	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, BMP380_FILTER_3X));
	ret = regmap_update_bits_check(data->regmap, BMP380_REG_CONFIG, BMP380_FILTER_MASK,
				       FIELD_PREP(BMP380_FILTER_MASK, data->iir_filter_coeff),
				       &aux);
	if (ret) {
		dev_err(data->dev, "failed to write config register\n");
		return ret;
	}
	change = change || aux;

	if (change) {
		/*
@@ -1101,10 +1317,12 @@ static int bmp380_chip_config(struct bmp280_data *data)
}

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 struct bmp280_chip_info bmp380_chip_info = {
	.id_reg = BMP380_REG_ID,
	.start_up_time = 2000,
	.channels = bmp380_channels,
	.num_channels = 2,

	.oversampling_temp_avail = bmp380_oversampling_avail,
@@ -1115,6 +1333,14 @@ static const struct bmp280_chip_info bmp380_chip_info = {
	.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,

	.chip_config = bmp380_chip_config,
	.read_temp = bmp380_read_temp,
	.read_press = bmp380_read_press,
@@ -1356,6 +1582,7 @@ static const int bmp180_oversampling_press_avail[] = { 1, 2, 4, 8 };
static const struct bmp280_chip_info bmp180_chip_info = {
	.id_reg = BMP280_REG_ID,
	.start_up_time = 2000,
	.channels = bmp280_channels,
	.num_channels = 2,

	.oversampling_temp_avail = bmp180_oversampling_temp_avail,
@@ -1454,7 +1681,6 @@ int bmp280_common_probe(struct device *dev,
	data->dev = dev;

	indio_dev->name = name;
	indio_dev->channels = bmp280_channels;
	indio_dev->info = &bmp280_info;
	indio_dev->modes = INDIO_DIRECT_MODE;

@@ -1477,10 +1703,13 @@ int bmp280_common_probe(struct device *dev,
	data->chip_info = chip_info;

	/* Apply initial values from chip info structure */
	indio_dev->channels = chip_info->channels;
	indio_dev->num_channels = chip_info->num_channels;
	data->oversampling_press = chip_info->oversampling_press_default;
	data->oversampling_humid = chip_info->oversampling_humid_default;
	data->oversampling_temp = chip_info->oversampling_temp_default;
	data->iir_filter_coeff = chip_info->iir_filter_coeff_default;
	data->sampling_freq = chip_info->sampling_freq_default;
	data->start_up_time = chip_info->start_up_time;

	/* Bring up regulators */
+0 −18
Original line number Diff line number Diff line
@@ -54,24 +54,6 @@
#define BMP380_OSRS_PRESS_MASK		GENMASK(2, 0)

#define BMP380_ODRS_MASK		GENMASK(4, 0)
#define BMP380_ODRS_200HZ		0x00
#define BMP380_ODRS_100HZ		0x01
#define BMP380_ODRS_50HZ		0x02
#define BMP380_ODRS_25HZ		0x03
#define BMP380_ODRS_12_5HZ		0x04
#define BMP380_ODRS_6_25HZ		0x05
#define BMP380_ODRS_3_1HZ		0x06
#define BMP380_ODRS_1_5HZ		0x07
#define BMP380_ODRS_0_78HZ		0x08
#define BMP380_ODRS_0_39HZ		0x09
#define BMP380_ODRS_0_2HZ		0x0A
#define BMP380_ODRS_0_1HZ		0x0B
#define BMP380_ODRS_0_05HZ		0x0C
#define BMP380_ODRS_0_02HZ		0x0D
#define BMP380_ODRS_0_01HZ		0x0E
#define BMP380_ODRS_0_006HZ		0x0F
#define BMP380_ODRS_0_003HZ		0x10
#define BMP380_ODRS_0_0015HZ		0x11

#define BMP380_CTRL_SENSORS_MASK	GENMASK(1, 0)
#define BMP380_CTRL_SENSORS_PRESS_EN	BIT(0)