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

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
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>

#include "ad7091r-base.h"

@@ -42,6 +43,7 @@ enum ad7091r_mode {
struct ad7091r_state {
	struct device *dev;
	struct regmap *map;
	struct regulator *vref;
	const struct ad7091r_chip_info *chip_info;
	enum ad7091r_mode mode;
	struct mutex lock; /*lock to prevent concurent reads */
@@ -141,6 +143,21 @@ static int ad7091r_read_raw(struct iio_dev *iio_dev,
		ret = IIO_VAL_INT;
		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:
		ret = -EINVAL;
		break;
@@ -183,6 +200,13 @@ static irqreturn_t ad7091r_event_handler(int irq, void *private)
	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,
		const struct ad7091r_chip_info *chip_info,
		struct regmap *map, int irq)
@@ -216,6 +240,20 @@ int ad7091r_probe(struct device *dev, const char *name,
			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*/
	ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND);
	if (ret)
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ struct ad7091r_state;
struct ad7091r_chip_info {
	unsigned int num_channels;
	const struct iio_chan_spec *channels;
	unsigned int vref_mV;
};

extern const struct regmap_config ad7091r_regmap_config;
+5 −0
Original line number Diff line number Diff line
@@ -35,10 +35,13 @@ static const struct iio_event_spec ad7091r5_events[] = {
#define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \
	.type = IIO_VOLTAGE, \
	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
	.indexed = 1, \
	.channel = idx, \
	.event_spec = ev, \
	.num_event_specs = num_ev, \
	.scan_type.storagebits = 16, \
	.scan_type.realbits = bits, \
}
static const struct iio_chan_spec ad7091r5_channels_irq[] = {
	AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
@@ -57,11 +60,13 @@ static const struct iio_chan_spec ad7091r5_channels_noirq[] = {
static const struct ad7091r_chip_info ad7091r5_chip_info_irq = {
	.channels = ad7091r5_channels_irq,
	.num_channels = ARRAY_SIZE(ad7091r5_channels_irq),
	.vref_mV = 2500,
};

static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
	.channels = ad7091r5_channels_noirq,
	.num_channels = ARRAY_SIZE(ad7091r5_channels_noirq),
	.vref_mV = 2500,
};

static int ad7091r5_i2c_probe(struct i2c_client *i2c,