iio: accel: adxl345: extend sample frequency adjustments

Introduce enums and functions to work with the sample frequency
adjustments. Let the sample frequency adjust via IIO and configure
a reasonable default.

Replace the old static sample frequency handling. During adjustment of
bw registers, measuring is disabled and afterwards enabled again.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
Link: https://patch.msgid.link/20250510224405.17910-2-l.rubusch@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
Lothar Rubusch
2025-06-09 07:45:35 +01:00
committed by Jonathan Cameron
parent 9182f3b4c3
commit 93ddd06492
2 changed files with 118 additions and 34 deletions
+1 -1
View File
@@ -69,7 +69,7 @@
* BW_RATE bits - Bandwidth and output data rate. The default value is
* 0x0A, which translates to a 100 Hz output data rate
*/
#define ADXL345_BW_RATE GENMASK(3, 0)
#define ADXL345_BW_RATE_MSK GENMASK(3, 0)
#define ADXL345_BW_LOW_POWER BIT(4)
#define ADXL345_BASE_RATE_NANO_HZ 97656250LL
+117 -33
View File
@@ -64,6 +64,45 @@ static const unsigned int adxl345_tap_time_reg[] = {
[ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR,
};
enum adxl345_odr {
ADXL345_ODR_0P10HZ = 0,
ADXL345_ODR_0P20HZ,
ADXL345_ODR_0P39HZ,
ADXL345_ODR_0P78HZ,
ADXL345_ODR_1P56HZ,
ADXL345_ODR_3P13HZ,
ADXL345_ODR_6P25HZ,
ADXL345_ODR_12P50HZ,
ADXL345_ODR_25HZ,
ADXL345_ODR_50HZ,
ADXL345_ODR_100HZ,
ADXL345_ODR_200HZ,
ADXL345_ODR_400HZ,
ADXL345_ODR_800HZ,
ADXL345_ODR_1600HZ,
ADXL345_ODR_3200HZ,
};
/* Certain features recommend 12.5 Hz - 400 Hz ODR */
static const int adxl345_odr_tbl[][2] = {
[ADXL345_ODR_0P10HZ] = { 0, 97000 },
[ADXL345_ODR_0P20HZ] = { 0, 195000 },
[ADXL345_ODR_0P39HZ] = { 0, 390000 },
[ADXL345_ODR_0P78HZ] = { 0, 781000 },
[ADXL345_ODR_1P56HZ] = { 1, 562000 },
[ADXL345_ODR_3P13HZ] = { 3, 125000 },
[ADXL345_ODR_6P25HZ] = { 6, 250000 },
[ADXL345_ODR_12P50HZ] = { 12, 500000 },
[ADXL345_ODR_25HZ] = { 25, 0 },
[ADXL345_ODR_50HZ] = { 50, 0 },
[ADXL345_ODR_100HZ] = { 100, 0 },
[ADXL345_ODR_200HZ] = { 200, 0 },
[ADXL345_ODR_400HZ] = { 400, 0 },
[ADXL345_ODR_800HZ] = { 800, 0 },
[ADXL345_ODR_1600HZ] = { 1600, 0 },
[ADXL345_ODR_3200HZ] = { 3200, 0 },
};
struct adxl345_state {
const struct adxl345_chip_info *info;
struct regmap *regmap;
@@ -107,6 +146,7 @@ static struct iio_event_spec adxl345_events[] = {
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = (index), \
.scan_type = { \
.sign = 's', \
@@ -383,14 +423,53 @@ static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int,
return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us);
}
static int adxl345_find_odr(struct adxl345_state *st, int val,
int val2, enum adxl345_odr *odr)
{
int i;
for (i = 0; i < ARRAY_SIZE(adxl345_odr_tbl); i++) {
if (val == adxl345_odr_tbl[i][0] &&
val2 == adxl345_odr_tbl[i][1]) {
*odr = i;
return 0;
}
}
return -EINVAL;
}
static int adxl345_set_odr(struct adxl345_state *st, enum adxl345_odr odr)
{
return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE,
ADXL345_BW_RATE_MSK,
FIELD_PREP(ADXL345_BW_RATE_MSK, odr));
}
static int adxl345_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type,
int *length, long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*vals = (int *)adxl345_odr_tbl;
*type = IIO_VAL_INT_PLUS_MICRO;
*length = ARRAY_SIZE(adxl345_odr_tbl) * 2;
return IIO_AVAIL_LIST;
}
return -EINVAL;
}
static int adxl345_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct adxl345_state *st = iio_priv(indio_dev);
__le16 accel;
long long samp_freq_nhz;
unsigned int regval;
enum adxl345_odr odr;
int ret;
switch (mask) {
@@ -428,12 +507,10 @@ static int adxl345_read_raw(struct iio_dev *indio_dev,
ret = regmap_read(st->regmap, ADXL345_REG_BW_RATE, &regval);
if (ret)
return ret;
samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<
(regval & ADXL345_BW_RATE);
*val = div_s64_rem(samp_freq_nhz, NANOHZ_PER_HZ, val2);
return IIO_VAL_INT_PLUS_NANO;
odr = FIELD_GET(ADXL345_BW_RATE_MSK, regval);
*val = adxl345_odr_tbl[odr][0];
*val2 = adxl345_odr_tbl[odr][1];
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
@@ -444,7 +521,12 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct adxl345_state *st = iio_priv(indio_dev);
s64 n;
enum adxl345_odr odr;
int ret;
ret = adxl345_set_measure_en(st, false);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
@@ -452,20 +534,26 @@ static int adxl345_write_raw(struct iio_dev *indio_dev,
* 8-bit resolution at +/- 2g, that is 4x accel data scale
* factor
*/
return regmap_write(st->regmap,
ADXL345_REG_OFS_AXIS(chan->address),
val / 4);
ret = regmap_write(st->regmap,
ADXL345_REG_OFS_AXIS(chan->address),
val / 4);
if (ret)
return ret;
break;
case IIO_CHAN_INFO_SAMP_FREQ:
n = div_s64(val * NANOHZ_PER_HZ + val2,
ADXL345_BASE_RATE_NANO_HZ);
ret = adxl345_find_odr(st, val, val2, &odr);
if (ret)
return ret;
return regmap_update_bits(st->regmap, ADXL345_REG_BW_RATE,
ADXL345_BW_RATE,
clamp_val(ilog2(n), 0,
ADXL345_BW_RATE));
ret = adxl345_set_odr(st, odr);
if (ret)
return ret;
break;
default:
return -EINVAL;
}
return -EINVAL;
return adxl345_set_measure_en(st, true);
}
static int adxl345_read_event_config(struct iio_dev *indio_dev,
@@ -654,7 +742,7 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_NANO;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -667,19 +755,6 @@ static void adxl345_powerdown(void *ptr)
adxl345_set_measure_en(st, false);
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
"0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"
);
static struct attribute *adxl345_attrs[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
static const struct attribute_group adxl345_attrs_group = {
.attrs = adxl345_attrs,
};
static int adxl345_set_fifo(struct adxl345_state *st)
{
unsigned int intio;
@@ -931,9 +1006,9 @@ err:
}
static const struct iio_info adxl345_info = {
.attrs = &adxl345_attrs_group,
.read_raw = adxl345_read_raw,
.write_raw = adxl345_write_raw,
.read_avail = adxl345_read_avail,
.write_raw_get_fmt = adxl345_write_raw_get_fmt,
.read_event_config = adxl345_read_event_config,
.write_event_config = adxl345_write_event_config,
@@ -999,6 +1074,15 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
indio_dev->available_scan_masks = adxl345_scan_masks;
/*
* Using I2C at 100kHz would limit the maximum ODR to 200Hz, operation
* at an output rate above the recommended maximum may result in
* undesired behavior.
*/
ret = adxl345_set_odr(st, ADXL345_ODR_200HZ);
if (ret)
return ret;
/* Reset interrupts at start up */
ret = regmap_write(st->regmap, ADXL345_REG_INT_ENABLE, 0x00);
if (ret)