aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio/adc/ad7192.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/iio/adc/ad7192.c')
-rw-r--r--drivers/staging/iio/adc/ad7192.c236
1 files changed, 148 insertions, 88 deletions
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 2fc8bc22b57b..b6d12fe7c12a 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -1,12 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* AD7190 AD7192 AD7193 AD7195 SPI ADC driver
*
* Copyright 2011-2015 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -156,14 +156,16 @@
struct ad7192_state {
struct regulator *avdd;
struct regulator *dvdd;
+ struct clk *mclk;
u16 int_vref_mv;
- u32 mclk;
+ u32 fclk;
u32 f_order;
u32 mode;
u32 conf;
u32 scale_avail[8][2];
u8 gpocon;
u8 devid;
+ u8 clock_sel;
struct mutex lock; /* protect sensor state */
struct ad_sigma_delta sd;
@@ -216,8 +218,8 @@ static const struct ad_sd_calib_data ad7192_calib_arr[8] = {
static int ad7192_calibrate_all(struct ad7192_state *st)
{
- return ad_sd_calibrate_all(&st->sd, ad7192_calib_arr,
- ARRAY_SIZE(ad7192_calib_arr));
+ return ad_sd_calibrate_all(&st->sd, ad7192_calib_arr,
+ ARRAY_SIZE(ad7192_calib_arr));
}
static inline bool ad7192_valid_external_frequency(u32 freq)
@@ -226,23 +228,45 @@ static inline bool ad7192_valid_external_frequency(u32 freq)
freq <= AD7192_EXT_FREQ_MHZ_MAX);
}
-static int ad7192_setup(struct ad7192_state *st,
- const struct ad7192_platform_data *pdata)
+static int ad7192_of_clock_select(struct ad7192_state *st)
+{
+ struct device_node *np = st->sd.spi->dev.of_node;
+ unsigned int clock_sel;
+
+ clock_sel = AD7192_CLK_INT;
+
+ /* use internal clock */
+ if (PTR_ERR(st->mclk) == -ENOENT) {
+ if (of_property_read_bool(np, "adi,int-clock-output-enable"))
+ clock_sel = AD7192_CLK_INT_CO;
+ } else {
+ if (of_property_read_bool(np, "adi,clock-xtal"))
+ clock_sel = AD7192_CLK_EXT_MCLK1_2;
+ else
+ clock_sel = AD7192_CLK_EXT_MCLK2;
+ }
+
+ return clock_sel;
+}
+
+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 buf_en, bipolar, burnout_curr_en;
unsigned long long scale_uv;
int i, ret, id;
/* reset the serial interface */
ret = ad_sd_reset(&st->sd, 48);
if (ret < 0)
- goto out;
+ return ret;
usleep_range(500, 1000); /* Wait for at least 500us */
/* write/read test for device presence */
ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id);
if (ret)
- goto out;
+ return ret;
id &= AD7192_ID_MASK;
@@ -250,44 +274,28 @@ static int ad7192_setup(struct ad7192_state *st,
dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X)\n",
id);
- switch (pdata->clock_source_sel) {
- case AD7192_CLK_INT:
- case AD7192_CLK_INT_CO:
- st->mclk = AD7192_INT_FREQ_MHZ;
- break;
- case AD7192_CLK_EXT_MCLK1_2:
- case AD7192_CLK_EXT_MCLK2:
- if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) {
- st->mclk = pdata->ext_clk_hz;
- break;
- }
- dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n",
- pdata->ext_clk_hz);
- ret = -EINVAL;
- goto out;
- default:
- ret = -EINVAL;
- goto out;
- }
-
st->mode = AD7192_MODE_SEL(AD7192_MODE_IDLE) |
- AD7192_MODE_CLKSRC(pdata->clock_source_sel) |
+ AD7192_MODE_CLKSRC(st->clock_sel) |
AD7192_MODE_RATE(480);
st->conf = AD7192_CONF_GAIN(0);
- if (pdata->rej60_en)
+ rej60_en = of_property_read_bool(np, "adi,rejection-60-Hz-enable");
+ if (rej60_en)
st->mode |= AD7192_MODE_REJ60;
- if (pdata->sinc3_en)
+ sinc3_en = of_property_read_bool(np, "adi,sinc3-filter-enable");
+ if (sinc3_en)
st->mode |= AD7192_MODE_SINC3;
- if (pdata->refin2_en && st->devid != ID_AD7195)
+ refin2_en = of_property_read_bool(np, "adi,refin2-pins-enable");
+ if (refin2_en && st->devid != ID_AD7195)
st->conf |= AD7192_CONF_REFSEL;
- if (pdata->chop_en) {
+ chop_en = of_property_read_bool(np, "adi,chop-enable");
+ if (chop_en) {
st->conf |= AD7192_CONF_CHOP;
- if (pdata->sinc3_en)
+ if (sinc3_en)
st->f_order = 3; /* SINC 3rd order */
else
st->f_order = 4; /* SINC 4th order */
@@ -295,30 +303,34 @@ static int ad7192_setup(struct ad7192_state *st,
st->f_order = 1;
}
- if (pdata->buf_en)
+ buf_en = of_property_read_bool(np, "adi,buffer-enable");
+ if (buf_en)
st->conf |= AD7192_CONF_BUF;
- if (pdata->unipolar_en)
+ bipolar = of_property_read_bool(np, "bipolar");
+ if (!bipolar)
st->conf |= AD7192_CONF_UNIPOLAR;
- if (pdata->burnout_curr_en && pdata->buf_en && !pdata->chop_en) {
+ burnout_curr_en = of_property_read_bool(np,
+ "adi,burnout-currents-enable");
+ if (burnout_curr_en && buf_en && !chop_en) {
st->conf |= AD7192_CONF_BURN;
- } else if (pdata->burnout_curr_en) {
+ } else if (burnout_curr_en) {
dev_warn(&st->sd.spi->dev,
"Can't enable burnout currents: see CHOP or buffer\n");
}
ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
if (ret)
- goto out;
+ return ret;
ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
if (ret)
- goto out;
+ return ret;
ret = ad7192_calibrate_all(st);
if (ret)
- goto out;
+ return ret;
/* Populate available ADC input ranges */
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) {
@@ -332,35 +344,8 @@ static int ad7192_setup(struct ad7192_state *st,
}
return 0;
-out:
- dev_err(&st->sd.spi->dev, "setup failed\n");
- return ret;
}
-static ssize_t
-ad7192_show_scale_available(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);
- int i, len = 0;
-
- for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
- len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0],
- st->scale_avail[i][1]);
-
- len += sprintf(buf + len, "\n");
-
- return len;
-}
-
-static IIO_DEVICE_ATTR_NAMED(in_v_m_v_scale_available,
- in_voltage-voltage_scale_available,
- 0444, ad7192_show_scale_available, NULL, 0);
-
-static IIO_DEVICE_ATTR(in_voltage_scale_available, 0444,
- ad7192_show_scale_available, NULL, 0);
-
static ssize_t ad7192_show_ac_excitation(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -435,8 +420,6 @@ static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
AD7192_REG_MODE);
static struct attribute *ad7192_attributes[] = {
- &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr,
- &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
&iio_dev_attr_ac_excitation_en.dev_attr.attr,
NULL
@@ -447,8 +430,6 @@ static const struct attribute_group ad7192_attribute_group = {
};
static struct attribute *ad7195_attributes[] = {
- &iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr,
- &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
@@ -499,7 +480,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
*val -= 273 * ad7192_get_temp_scale(unipolar);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
- *val = st->mclk /
+ *val = st->fclk /
(st->f_order * 1024 * AD7192_MODE_RATE(st->mode));
return IIO_VAL_INT;
}
@@ -546,7 +527,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
break;
}
- div = st->mclk / (val * st->f_order * 1024);
+ div = st->fclk / (val * st->f_order * 1024);
if (div < 1 || div > 1023) {
ret = -EINVAL;
break;
@@ -579,10 +560,31 @@ static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev,
}
}
+static int ad7192_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct ad7192_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)st->scale_avail;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ /* Values are stored in a 2D matrix */
+ *length = ARRAY_SIZE(st->scale_avail) * 2;
+
+ return IIO_AVAIL_LIST;
+ }
+
+ return -EINVAL;
+}
+
static const struct iio_info ad7192_info = {
.read_raw = ad7192_read_raw,
.write_raw = ad7192_write_raw,
.write_raw_get_fmt = ad7192_write_raw_get_fmt,
+ .read_avail = ad7192_read_avail,
.attrs = &ad7192_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
};
@@ -591,6 +593,7 @@ static const struct iio_info ad7195_info = {
.read_raw = ad7192_read_raw,
.write_raw = ad7192_write_raw,
.write_raw_get_fmt = ad7192_write_raw_get_fmt,
+ .read_avail = ad7192_read_avail,
.attrs = &ad7195_attribute_group,
.validate_trigger = ad_sd_validate_trigger,
};
@@ -625,6 +628,42 @@ static const struct iio_chan_spec ad7193_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(14),
};
+static int ad7192_channels_config(struct iio_dev *indio_dev)
+{
+ struct ad7192_state *st = iio_priv(indio_dev);
+ const struct iio_chan_spec *channels;
+ struct iio_chan_spec *chan;
+ int i;
+
+ switch (st->devid) {
+ case ID_AD7193:
+ channels = ad7193_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad7193_channels);
+ break;
+ default:
+ channels = ad7192_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
+ break;
+ }
+
+ chan = devm_kcalloc(indio_dev->dev.parent, indio_dev->num_channels,
+ sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+
+ indio_dev->channels = chan;
+
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ *chan = channels[i];
+ if (chan->type != IIO_TEMP)
+ chan->info_mask_shared_by_type_available |=
+ BIT(IIO_CHAN_INFO_SCALE);
+ chan++;
+ }
+
+ return 0;
+}
+
static int ad7192_probe(struct spi_device *spi)
{
const struct ad7192_platform_data *pdata = dev_get_platdata(&spi->dev);
@@ -687,16 +726,9 @@ static int ad7192_probe(struct spi_device *spi)
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- switch (st->devid) {
- case ID_AD7193:
- indio_dev->channels = ad7193_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7193_channels);
- break;
- default:
- indio_dev->channels = ad7192_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
- break;
- }
+ ret = ad7192_channels_config(indio_dev);
+ if (ret < 0)
+ goto error_disable_dvdd;
if (st->devid == ID_AD7195)
indio_dev->info = &ad7195_info;
@@ -709,15 +741,42 @@ static int ad7192_probe(struct spi_device *spi)
if (ret)
goto error_disable_dvdd;
- ret = ad7192_setup(st, pdata);
- if (ret)
+ st->fclk = AD7192_INT_FREQ_MHZ;
+
+ st->mclk = devm_clk_get(&st->sd.spi->dev, "mclk");
+ if (IS_ERR(st->mclk) && PTR_ERR(st->mclk) != -ENOENT) {
+ ret = PTR_ERR(st->mclk);
goto error_remove_trigger;
+ }
+
+ st->clock_sel = ad7192_of_clock_select(st);
+
+ if (st->clock_sel == AD7192_CLK_EXT_MCLK1_2 ||
+ st->clock_sel == AD7192_CLK_EXT_MCLK2) {
+ ret = clk_prepare_enable(st->mclk);
+ if (ret < 0)
+ goto error_remove_trigger;
+
+ st->fclk = clk_get_rate(st->mclk);
+ if (!ad7192_valid_external_frequency(st->fclk)) {
+ ret = -EINVAL;
+ dev_err(&spi->dev,
+ "External clock frequency out of bounds\n");
+ goto error_disable_clk;
+ }
+ }
+
+ ret = ad7192_setup(st, spi->dev.of_node);
+ if (ret)
+ goto error_disable_clk;
ret = iio_device_register(indio_dev);
if (ret < 0)
- goto error_remove_trigger;
+ goto error_disable_clk;
return 0;
+error_disable_clk:
+ clk_disable_unprepare(st->mclk);
error_remove_trigger:
ad_sd_cleanup_buffer_and_trigger(indio_dev);
error_disable_dvdd:
@@ -734,6 +793,7 @@ static int ad7192_remove(struct spi_device *spi)
struct ad7192_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
+ clk_disable_unprepare(st->mclk);
ad_sd_cleanup_buffer_and_trigger(indio_dev);
regulator_disable(st->dvdd);