Commit 260442cc authored by Paul Cercueil's avatar Paul Cercueil Committed by Jonathan Cameron

iio: adc: ad7091r5: Add scale and external VREF support

The scale can now be obtained with the "in_voltage_scale" file.
By default, the scale returned corresponds to the internal VREF of 2.5V.

It is possible to use an external VREF (through the REFIN/REFOUT pin of
the chip), by passing a regulator to the driver. The scale will then be
calculated according to the voltage reported by the regulator.
Signed-off-by: default avatarPaul Cercueil <paul.cercueil@analog.com>
Co-developed-by: default avatarBeniamin Bia <beniamin.bia@analog.com>
Signed-off-by: default avatarBeniamin Bia <beniamin.bia@analog.com>
Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent ca693001
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "ad7091r-base.h" #include "ad7091r-base.h"
...@@ -42,6 +43,7 @@ enum ad7091r_mode { ...@@ -42,6 +43,7 @@ enum ad7091r_mode {
struct ad7091r_state { struct ad7091r_state {
struct device *dev; struct device *dev;
struct regmap *map; struct regmap *map;
struct regulator *vref;
const struct ad7091r_chip_info *chip_info; const struct ad7091r_chip_info *chip_info;
enum ad7091r_mode mode; enum ad7091r_mode mode;
struct mutex lock; /*lock to prevent concurent reads */ struct mutex lock; /*lock to prevent concurent reads */
...@@ -141,6 +143,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev, ...@@ -141,6 +143,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev,
ret = IIO_VAL_INT; ret = IIO_VAL_INT;
break; break;
case IIO_CHAN_INFO_SCALE:
if (st->vref) {
ret = regulator_get_voltage(st->vref);
if (ret < 0)
goto unlock;
*val = ret / 1000;
} else {
*val = st->chip_info->vref_mV;
}
*val2 = chan->scan_type.realbits;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default: default:
ret = -EINVAL; ret = -EINVAL;
break; break;
...@@ -183,6 +200,13 @@ static irqreturn_t ad7091r_event_handler(int irq, void *private) ...@@ -183,6 +200,13 @@ static irqreturn_t ad7091r_event_handler(int irq, void *private)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void ad7091r_remove(void *data)
{
struct ad7091r_state *st = data;
regulator_disable(st->vref);
}
int ad7091r_probe(struct device *dev, const char *name, int ad7091r_probe(struct device *dev, const char *name,
const struct ad7091r_chip_info *chip_info, const struct ad7091r_chip_info *chip_info,
struct regmap *map, int irq) struct regmap *map, int irq)
...@@ -216,6 +240,20 @@ int ad7091r_probe(struct device *dev, const char *name, ...@@ -216,6 +240,20 @@ int ad7091r_probe(struct device *dev, const char *name,
return ret; return ret;
} }
st->vref = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(st->vref)) {
if (PTR_ERR(st->vref) == -EPROBE_DEFER)
return -EPROBE_DEFER;
st->vref = NULL;
} else {
ret = regulator_enable(st->vref);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, ad7091r_remove, st);
if (ret)
return ret;
}
/* Use command mode by default to convert only desired channels*/ /* Use command mode by default to convert only desired channels*/
ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND); ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND);
if (ret) if (ret)
......
...@@ -14,6 +14,7 @@ struct ad7091r_state; ...@@ -14,6 +14,7 @@ struct ad7091r_state;
struct ad7091r_chip_info { struct ad7091r_chip_info {
unsigned int num_channels; unsigned int num_channels;
const struct iio_chan_spec *channels; const struct iio_chan_spec *channels;
unsigned int vref_mV;
}; };
extern const struct regmap_config ad7091r_regmap_config; extern const struct regmap_config ad7091r_regmap_config;
......
...@@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = { ...@@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = {
#define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \ #define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \ .indexed = 1, \
.channel = idx, \ .channel = idx, \
.event_spec = ev, \ .event_spec = ev, \
.num_event_specs = num_ev, \ .num_event_specs = num_ev, \
.scan_type.storagebits = 16, \
.scan_type.realbits = bits, \
} }
static const struct iio_chan_spec ad7091r5_channels_irq[] = { static const struct iio_chan_spec ad7091r5_channels_irq[] = {
AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)), AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
...@@ -57,11 +60,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = { ...@@ -57,11 +60,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = {
static const struct ad7091r_chip_info ad7091r5_chip_info_irq = { static const struct ad7091r_chip_info ad7091r5_chip_info_irq = {
.channels = ad7091r5_channels_irq, .channels = ad7091r5_channels_irq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_irq), .num_channels = ARRAY_SIZE(ad7091r5_channels_irq),
.vref_mV = 2500,
}; };
static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = { static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
.channels = ad7091r5_channels_noirq, .channels = ad7091r5_channels_noirq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_noirq), .num_channels = ARRAY_SIZE(ad7091r5_channels_noirq),
.vref_mV = 2500,
}; };
static int ad7091r5_i2c_probe(struct i2c_client *i2c, static int ad7091r5_i2c_probe(struct i2c_client *i2c,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment