diff options
-rw-r--r-- | drivers/iio/adc/lpc32xx_adc.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c index dacd7b1fe9d5..a6ee1c3a9064 100644 --- a/drivers/iio/adc/lpc32xx_adc.c +++ b/drivers/iio/adc/lpc32xx_adc.c @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> /* * LPC32XX registers definitions @@ -46,6 +47,7 @@ struct lpc32xx_adc_state { void __iomem *adc_base; struct clk *clk; struct completion completion; + struct regulator *vref; u32 value; }; @@ -58,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, { struct lpc32xx_adc_state *st = iio_priv(indio_dev); int ret; - if (mask == IIO_CHAN_INFO_RAW) { + + switch (mask) { + case IIO_CHAN_INFO_RAW: mutex_lock(&indio_dev->mlock); ret = clk_prepare_enable(st->clk); if (ret) { @@ -78,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); return IIO_VAL_INT; - } - return -EINVAL; + case IIO_CHAN_INFO_SCALE: + *val = regulator_get_voltage(st->vref) / 1000; + *val2 = 10; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } } static const struct iio_info lpc32xx_adc_iio_info = { .read_raw = &lpc32xx_read_raw, }; -#define LPC32XX_ADC_CHANNEL(_index) { \ +#define LPC32XX_ADC_CHANNEL_BASE(_index) \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = _index, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .address = LPC32XXAD_IN * _index, \ - .scan_index = _index, \ + .scan_index = _index, + +#define LPC32XX_ADC_CHANNEL(_index) { \ + LPC32XX_ADC_CHANNEL_BASE(_index) \ +} + +#define LPC32XX_ADC_SCALE_CHANNEL(_index) { \ + LPC32XX_ADC_CHANNEL_BASE(_index) \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ } static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { @@ -102,6 +120,12 @@ static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { LPC32XX_ADC_CHANNEL(2), }; +static const struct iio_chan_spec lpc32xx_adc_iio_scale_channels[] = { + LPC32XX_ADC_SCALE_CHANNEL(0), + LPC32XX_ADC_SCALE_CHANNEL(1), + LPC32XX_ADC_SCALE_CHANNEL(2), +}; + static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id) { struct lpc32xx_adc_state *st = dev_id; @@ -160,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) return retval; } + st->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(st->vref)) { + iodev->channels = lpc32xx_adc_iio_channels; + dev_info(&pdev->dev, + "Missing vref regulator: No scaling available\n"); + } else { + iodev->channels = lpc32xx_adc_iio_scale_channels; + } + platform_set_drvdata(pdev, iodev); init_completion(&st->completion); @@ -168,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) iodev->dev.parent = &pdev->dev; iodev->info = &lpc32xx_adc_iio_info; iodev->modes = INDIO_DIRECT_MODE; - iodev->channels = lpc32xx_adc_iio_channels; iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); retval = devm_iio_device_register(&pdev->dev, iodev); |