Compare commits

...

10 commits

Author SHA1 Message Date
Denis Benato
6c183eed99 iio: imu: bmi323: Use iio read_acpi_mount_matrix() helper
bmi150-accel and bmi323-imu are declared in an almost identical way in the ACPI and in some devices such as the Asus RC71L the "ROTM" property can be found: parse and use the ACPI-defined mount-matrix.

Co-developed-by: Luke D. Jones <luke@ljones.dev>
Co-developed-by: Jonathan LoBue <jlobue10@gmail.com>
Signed-off-by: Denis Benato <benato.denis96@gmail.com>
2024-05-23 19:28:34 +02:00
Alisa-Dariana Roman
6c46802cc0 iio: adc: ad7192: Add AD7194 support
Unlike the other AD719Xs, AD7194 has configurable channels. The user can
dynamically configure them in the devicetree.

Add sigma_delta_info member to chip_info structure. Since AD7194 is the
only chip that has no channel sequencer, num_slots should remain
undefined.

Also modify config AD7192 description for better scaling.

Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com>
Link: https://lore.kernel.org/r/20240514120222.56488-7-alisa.roman@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 19:02:23 +01:00
Alisa-Dariana Roman
caeb12568b dt-bindings: iio: adc: ad7192: Add AD7194 support
Unlike the other AD719Xs, AD7194 has configurable channels. The user can
dynamically configure them in the devicetree.

Also add an example for AD7194 devicetree.

Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://lore.kernel.org/r/20240514120222.56488-6-alisa.roman@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:56:26 +01:00
Alisa-Dariana Roman
5e97c1b1b2 dt-bindings: iio: adc: Add single-channel property
Devices that have both single-ended channels and differential channels
cause a bit of confusion when the channels are configured in the
devicetree.

Clarify difference between these two types of channels for such devices
by adding single-channel property alongside diff-channels. They should
be mutually exclusive.

Devices that have only single-ended channels can still use reg property
to reference a channel like before.

Suggested-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com>
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://lore.kernel.org/r/20240514120222.56488-5-alisa.roman@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:54:42 +01:00
Alisa-Dariana Roman
535dc90900 iio: adc: ad7192: Add aincom supply
AINCOM should actually be a supply. AINx inputs are referenced to AINCOM
in pseudo-differential operation mode. AINCOM voltage represents the
offset of corresponding channels.

Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com>
Link: https://lore.kernel.org/r/20240514120222.56488-4-alisa.roman@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:52:04 +01:00
Alisa-Dariana Roman
2cadb27e98 dt-bindings: iio: adc: ad7192: Add aincom supply
AINCOM should actually be a supply. AINx inputs are referenced to AINCOM
in pseudo-differential operation mode. AINCOM voltage represents the
offset of corresponding channels.

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com>
Link: https://lore.kernel.org/r/20240514120222.56488-3-alisa.roman@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:46:03 +01:00
Alisa-Dariana Roman
a4f0d5b69b iio: adc: ad7192: Use standard attribute
Replace custom attribute filter_low_pass_3db_frequency_available with
standard attribute.

Store the available values in ad7192_state struct.

The function that used to compute those values replaced by
ad7192_update_filter_freq_avail().

Function ad7192_show_filter_avail() is no longer needed.

Note that the initial available values are hardcoded.

Also moved the mutex lock and unlock in order to protect the whole
switch statement since each branch modifies the state of the device.

Reviewed-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Alisa-Dariana Roman <alisa.roman@analog.com>
Link: https://lore.kernel.org/r/20240514120222.56488-2-alisa.roman@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:44:39 +01:00
Vasileios Amoiridis
5ff1aadd15 iio: pressure: bmp280: Add triggered buffer support
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@gmail.com>
Signed-off-by: Vasileios Amoiridis <vassilisamir@gmail.com>
Link: https://lore.kernel.org/r/20240512230524.53990-6-vassilisamir@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:41:07 +01:00
Vasileios Amoiridis
502ff77570 iio: pressure: bmp280: Add SCALE, RAW values in channels and refactorize them
Add extra IIO_CHAN_INFO_SCALE and IIO_CHAN_INFO_RAW channels in order
to be able to calculate the processed value with standard userspace
IIO tools. Can be used for triggered buffers as well.

Even though it is not a good design choice to have SCALE, RAW and
PROCESSED together, the PROCESSED channel is kept for ABI compatibility.

While at it, separate BMPxxx and BMExxx device channels since BME
supports also humidity measurements.

Signed-off-by: Vasileios Amoiridis <vassilisamir@gmail.com>
Link: https://lore.kernel.org/r/20240512230524.53990-5-vassilisamir@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:41:07 +01:00
Vasileios Amoiridis
c1da715c14 iio: pressure: bmp280: Generalize read_{temp,press,humid}() functions
Add the coefficients for the IIO standard units and the IIO value
inside the chip_info structure.

Move the calculations for the IIO unit compatibility from inside the
read_{temp,press,humid}() functions and move them to the general
read_raw() function.

In this way, all the data for the calculation of the value are
located in the chip_info structure of the respective sensor.

Signed-off-by: Vasileios Amoiridis <vassilisamir@gmail.com>
Link: https://lore.kernel.org/r/20240512230524.53990-4-vassilisamir@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2024-05-19 18:41:07 +01:00
9 changed files with 884 additions and 157 deletions

