@@ -20,6 +20,7 @@
#include <linux/regulator/driver.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
+#include <linux/util_macros.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -75,11 +76,15 @@
#define AD7768_PWR_PWRMODE(x) FIELD_PREP(AD7768_PWR_PWRMODE_MSK, x)
/* AD7768_REG_DIGITAL_FILTER */
-#define AD7768_DIG_FIL_FIL_MSK GENMASK(6, 4)
+#define AD7768_DIG_FIL_FIL_MSK GENMASK(7, 4)
#define AD7768_DIG_FIL_FIL(x) FIELD_PREP(AD7768_DIG_FIL_FIL_MSK, x)
#define AD7768_DIG_FIL_DEC_MSK GENMASK(2, 0)
#define AD7768_DIG_FIL_DEC_RATE(x) FIELD_PREP(AD7768_DIG_FIL_DEC_MSK, x)
+/* AD7768_SINC3_DEC_RATE */
+#define AD7768_SINC3_DEC_RATE_MSB_MSK GENMASK(12, 8)
+#define AD7768_SINC3_DEC_RATE_LSB_MSK GENMASK(7, 0)
+
/* AD7768_REG_CONVERSION */
#define AD7768_CONV_MODE_MSK GENMASK(2, 0)
#define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x)
@@ -124,22 +129,20 @@ enum ad7768_mclk_div {
AD7768_MCLK_DIV_2
};
-enum ad7768_dec_rate {
- AD7768_DEC_RATE_32 = 0,
- AD7768_DEC_RATE_64 = 1,
- AD7768_DEC_RATE_128 = 2,
- AD7768_DEC_RATE_256 = 3,
- AD7768_DEC_RATE_512 = 4,
- AD7768_DEC_RATE_1024 = 5,
- AD7768_DEC_RATE_8 = 9,
- AD7768_DEC_RATE_16 = 10
+enum ad7768_filter_type {
+ AD7768_FILTER_SINC5,
+ AD7768_FILTER_SINC3,
+ AD7768_FILTER_WIDEBAND,
+ AD7768_FILTER_SINC3_REJ60,
};
-struct ad7768_clk_configuration {
- enum ad7768_mclk_div mclk_div;
- enum ad7768_dec_rate dec_rate;
- unsigned int clk_div;
- enum ad7768_pwrmode pwrmode;
+enum ad7768_filter_regval {
+ AD7768_FILTER_REGVAL_SINC5 = 0,
+ AD7768_FILTER_REGVAL_SINC5_X8 = 1,
+ AD7768_FILTER_REGVAL_SINC5_X16 = 2,
+ AD7768_FILTER_REGVAL_SINC3 = 3,
+ AD7768_FILTER_REGVAL_WIDEBAND = 4,
+ AD7768_FILTER_REGVAL_SINC3_REJ60 = 11,
};
enum ad7768_scan_type {
@@ -151,18 +154,40 @@ static const int ad7768_mclk_div_rates[4] = {
16, 8, 4, 2,
};
-static const struct ad7768_clk_configuration ad7768_clk_config[] = {
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_32, 64, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_64, 128, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_128, 256, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_128, 512, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_256, 1024, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_512, 2048, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_1024, 4096, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_8, AD7768_DEC_RATE_1024, 8192, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE },
+static const int ad7768_dec_rate_values[8] = {
+ 8, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+/* Decimation Rate range for each filter type */
+static const int ad7768_dec_rate_range[][3] = {
+ [AD7768_FILTER_SINC5] = { 8, 8, 1024 },
+ [AD7768_FILTER_SINC3] = { 32, 32, 163840 },
+ [AD7768_FILTER_WIDEBAND] = { 32, 32, 1024 },
+ [AD7768_FILTER_SINC3_REJ60] = { 32, 32, 163840 },
+};
+
+/*
+ * The AD7768-1 supports three primary filter types:
+ * Sinc5, Sinc3, and Wideband.
+ * However, the filter register values can also encode
+ * additional parameters such as decimation rates and
+ * 60Hz rejection. This utility function separates the
+ * filter type from these parameters.
+ */
+static const int ad7768_filter_regval_to_type[] = {
+ [AD7768_FILTER_REGVAL_SINC5] = AD7768_FILTER_SINC5,
+ [AD7768_FILTER_REGVAL_SINC5_X8] = AD7768_FILTER_SINC5,
+ [AD7768_FILTER_REGVAL_SINC5_X16] = AD7768_FILTER_SINC5,
+ [AD7768_FILTER_REGVAL_SINC3] = AD7768_FILTER_SINC3,
+ [AD7768_FILTER_REGVAL_WIDEBAND] = AD7768_FILTER_WIDEBAND,
+ [AD7768_FILTER_REGVAL_SINC3_REJ60] = AD7768_FILTER_SINC3_REJ60,
+};
+
+static const char * const ad7768_filter_enum[] = {
+ [AD7768_FILTER_SINC5] = "sinc5",
+ [AD7768_FILTER_SINC3] = "sinc3",
+ [AD7768_FILTER_WIDEBAND] = "wideband",
+ [AD7768_FILTER_SINC3_REJ60] = "sinc3+rej60"
};
static const struct iio_scan_type ad7768_scan_type[] = {
@@ -181,13 +206,34 @@ static const struct iio_scan_type ad7768_scan_type[] = {
},
};
+static int ad7768_get_fil_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan);
+static int ad7768_set_fil_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan, unsigned int filter);
+
+static const struct iio_enum ad7768_flt_type_iio_enum = {
+ .items = ad7768_filter_enum,
+ .num_items = ARRAY_SIZE(ad7768_filter_enum),
+ .set = ad7768_set_fil_type_attr,
+ .get = ad7768_get_fil_type_attr,
+};
+
+static struct iio_chan_spec_ext_info ad7768_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7768_flt_type_iio_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, &ad7768_flt_type_iio_enum),
+ { },
+};
+
static const struct iio_chan_spec ad7768_channels[] = {
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .ext_info = ad7768_ext_info,
.indexed = 1,
.channel = 0,
.scan_index = 0,
@@ -206,9 +252,11 @@ struct ad7768_state {
struct clk *mclk;
struct gpio_chip gpiochip;
unsigned int mclk_freq;
- unsigned int dec_rate;
+ unsigned int mclk_div;
+ unsigned int oversampling_ratio;
+ enum ad7768_filter_type filter_type;
unsigned int samp_freq;
- unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_clk_config)];
+ unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)];
struct completion completion;
struct iio_trigger *trig;
struct gpio_desc *gpio_sync_in;
@@ -307,6 +355,24 @@ static int ad7768_send_sync_pulse(struct ad7768_state *st)
return 0;
}
+static int ad7768_set_mclk_div(struct ad7768_state *st, unsigned int mclk_div)
+{
+ unsigned int mclk_div_value;
+
+ mclk_div_value = AD7768_PWR_MCLK_DIV(mclk_div);
+ /*
+ * Set power mode based on mclk_div value.
+ * ECO_MODE is only recommended for MCLK_DIV 16
+ */
+ mclk_div_value |= mclk_div > AD7768_MCLK_DIV_16 ?
+ AD7768_PWR_PWRMODE(AD7768_FAST_MODE) :
+ AD7768_PWR_PWRMODE(AD7768_ECO_MODE);
+
+ return regmap_update_bits(st->regmap, AD7768_REG_POWER_CLOCK,
+ AD7768_PWR_MCLK_DIV_MSK | AD7768_PWR_PWRMODE_MSK,
+ mclk_div_value);
+}
+
static int ad7768_set_mode(struct ad7768_state *st,
enum ad7768_conv_mode mode)
{
@@ -340,7 +406,7 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
* register provides 24-bit data, the precision is reduced by
* right-shifting the read value by 8 bits.
*/
- if (st->dec_rate == 8)
+ if (st->oversampling_ratio == 8)
readval >>= 8;
/*
@@ -387,22 +453,101 @@ static int ad7768_reg_access(struct iio_dev *indio_dev,
return ret;
}
-static int ad7768_set_dig_fil(struct ad7768_state *st,
- enum ad7768_dec_rate dec_rate)
+static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st,
+ unsigned int dec_rate)
{
- unsigned int mode;
+ unsigned int max_dec_rate;
+ u8 dec_rate_reg[2];
int ret;
- if (dec_rate == AD7768_DEC_RATE_8 || dec_rate == AD7768_DEC_RATE_16)
- mode = AD7768_DIG_FIL_FIL(dec_rate);
- else
- mode = AD7768_DIG_FIL_DEC_RATE(dec_rate);
+ /*
+ * Maximum dec_rate is limited by the MCLK_DIV value
+ * and by the ODR. The edge case is for MCLK_DIV = 2
+ * ODR = 50 SPS.
+ * max_dec_rate <= MCLK / (2 * 50)
+ */
+ max_dec_rate = st->mclk_freq / 100;
+ dec_rate = clamp_t(unsigned int, dec_rate, 32, max_dec_rate);
+ /*
+ * Calculate the equivalent value to sinc3 decimation ratio
+ * to be written on the SINC3_DECIMATION_RATE register:
+ * Value = (DEC_RATE / 32) -1
+ */
+ dec_rate = DIV_ROUND_UP(dec_rate, 32) - 1;
+ dec_rate_reg[0] = FIELD_GET(AD7768_SINC3_DEC_RATE_MSB_MSK, dec_rate);
+ dec_rate_reg[1] = FIELD_GET(AD7768_SINC3_DEC_RATE_LSB_MSK, dec_rate);
+ ret = regmap_bulk_write(st->regmap, AD7768_REG_SINC3_DEC_RATE_MSB,
+ dec_rate_reg, 2);
+ if (ret)
+ return ret;
- ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, mode);
- if (ret < 0)
+ st->oversampling_ratio = (dec_rate + 1) * 32;
+
+ return 0;
+}
+
+static int ad7768_configure_dig_fil(struct iio_dev *dev,
+ enum ad7768_filter_type filter_type,
+ unsigned int dec_rate)
+{
+ struct ad7768_state *st = iio_priv(dev);
+ unsigned int dec_rate_idx, dig_filter_regval;
+ int ret;
+
+ switch (filter_type) {
+ case AD7768_FILTER_SINC3:
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3);
+ break;
+ case AD7768_FILTER_SINC3_REJ60:
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3_REJ60);
+ break;
+ case AD7768_FILTER_WIDEBAND:
+ /* Skip decimations 8 and 16, not supported by the wideband filter */
+ dec_rate_idx = find_closest(dec_rate, &ad7768_dec_rate_values[2],
+ ARRAY_SIZE(ad7768_dec_rate_values) - 2);
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_WIDEBAND) |
+ AD7768_DIG_FIL_DEC_RATE(dec_rate_idx);
+ /* Correct the index offset */
+ dec_rate_idx += 2;
+ break;
+ case AD7768_FILTER_SINC5:
+ dec_rate_idx = find_closest(dec_rate, ad7768_dec_rate_values,
+ ARRAY_SIZE(ad7768_dec_rate_values));
+
+ /*
+ * Decimations 8 (idx 0) and 16 (idx 1) are set in the
+ * FILTER[6:4] field. The other decimations are set in the
+ * DEC_RATE[2:0] field, and the idx need to be offsetted by two.
+ */
+ if (dec_rate_idx == 0)
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X8);
+ else if (dec_rate_idx == 1)
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X16);
+ else
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5) |
+ AD7768_DIG_FIL_DEC_RATE(dec_rate_idx - 2);
+ break;
+ }
+
+ ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, dig_filter_regval);
+ if (ret)
return ret;
- /* A sync-in pulse is required every time the filter dec rate changes */
+ st->filter_type = filter_type;
+ /*
+ * The decimation for SINC3 filters are configured in different
+ * registers
+ */
+ if (filter_type == AD7768_FILTER_SINC3 ||
+ filter_type == AD7768_FILTER_SINC3_REJ60) {
+ ret = ad7768_set_sinc3_dec_rate(st, dec_rate);
+ if (ret)
+ return ret;
+ } else {
+ st->oversampling_ratio = ad7768_dec_rate_values[dec_rate_idx];
+ }
+
+ /* A sync-in pulse is required after every configuration change */
return ad7768_send_sync_pulse(st);
}
@@ -527,43 +672,72 @@ static int ad7768_gpio_init(struct iio_dev *indio_dev)
static int ad7768_set_freq(struct ad7768_state *st,
unsigned int freq)
{
- unsigned int diff_new, diff_old, pwr_mode, i, idx;
+ unsigned int diff_new, diff_old, i, idx;
int res, ret;
+ freq = clamp_t(unsigned int, freq, 50, 1024000);
diff_old = U32_MAX;
idx = 0;
- res = DIV_ROUND_CLOSEST(st->mclk_freq, freq);
+ if (freq == 0)
+ return -EINVAL;
+
+ res = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio);
/* Find the closest match for the desired sampling frequency */
- for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
- diff_new = abs(res - ad7768_clk_config[i].clk_div);
+ for (i = 0; i < ARRAY_SIZE(ad7768_mclk_div_rates); i++) {
+ diff_new = abs(res - ad7768_mclk_div_rates[i]);
if (diff_new < diff_old) {
diff_old = diff_new;
idx = i;
}
}
- /*
- * Set both the mclk_div and pwrmode with a single write to the
- * POWER_CLOCK register
- */
- pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) |
- AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode);
- ret = regmap_write(st->regmap, AD7768_REG_POWER_CLOCK, pwr_mode);
- if (ret < 0)
+ /* Set both the mclk_div and pwrmode */
+ ret = ad7768_set_mclk_div(st, idx);
+ if (ret)
return ret;
- ret = ad7768_set_dig_fil(st, ad7768_clk_config[idx].dec_rate);
- if (ret < 0)
+ st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq,
+ ad7768_mclk_div_rates[idx] * st->oversampling_ratio);
+
+ /* A sync-in pulse is required after every configuration change */
+ return ad7768_send_sync_pulse(st);
+}
+
+static int ad7768_set_fil_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan,
+ unsigned int filter)
+{
+ struct ad7768_state *st = iio_priv(dev);
+ int ret;
+
+ ret = ad7768_configure_dig_fil(dev, filter, st->oversampling_ratio);
+ if (ret)
return ret;
- st->dec_rate = ad7768_clk_config[idx].clk_div /
- ad7768_mclk_div_rates[ad7768_clk_config[idx].mclk_div];
- st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq,
- ad7768_clk_config[idx].clk_div);
+ /* Update sampling frequency */
+ return ad7768_set_freq(st, st->samp_freq);
+}
- return 0;
+static int ad7768_get_fil_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad7768_state *st = iio_priv(dev);
+ int ret;
+ unsigned int mode;
+
+ ret = regmap_read(st->regmap, AD7768_REG_DIGITAL_FILTER, &mode);
+ if (ret)
+ return ret;
+
+ mode = FIELD_GET(AD7768_DIG_FIL_FIL_MSK, mode);
+
+ /*
+ * From the register value, get the corresponding
+ * filter type.
+ */
+ return ad7768_filter_regval_to_type[mode];
}
static int ad7768_read_raw(struct iio_dev *indio_dev,
@@ -607,6 +781,11 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SAMP_FREQ:
*val = st->samp_freq;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = st->oversampling_ratio;
+
return IIO_VAL_INT;
}
@@ -619,16 +798,25 @@ static int ad7768_read_avail(struct iio_dev *indio_dev,
long info)
{
struct ad7768_state *st = iio_priv(indio_dev);
- int i;
+ int i, freq_filtered, len = 0;
switch (info) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = (int *)ad7768_dec_rate_range[st->filter_type];
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SAMP_FREQ:
- for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++)
- st->samp_freq_avail[i] = DIV_ROUND_CLOSEST(st->mclk_freq,
- ad7768_clk_config[i].clk_div);
+ freq_filtered = DIV_ROUND_CLOSEST(st->mclk_freq, st->oversampling_ratio);
+ for (i = 0; i < ARRAY_SIZE(ad7768_mclk_div_rates); i++) {
+ st->samp_freq_avail[len] = DIV_ROUND_CLOSEST(freq_filtered,
+ ad7768_mclk_div_rates[i]);
+ /* Sampling frequency cannot be lower than the minimum of 50 SPS */
+ if (st->samp_freq_avail[len] >= 50)
+ len++;
+ }
*vals = (int *)st->samp_freq_avail;
- *length = ARRAY_SIZE(ad7768_clk_config);
+ *length = len;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
default:
@@ -636,20 +824,45 @@ static int ad7768_read_avail(struct iio_dev *indio_dev,
}
}
-static int ad7768_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long info)
+static int __ad7768_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
{
struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
return ad7768_set_freq(st, val);
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = ad7768_configure_dig_fil(indio_dev, st->filter_type, val);
+ if (ret)
+ return ret;
+
+ /* Update sampling frequency */
+ return ad7768_set_freq(st, st->samp_freq);
default:
return -EINVAL;
}
}
+static int ad7768_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ int ret;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = __ad7768_write_raw(indio_dev, chan, val, val2, info);
+ iio_device_release_direct_mode(indio_dev);
+
+ return ret;
+}
+
static int ad7768_read_label(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, char *label)
{
@@ -663,7 +876,7 @@ static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev,
{
struct ad7768_state *st = iio_priv(indio_dev);
- return st->dec_rate == 8 ? AD7768_SCAN_TYPE_HIGH_SPEED :
+ return st->oversampling_ratio == 8 ? AD7768_SCAN_TYPE_HIGH_SPEED :
AD7768_SCAN_TYPE_NORMAL;
}
@@ -771,6 +984,14 @@ static int ad7768_setup(struct iio_dev *indio_dev)
return ret;
}
+ /*
+ * Set Default Digital Filter configuration:
+ * SINC5 filter with x32 Decimation rate
+ */
+ ret = ad7768_configure_dig_fil(indio_dev, AD7768_FILTER_SINC5, 32);
+ if (ret)
+ return ret;
+
/* Set the default sampling frequency to 32000 kSPS */
return ad7768_set_freq(st, 32000);
}