summaryrefslogtreecommitdiff
path: root/drivers/iio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/adc/ad7124.c4
-rw-r--r--drivers/iio/adc/mcp3911.c39
-rw-r--r--drivers/iio/adc/pac1934.c2
-rw-r--r--drivers/iio/filter/admv8818.c224
4 files changed, 207 insertions, 62 deletions
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 30a7392c4f8b..9c9e0c950b42 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -300,9 +300,9 @@ static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
switch (st->channels[channel].cfg.filter_type) {
case AD7124_SINC3_FILTER:
- return DIV_ROUND_CLOSEST(fadc * 230, 1000);
+ return DIV_ROUND_CLOSEST(fadc * 272, 1000);
case AD7124_SINC4_FILTER:
- return DIV_ROUND_CLOSEST(fadc * 262, 1000);
+ return DIV_ROUND_CLOSEST(fadc * 230, 1000);
default:
return -EINVAL;
}
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index b097f04172c8..4bd6b5aac4fe 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -6,7 +6,7 @@
* Copyright (C) 2018 Kent Gustavsson <kent@minoris.se>
*/
#include <linux/bitfield.h>
-#include <linux/bits.h>
+#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -79,6 +79,8 @@
#define MCP3910_CONFIG1_CLKEXT BIT(6)
#define MCP3910_CONFIG1_VREFEXT BIT(7)
+#define MCP3910_CHANNEL(ch) (MCP3911_REG_CHANNEL0 + (ch))
+
#define MCP3910_REG_OFFCAL_CH0 0x0f
#define MCP3910_OFFCAL(ch) (MCP3910_REG_OFFCAL_CH0 + (ch) * 6)
@@ -110,6 +112,7 @@ struct mcp3911_chip_info {
int (*get_offset)(struct mcp3911 *adc, int channel, int *val);
int (*set_offset)(struct mcp3911 *adc, int channel, int val);
int (*set_scale)(struct mcp3911 *adc, int channel, u32 val);
+ int (*get_raw)(struct mcp3911 *adc, int channel, int *val);
};
struct mcp3911 {
@@ -170,6 +173,18 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask, u32 val, u8 len
return mcp3911_write(adc, reg, val, len);
}
+static int mcp3911_read_s24(struct mcp3911 *const adc, u8 const reg, s32 *const val)
+{
+ u32 uval;
+ int const ret = mcp3911_read(adc, reg, &uval, 3);
+
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(uval, 23);
+ return ret;
+}
+
static int mcp3910_enable_offset(struct mcp3911 *adc, bool enable)
{
unsigned int mask = MCP3910_CONFIG0_EN_OFFCAL;
@@ -194,6 +209,11 @@ static int mcp3910_set_offset(struct mcp3911 *adc, int channel, int val)
return adc->chip->enable_offset(adc, 1);
}
+static int mcp3910_get_raw(struct mcp3911 *adc, int channel, s32 *val)
+{
+ return mcp3911_read_s24(adc, MCP3910_CHANNEL(channel), val);
+}
+
static int mcp3911_enable_offset(struct mcp3911 *adc, bool enable)
{
unsigned int mask = MCP3911_STATUSCOM_EN_OFFCAL;
@@ -218,6 +238,11 @@ static int mcp3911_set_offset(struct mcp3911 *adc, int channel, int val)
return adc->chip->enable_offset(adc, 1);
}
+static int mcp3911_get_raw(struct mcp3911 *adc, int channel, s32 *val)
+{
+ return mcp3911_read_s24(adc, MCP3911_CHANNEL(channel), val);
+}
+
static int mcp3910_get_osr(struct mcp3911 *adc, u32 *val)
{
int ret;
@@ -321,12 +346,9 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
guard(mutex)(&adc->lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = mcp3911_read(adc,
- MCP3911_CHANNEL(channel->channel), val, 3);
+ ret = adc->chip->get_raw(adc, channel->channel, val);
if (ret)
return ret;
-
- *val = sign_extend32(*val, 23);
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
ret = adc->chip->get_offset(adc, channel->channel, val);
@@ -799,6 +821,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3911] = {
.channels = mcp3911_channels,
@@ -810,6 +833,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3911_get_offset,
.set_offset = mcp3911_set_offset,
.set_scale = mcp3911_set_scale,
+ .get_raw = mcp3911_get_raw,
},
[MCP3912] = {
.channels = mcp3912_channels,
@@ -821,6 +845,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3913] = {
.channels = mcp3913_channels,
@@ -832,6 +857,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3914] = {
.channels = mcp3914_channels,
@@ -843,6 +869,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3918] = {
.channels = mcp3918_channels,
@@ -854,6 +881,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
[MCP3919] = {
.channels = mcp3919_channels,
@@ -865,6 +893,7 @@ static const struct mcp3911_chip_info mcp3911_chip_info[] = {
.get_offset = mcp3910_get_offset,
.set_offset = mcp3910_set_offset,
.set_scale = mcp3910_set_scale,
+ .get_raw = mcp3910_get_raw,
},
};
static const struct of_device_id mcp3911_dt_ids[] = {
diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c
index 7ef249d83286..c3f9fa307b84 100644
--- a/drivers/iio/adc/pac1934.c
+++ b/drivers/iio/adc/pac1934.c
@@ -1081,7 +1081,7 @@ static int pac1934_chip_identify(struct pac1934_chip_info *info)
/*
* documentation related to the ACPI device definition
- * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC1934-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
+ * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ApplicationNotes/ApplicationNotes/PAC193X-Integration-Notes-for-Microsoft-Windows-10-and-Windows-11-Driver-Support-DS00002534.pdf
*/
static int pac1934_acpi_parse_channel_config(struct i2c_client *client,
struct pac1934_chip_info *info)
diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c
index d85b7d3de866..cc8ce0fe74e7 100644
--- a/drivers/iio/filter/admv8818.c
+++ b/drivers/iio/filter/admv8818.c
@@ -14,6 +14,7 @@
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/units.h>
@@ -70,6 +71,16 @@
#define ADMV8818_HPF_WR0_MSK GENMASK(7, 4)
#define ADMV8818_LPF_WR0_MSK GENMASK(3, 0)
+#define ADMV8818_BAND_BYPASS 0
+#define ADMV8818_BAND_MIN 1
+#define ADMV8818_BAND_MAX 4
+#define ADMV8818_BAND_CORNER_LOW 0
+#define ADMV8818_BAND_CORNER_HIGH 1
+
+#define ADMV8818_STATE_MIN 0
+#define ADMV8818_STATE_MAX 15
+#define ADMV8818_NUM_STATES 16
+
enum {
ADMV8818_BW_FREQ,
ADMV8818_CENTER_FREQ
@@ -90,20 +101,24 @@ struct admv8818_state {
struct mutex lock;
unsigned int filter_mode;
u64 cf_hz;
+ u64 lpf_margin_hz;
+ u64 hpf_margin_hz;
};
-static const unsigned long long freq_range_hpf[4][2] = {
+static const unsigned long long freq_range_hpf[5][2] = {
+ {0ULL, 0ULL}, /* bypass */
{1750000000ULL, 3550000000ULL},
{3400000000ULL, 7250000000ULL},
{6600000000, 12000000000},
{12500000000, 19900000000}
};
-static const unsigned long long freq_range_lpf[4][2] = {
+static const unsigned long long freq_range_lpf[5][2] = {
+ {U64_MAX, U64_MAX}, /* bypass */
{2050000000ULL, 3850000000ULL},
{3350000000ULL, 7250000000ULL},
{7000000000, 13000000000},
- {12550000000, 18500000000}
+ {12550000000, 18850000000}
};
static const struct regmap_config admv8818_regmap_config = {
@@ -121,44 +136,59 @@ static const char * const admv8818_modes[] = {
static int __admv8818_hpf_select(struct admv8818_state *st, u64 freq)
{
- unsigned int hpf_step = 0, hpf_band = 0, i, j;
- u64 freq_step;
- int ret;
+ int band, state, ret;
+ unsigned int hpf_state = ADMV8818_STATE_MIN, hpf_band = ADMV8818_BAND_BYPASS;
+ u64 freq_error, min_freq_error, freq_corner, freq_step;
- if (freq < freq_range_hpf[0][0])
+ if (freq < freq_range_hpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW])
goto hpf_write;
- if (freq > freq_range_hpf[3][1]) {
- hpf_step = 15;
- hpf_band = 4;
-
+ if (freq >= freq_range_hpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH]) {
+ hpf_state = ADMV8818_STATE_MAX;
+ hpf_band = ADMV8818_BAND_MAX;
goto hpf_write;
}
- for (i = 0; i < 4; i++) {
- freq_step = div_u64((freq_range_hpf[i][1] -
- freq_range_hpf[i][0]), 15);
+ /* Close HPF frequency gap between 12 and 12.5 GHz */
+ if (freq >= 12000ULL * HZ_PER_MHZ && freq < 12500ULL * HZ_PER_MHZ) {
+ hpf_state = ADMV8818_STATE_MAX;
+ hpf_band = 3;
+ goto hpf_write;
+ }
- if (freq > freq_range_hpf[i][0] &&
- (freq < freq_range_hpf[i][1] + freq_step)) {
- hpf_band = i + 1;
+ min_freq_error = U64_MAX;
+ for (band = ADMV8818_BAND_MIN; band <= ADMV8818_BAND_MAX; band++) {
+ /*
+ * This (and therefore all other ranges) have a corner
+ * frequency higher than the target frequency.
+ */
+ if (freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] > freq)
+ break;
- for (j = 1; j <= 16; j++) {
- if (freq < (freq_range_hpf[i][0] + (freq_step * j))) {
- hpf_step = j - 1;
- break;
- }
+ freq_step = freq_range_hpf[band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW];
+ freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1);
+
+ for (state = ADMV8818_STATE_MIN; state <= ADMV8818_STATE_MAX; state++) {
+ freq_corner = freq_range_hpf[band][ADMV8818_BAND_CORNER_LOW] +
+ freq_step * state;
+
+ /*
+ * This (and therefore all other states) have a corner
+ * frequency higher than the target frequency.
+ */
+ if (freq_corner > freq)
+ break;
+
+ freq_error = freq - freq_corner;
+ if (freq_error < min_freq_error) {
+ min_freq_error = freq_error;
+ hpf_state = state;
+ hpf_band = band;
}
- break;
}
}
- /* Close HPF frequency gap between 12 and 12.5 GHz */
- if (freq >= 12000 * HZ_PER_MHZ && freq <= 12500 * HZ_PER_MHZ) {
- hpf_band = 3;
- hpf_step = 15;
- }
-
hpf_write:
ret = regmap_update_bits(st->regmap, ADMV8818_REG_WR0_SW,
ADMV8818_SW_IN_SET_WR0_MSK |
@@ -170,7 +200,7 @@ hpf_write:
return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
ADMV8818_HPF_WR0_MSK,
- FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_step));
+ FIELD_PREP(ADMV8818_HPF_WR0_MSK, hpf_state));
}
static int admv8818_hpf_select(struct admv8818_state *st, u64 freq)
@@ -186,31 +216,52 @@ static int admv8818_hpf_select(struct admv8818_state *st, u64 freq)
static int __admv8818_lpf_select(struct admv8818_state *st, u64 freq)
{
- unsigned int lpf_step = 0, lpf_band = 0, i, j;
- u64 freq_step;
- int ret;
+ int band, state, ret;
+ unsigned int lpf_state = ADMV8818_STATE_MIN, lpf_band = ADMV8818_BAND_BYPASS;
+ u64 freq_error, min_freq_error, freq_corner, freq_step;
- if (freq > freq_range_lpf[3][1])
+ if (freq > freq_range_lpf[ADMV8818_BAND_MAX][ADMV8818_BAND_CORNER_HIGH])
goto lpf_write;
- if (freq < freq_range_lpf[0][0]) {
- lpf_band = 1;
-
+ if (freq < freq_range_lpf[ADMV8818_BAND_MIN][ADMV8818_BAND_CORNER_LOW]) {
+ lpf_state = ADMV8818_STATE_MIN;
+ lpf_band = ADMV8818_BAND_MIN;
goto lpf_write;
}
- for (i = 0; i < 4; i++) {
- if (freq > freq_range_lpf[i][0] && freq < freq_range_lpf[i][1]) {
- lpf_band = i + 1;
- freq_step = div_u64((freq_range_lpf[i][1] - freq_range_lpf[i][0]), 15);
+ min_freq_error = U64_MAX;
+ for (band = ADMV8818_BAND_MAX; band >= ADMV8818_BAND_MIN; --band) {
+ /*
+ * At this point the highest corner frequency of
+ * all remaining ranges is below the target.
+ * LPF corner should be >= the target.
+ */
+ if (freq > freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH])
+ break;
+
+ freq_step = freq_range_lpf[band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW];
+ freq_step = div_u64(freq_step, ADMV8818_NUM_STATES - 1);
+
+ for (state = ADMV8818_STATE_MAX; state >= ADMV8818_STATE_MIN; --state) {
+
+ freq_corner = freq_range_lpf[band][ADMV8818_BAND_CORNER_LOW] +
+ state * freq_step;
- for (j = 0; j <= 15; j++) {
- if (freq < (freq_range_lpf[i][0] + (freq_step * j))) {
- lpf_step = j;
- break;
- }
+ /*
+ * At this point all other states in range will
+ * place the corner frequency below the target
+ * LPF corner should >= the target.
+ */
+ if (freq > freq_corner)
+ break;
+
+ freq_error = freq_corner - freq;
+ if (freq_error < min_freq_error) {
+ min_freq_error = freq_error;
+ lpf_state = state;
+ lpf_band = band;
}
- break;
}
}
@@ -225,7 +276,7 @@ lpf_write:
return regmap_update_bits(st->regmap, ADMV8818_REG_WR0_FILTER,
ADMV8818_LPF_WR0_MSK,
- FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_step));
+ FIELD_PREP(ADMV8818_LPF_WR0_MSK, lpf_state));
}
static int admv8818_lpf_select(struct admv8818_state *st, u64 freq)
@@ -242,16 +293,28 @@ static int admv8818_lpf_select(struct admv8818_state *st, u64 freq)
static int admv8818_rfin_band_select(struct admv8818_state *st)
{
int ret;
+ u64 hpf_corner_target, lpf_corner_target;
st->cf_hz = clk_get_rate(st->clkin);
+ /* Check for underflow */
+ if (st->cf_hz > st->hpf_margin_hz)
+ hpf_corner_target = st->cf_hz - st->hpf_margin_hz;
+ else
+ hpf_corner_target = 0;
+
+ /* Check for overflow */
+ lpf_corner_target = st->cf_hz + st->lpf_margin_hz;
+ if (lpf_corner_target < st->cf_hz)
+ lpf_corner_target = U64_MAX;
+
mutex_lock(&st->lock);
- ret = __admv8818_hpf_select(st, st->cf_hz);
+ ret = __admv8818_hpf_select(st, hpf_corner_target);
if (ret)
goto exit;
- ret = __admv8818_lpf_select(st, st->cf_hz);
+ ret = __admv8818_lpf_select(st, lpf_corner_target);
exit:
mutex_unlock(&st->lock);
return ret;
@@ -278,8 +341,11 @@ static int __admv8818_read_hpf_freq(struct admv8818_state *st, u64 *hpf_freq)
hpf_state = FIELD_GET(ADMV8818_HPF_WR0_MSK, data);
- *hpf_freq = div_u64(freq_range_hpf[hpf_band - 1][1] - freq_range_hpf[hpf_band - 1][0], 15);
- *hpf_freq = freq_range_hpf[hpf_band - 1][0] + (*hpf_freq * hpf_state);
+ *hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW];
+ *hpf_freq = div_u64(*hpf_freq, ADMV8818_NUM_STATES - 1);
+ *hpf_freq = freq_range_hpf[hpf_band][ADMV8818_BAND_CORNER_LOW] +
+ (*hpf_freq * hpf_state);
return ret;
}
@@ -316,8 +382,11 @@ static int __admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
lpf_state = FIELD_GET(ADMV8818_LPF_WR0_MSK, data);
- *lpf_freq = div_u64(freq_range_lpf[lpf_band - 1][1] - freq_range_lpf[lpf_band - 1][0], 15);
- *lpf_freq = freq_range_lpf[lpf_band - 1][0] + (*lpf_freq * lpf_state);
+ *lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_HIGH] -
+ freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW];
+ *lpf_freq = div_u64(*lpf_freq, ADMV8818_NUM_STATES - 1);
+ *lpf_freq = freq_range_lpf[lpf_band][ADMV8818_BAND_CORNER_LOW] +
+ (*lpf_freq * lpf_state);
return ret;
}
@@ -333,6 +402,19 @@ static int admv8818_read_lpf_freq(struct admv8818_state *st, u64 *lpf_freq)
return ret;
}
+static int admv8818_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
+ return IIO_VAL_INT_64;
+ default:
+ return -EINVAL;
+ }
+}
+
static int admv8818_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long info)
@@ -341,6 +423,9 @@ static int admv8818_write_raw(struct iio_dev *indio_dev,
u64 freq = ((u64)val2 << 32 | (u32)val);
+ if ((s64)freq < 0)
+ return -EINVAL;
+
switch (info) {
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return admv8818_lpf_select(st, freq);
@@ -502,6 +587,7 @@ set_mode:
static const struct iio_info admv8818_info = {
.write_raw = admv8818_write_raw,
+ .write_raw_get_fmt = admv8818_write_raw_get_fmt,
.read_raw = admv8818_read_raw,
.debugfs_reg_access = &admv8818_reg_access,
};
@@ -641,6 +727,32 @@ static int admv8818_clk_setup(struct admv8818_state *st)
return devm_add_action_or_reset(&spi->dev, admv8818_clk_notifier_unreg, st);
}
+static int admv8818_read_properties(struct admv8818_state *st)
+{
+ struct spi_device *spi = st->spi;
+ u32 mhz;
+ int ret;
+
+ ret = device_property_read_u32(&spi->dev, "adi,lpf-margin-mhz", &mhz);
+ if (ret == 0)
+ st->lpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
+ else if (ret == -EINVAL)
+ st->lpf_margin_hz = 0;
+ else
+ return ret;
+
+
+ ret = device_property_read_u32(&spi->dev, "adi,hpf-margin-mhz", &mhz);
+ if (ret == 0)
+ st->hpf_margin_hz = (u64)mhz * HZ_PER_MHZ;
+ else if (ret == -EINVAL)
+ st->hpf_margin_hz = 0;
+ else if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
static int admv8818_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
@@ -672,6 +784,10 @@ static int admv8818_probe(struct spi_device *spi)
mutex_init(&st->lock);
+ ret = admv8818_read_properties(st);
+ if (ret)
+ return ret;
+
ret = admv8818_init(st);
if (ret)
return ret;