summaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc/ad4130.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/ad4130.c')
-rw-r--r--drivers/iio/adc/ad4130.c139
1 files changed, 94 insertions, 45 deletions
diff --git a/drivers/iio/adc/ad4130.c b/drivers/iio/adc/ad4130.c
index de32cc9d18c5..0f4c9cd6c102 100644
--- a/drivers/iio/adc/ad4130.c
+++ b/drivers/iio/adc/ad4130.c
@@ -6,6 +6,7 @@
#include <linux/bitfield.h>
#include <linux/bitops.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
@@ -203,7 +204,7 @@ enum ad4130_mode {
AD4130_MODE_IDLE = 0b0100,
};
-enum ad4130_filter_mode {
+enum ad4130_filter_type {
AD4130_FILTER_SINC4,
AD4130_FILTER_SINC4_SINC1,
AD4130_FILTER_SINC3,
@@ -223,6 +224,10 @@ enum ad4130_pin_function {
AD4130_PIN_FN_VBIAS = BIT(3),
};
+/*
+ * If you make adaptations in this struct, you most likely also have to adapt
+ * ad4130_setup_info_eq(), too.
+ */
struct ad4130_setup_info {
unsigned int iout0_val;
unsigned int iout1_val;
@@ -230,7 +235,7 @@ struct ad4130_setup_info {
unsigned int pga;
unsigned int fs;
u32 ref_sel;
- enum ad4130_filter_mode filter_mode;
+ enum ad4130_filter_type filter_type;
bool ref_bufp;
bool ref_bufm;
};
@@ -251,7 +256,7 @@ struct ad4130_chan_info {
};
struct ad4130_filter_config {
- enum ad4130_filter_mode filter_mode;
+ enum ad4130_filter_type filter_type;
unsigned int odr_div;
unsigned int fs_max;
enum iio_available_type samp_freq_avail_type;
@@ -337,9 +342,9 @@ static const unsigned int ad4130_burnout_current_na_tbl[AD4130_BURNOUT_MAX] = {
[AD4130_BURNOUT_4000NA] = 4000,
};
-#define AD4130_VARIABLE_ODR_CONFIG(_filter_mode, _odr_div, _fs_max) \
+#define AD4130_VARIABLE_ODR_CONFIG(_filter_type, _odr_div, _fs_max) \
{ \
- .filter_mode = (_filter_mode), \
+ .filter_type = (_filter_type), \
.odr_div = (_odr_div), \
.fs_max = (_fs_max), \
.samp_freq_avail_type = IIO_AVAIL_RANGE, \
@@ -350,9 +355,9 @@ static const unsigned int ad4130_burnout_current_na_tbl[AD4130_BURNOUT_MAX] = {
}, \
}
-#define AD4130_FIXED_ODR_CONFIG(_filter_mode, _odr_div) \
+#define AD4130_FIXED_ODR_CONFIG(_filter_type, _odr_div) \
{ \
- .filter_mode = (_filter_mode), \
+ .filter_type = (_filter_type), \
.odr_div = (_odr_div), \
.fs_max = AD4130_FILTER_SELECT_MIN, \
.samp_freq_avail_type = IIO_AVAIL_LIST, \
@@ -374,7 +379,7 @@ static const struct ad4130_filter_config ad4130_filter_configs[] = {
AD4130_FIXED_ODR_CONFIG(AD4130_FILTER_SINC3_PF4, 148),
};
-static const char * const ad4130_filter_modes_str[] = {
+static const char * const ad4130_filter_types_str[] = {
[AD4130_FILTER_SINC4] = "sinc4",
[AD4130_FILTER_SINC4_SINC1] = "sinc4+sinc1",
[AD4130_FILTER_SINC3] = "sinc3",
@@ -591,6 +596,40 @@ static irqreturn_t ad4130_irq_handler(int irq, void *private)
return IRQ_HANDLED;
}
+static bool ad4130_setup_info_eq(struct ad4130_setup_info *a,
+ struct ad4130_setup_info *b)
+{
+ /*
+ * This is just to make sure that the comparison is adapted after
+ * struct ad4130_setup_info was changed.
+ */
+ static_assert(sizeof(*a) ==
+ sizeof(struct {
+ unsigned int iout0_val;
+ unsigned int iout1_val;
+ unsigned int burnout;
+ unsigned int pga;
+ unsigned int fs;
+ u32 ref_sel;
+ enum ad4130_filter_type filter_type;
+ bool ref_bufp;
+ bool ref_bufm;
+ }));
+
+ if (a->iout0_val != b->iout0_val ||
+ a->iout1_val != b->iout1_val ||
+ a->burnout != b->burnout ||
+ a->pga != b->pga ||
+ a->fs != b->fs ||
+ a->ref_sel != b->ref_sel ||
+ a->filter_type != b->filter_type ||
+ a->ref_bufp != b->ref_bufp ||
+ a->ref_bufm != b->ref_bufm)
+ return false;
+
+ return true;
+}
+
static int ad4130_find_slot(struct ad4130_state *st,
struct ad4130_setup_info *target_setup_info,
unsigned int *slot, bool *overwrite)
@@ -604,8 +643,7 @@ static int ad4130_find_slot(struct ad4130_state *st,
struct ad4130_slot_info *slot_info = &st->slots_info[i];
/* Immediately accept a matching setup info. */
- if (!memcmp(target_setup_info, &slot_info->setup,
- sizeof(*target_setup_info))) {
+ if (ad4130_setup_info_eq(target_setup_info, &slot_info->setup)) {
*slot = i;
return 0;
}
@@ -691,7 +729,7 @@ static int ad4130_write_slot_setup(struct ad4130_state *st,
if (ret)
return ret;
- val = FIELD_PREP(AD4130_FILTER_MODE_MASK, setup_info->filter_mode) |
+ val = FIELD_PREP(AD4130_FILTER_MODE_MASK, setup_info->filter_type) |
FIELD_PREP(AD4130_FILTER_SELECT_MASK, setup_info->fs);
ret = regmap_write(st->regmap, AD4130_FILTER_X_REG(slot), val);
@@ -835,11 +873,11 @@ static int ad4130_set_channel_enable(struct ad4130_state *st,
* (used in ad4130_fs_to_freq)
*/
-static void ad4130_freq_to_fs(enum ad4130_filter_mode filter_mode,
+static void ad4130_freq_to_fs(enum ad4130_filter_type filter_type,
int val, int val2, unsigned int *fs)
{
const struct ad4130_filter_config *filter_config =
- &ad4130_filter_configs[filter_mode];
+ &ad4130_filter_configs[filter_type];
u64 dividend, divisor;
int temp;
@@ -858,11 +896,11 @@ static void ad4130_freq_to_fs(enum ad4130_filter_mode filter_mode,
*fs = temp;
}
-static void ad4130_fs_to_freq(enum ad4130_filter_mode filter_mode,
+static void ad4130_fs_to_freq(enum ad4130_filter_type filter_type,
unsigned int fs, int *val, int *val2)
{
const struct ad4130_filter_config *filter_config =
- &ad4130_filter_configs[filter_mode];
+ &ad4130_filter_configs[filter_type];
unsigned int dividend, divisor;
u64 temp;
@@ -874,7 +912,7 @@ static void ad4130_fs_to_freq(enum ad4130_filter_mode filter_mode,
*val = div_u64_rem(temp, NANO, val2);
}
-static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
+static int ad4130_set_filter_type(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
unsigned int val)
{
@@ -882,17 +920,17 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
unsigned int channel = chan->scan_index;
struct ad4130_chan_info *chan_info = &st->chans_info[channel];
struct ad4130_setup_info *setup_info = &chan_info->setup;
- enum ad4130_filter_mode old_filter_mode;
+ enum ad4130_filter_type old_filter_type;
int freq_val, freq_val2;
unsigned int old_fs;
int ret = 0;
guard(mutex)(&st->lock);
- if (setup_info->filter_mode == val)
+ if (setup_info->filter_type == val)
return 0;
old_fs = setup_info->fs;
- old_filter_mode = setup_info->filter_mode;
+ old_filter_type = setup_info->filter_type;
/*
* When switching between filter modes, try to match the ODR as
@@ -900,48 +938,55 @@ static int ad4130_set_filter_mode(struct iio_dev *indio_dev,
* using the old filter mode, then convert it back into FS using
* the new filter mode.
*/
- ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+ ad4130_fs_to_freq(setup_info->filter_type, setup_info->fs,
&freq_val, &freq_val2);
ad4130_freq_to_fs(val, freq_val, freq_val2, &setup_info->fs);
- setup_info->filter_mode = val;
+ setup_info->filter_type = val;
ret = ad4130_write_channel_setup(st, channel, false);
if (ret) {
setup_info->fs = old_fs;
- setup_info->filter_mode = old_filter_mode;
+ setup_info->filter_type = old_filter_type;
return ret;
}
return 0;
}
-static int ad4130_get_filter_mode(struct iio_dev *indio_dev,
+static int ad4130_get_filter_type(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct ad4130_state *st = iio_priv(indio_dev);
unsigned int channel = chan->scan_index;
struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
- enum ad4130_filter_mode filter_mode;
+ enum ad4130_filter_type filter_type;
guard(mutex)(&st->lock);
- filter_mode = setup_info->filter_mode;
+ filter_type = setup_info->filter_type;
- return filter_mode;
+ return filter_type;
}
-static const struct iio_enum ad4130_filter_mode_enum = {
- .items = ad4130_filter_modes_str,
- .num_items = ARRAY_SIZE(ad4130_filter_modes_str),
- .set = ad4130_set_filter_mode,
- .get = ad4130_get_filter_mode,
+static const struct iio_enum ad4130_filter_type_enum = {
+ .items = ad4130_filter_types_str,
+ .num_items = ARRAY_SIZE(ad4130_filter_types_str),
+ .set = ad4130_set_filter_type,
+ .get = ad4130_get_filter_type,
};
-static const struct iio_chan_spec_ext_info ad4130_filter_mode_ext_info[] = {
- IIO_ENUM("filter_mode", IIO_SEPARATE, &ad4130_filter_mode_enum),
+static const struct iio_chan_spec_ext_info ad4130_ext_info[] = {
+ /*
+ * `filter_type` is the standardized IIO ABI for digital filtering.
+ * `filter_mode` is just kept for backwards compatibility.
+ */
+ IIO_ENUM("filter_mode", IIO_SEPARATE, &ad4130_filter_type_enum),
IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_TYPE,
- &ad4130_filter_mode_enum),
+ &ad4130_filter_type_enum),
+ IIO_ENUM("filter_type", IIO_SEPARATE, &ad4130_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE,
+ &ad4130_filter_type_enum),
{ }
};
@@ -955,7 +1000,7 @@ static const struct iio_chan_spec ad4130_channel_template = {
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
- .ext_info = ad4130_filter_mode_ext_info,
+ .ext_info = ad4130_ext_info,
.scan_type = {
.sign = 'u',
.endianness = IIO_BE,
@@ -1005,7 +1050,7 @@ static int ad4130_set_channel_freq(struct ad4130_state *st,
guard(mutex)(&st->lock);
old_fs = setup_info->fs;
- ad4130_freq_to_fs(setup_info->filter_mode, val, val2, &fs);
+ ad4130_freq_to_fs(setup_info->filter_type, val, val2, &fs);
if (fs == setup_info->fs)
return 0;
@@ -1060,13 +1105,11 @@ static int _ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
static int ad4130_read_sample(struct iio_dev *indio_dev, unsigned int channel,
int *val)
{
- iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
- struct ad4130_state *st = iio_priv(indio_dev);
+ struct ad4130_state *st = iio_priv(indio_dev);
- guard(mutex)(&st->lock);
- return _ad4130_read_sample(indio_dev, channel, val);
- }
- unreachable();
+ guard(mutex)(&st->lock);
+
+ return _ad4130_read_sample(indio_dev, channel, val);
}
static int ad4130_read_raw(struct iio_dev *indio_dev,
@@ -1076,10 +1119,16 @@ static int ad4130_read_raw(struct iio_dev *indio_dev,
struct ad4130_state *st = iio_priv(indio_dev);
unsigned int channel = chan->scan_index;
struct ad4130_setup_info *setup_info = &st->chans_info[channel].setup;
+ int ret;
switch (info) {
case IIO_CHAN_INFO_RAW:
- return ad4130_read_sample(indio_dev, channel, val);
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad4130_read_sample(indio_dev, channel, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
case IIO_CHAN_INFO_SCALE: {
guard(mutex)(&st->lock);
*val = st->scale_tbls[setup_info->ref_sel][setup_info->pga][0];
@@ -1093,7 +1142,7 @@ static int ad4130_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ: {
guard(mutex)(&st->lock);
- ad4130_fs_to_freq(setup_info->filter_mode, setup_info->fs,
+ ad4130_fs_to_freq(setup_info->filter_type, setup_info->fs,
val, val2);
return IIO_VAL_INT_PLUS_NANO;
@@ -1123,7 +1172,7 @@ static int ad4130_read_avail(struct iio_dev *indio_dev,
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SAMP_FREQ:
scoped_guard(mutex, &st->lock) {
- filter_config = &ad4130_filter_configs[setup_info->filter_mode];
+ filter_config = &ad4130_filter_configs[setup_info->filter_type];
}
*vals = (int *)filter_config->samp_freq_avail;