iio: accel: adxl372: introduce chip_info structure

Introduce a chip_info structure to parameterize device-specific
properties such as ODR/bandwidth frequency tables, activity/inactivity
timer scale factors, and the maximum ODR value. This refactors the
driver to use chip_info lookups instead of hardcoded values, preparing
the driver to support multiple device variants.

The sampling_frequency and filter_low_pass_3db_frequency available
attributes are switched from custom sysfs callbacks to read_avail()
based handling via info_mask_shared_by_type_available. This enforces
consistent formatting through the IIO framework and makes the values
accessible to in-kernel consumers.

The SPI/I2C probe functions are updated to pass a chip_info pointer
instead of a device name string.

No functional change intended.

Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
Antoniu Miclaus 2026-03-21 12:04:56 +02:00 committed by Jonathan Cameron
parent 8c7440c686
commit 23d742859a
4 changed files with 112 additions and 75 deletions

View File

@ -181,6 +181,7 @@ enum adxl372_odr {
ADXL372_ODR_1600HZ,
ADXL372_ODR_3200HZ,
ADXL372_ODR_6400HZ,
ADXL372_ODR_NUM
};
enum adxl372_bandwidth {
@ -215,14 +216,35 @@ enum adxl372_fifo_mode {
ADXL372_FIFO_OLD_SAVED
};
static const int adxl372_samp_freq_tbl[5] = {
400, 800, 1600, 3200, 6400,
static const int adxl372_samp_freq_tbl[ADXL372_ODR_NUM] = {
[ADXL372_ODR_400HZ] = 400,
[ADXL372_ODR_800HZ] = 800,
[ADXL372_ODR_1600HZ] = 1600,
[ADXL372_ODR_3200HZ] = 3200,
[ADXL372_ODR_6400HZ] = 6400,
};
static const int adxl372_bw_freq_tbl[5] = {
200, 400, 800, 1600, 3200,
static const int adxl372_bw_freq_tbl[ADXL372_ODR_NUM] = {
[ADXL372_BW_200HZ] = 200,
[ADXL372_BW_400HZ] = 400,
[ADXL372_BW_800HZ] = 800,
[ADXL372_BW_1600HZ] = 1600,
[ADXL372_BW_3200HZ] = 3200,
};
const struct adxl372_chip_info adxl372_chip_info = {
.name = "adxl372",
.samp_freq_tbl = adxl372_samp_freq_tbl,
.bw_freq_tbl = adxl372_bw_freq_tbl,
.num_freqs = ARRAY_SIZE(adxl372_samp_freq_tbl),
.act_time_scale_us = 3300,
.act_time_scale_low_us = 6600,
.inact_time_scale_ms = 13,
.inact_time_scale_low_ms = 26,
.max_odr = ADXL372_ODR_6400HZ,
};
EXPORT_SYMBOL_NS_GPL(adxl372_chip_info, "IIO_ADXL372");
struct adxl372_axis_lookup {
unsigned int bits;
enum adxl372_fifo_format fifo_format;
@ -258,8 +280,12 @@ static const struct iio_event_spec adxl372_events[] = {
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
.info_mask_shared_by_type = \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.info_mask_shared_by_type_available = \
BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = index, \
.scan_type = { \
@ -280,6 +306,7 @@ static const struct iio_chan_spec adxl372_channels[] = {
};
struct adxl372_state {
const struct adxl372_chip_info *chip_info;
int irq;
struct device *dev;
struct regmap *regmap;
@ -468,13 +495,14 @@ static int adxl372_set_activity_time_ms(struct adxl372_state *st,
int ret;
/*
* 3.3 ms per code is the scale factor of the TIME_ACT register for
* ODR = 6400 Hz. It is 6.6 ms per code for ODR = 3200 Hz and below.
* The scale factor of the TIME_ACT register depends on the ODR.
* A higher scale factor is used at the maximum ODR and a lower
* one at all other rates.
*/
if (st->odr == ADXL372_ODR_6400HZ)
scale_factor = 3300;
if (st->odr == st->chip_info->max_odr)
scale_factor = st->chip_info->act_time_scale_us;
else
scale_factor = 6600;
scale_factor = st->chip_info->act_time_scale_low_us;
reg_val = DIV_ROUND_CLOSEST(act_time_ms * 1000, scale_factor);
@ -498,13 +526,14 @@ static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
int ret;
/*
* 13 ms per code is the scale factor of the TIME_INACT register for
* ODR = 6400 Hz. It is 26 ms per code for ODR = 3200 Hz and below.
* The scale factor of the TIME_INACT register depends on the ODR.
* A higher scale factor is used at the maximum ODR and a lower
* one at all other rates.
*/
if (st->odr == ADXL372_ODR_6400HZ)
scale_factor = 13;
if (st->odr == st->chip_info->max_odr)
scale_factor = st->chip_info->inact_time_scale_ms;
else
scale_factor = 26;
scale_factor = st->chip_info->inact_time_scale_low_ms;
res = DIV_ROUND_CLOSEST(inact_time_ms, scale_factor);
reg_val_h = (res >> 8) & 0xFF;
@ -714,7 +743,7 @@ static int adxl372_setup(struct adxl372_state *st)
if (ret < 0)
return ret;
ret = adxl372_set_odr(st, ADXL372_ODR_6400HZ);
ret = adxl372_set_odr(st, st->chip_info->max_odr);
if (ret < 0)
return ret;
@ -774,10 +803,10 @@ static int adxl372_read_raw(struct iio_dev *indio_dev,
*val2 = ADXL372_USCALE;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
*val = adxl372_samp_freq_tbl[st->odr];
*val = st->chip_info->samp_freq_tbl[st->odr];
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = adxl372_bw_freq_tbl[st->bw];
*val = st->chip_info->bw_freq_tbl[st->bw];
return IIO_VAL_INT;
}
@ -793,23 +822,17 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
odr_index = adxl372_find_closest_match(adxl372_samp_freq_tbl,
ARRAY_SIZE(adxl372_samp_freq_tbl),
val);
odr_index = adxl372_find_closest_match(st->chip_info->samp_freq_tbl,
st->chip_info->num_freqs,
val);
ret = adxl372_set_odr(st, odr_index);
if (ret < 0)
return ret;
/*
* The timer period depends on the ODR selected.
* At 3200 Hz and below, it is 6.6 ms; at 6400 Hz, it is 3.3 ms
*/
/* Recalculate activity time as the timer period depends on ODR */
ret = adxl372_set_activity_time_ms(st, st->act_time_ms);
if (ret < 0)
return ret;
/*
* The timer period depends on the ODR selected.
* At 3200 Hz and below, it is 26 ms; at 6400 Hz, it is 13 ms
*/
/* Recalculate inactivity time as the timer period depends on ODR */
ret = adxl372_set_inactivity_time_ms(st, st->inact_time_ms);
if (ret < 0)
return ret;
@ -822,9 +845,9 @@ static int adxl372_write_raw(struct iio_dev *indio_dev,
return ret;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
bw_index = adxl372_find_closest_match(adxl372_bw_freq_tbl,
ARRAY_SIZE(adxl372_bw_freq_tbl),
val);
bw_index = adxl372_find_closest_match(st->chip_info->bw_freq_tbl,
st->chip_info->num_freqs,
val);
return adxl372_set_bandwidth(st, bw_index);
default:
return -EINVAL;
@ -954,24 +977,6 @@ static int adxl372_write_event_config(struct iio_dev *indio_dev, const struct ii
return adxl372_set_interrupts(st, st->int1_bitmask, 0);
}
static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adxl372_state *st = iio_priv(indio_dev);
int i;
size_t len = 0;
for (i = 0; i <= st->odr; i++)
len += scnprintf(buf + len, PAGE_SIZE - len,
"%d ", adxl372_bw_freq_tbl[i]);
buf[len - 1] = '\n';
return len;
}
static ssize_t adxl372_get_fifo_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
@ -1139,25 +1144,38 @@ static const struct iio_trigger_ops adxl372_peak_data_trigger_ops = {
.set_trigger_state = adxl372_peak_dready_trig_set_state,
};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
0444, adxl372_show_filter_freq_avail, NULL, 0);
static int adxl372_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
struct adxl372_state *st = iio_priv(indio_dev);
static struct attribute *adxl372_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
&iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group adxl372_attrs_group = {
.attrs = adxl372_attributes,
};
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*vals = st->chip_info->samp_freq_tbl;
*type = IIO_VAL_INT;
*length = st->chip_info->num_freqs;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*vals = st->chip_info->bw_freq_tbl;
*type = IIO_VAL_INT;
/*
* Bandwidth cannot exceed half the sampling frequency
* (Nyquist), so limit available values based on current ODR.
*/
*length = st->odr + 1;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static const struct iio_info adxl372_info = {
.validate_trigger = &adxl372_validate_trigger,
.attrs = &adxl372_attrs_group,
.read_raw = adxl372_read_raw,
.write_raw = adxl372_write_raw,
.read_avail = adxl372_read_avail,
.read_event_config = adxl372_read_event_config,
.write_event_config = adxl372_write_event_config,
.read_event_value = adxl372_read_event_value,
@ -1173,7 +1191,7 @@ bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg)
EXPORT_SYMBOL_NS_GPL(adxl372_readable_noinc_reg, "IIO_ADXL372");
int adxl372_probe(struct device *dev, struct regmap *regmap,
int irq, const char *name)
int irq, const struct adxl372_chip_info *chip_info)
{
struct iio_dev *indio_dev;
struct adxl372_state *st;
@ -1189,13 +1207,14 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
st->dev = dev;
st->regmap = regmap;
st->irq = irq;
st->chip_info = chip_info;
mutex_init(&st->threshold_m);
indio_dev->channels = adxl372_channels;
indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
indio_dev->available_scan_masks = adxl372_channel_masks;
indio_dev->name = name;
indio_dev->name = chip_info->name;
indio_dev->info = &adxl372_info;
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;

View File

@ -10,8 +10,22 @@
#define ADXL372_REVID 0x03
struct adxl372_chip_info {
const char *name;
const int *samp_freq_tbl;
const int *bw_freq_tbl;
unsigned int num_freqs;
unsigned int act_time_scale_us;
unsigned int act_time_scale_low_us;
unsigned int inact_time_scale_ms;
unsigned int inact_time_scale_low_ms;
unsigned int max_odr;
};
extern const struct adxl372_chip_info adxl372_chip_info;
int adxl372_probe(struct device *dev, struct regmap *regmap,
int irq, const char *name);
int irq, const struct adxl372_chip_info *chip_info);
bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg);
#endif /* _ADXL372_H_ */

View File

@ -20,11 +20,13 @@ static const struct regmap_config adxl372_regmap_config = {
static int adxl372_i2c_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct adxl372_chip_info *chip_info;
struct regmap *regmap;
unsigned int regval;
int ret;
chip_info = i2c_get_match_data(client);
regmap = devm_regmap_init_i2c(client, &adxl372_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
@ -38,17 +40,17 @@ static int adxl372_i2c_probe(struct i2c_client *client)
dev_warn(&client->dev,
"I2C might not work properly with other devices on the bus");
return adxl372_probe(&client->dev, regmap, client->irq, id->name);
return adxl372_probe(&client->dev, regmap, client->irq, chip_info);
}
static const struct i2c_device_id adxl372_i2c_id[] = {
{ "adxl372" },
{ "adxl372", (kernel_ulong_t)&adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
static const struct of_device_id adxl372_of_match[] = {
{ .compatible = "adi,adxl372" },
{ .compatible = "adi,adxl372", .data = &adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl372_of_match);

View File

@ -22,24 +22,26 @@ static const struct regmap_config adxl372_spi_regmap_config = {
static int adxl372_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
const struct adxl372_chip_info *chip_info;
struct regmap *regmap;
chip_info = spi_get_device_match_data(spi);
regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return adxl372_probe(&spi->dev, regmap, spi->irq, id->name);
return adxl372_probe(&spi->dev, regmap, spi->irq, chip_info);
}
static const struct spi_device_id adxl372_spi_id[] = {
{ "adxl372", 0 },
{ "adxl372", (kernel_ulong_t)&adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
static const struct of_device_id adxl372_of_match[] = {
{ .compatible = "adi,adxl372" },
{ .compatible = "adi,adxl372", .data = &adxl372_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, adxl372_of_match);