Commit e32cff6f authored by Gregory CLEMENT's avatar Gregory CLEMENT Committed by Jonathan Cameron

iio: adc: lpc32xx: Add scale feature

Until now this driver only exposed the raw value of the channels. With
this patch, the scale value is also exposed.

It depends of a regulator supply, and unlike most of the other driver, do
not having this regulator won't prevent to use the driver. The reason for
it is to allow to continue to use this driver with an old device tree. If
there is no regulator supply then the scale won't be exposed.
Signed-off-by: default avatarGregory CLEMENT <gregory.clement@bootlin.com>
Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 9f29b00c
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
/* /*
* LPC32XX registers definitions * LPC32XX registers definitions
...@@ -46,6 +47,7 @@ struct lpc32xx_adc_state { ...@@ -46,6 +47,7 @@ struct lpc32xx_adc_state {
void __iomem *adc_base; void __iomem *adc_base;
struct clk *clk; struct clk *clk;
struct completion completion; struct completion completion;
struct regulator *vref;
u32 value; u32 value;
}; };
...@@ -58,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, ...@@ -58,7 +60,9 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
{ {
struct lpc32xx_adc_state *st = iio_priv(indio_dev); struct lpc32xx_adc_state *st = iio_priv(indio_dev);
int ret; int ret;
if (mask == IIO_CHAN_INFO_RAW) {
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
ret = clk_prepare_enable(st->clk); ret = clk_prepare_enable(st->clk);
if (ret) { if (ret) {
...@@ -78,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev, ...@@ -78,22 +82,36 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT; return IIO_VAL_INT;
}
case IIO_CHAN_INFO_SCALE:
*val = regulator_get_voltage(st->vref) / 1000;
*val2 = 10;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL; return -EINVAL;
}
} }
static const struct iio_info lpc32xx_adc_iio_info = { static const struct iio_info lpc32xx_adc_iio_info = {
.read_raw = &lpc32xx_read_raw, .read_raw = &lpc32xx_read_raw,
}; };
#define LPC32XX_ADC_CHANNEL(_index) { \ #define LPC32XX_ADC_CHANNEL_BASE(_index) \
.type = IIO_VOLTAGE, \ .type = IIO_VOLTAGE, \
.indexed = 1, \ .indexed = 1, \
.channel = _index, \ .channel = _index, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.address = LPC32XXAD_IN * _index, \ .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[] = { static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
...@@ -102,6 +120,12 @@ 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), 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) static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id)
{ {
struct lpc32xx_adc_state *st = dev_id; struct lpc32xx_adc_state *st = dev_id;
...@@ -160,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) ...@@ -160,6 +184,15 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
return retval; 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); platform_set_drvdata(pdev, iodev);
init_completion(&st->completion); init_completion(&st->completion);
...@@ -168,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev) ...@@ -168,7 +201,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
iodev->dev.parent = &pdev->dev; iodev->dev.parent = &pdev->dev;
iodev->info = &lpc32xx_adc_iio_info; iodev->info = &lpc32xx_adc_iio_info;
iodev->modes = INDIO_DIRECT_MODE; iodev->modes = INDIO_DIRECT_MODE;
iodev->channels = lpc32xx_adc_iio_channels;
iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels); iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
retval = devm_iio_device_register(&pdev->dev, iodev); retval = devm_iio_device_register(&pdev->dev, iodev);
......
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