aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio/adc/ad7192.c
diff options
context:
space:
mode:
authorMaxime Ripard <mripard@kernel.org>2019-10-03 16:38:50 +0200
committerMaxime Ripard <mripard@kernel.org>2019-10-03 16:38:50 +0200
commit4092de1ba34eb376791809fb366bc15f8a9e0b7c (patch)
tree6262d4dfcfa7ff9eda8e8d1d0a711711fcae8785 /drivers/staging/iio/adc/ad7192.c
parentRevert "drm/sun4i: dsi: Change the start delay calculation" (diff)
parentLinux 5.4-rc1 (diff)
downloadlinux-dev-4092de1ba34eb376791809fb366bc15f8a9e0b7c.tar.xz
linux-dev-4092de1ba34eb376791809fb366bc15f8a9e0b7c.zip
Merge drm/drm-next into drm-misc-next
We haven't done any backmerge for a while due to the merge window, and it starts to become an issue for komeda. Let's bring 5.4-rc1 in. Signed-off-by: Maxime Ripard <mripard@kernel.org>
Diffstat (limited to 'drivers/staging/iio/adc/ad7192.c')
-rw-r--r--drivers/staging/iio/adc/ad7192.c175
1 files changed, 147 insertions, 28 deletions
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index b6d12fe7c12a..e6b660489165 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -25,8 +25,6 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/adc/ad_sigma_delta.h>
-#include "ad7192.h"
-
/* Registers */
#define AD7192_REG_COMM 0 /* Communications Register (WO, 8-bit) */
#define AD7192_REG_STAT 0 /* Status Register (RO, 8-bit) */
@@ -145,6 +143,10 @@
#define AD7192_EXT_FREQ_MHZ_MAX 5120000
#define AD7192_INT_FREQ_MHZ 4915200
+#define AD7192_NO_SYNC_FILTER 1
+#define AD7192_SYNC3_FILTER 3
+#define AD7192_SYNC4_FILTER 4
+
/* NOTE:
* The AD7190/2/5 features a dual use data out ready DOUT/RDY output.
* In order to avoid contentions on the SPI bus, it's therefore necessary
@@ -252,7 +254,7 @@ static int ad7192_of_clock_select(struct ad7192_state *st)
static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
{
struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi);
- bool rej60_en, sinc3_en, refin2_en, chop_en;
+ bool rej60_en, refin2_en;
bool buf_en, bipolar, burnout_curr_en;
unsigned long long scale_uv;
int i, ret, id;
@@ -284,24 +286,12 @@ static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
if (rej60_en)
st->mode |= AD7192_MODE_REJ60;
- sinc3_en = of_property_read_bool(np, "adi,sinc3-filter-enable");
- if (sinc3_en)
- st->mode |= AD7192_MODE_SINC3;
-
refin2_en = of_property_read_bool(np, "adi,refin2-pins-enable");
if (refin2_en && st->devid != ID_AD7195)
st->conf |= AD7192_CONF_REFSEL;
- chop_en = of_property_read_bool(np, "adi,chop-enable");
- if (chop_en) {
- st->conf |= AD7192_CONF_CHOP;
- if (sinc3_en)
- st->f_order = 3; /* SINC 3rd order */
- else
- st->f_order = 4; /* SINC 4th order */
- } else {
- st->f_order = 1;
- }
+ st->conf &= ~AD7192_CONF_CHOP;
+ st->f_order = AD7192_NO_SYNC_FILTER;
buf_en = of_property_read_bool(np, "adi,buffer-enable");
if (buf_en)
@@ -313,7 +303,7 @@ static int ad7192_setup(struct ad7192_state *st, struct device_node *np)
burnout_curr_en = of_property_read_bool(np,
"adi,burnout-currents-enable");
- if (burnout_curr_en && buf_en && !chop_en) {
+ if (burnout_curr_en && buf_en) {
st->conf |= AD7192_CONF_BURN;
} else if (burnout_curr_en) {
dev_warn(&st->sd.spi->dev,
@@ -411,6 +401,49 @@ static ssize_t ad7192_set(struct device *dev,
return ret ? ret : len;
}
+static void ad7192_get_available_filter_freq(struct ad7192_state *st,
+ int *freq)
+{
+ unsigned int fadc;
+
+ /* Formulas for filter at page 25 of the datasheet */
+ fadc = DIV_ROUND_CLOSEST(st->fclk,
+ AD7192_SYNC4_FILTER * AD7192_MODE_RATE(st->mode));
+ freq[0] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
+
+ fadc = DIV_ROUND_CLOSEST(st->fclk,
+ AD7192_SYNC3_FILTER * AD7192_MODE_RATE(st->mode));
+ freq[1] = DIV_ROUND_CLOSEST(fadc * 240, 1024);
+
+ fadc = DIV_ROUND_CLOSEST(st->fclk, AD7192_MODE_RATE(st->mode));
+ freq[2] = DIV_ROUND_CLOSEST(fadc * 230, 1024);
+ freq[3] = DIV_ROUND_CLOSEST(fadc * 272, 1024);
+}
+
+static ssize_t ad7192_show_filter_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct ad7192_state *st = iio_priv(indio_dev);
+ unsigned int freq_avail[4], i;
+ size_t len = 0;
+
+ ad7192_get_available_filter_freq(st, freq_avail);
+
+ for (i = 0; i < ARRAY_SIZE(freq_avail); i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len,
+ "%d.%d ", freq_avail[i] / 1000,
+ freq_avail[i] % 1000);
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(filter_low_pass_3db_frequency_available,
+ 0444, ad7192_show_filter_avail, NULL, 0);
+
static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
ad7192_show_bridge_switch, ad7192_set,
AD7192_REG_GPOCON);
@@ -420,6 +453,7 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
AD7192_REG_MODE);
static struct attribute *ad7192_attributes[] = {
+ &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
&iio_dev_attr_ac_excitation_en.dev_attr.attr,
NULL
@@ -430,6 +464,7 @@ static const struct attribute_group ad7192_attribute_group = {
};
static struct attribute *ad7195_attributes[] = {
+ &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
@@ -443,6 +478,75 @@ static unsigned int ad7192_get_temp_scale(bool unipolar)
return unipolar ? 2815 * 2 : 2815;
}
+static int ad7192_set_3db_filter_freq(struct ad7192_state *st,
+ int val, int val2)
+{
+ int freq_avail[4], i, ret, freq;
+ unsigned int diff_new, diff_old;
+ int idx = 0;
+
+ diff_old = U32_MAX;
+ freq = val * 1000 + val2;
+
+ ad7192_get_available_filter_freq(st, freq_avail);
+
+ for (i = 0; i < ARRAY_SIZE(freq_avail); i++) {
+ diff_new = abs(freq - freq_avail[i]);
+ if (diff_new < diff_old) {
+ diff_old = diff_new;
+ idx = i;
+ }
+ }
+
+ switch (idx) {
+ case 0:
+ st->f_order = AD7192_SYNC4_FILTER;
+ st->mode &= ~AD7192_MODE_SINC3;
+
+ st->conf |= AD7192_CONF_CHOP;
+ break;
+ case 1:
+ st->f_order = AD7192_SYNC3_FILTER;
+ st->mode |= AD7192_MODE_SINC3;
+
+ st->conf |= AD7192_CONF_CHOP;
+ break;
+ case 2:
+ st->f_order = AD7192_NO_SYNC_FILTER;
+ st->mode &= ~AD7192_MODE_SINC3;
+
+ st->conf &= ~AD7192_CONF_CHOP;
+ break;
+ case 3:
+ st->f_order = AD7192_NO_SYNC_FILTER;
+ st->mode |= AD7192_MODE_SINC3;
+
+ st->conf &= ~AD7192_CONF_CHOP;
+ break;
+ }
+
+ ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
+ if (ret < 0)
+ return ret;
+
+ return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
+}
+
+static int ad7192_get_3db_filter_freq(struct ad7192_state *st)
+{
+ unsigned int fadc;
+
+ fadc = DIV_ROUND_CLOSEST(st->fclk,
+ st->f_order * AD7192_MODE_RATE(st->mode));
+
+ if (st->conf & AD7192_CONF_CHOP)
+ return DIV_ROUND_CLOSEST(fadc * 240, 1024);
+ if (st->mode & AD7192_MODE_SINC3)
+ return DIV_ROUND_CLOSEST(fadc * 272, 1024);
+ else
+ return DIV_ROUND_CLOSEST(fadc * 230, 1024);
+}
+
static int ad7192_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -483,6 +587,10 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val = st->fclk /
(st->f_order * 1024 * AD7192_MODE_RATE(st->mode));
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ *val = ad7192_get_3db_filter_freq(st);
+ *val2 = 1000;
+ return IIO_VAL_FRACTIONAL;
}
return -EINVAL;
@@ -537,6 +645,9 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
st->mode |= AD7192_MODE_RATE(div);
ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
break;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ ret = ad7192_set_3db_filter_freq(st, val, val2 / 1000);
+ break;
default:
ret = -EINVAL;
}
@@ -555,6 +666,8 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
@@ -655,6 +768,8 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
for (i = 0; i < indio_dev->num_channels; i++) {
*chan = channels[i];
+ chan->info_mask_shared_by_all |=
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY);
if (chan->type != IIO_TEMP)
chan->info_mask_shared_by_type_available |=
BIT(IIO_CHAN_INFO_SCALE);
@@ -666,16 +781,10 @@ static int ad7192_channels_config(struct iio_dev *indio_dev)
static int ad7192_probe(struct spi_device *spi)
{
- const struct ad7192_platform_data *pdata = dev_get_platdata(&spi->dev);
struct ad7192_state *st;
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- if (!pdata) {
- dev_err(&spi->dev, "no platform data?\n");
- return -ENODEV;
- }
-
if (!spi->irq) {
dev_err(&spi->dev, "no IRQ?\n");
return -ENODEV;
@@ -713,12 +822,10 @@ static int ad7192_probe(struct spi_device *spi)
voltage_uv = regulator_get_voltage(st->avdd);
- if (pdata->vref_mv)
- st->int_vref_mv = pdata->vref_mv;
- else if (voltage_uv)
+ if (voltage_uv)
st->int_vref_mv = voltage_uv / 1000;
else
- dev_warn(&spi->dev, "reference voltage undefined\n");
+ dev_err(&spi->dev, "Device tree error, reference voltage undefined\n");
spi_set_drvdata(spi, indio_dev);
st->devid = spi_get_device_id(spi)->driver_data;
@@ -809,11 +916,23 @@ static const struct spi_device_id ad7192_id[] = {
{"ad7195", ID_AD7195},
{}
};
+
MODULE_DEVICE_TABLE(spi, ad7192_id);
+static const struct of_device_id ad7192_of_match[] = {
+ { .compatible = "adi,ad7190" },
+ { .compatible = "adi,ad7192" },
+ { .compatible = "adi,ad7193" },
+ { .compatible = "adi,ad7195" },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, ad7192_of_match);
+
static struct spi_driver ad7192_driver = {
.driver = {
.name = "ad7192",
+ .of_match_table = ad7192_of_match,
},
.probe = ad7192_probe,
.remove = ad7192_remove,