Compare commits
10 commits
9d7216f74b
...
6c183eed99
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c183eed99 | ||
|
|
6c46802cc0 | ||
|
|
caeb12568b | ||
|
|
5e97c1b1b2 | ||
|
|
535dc90900 | ||
|
|
2cadb27e98 | ||
|
|
a4f0d5b69b | ||
|
|
5ff1aadd15 | ||
|
|
502ff77570 | ||
|
|
c1da715c14 |
9 changed files with 884 additions and 157 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue