iio: adc: ti-adc161s626: add regulator support
authorMatt Ranostay <mranostay@gmail.com>
Sun, 18 Sep 2016 22:42:15 +0000 (15:42 -0700)
committerJonathan Cameron <jic23@kernel.org>
Tue, 27 Sep 2016 19:33:03 +0000 (20:33 +0100)
Allow IIO_CHAN_INFO_SCALE and IIO_CHAN_INFO_OFFSET attributes for
processing by checking voltage from a regulator.

Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Documentation/devicetree/bindings/iio/adc/ti-adc161s626.txt
drivers/iio/adc/ti-adc161s626.c

index 9ed2315781e4ba00ad3831f79e972c8f8ae14bb5..3d25011f0c99beb664506d0a97583cf635f45cef 100644 (file)
@@ -3,6 +3,7 @@
 Required properties:
  - compatible: Should be "ti,adc141s626" or "ti,adc161s626"
  - reg: spi chip select number for the device
+ - vdda-supply: supply voltage to VDDA pin
 
 Recommended properties:
  - spi-max-frequency: Definition as per
@@ -11,6 +12,7 @@ Recommended properties:
 Example:
 adc@0 {
        compatible = "ti,adc161s626";
+       vdda-supply = <&vdda_fixed>;
        reg = <0>;
        spi-max-frequency = <4300000>;
 };
index f94b69f9c2882025b62d60375556a8a98f1170ba..4836a0d7aef57fd98bf0bb9408ed9a4f49f0a45f 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/iio/buffer.h>
 #include <linux/iio/trigger_consumer.h>
 #include <linux/iio/triggered_buffer.h>
+#include <linux/regulator/consumer.h>
 
 #define TI_ADC_DRV_NAME        "ti-adc161s626"
 
@@ -39,7 +40,9 @@ static const struct iio_chan_spec ti_adc141s626_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .channel = 0,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_OFFSET),
                .scan_index = 0,
                .scan_type = {
                        .sign = 's',
@@ -54,7 +57,9 @@ static const struct iio_chan_spec ti_adc161s626_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .channel = 0,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_OFFSET),
                .scan_index = 0,
                .scan_type = {
                        .sign = 's',
@@ -68,6 +73,8 @@ static const struct iio_chan_spec ti_adc161s626_channels[] = {
 struct ti_adc_data {
        struct iio_dev *indio_dev;
        struct spi_device *spi;
+       struct regulator *ref;
+
        u8 read_size;
        u8 shift;
 
@@ -135,18 +142,32 @@ static int ti_adc_read_raw(struct iio_dev *indio_dev,
        struct ti_adc_data *data = iio_priv(indio_dev);
        int ret;
 
-       if (mask != IIO_CHAN_INFO_RAW)
-               return -EINVAL;
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
 
-       ret = iio_device_claim_direct_mode(indio_dev);
-       if (ret)
-               return ret;
+               ret = ti_adc_read_measurement(data, chan, val);
+               iio_device_release_direct_mode(indio_dev);
 
-       ret = ti_adc_read_measurement(data, chan, val);
-       iio_device_release_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
 
-       if (!ret)
                return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               ret = regulator_get_voltage(data->ref);
+               if (ret < 0)
+                       return ret;
+
+               *val = ret / 1000;
+               *val2 = chan->scan_type.realbits;
+
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_OFFSET:
+               *val = 1 << (chan->scan_type.realbits - 1);
+               return IIO_VAL_INT;
+       }
 
        return 0;
 }
@@ -191,10 +212,17 @@ static int ti_adc_probe(struct spi_device *spi)
                break;
        }
 
+       data->ref = devm_regulator_get(&spi->dev, "vdda");
+       if (!IS_ERR(data->ref)) {
+               ret = regulator_enable(data->ref);
+               if (ret < 0)
+                       return ret;
+       }
+
        ret = iio_triggered_buffer_setup(indio_dev, NULL,
                                         ti_adc_trigger_handler, NULL);
        if (ret)
-               return ret;
+               goto error_regulator_disable;
 
        ret = iio_device_register(indio_dev);
        if (ret)
@@ -205,15 +233,20 @@ static int ti_adc_probe(struct spi_device *spi)
 error_unreg_buffer:
        iio_triggered_buffer_cleanup(indio_dev);
 
+error_regulator_disable:
+       regulator_disable(data->ref);
+
        return ret;
 }
 
 static int ti_adc_remove(struct spi_device *spi)
 {
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct ti_adc_data *data = iio_priv(indio_dev);
 
        iio_device_unregister(indio_dev);
        iio_triggered_buffer_cleanup(indio_dev);
+       regulator_disable(data->ref);
 
        return 0;
 }