View file

@ -38,6 +38,14 @@ properties:
The first value specifies the positive input pin, the second
specifies the negative input pin.
single-channel:
$ref: /schemas/types.yaml#/definitions/uint32
description:
When devices combine single-ended and differential channels, allow the
channel for a single element to be specified, independent of reg (as for
differential channels). If this and diff-channels are not present reg
shall be used instead.
settling-time-us:
description:
Time between enabling the channel and first stable readings.
@ -50,4 +58,15 @@ properties:
device design and can interact with other characteristics such as
settling time.
anyOf:
- oneOf:
- required:
- reg
- diff-channels
- required:
- reg
- single-channel
- required:
- reg
additionalProperties: true

View file

@ -21,8 +21,15 @@ properties:
- adi,ad7190
- adi,ad7192
- adi,ad7193
- adi,ad7194
- adi,ad7195
"#address-cells":
const: 1
"#size-cells":
const: 0
reg:
maxItems: 1
@ -41,6 +48,11 @@ properties:
interrupts:
maxItems: 1
aincom-supply:
description: |
AINCOM voltage supply. Analog inputs AINx are referenced to this input
when configured for pseudo-differential operation.
dvdd-supply:
description: DVdd voltage supply
@ -84,6 +96,42 @@ properties:
description: see Documentation/devicetree/bindings/iio/adc/adc.yaml
type: boolean
patternProperties:
"^channel@[0-9a-f]+$":
type: object
$ref: adc.yaml
unevaluatedProperties: false
properties:
reg:
description: The channel index.
minimum: 0
maximum: 271
diff-channels:
description:
Both inputs can be connected to pins AIN1 to AIN16 by choosing the
appropriate value from 1 to 16.
items:
minimum: 1
maximum: 16
single-channel:
description:
Positive input can be connected to pins AIN1 to AIN16 by choosing the
appropriate value from 1 to 16. Negative input is connected to AINCOM.
items:
minimum: 1
maximum: 16
oneOf:
- required:
- reg
- diff-channels
- required:
- reg
- single-channel
required:
- compatible
- reg
@ -98,6 +146,17 @@ required:
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- if:
properties:
compatible:
enum:
- adi,ad7190
- adi,ad7192
- adi,ad7193
- adi,ad7195
then:
patternProperties:
"^channel@[0-9a-f]+$": false
unevaluatedProperties: false
@ -117,6 +176,7 @@ examples:
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
aincom-supply = <&aincom>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
vref-supply = <&vref>;
@ -127,3 +187,38 @@ examples:
adi,burnout-currents-enable;
};
};
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,ad7194";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <1000000>;
spi-cpol;
spi-cpha;
clocks = <&ad7192_mclk>;
clock-names = "mclk";
interrupts = <25 0x2>;
interrupt-parent = <&gpio>;
aincom-supply = <&aincom>;
dvdd-supply = <&dvdd>;
avdd-supply = <&avdd>;
vref-supply = <&vref>;
channel@0 {
reg = <0>;
diff-channels = <1 6>;
};
channel@1 {
reg = <1>;
single-channel = <1>;
};
};
};

View file

@ -88,12 +88,17 @@ config AD7173
called ad7173.
config AD7192
tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver"
tristate "Analog Devices AD7192 and similar ADC driver"
depends on SPI
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7190,
AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC).
Say yes here to build support for Analog Devices SPI analog to digital
converters (ADC):
- AD7190
- AD7192
- AD7193
- AD7194
- AD7195
If unsure, say N (but it's safe to say "Y").
To compile this driver as a module, choose M here: the

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* AD7190 AD7192 AD7193 AD7195 SPI ADC driver
* AD7192 and similar SPI ADC driver
*
* Copyright 2011-2015 Analog Devices Inc.
*/
@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -128,10 +129,24 @@
#define AD7193_CH_AIN8 0x480 /* AIN7 - AINCOM */
#define AD7193_CH_AINCOM 0x600 /* AINCOM - AINCOM */
#define AD7194_CH_POS(x) (((x) - 1) << 4)
#define AD7194_CH_NEG(x) ((x) - 1)
/* 10th bit corresponds to CON18(Pseudo) */
#define AD7194_CH(p) (BIT(10) | AD7194_CH_POS(p))
#define AD7194_DIFF_CH(p, n) (AD7194_CH_POS(p) | AD7194_CH_NEG(n))
#define AD7194_CH_TEMP 0x100
#define AD7194_CH_BASE_NR 2
#define AD7194_CH_AIN_START 1
#define AD7194_CH_AIN_NR 16
#define AD7194_CH_MAX_NR 272
/* ID Register Bit Designations (AD7192_REG_ID) */
#define CHIPID_AD7190 0x4
#define CHIPID_AD7192 0x0
#define CHIPID_AD7193 0x2
#define CHIPID_AD7194 0x3
#define CHIPID_AD7195 0x6
#define AD7192_ID_MASK GENMASK(3, 0)
@ -169,6 +184,7 @@ enum {
ID_AD7190,
ID_AD7192,
ID_AD7193,
ID_AD7194,
ID_AD7195,
};
@ -177,7 +193,9 @@ struct ad7192_chip_info {
const char *name;
const struct iio_chan_spec *channels;
u8 num_channels;
const struct ad_sigma_delta_info *sigma_delta_info;
const struct iio_info *info;
int (*parse_channels)(struct iio_dev *indio_dev);
};
struct ad7192_state {
@ -186,10 +204,12 @@ struct ad7192_state {
struct regulator *vref;
struct clk *mclk;
u16 int_vref_mv;
u32 aincom_mv;
u32 fclk;
u32 mode;
u32 conf;
u32 scale_avail[8][2];
u32 filter_freq_avail[4][2];
u32 oversampling_ratio_avail[4];
u8 gpocon;
u8 clock_sel;
@ -343,6 +363,18 @@ static const struct ad_sigma_delta_info ad7192_sigma_delta_info = {
.irq_flags = IRQF_TRIGGER_FALLING,
};
static const struct ad_sigma_delta_info ad7194_sigma_delta_info = {
.set_channel = ad7192_set_channel,
.append_status = ad7192_append_status,
.disable_all = ad7192_disable_all,
.set_mode = ad7192_set_mode,
.has_registers = true,
.addr_shift = 3,
.read_mask = BIT(6),
.status_ch_mask = GENMASK(3, 0),
.irq_flags = IRQF_TRIGGER_FALLING,
};
static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
{AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN1},
{AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN1},
@ -473,6 +505,16 @@ static int ad7192_setup(struct iio_dev *indio_dev, struct device *dev)
st->oversampling_ratio_avail[2] = 8;
st->oversampling_ratio_avail[3] = 16;
st->filter_freq_avail[0][0] = 600;
st->filter_freq_avail[1][0] = 800;
st->filter_freq_avail[2][0] = 2300;
st->filter_freq_avail[3][0] = 2720;
st->filter_freq_avail[0][1] = 1000;
st->filter_freq_avail[1][1] = 1000;
st->filter_freq_avail[2][1] = 1000;
st->filter_freq_avail[3][1] = 1000;
return 0;
}
@ -586,48 +628,24 @@ static int ad7192_get_f_adc(struct ad7192_state *st)
f_order * FIELD_GET(AD7192_MODE_RATE_MASK, st->mode));
}
static void ad7192_get_available_filter_freq(struct ad7192_state *st,
int *freq)
static void ad7192_update_filter_freq_avail(struct ad7192_state *st)
{
unsigned int fadc;
/* Formulas for filter at page 25 of the datasheet */
fadc = ad7192_compute_f_adc(st, false, true);
freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
st->filter_freq_avail[0][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = ad7192_compute_f_adc(st, true, true);
freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
st->filter_freq_avail[1][0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
fadc = ad7192_compute_f_adc(st, false, false);
freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
st->filter_freq_avail[2][0] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
fadc = ad7192_compute_f_adc(st, true, false);
freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
st->filter_freq_avail[3][0] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
}
static ssize_t ad7192_show_filter_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
unsigned int freq_avail[4], i;
size_t len = 0;
ad7192_get_available_filter_freq(st, freq_avail);
for (i = 0; i < ARRAY_SIZE(freq_avail); i++)
len += sysfs_emit_at(buf, len, "%d.%03d ", freq_avail[i] / 1000,
freq_avail[i] % 1000);
buf[len - 1] = '\n';
return len;
}
static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available,
0444, ad7192_show_filter_avail, NULL, 0);
static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
ad7192_show_bridge_switch, ad7192_set,
AD7192_REG_GPOCON);
@ -637,7 +655,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
AD7192_REG_CONF);
static struct attribute *ad7192_attributes[] = {
&iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
@ -647,7 +664,6 @@ static const struct attribute_group ad7192_attribute_group = {
};
static struct attribute *ad7195_attributes[] = {
&iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
&iio_dev_attr_ac_excitation_en.dev_attr.attr,
NULL
@ -665,17 +681,15 @@ static unsigned int ad7192_get_temp_scale(bool unipolar)
static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
int val, int val2)
{
int freq_avail[4], i, ret, freq;
int i, ret, freq;
unsigned int diff_new, diff_old;
int idx = 0;
diff_old = U32_MAX;
freq = val * 1000 + val2;
ad7192_get_available_filter_freq(st, freq_avail);
for (i = 0; i < ARRAY_SIZE(freq_avail); i++) {
diff_new = abs(freq - freq_avail[i]);
for (i = 0; i < ARRAY_SIZE(st->filter_freq_avail); i++) {
diff_new = abs(freq - st->filter_freq_avail[i][0]);
if (diff_new < diff_old) {
diff_old = diff_new;
idx = i;
@ -759,10 +773,24 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val = -(1 << (chan->scan_type.realbits - 1));
else
*val = 0;
switch (chan->type) {
case IIO_VOLTAGE:
/*
* Only applies to pseudo-differential inputs.
* AINCOM voltage has to be converted to "raw" units.
*/
if (st->aincom_mv && !chan->differential)
*val += DIV_ROUND_CLOSEST_ULL((u64)st->aincom_mv * NANO,
st->scale_avail[gain][1]);
return IIO_VAL_INT;
/* Kelvin to Celsius */
if (chan->type == IIO_TEMP)
case IIO_TEMP:
*val -= 273 * ad7192_get_temp_scale(unipolar);
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
*val = DIV_ROUND_CLOSEST(ad7192_get_f_adc(st), 1024);
return IIO_VAL_INT;
@ -792,10 +820,11 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
mutex_lock(&st->lock);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = -EINVAL;
mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i][1]) {
ret = 0;
@ -809,7 +838,6 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
ad7192_calibrate_all(st);
break;
}
mutex_unlock(&st->lock);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
if (!val) {
@ -826,13 +854,13 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
st->mode &= ~AD7192_MODE_RATE_MASK;
st->mode |= FIELD_PREP(AD7192_MODE_RATE_MASK, div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
ad7192_update_filter_freq_avail(st);
break;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
ret = -EINVAL;
mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->oversampling_ratio_avail); i++)
if (val == st->oversampling_ratio_avail[i]) {
ret = 0;
@ -845,12 +873,14 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
3, st->mode);
break;
}
mutex_unlock(&st->lock);
ad7192_update_filter_freq_avail(st);
break;
default:
ret = -EINVAL;
}
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
return ret;
@ -888,6 +918,12 @@ static int ad7192_read_avail(struct iio_dev *indio_dev,
/* Values are stored in a 2D matrix */
*length = ARRAY_SIZE(st->scale_avail) * 2;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*vals = (int *)st->filter_freq_avail;
*type = IIO_VAL_FRACTIONAL;
*length = ARRAY_SIZE(st->filter_freq_avail) * 2;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*vals = (int *)st->oversampling_ratio_avail;
@ -930,6 +966,14 @@ static const struct iio_info ad7192_info = {
.update_scan_mode = ad7192_update_scan_mode,
};
static const struct iio_info ad7194_info = {
.read_raw = ad7192_read_raw,
.write_raw = ad7192_write_raw,
.write_raw_get_fmt = ad7192_write_raw_get_fmt,
.read_avail = ad7192_read_avail,
.validate_trigger = ad_sd_validate_trigger,
};
static const struct iio_info ad7195_info = {
.read_raw = ad7192_read_raw,
.write_raw = ad7192_write_raw,
@ -956,7 +1000,9 @@ static const struct iio_info ad7195_info = {
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
(_mask_all), \
.info_mask_shared_by_type_available = (_mask_type_av), \
.info_mask_shared_by_all_available = (_mask_all_av), \
.info_mask_shared_by_all_available = \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) | \
(_mask_all_av), \
.ext_info = (_ext_info), \
.scan_index = (_si), \
.scan_type = { \
@ -1019,12 +1065,98 @@ static const struct iio_chan_spec ad7193_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(14),
};
static bool ad7194_validate_ain_channel(struct device *dev, u32 ain)
{
return in_range(ain, AD7194_CH_AIN_START, AD7194_CH_AIN_NR);
}
static int ad7194_parse_channels(struct iio_dev *indio_dev)
{
struct device *dev = indio_dev->dev.parent;
struct iio_chan_spec *ad7194_channels;
const struct iio_chan_spec ad7194_chan = AD7193_CHANNEL(0, 0, 0);
const struct iio_chan_spec ad7194_chan_diff = AD7193_DIFF_CHANNEL(0, 0, 0, 0);
const struct iio_chan_spec ad7194_chan_temp = AD719x_TEMP_CHANNEL(0, 0);
const struct iio_chan_spec ad7194_chan_timestamp = IIO_CHAN_SOFT_TIMESTAMP(0);
unsigned int num_channels, index = 0;
u32 ain[2];
int ret;
num_channels = device_get_child_node_count(dev);
if (num_channels > AD7194_CH_MAX_NR)
return dev_err_probe(dev, -EINVAL, "Too many channels: %u\n",
num_channels);
num_channels += AD7194_CH_BASE_NR;
ad7194_channels = devm_kcalloc(dev, num_channels,
sizeof(*ad7194_channels), GFP_KERNEL);
if (!ad7194_channels)
return -ENOMEM;
indio_dev->channels = ad7194_channels;
indio_dev->num_channels = num_channels;
device_for_each_child_node_scoped(dev, child) {
ret = fwnode_property_read_u32_array(child, "diff-channels",
ain, ARRAY_SIZE(ain));
if (ret == 0) {
ret = ad7194_validate_ain_channel(dev, ain[0]);
if (ret)
return dev_err_probe(dev, -EINVAL,
"Invalid AIN channel: %u\n",
ain[0]);
ret = ad7194_validate_ain_channel(dev, ain[1]);
if (ret)
return dev_err_probe(dev, -EINVAL,
"Invalid AIN channel: %u\n",
ain[1]);
*ad7194_channels = ad7194_chan_diff;
ad7194_channels->scan_index = index++;
ad7194_channels->channel = ain[0];
ad7194_channels->channel2 = ain[1];
ad7194_channels->address = AD7194_DIFF_CH(ain[0], ain[1]);
} else {
ret = fwnode_property_read_u32(child, "single-channel",
&ain[0]);
if (ret)
return dev_err_probe(dev, ret,
"Missing channel property\n");
ret = ad7194_validate_ain_channel(dev, ain[0]);
if (ret)
return dev_err_probe(dev, -EINVAL,
"Invalid AIN channel: %u\n",
ain[0]);
*ad7194_channels = ad7194_chan;
ad7194_channels->scan_index = index++;
ad7194_channels->channel = ain[0];
ad7194_channels->address = AD7194_CH(ain[0]);
}
ad7194_channels++;
}
*ad7194_channels = ad7194_chan_temp;
ad7194_channels->scan_index = index++;
ad7194_channels->address = AD7194_CH_TEMP;
ad7194_channels++;
*ad7194_channels = ad7194_chan_timestamp;
ad7194_channels->scan_index = index;
return 0;
}
static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
[ID_AD7190] = {
.chip_id = CHIPID_AD7190,
.name = "ad7190",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7192] = {
@ -1032,6 +1164,7 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
.name = "ad7192",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7193] = {
@ -1039,13 +1172,22 @@ static const struct ad7192_chip_info ad7192_chip_info_tbl[] = {
.name = "ad7193",
.channels = ad7193_channels,
.num_channels = ARRAY_SIZE(ad7193_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7192_info,
},
[ID_AD7194] = {
.chip_id = CHIPID_AD7194,
.name = "ad7194",
.info = &ad7194_info,
.sigma_delta_info = &ad7194_sigma_delta_info,
.parse_channels = ad7194_parse_channels,
},
[ID_AD7195] = {
.chip_id = CHIPID_AD7195,
.name = "ad7195",
.channels = ad7192_channels,
.num_channels = ARRAY_SIZE(ad7192_channels),
.sigma_delta_info = &ad7192_sigma_delta_info,
.info = &ad7195_info,
},
};
@ -1059,6 +1201,7 @@ static int ad7192_probe(struct spi_device *spi)
{
struct ad7192_state *st;
struct iio_dev *indio_dev;
struct regulator *aincom;
int ret;
if (!spi->irq) {
@ -1074,6 +1217,35 @@ static int ad7192_probe(struct spi_device *spi)
mutex_init(&st->lock);
/*
* Regulator aincom is optional to maintain compatibility with older DT.
* Newer firmware should provide a zero volt fixed supply if wired to
* ground.
*/
aincom = devm_regulator_get_optional(&spi->dev, "aincom");
if (IS_ERR(aincom)) {
if (PTR_ERR(aincom) != -ENODEV)
return dev_err_probe(&spi->dev, PTR_ERR(aincom),
"Failed to get AINCOM supply\n");
st->aincom_mv = 0;
} else {
ret = regulator_enable(aincom);
if (ret)
return dev_err_probe(&spi->dev, ret,
"Failed to enable specified AINCOM supply\n");
ret = devm_add_action_or_reset(&spi->dev, ad7192_reg_disable, aincom);
if (ret)
return ret;
ret = regulator_get_voltage(aincom);
if (ret < 0)
return dev_err_probe(&spi->dev, ret,
"Device tree error, AINCOM voltage undefined\n");
st->aincom_mv = ret / MILLI;
}
st->avdd = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(st->avdd))
return PTR_ERR(st->avdd);
@ -1122,11 +1294,17 @@ static int ad7192_probe(struct spi_device *spi)
st->chip_info = spi_get_device_match_data(spi);
indio_dev->name = st->chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = st->chip_info->info;
if (st->chip_info->parse_channels) {
ret = st->chip_info->parse_channels(indio_dev);
if (ret)
return ret;
} else {
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = st->chip_info->info;
}
ret = ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info);
ret = ad_sd_init(&st->sd, indio_dev, spi, st->chip_info->sigma_delta_info);
if (ret)
return ret;
@ -1163,6 +1341,7 @@ static const struct of_device_id ad7192_of_match[] = {
{ .compatible = "adi,ad7190", .data = &ad7192_chip_info_tbl[ID_AD7190] },
{ .compatible = "adi,ad7192", .data = &ad7192_chip_info_tbl[ID_AD7192] },
{ .compatible = "adi,ad7193", .data = &ad7192_chip_info_tbl[ID_AD7193] },
{ .compatible = "adi,ad7194", .data = &ad7192_chip_info_tbl[ID_AD7194] },
{ .compatible = "adi,ad7195", .data = &ad7192_chip_info_tbl[ID_AD7195] },
{}
};
@ -1172,6 +1351,7 @@ static const struct spi_device_id ad7192_ids[] = {
{ "ad7190", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7190] },
{ "ad7192", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7192] },
{ "ad7193", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7193] },
{ "ad7194", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7194] },
{ "ad7195", (kernel_ulong_t)&ad7192_chip_info_tbl[ID_AD7195] },
{}
};
@ -1188,6 +1368,6 @@ static struct spi_driver ad7192_driver = {
module_spi_driver(ad7192_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
MODULE_DESCRIPTION("Analog Devices AD7192 and similar ADC");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);

View file

@ -2083,9 +2083,11 @@ int bmi323_core_probe(struct device *dev)
if (ret)
return -EINVAL;
if (!iio_read_acpi_mount_matrix(dev, &data->orientation, "ROTM")) {
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
}
indio_dev->name = "bmi323-imu";
indio_dev->info = &bmi323_info;

View file

@ -31,6 +31,8 @@ config BMP280
select REGMAP
select BMP280_I2C if (I2C)
select BMP280_SPI if (SPI_MASTER)
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Bosch Sensortec BMP180, BMP280, BMP380
and BMP580 pressure and temperature sensors. Also supports the BME280 with

View file

@ -41,7 +41,10 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <asm/unaligned.h>
@ -134,46 +137,131 @@ enum {
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,
},
{
.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),
},
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static int bmp280_read_calib(struct bmp280_data *data)
@ -289,7 +377,7 @@ static int bme280_read_humid_adc(struct bmp280_data *data, u16 *adc_humidity)
int ret;
ret = regmap_bulk_read(data->regmap, BME280_REG_HUMIDITY_MSB,
&data->be16, sizeof(data->be16));
&data->be16, BME280_NUM_HUMIDITY_BYTES);
if (ret) {
dev_err(data->dev, "failed to read humidity\n");
return ret;
@ -335,7 +423,7 @@ static int bmp280_read_temp_adc(struct bmp280_data *data, u32 *adc_temp)
int ret;
ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
data->buf, sizeof(data->buf));
data->buf, BMP280_NUM_TEMP_BYTES);
if (ret) {
dev_err(data->dev, "failed to read temperature\n");
return ret;
@ -396,7 +484,7 @@ static int bmp280_read_press_adc(struct bmp280_data *data, u32 *adc_press)
int ret;
ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_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;
@ -445,10 +533,8 @@ static u32 bmp280_compensate_press(struct bmp280_data *data,
return (u32)p;
}
static int bmp280_read_temp(struct bmp280_data *data,
int *val, int *val2)
static int bmp280_read_temp(struct bmp280_data *data, s32 *comp_temp)
{
s32 comp_temp;
u32 adc_temp;
int ret;
@ -456,16 +542,15 @@ static int bmp280_read_temp(struct bmp280_data *data,
if (ret)
return ret;
comp_temp = bmp280_compensate_temp(data, adc_temp);
*comp_temp = bmp280_compensate_temp(data, adc_temp);
*val = comp_temp * 10;
return IIO_VAL_INT;
return 0;
}
static int bmp280_read_press(struct bmp280_data *data,
int *val, int *val2)
static int bmp280_read_press(struct bmp280_data *data, u32 *comp_press)
{
u32 comp_press, adc_press, t_fine;
u32 adc_press;
s32 t_fine;
int ret;
ret = bmp280_get_t_fine(data, &t_fine);
@ -476,17 +561,13 @@ static int bmp280_read_press(struct bmp280_data *data,
if (ret)
return ret;
comp_press = bmp280_compensate_press(data, adc_press, t_fine);
*comp_press = bmp280_compensate_press(data, adc_press, t_fine);
*val = comp_press;
*val2 = 256000;
return IIO_VAL_FRACTIONAL;
return 0;
}
static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2)
static int bme280_read_humid(struct bmp280_data *data, u32 *comp_humidity)
{
u32 comp_humidity;
u16 adc_humidity;
s32 t_fine;
int ret;
@ -499,11 +580,9 @@ static int bme280_read_humid(struct bmp280_data *data, int *val, int *val2)
if (ret)
return ret;
comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine);
*comp_humidity = bme280_compensate_humidity(data, adc_humidity, t_fine);
*val = comp_humidity * 1000 / 1024;
return IIO_VAL_INT;
return 0;
}
static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
@ -511,6 +590,8 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct bmp280_data *data = iio_priv(indio_dev);
int chan_value;
int ret;
guard(mutex)(&data->lock);
@ -518,11 +599,72 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
return data->chip_info->read_humid(data, val, val2);
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:
return data->chip_info->read_press(data, val, val2);
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:
return data->chip_info->read_temp(data, val, val2);
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:
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;
}
@ -793,6 +935,16 @@ static const struct iio_info bmp280_info = {
.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_chip_config(struct bmp280_data *data)
{
u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
@ -820,8 +972,78 @@ static int bmp280_chip_config(struct bmp280_data *data)
return ret;
}
static irqreturn_t bmp280_buffer_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmp280_data *data = iio_priv(indio_dev);
s32 adc_temp, adc_press, adc_humidity, t_fine;
u8 sizeof_burst_read;
int ret;
guard(mutex)(&data->lock);
/*
* If humidity channel is enabled it means that we are called for the
* BME280 humidity sensor.
*/
if (test_bit(BME280_HUMID, indio_dev->active_scan_mask))
sizeof_burst_read = BME280_BURST_READ_BYTES;
else
sizeof_burst_read = BMP280_BURST_READ_BYTES;
/* Burst read data registers */
ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB,
data->buf, sizeof_burst_read);
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;
}
data->sensor_data[1] = 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);
data->sensor_data[0] = bmp280_compensate_press(data, adc_press, t_fine);
/* Humidity calculations */
if (test_bit(BME280_HUMID, indio_dev->active_scan_mask)) {
adc_humidity = get_unaligned_be16(&data->buf[6]);
if (adc_humidity == BMP280_HUMIDITY_SKIPPED) {
dev_err(data->dev, "reading humidity skipped\n");
goto out;
}
data->sensor_data[2] = bme280_compensate_humidity(data, adc_humidity, t_fine);
}
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 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,
@ -830,7 +1052,8 @@ const struct bmp280_chip_info bmp280_chip_info = {
.regmap_config = &bmp280_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
.num_channels = 2,
.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),
@ -850,10 +1073,17 @@ const struct bmp280_chip_info bmp280_chip_info = {
.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,
.buffer_handler = bmp280_buffer_handler,
};
EXPORT_SYMBOL_NS(bmp280_chip_info, IIO_BMP280);
@ -877,6 +1107,7 @@ static int bme280_chip_config(struct bmp280_data *data)
}
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,
@ -884,8 +1115,9 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_chip_id = ARRAY_SIZE(bme280_chip_ids),
.regmap_config = &bmp280_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
.num_channels = 3,
.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),
@ -899,11 +1131,20 @@ const struct bmp280_chip_info bme280_chip_info = {
.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,
.buffer_handler = bmp280_buffer_handler,
};
EXPORT_SYMBOL_NS(bme280_chip_info, IIO_BMP280);
@ -958,7 +1199,7 @@ static int bmp380_read_temp_adc(struct bmp280_data *data, u32 *adc_temp)
int ret;
ret = regmap_bulk_read(data->regmap, BMP380_REG_TEMP_XLSB,
data->buf, sizeof(data->buf));
data->buf, BMP280_NUM_TEMP_BYTES);
if (ret) {
dev_err(data->dev, "failed to read temperature\n");
return ret;
@ -1027,7 +1268,7 @@ static int bmp380_read_press_adc(struct bmp280_data *data, u32 *adc_press)
int ret;
ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB,
data->buf, sizeof(data->buf));
data->buf, BMP280_NUM_PRESS_BYTES);
if (ret) {
dev_err(data->dev, "failed to read pressure\n");
return ret;
@ -1091,9 +1332,8 @@ static u32 bmp380_compensate_press(struct bmp280_data *data,
return comp_press;
}
static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2)
static int bmp380_read_temp(struct bmp280_data *data, s32 *comp_temp)
{
s32 comp_temp;
u32 adc_temp;
int ret;
@ -1101,15 +1341,14 @@ static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2)
if (ret)
return ret;
comp_temp = bmp380_compensate_temp(data, adc_temp);
*comp_temp = bmp380_compensate_temp(data, adc_temp);
*val = comp_temp * 10;
return IIO_VAL_INT;
return 0;
}
static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2)
static int bmp380_read_press(struct bmp280_data *data, u32 *comp_press)
{
u32 adc_press, comp_press, t_fine;
u32 adc_press, t_fine;
int ret;
ret = bmp380_get_t_fine(data, &t_fine);
@ -1120,12 +1359,9 @@ static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2)
if (ret)
return ret;
comp_press = bmp380_compensate_press(data, adc_press, t_fine);
*comp_press = bmp380_compensate_press(data, adc_press, t_fine);
*val = comp_press;
*val2 = 100000;
return IIO_VAL_FRACTIONAL;
return 0;
}
static int bmp380_read_calib(struct bmp280_data *data)
@ -1293,9 +1529,58 @@ static int bmp380_chip_config(struct bmp280_data *data)
return 0;
}
static irqreturn_t bmp380_buffer_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bmp280_data *data = iio_priv(indio_dev);
s32 adc_temp, adc_press, t_fine;
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;
}
data->sensor_data[1] = 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);
data->sensor_data[0] = bmp380_compensate_press(data, adc_press, t_fine);
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 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,
@ -1304,7 +1589,8 @@ const struct bmp280_chip_info bmp380_chip_info = {
.regmap_config = &bmp380_regmap_config,
.start_up_time = 2000,
.channels = bmp380_channels,
.num_channels = 2,
.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),
@ -1322,11 +1608,18 @@ const struct bmp280_chip_info bmp380_chip_info = {
.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,
.preinit = bmp380_preinit,
.buffer_handler = bmp380_buffer_handler,
};
EXPORT_SYMBOL_NS(bmp380_chip_info, IIO_BMP280);
@ -1442,58 +1735,44 @@ static int bmp580_nvm_operation(struct bmp280_data *data, bool is_write)
* for what is expected on IIO ABI.
*/
static int bmp580_read_temp(struct bmp280_data *data, int *val, int *val2)
static int bmp580_read_temp(struct bmp280_data *data, s32 *raw_temp)
{
s32 raw_temp;
int ret;
ret = regmap_bulk_read(data->regmap, BMP580_REG_TEMP_XLSB, data->buf,
sizeof(data->buf));
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;
}
raw_temp = get_unaligned_le24(data->buf);
if (raw_temp == BMP580_TEMP_SKIPPED) {
*raw_temp = get_unaligned_le24(data->buf);
if (*raw_temp == BMP580_TEMP_SKIPPED) {
dev_err(data->dev, "reading temperature skipped\n");
return -EIO;
}
/*
* Temperature is returned in Celsius degrees in fractional
* form down 2^16. We rescale by x1000 to return milli Celsius
* to respect IIO ABI.
*/
*val = raw_temp * 1000;
*val2 = 16;
return IIO_VAL_FRACTIONAL_LOG2;
return 0;
}
static int bmp580_read_press(struct bmp280_data *data, int *val, int *val2)
static int bmp580_read_press(struct bmp280_data *data, u32 *raw_press)
{
u32 raw_press;
int ret;
ret = regmap_bulk_read(data->regmap, BMP580_REG_PRESS_XLSB, data->buf,
sizeof(data->buf));
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;
}
raw_press = get_unaligned_le24(data->buf);
if (raw_press == BMP580_PRESS_SKIPPED) {
*raw_press = get_unaligned_le24(data->buf);
if (*raw_press == BMP580_PRESS_SKIPPED) {
dev_err(data->dev, "reading pressure skipped\n");
return -EIO;
}
/*
* Pressure is returned in Pascals in fractional form down 2^16.
* We rescale /1000 to convert to kilopascal to respect IIO ABI.
*/
*val = raw_press;
*val2 = 64000; /* 2^6 * 1000 */
return IIO_VAL_FRACTIONAL;
return 0;
}
static const int bmp580_odr_table[][2] = {
@ -1827,8 +2106,55 @@ static int bmp580_chip_config(struct bmp280_data *data)
return 0;
}
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);
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] = adc_temp;
/* 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 };
static const int bmp580_press_coeffs[] = { 1, 64000};
const struct bmp280_chip_info bmp580_chip_info = {
.id_reg = BMP580_REG_CHIP_ID,
@ -1837,7 +2163,8 @@ const struct bmp280_chip_info bmp580_chip_info = {
.regmap_config = &bmp580_regmap_config,
.start_up_time = 2000,
.channels = bmp380_channels,
.num_channels = 2,
.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),
@ -1855,10 +2182,17 @@ const struct bmp280_chip_info bmp580_chip_info = {
.num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp380_iir_filter_coeffs_avail),
.iir_filter_coeff_default = 2,
.temp_coeffs = bmp580_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL_LOG2,
.press_coeffs = bmp580_press_coeffs,
.press_coeffs_type = IIO_VAL_FRACTIONAL,
.chip_config = bmp580_chip_config,
.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);
@ -2010,9 +2344,8 @@ static s32 bmp180_compensate_temp(struct bmp280_data *data, u32 adc_temp)
return (bmp180_calc_t_fine(data, adc_temp) + 8) / 16;
}
static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2)
static int bmp180_read_temp(struct bmp280_data *data, s32 *comp_temp)
{
s32 comp_temp;
u32 adc_temp;
int ret;
@ -2020,10 +2353,9 @@ static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2)
if (ret)
return ret;
comp_temp = bmp180_compensate_temp(data, adc_temp);
*comp_temp = bmp180_compensate_temp(data, adc_temp);
*val = comp_temp * 100;
return IIO_VAL_INT;
return 0;
}
static int bmp180_read_press_adc(struct bmp280_data *data, u32 *adc_press)
@ -2039,7 +2371,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;
@ -2086,9 +2418,9 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, u32 adc_press,
return p + ((x1 + x2 + 3791) >> 4);
}
static int bmp180_read_press(struct bmp280_data *data, int *val, int *val2)
static int bmp180_read_press(struct bmp280_data *data, u32 *comp_press)
{
u32 comp_press, adc_press;
u32 adc_press;
s32 t_fine;
int ret;
@ -2100,12 +2432,9 @@ static int bmp180_read_press(struct bmp280_data *data, int *val, int *val2)
if (ret)
return ret;
comp_press = bmp180_compensate_press(data, adc_press, t_fine);
*comp_press = bmp180_compensate_press(data, adc_press, t_fine);
*val = comp_press;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
return 0;
}
static int bmp180_chip_config(struct bmp280_data *data)
@ -2113,9 +2442,41 @@ 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 };
static const int bmp180_temp_coeffs[] = { 100, 1 };
static const int bmp180_press_coeffs[] = { 1, 1000 };
const struct bmp280_chip_info bmp180_chip_info = {
.id_reg = BMP280_REG_ID,
@ -2124,7 +2485,8 @@ const struct bmp280_chip_info bmp180_chip_info = {
.regmap_config = &bmp180_regmap_config,
.start_up_time = 2000,
.channels = bmp280_channels,
.num_channels = 2,
.num_channels = ARRAY_SIZE(bmp280_channels),
.avail_scan_masks = bmp280_avail_scan_masks,
.oversampling_temp_avail = bmp180_oversampling_temp_avail,
.num_oversampling_temp_avail =
@ -2136,10 +2498,17 @@ const struct bmp280_chip_info bmp180_chip_info = {
ARRAY_SIZE(bmp180_oversampling_press_avail),
.oversampling_press_default = BMP180_MEAS_PRESS_8X,
.temp_coeffs = bmp180_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp180_press_coeffs,
.press_coeffs_type = IIO_VAL_FRACTIONAL,
.chip_config = bmp180_chip_config,
.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);
@ -2185,6 +2554,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;
}
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;
@ -2231,6 +2624,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;
@ -2316,6 +2710,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,
NULL);
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

View file

@ -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;
/*

View file

@ -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];
@ -424,6 +440,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;
@ -445,12 +462,21 @@ struct bmp280_chip_info {
int num_sampling_freq_avail;
int sampling_freq_default;
const int *temp_coeffs;
const int temp_coeffs_type;
const int *press_coeffs;
const int press_coeffs_type;
const int *humid_coeffs;
const int humid_coeffs_type;
int (*chip_config)(struct bmp280_data *data);
int (*read_temp)(struct bmp280_data *data, int *val, int *val2);
int (*read_press)(struct bmp280_data *data, int *val, int *val2);
int (*read_humid)(struct bmp280_data *data, int *val, int *val2);
int (*read_temp)(struct bmp280_data *data, s32 *adc_temp);
int (*read_press)(struct bmp280_data *data, u32 *adc_press);
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 */