Support for booth 10 and 12 Bits spi Microchip ADCs from 1 to 8 channels CHIPS
The original driver only have support for 4 and 8 channels
Add device tree support too. 
 
Signed-off-by: Soeren Andersen <san at rosetechnology.dk>
---
 Documentation/devicetree/bindings/iio/adc/mcp3x0x.txt |  29 ++++++++++
 drivers/iio/adc/Kconfig                               |   9 ++--
 drivers/iio/adc/Makefile                              |   2 +-
 drivers/iio/adc/mcp320x.c                             | 249 
--------------------------------------------------------------------------------------
 drivers/iio/adc/mcp3x0x.c                             | 431 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 466 insertions(+), 254 deletions(-)

diff --git a/Documentation/devicetree/bindings/iio/adc/mcp3x0x.txt 
b/Documentation/devicetree/bindings/iio/adc/mcp3x0x.txt
new file mode 100644
index 0000000..56f06d0
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/mcp3x0x.txt
@@ -0,0 +1,29 @@
+* Microchip Analog to Digital Converter (ADC)
+
+The node for this driver must be a child node of a SPI controller, hence
+all mandatory properties described in
+
+        Documentation/devicetree/bindings/spi/spi-bus.txt
+
+must be specified.
+
+Required properties:
+               - compatible:   Must be one of the following, depending on the
+                       model:
+                               "mcp3001"
+                               "mcp3002"
+                               "mcp3004"
+                               "mcp3008"
+                               "mcp3201"
+                               "mcp3202"
+                               "mcp3204"
+                               "mcp3208"
+
+
+Examples:
+spi_controller {
+       mcp3x0x@0 {
+               compatible = "mcp3002";
+               reg = <0>;
+               spi-max-frequency = <1000000>;
+       };
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index a80d236..8b3d3c7 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -147,15 +147,16 @@ config MAX1363
          max11646, max11647) Provides direct access via sysfs and buffered
          data via the iio dev interface.
 
-config MCP320X
-       tristate "Microchip Technology MCP3204/08"
+config MCP3X0X
+       tristate "Microchip Technology MCP3x01/02/04/08"
        depends on SPI
        help
-         Say yes here to build support for Microchip Technology's MCP3204 or
+         Say yes here to build support for Microchip Technology's
+         MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or
          MCP3208 analog to digital converter.
 
          This driver can also be built as a module. If so, the module will be
-         called mcp320x.
+         called mcp3x0x.
 
 config MCP3422
        tristate "Microchip Technology MCP3422/3/4/6/7/8 driver"
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 9d60f2d..f25bd54 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_AT91_ADC) += at91_adc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1363) += max1363.o
-obj-$(CONFIG_MCP320X) += mcp320x.o
+obj-$(CONFIG_MCP3X0X) += mcp3x0x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c
deleted file mode 100644
index 28a086e..0000000
--- a/drivers/iio/adc/mcp320x.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2013 Oskar Andero <[email protected]>
- *
- * Driver for Microchip Technology's MCP3204 and MCP3208 ADC chips.
- * Datasheet can be found here:
- * http://ww1.microchip.com/downloads/en/devicedoc/21298c.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/spi/spi.h>
-#include <linux/module.h>
-#include <linux/iio/iio.h>
-#include <linux/regulator/consumer.h>
-
-#define MCP_SINGLE_ENDED       (1 << 3)
-#define MCP_START_BIT          (1 << 4)
-
-enum {
-       mcp3204,
-       mcp3208,
-};
-
-struct mcp320x {
-       struct spi_device *spi;
-       struct spi_message msg;
-       struct spi_transfer transfer[2];
-
-       u8 tx_buf;
-       u8 rx_buf[2];
-
-       struct regulator *reg;
-       struct mutex lock;
-};
-
-static int mcp320x_adc_conversion(struct mcp320x *adc, u8 msg)
-{
-       int ret;
-
-       adc->tx_buf = msg;
-       ret = spi_sync(adc->spi, &adc->msg);
-       if (ret < 0)
-               return ret;
-
-       return ((adc->rx_buf[0] & 0x3f) << 6)  |
-               (adc->rx_buf[1] >> 2);
-}
-
-static int mcp320x_read_raw(struct iio_dev *indio_dev,
-                           struct iio_chan_spec const *channel, int *val,
-                           int *val2, long mask)
-{
-       struct mcp320x *adc = iio_priv(indio_dev);
-       int ret = -EINVAL;
-
-       mutex_lock(&adc->lock);
-
-       switch (mask) {
-       case IIO_CHAN_INFO_RAW:
-               if (channel->differential)
-                       ret = mcp320x_adc_conversion(adc,
-                               MCP_START_BIT | channel->address);
-               else
-                       ret = mcp320x_adc_conversion(adc,
-                               MCP_START_BIT | MCP_SINGLE_ENDED |
-                               channel->address);
-               if (ret < 0)
-                       goto out;
-
-               *val = ret;
-               ret = IIO_VAL_INT;
-               break;
-
-       case IIO_CHAN_INFO_SCALE:
-               /* Digital output code = (4096 * Vin) / Vref */
-               ret = regulator_get_voltage(adc->reg);
-               if (ret < 0)
-                       goto out;
-
-               *val = ret / 1000;
-               *val2 = 12;
-               ret = IIO_VAL_FRACTIONAL_LOG2;
-               break;
-
-       default:
-               break;
-       }
-
-out:
-       mutex_unlock(&adc->lock);
-
-       return ret;
-}
-
-#define MCP320X_VOLTAGE_CHANNEL(num)                           \
-       {                                                       \
-               .type = IIO_VOLTAGE,                            \
-               .indexed = 1,                                   \
-               .channel = (num),                               \
-               .address = (num),                               \
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
-               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
-       }
-
-#define MCP320X_VOLTAGE_CHANNEL_DIFF(num)                      \
-       {                                                       \
-               .type = IIO_VOLTAGE,                            \
-               .indexed = 1,                                   \
-               .channel = (num * 2),                           \
-               .channel2 = (num * 2 + 1),                      \
-               .address = (num * 2),                           \
-               .differential = 1,                              \
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
-               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
-       }
-
-static const struct iio_chan_spec mcp3204_channels[] = {
-       MCP320X_VOLTAGE_CHANNEL(0),
-       MCP320X_VOLTAGE_CHANNEL(1),
-       MCP320X_VOLTAGE_CHANNEL(2),
-       MCP320X_VOLTAGE_CHANNEL(3),
-       MCP320X_VOLTAGE_CHANNEL_DIFF(0),
-       MCP320X_VOLTAGE_CHANNEL_DIFF(1),
-};
-
-static const struct iio_chan_spec mcp3208_channels[] = {
-       MCP320X_VOLTAGE_CHANNEL(0),
-       MCP320X_VOLTAGE_CHANNEL(1),
-       MCP320X_VOLTAGE_CHANNEL(2),
-       MCP320X_VOLTAGE_CHANNEL(3),
-       MCP320X_VOLTAGE_CHANNEL(4),
-       MCP320X_VOLTAGE_CHANNEL(5),
-       MCP320X_VOLTAGE_CHANNEL(6),
-       MCP320X_VOLTAGE_CHANNEL(7),
-       MCP320X_VOLTAGE_CHANNEL_DIFF(0),
-       MCP320X_VOLTAGE_CHANNEL_DIFF(1),
-       MCP320X_VOLTAGE_CHANNEL_DIFF(2),
-       MCP320X_VOLTAGE_CHANNEL_DIFF(3),
-};
-
-static const struct iio_info mcp320x_info = {
-       .read_raw = mcp320x_read_raw,
-       .driver_module = THIS_MODULE,
-};
-
-struct mcp3208_chip_info {
-       const struct iio_chan_spec *channels;
-       unsigned int num_channels;
-};
-
-static const struct mcp3208_chip_info mcp3208_chip_infos[] = {
-       [mcp3204] = {
-               .channels = mcp3204_channels,
-               .num_channels = ARRAY_SIZE(mcp3204_channels)
-       },
-       [mcp3208] = {
-               .channels = mcp3208_channels,
-               .num_channels = ARRAY_SIZE(mcp3208_channels)
-       },
-};
-
-static int mcp320x_probe(struct spi_device *spi)
-{
-       struct iio_dev *indio_dev;
-       struct mcp320x *adc;
-       const struct mcp3208_chip_info *chip_info;
-       int ret;
-
-       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
-       if (!indio_dev)
-               return -ENOMEM;
-
-       adc = iio_priv(indio_dev);
-       adc->spi = spi;
-
-       indio_dev->dev.parent = &spi->dev;
-       indio_dev->name = spi_get_device_id(spi)->name;
-       indio_dev->modes = INDIO_DIRECT_MODE;
-       indio_dev->info = &mcp320x_info;
-
-       chip_info = &mcp3208_chip_infos[spi_get_device_id(spi)->driver_data];
-       indio_dev->channels = chip_info->channels;
-       indio_dev->num_channels = chip_info->num_channels;
-
-       adc->transfer[0].tx_buf = &adc->tx_buf;
-       adc->transfer[0].len = sizeof(adc->tx_buf);
-       adc->transfer[1].rx_buf = adc->rx_buf;
-       adc->transfer[1].len = sizeof(adc->rx_buf);
-
-       spi_message_init_with_transfers(&adc->msg, adc->transfer,
-                                       ARRAY_SIZE(adc->transfer));
-
-       adc->reg = devm_regulator_get(&spi->dev, "vref");
-       if (IS_ERR(adc->reg))
-               return PTR_ERR(adc->reg);
-
-       ret = regulator_enable(adc->reg);
-       if (ret < 0)
-               return ret;
-
-       mutex_init(&adc->lock);
-
-       ret = iio_device_register(indio_dev);
-       if (ret < 0)
-               goto reg_disable;
-
-       return 0;
-
-reg_disable:
-       regulator_disable(adc->reg);
-
-       return ret;
-}
-
-static int mcp320x_remove(struct spi_device *spi)
-{
-       struct iio_dev *indio_dev = spi_get_drvdata(spi);
-       struct mcp320x *adc = iio_priv(indio_dev);
-
-       iio_device_unregister(indio_dev);
-       regulator_disable(adc->reg);
-
-       return 0;
-}
-
-static const struct spi_device_id mcp320x_id[] = {
-       { "mcp3204", mcp3204 },
-       { "mcp3208", mcp3208 },
-       { }
-};
-MODULE_DEVICE_TABLE(spi, mcp320x_id);
-
-static struct spi_driver mcp320x_driver = {
-       .driver = {
-               .name = "mcp320x",
-               .owner = THIS_MODULE,
-       },
-       .probe = mcp320x_probe,
-       .remove = mcp320x_remove,
-       .id_table = mcp320x_id,
-};
-module_spi_driver(mcp320x_driver);
-
-MODULE_AUTHOR("Oskar Andero <[email protected]>");
-MODULE_DESCRIPTION("Microchip Technology MCP3204/08");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/mcp3x0x.c b/drivers/iio/adc/mcp3x0x.c
new file mode 100644
index 0000000..f431e5c
--- /dev/null
+++ b/drivers/iio/adc/mcp3x0x.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2013 Oskar Andero <[email protected]>
+ * Copyright (C) 2014 Allan Bendorff Jensen <[email protected]>
+ *
+ * Driver for following ADC chips from Microchip Technology's:
+ * 10 Bit converter
+ * MCP3001
+ * MCP3002
+ * MCP3004
+ * MCP3008
+ * ------------
+ * 12 bit converter
+ * MCP3201
+ * MCP3202
+ * MCP3204
+ * MCP3208
+ * ------------
+ * Datasheet can be found here:
+ * http://www.microchip.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/regulator/consumer.h>
+
+static int mcp3x0x_read_raw(struct iio_dev *indio_dev,
+                       struct iio_chan_spec const *channel, int *val,
+                       int *val2, long mask);
+
+enum {
+       mcp3001,
+       mcp3002,
+       mcp3004,
+       mcp3008,
+       mcp3201,
+       mcp3202,
+       mcp3204,
+       mcp3208,
+};
+
+struct mcp3x0x {
+       struct spi_device *spi;
+       struct spi_message msg;
+       struct spi_transfer transfer[2];
+
+       u8 tx_buf;
+       u8 rx_buf[2];
+
+       struct regulator *reg;
+       struct mutex lock;
+};
+
+#define MCP3X0X_VOLTAGE_CHANNEL(num)                                   \
+       {                                                               \
+               .type = IIO_VOLTAGE,                                    \
+               .indexed = 1,                                           \
+               .channel = (num),                                       \
+               .address = (num),                                       \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)    \
+       }
+
+#define MCP3X0X_VOLTAGE_CHANNEL_DIFF(num)                              \
+       {                                                               \
+               .type = IIO_VOLTAGE,                                    \
+               .indexed = 1,                                           \
+               .channel = (num * 2),                                   \
+               .channel2 = (num * 2 + 1),                              \
+               .address = (num * 2),                                   \
+               .differential = 1,                                      \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)    \
+       }
+
+static const struct iio_chan_spec mcp3x01_channels[] = {
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(0),
+};
+
+static const struct iio_chan_spec mcp3x02_channels[] = {
+       MCP3X0X_VOLTAGE_CHANNEL(0),
+       MCP3X0X_VOLTAGE_CHANNEL(1),
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(0),
+};
+
+static const struct iio_chan_spec mcp3x04_channels[] = {
+       MCP3X0X_VOLTAGE_CHANNEL(0),
+       MCP3X0X_VOLTAGE_CHANNEL(1),
+       MCP3X0X_VOLTAGE_CHANNEL(2),
+       MCP3X0X_VOLTAGE_CHANNEL(3),
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(0),
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(1),
+};
+
+static const struct iio_chan_spec mcp3x08_channels[] = {
+       MCP3X0X_VOLTAGE_CHANNEL(0),
+       MCP3X0X_VOLTAGE_CHANNEL(1),
+       MCP3X0X_VOLTAGE_CHANNEL(2),
+       MCP3X0X_VOLTAGE_CHANNEL(3),
+       MCP3X0X_VOLTAGE_CHANNEL(4),
+       MCP3X0X_VOLTAGE_CHANNEL(5),
+       MCP3X0X_VOLTAGE_CHANNEL(6),
+       MCP3X0X_VOLTAGE_CHANNEL(7),
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(0),
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(1),
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(2),
+       MCP3X0X_VOLTAGE_CHANNEL_DIFF(3),
+};
+
+static const struct iio_info mcp3x0x_info = {
+       .read_raw = mcp3x0x_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+struct mcp3X0X_chip_info {
+       const struct iio_chan_spec *channels;
+       unsigned int num_channels;
+       unsigned int resolution;
+};
+
+static const struct mcp3X0X_chip_info mcp3X0X_chip_infos[] = {
+       [mcp3001] = {
+               .channels = mcp3x01_channels,
+               .num_channels = ARRAY_SIZE(mcp3x01_channels)
+       },
+       [mcp3002] = {
+               .channels = mcp3x02_channels,
+               .num_channels = ARRAY_SIZE(mcp3x02_channels)
+       },
+       [mcp3004] = {
+               .channels = mcp3x04_channels,
+               .num_channels = ARRAY_SIZE(mcp3x04_channels)
+       },
+       [mcp3008] = {
+               .channels = mcp3x08_channels,
+               .num_channels = ARRAY_SIZE(mcp3x08_channels)
+       },
+       [mcp3201] = {
+               .channels = mcp3x01_channels,
+               .num_channels = ARRAY_SIZE(mcp3x01_channels)
+       },
+       [mcp3202] = {
+               .channels = mcp3x02_channels,
+               .num_channels = ARRAY_SIZE(mcp3x02_channels)
+       },
+       [mcp3204] = {
+               .channels = mcp3x04_channels,
+               .num_channels = ARRAY_SIZE(mcp3x04_channels)
+       },
+       [mcp3208] = {
+               .channels = mcp3x08_channels,
+               .num_channels = ARRAY_SIZE(mcp3x08_channels)
+       },
+};
+
+static int channel_to_tx_data(const struct mcp3X0X_chip_info *chip_info,
+                       const unsigned int channel, bool differential)
+{
+       unsigned int tx_data = 0;
+
+       if (chip_info->num_channels - 1 == 2) {
+               tx_data = 0x12 | (differential ? 0 << 3 : 1 << 3) |
+                               ((channel & 0x01) << 2);
+       } else if (chip_info->num_channels - 2 == 4) {
+               tx_data = 0x20 | (differential ? 0 << 4 : 1 << 4) |
+                               ((channel & 0x03) << 1);
+       } else if (chip_info->num_channels - 4 == 8) {
+               tx_data = 0x20 | (differential ? 0 << 4 : 1 << 4) |
+                               ((channel & 0x07) << 1);
+       }
+
+       return tx_data;
+}
+
+static int mcp3x0x_adc_conversion(struct mcp3x0x *adc, u8 channel,
+                       bool differential, int device_index)
+{
+       int ret;
+       u16 adc_value;
+       __be16 buf;
+
+       const struct mcp3X0X_chip_info *chip_info = NULL;
+
+       if (device_index == -1)
+               return -1;
+
+       chip_info = &mcp3X0X_chip_infos[device_index];
+       if (chip_info == NULL)
+               return -1;
+
+       adc->rx_buf[0] = 0;
+       adc->rx_buf[1] = 0;
+       adc->tx_buf = channel_to_tx_data(chip_info, channel, differential);
+
+       if (device_index != mcp3001 && device_index != mcp3201) {
+               ret = spi_sync(adc->spi, &adc->msg);
+               if (ret < 0)
+                       return ret;
+       } else {
+               ret = spi_read(adc->spi, (u8 *)&buf, 2);
+               if (ret < 0)
+                       return ret;
+       }
+
+       switch (device_index) {
+       case mcp3001:
+               adc_value = (be16_to_cpu(buf) >> 3);
+               break;
+       case mcp3002:
+               spi_sync(adc->spi, &adc->msg);
+               adc_value = adc->rx_buf[0];
+               adc_value = ((adc_value << 2) |
+                       ((adc->rx_buf[1] & 0xC0) >> 6)) & 0x03ff;
+               break;
+       case mcp3004:
+       case mcp3008:
+               adc_value = adc->rx_buf[0] & 0x7f;
+               adc_value = ((adc_value << 3) |
+                       ((adc->rx_buf[1] & 0xe0) >> 5)) & 0x03ff;
+               break;
+       case mcp3201:
+               adc_value = (be16_to_cpu(buf) >> 1);
+               break;
+       case mcp3202:
+               adc_value = adc->rx_buf[0];
+               adc_value = ((adc_value << 4) |
+                       ((adc->rx_buf[1] & 0xf0) >> 4)) & 0x0fff;
+               break;
+       case mcp3204:
+       case mcp3208:
+               adc_value = adc->rx_buf[0] & 0x7f;
+               adc_value = ((adc_value << 5) |
+                       ((adc->rx_buf[1] & 0xf8) >> 3)) & 0x0fff;
+               break;
+       default:
+               adc_value = 0;
+               break;
+       }
+
+       return adc_value;
+}
+
+static int mcp3x0x_read_raw(struct iio_dev *indio_dev,
+                       struct iio_chan_spec const *channel, int *val,
+                       int *val2, long mask)
+{
+       struct mcp3x0x *adc = iio_priv(indio_dev);
+       int ret = -EINVAL;
+       int device_index = 0;
+
+       mutex_lock(&adc->lock);
+
+       device_index = spi_get_device_id(adc->spi)->driver_data;
+
+       if (device_index == -1)
+               goto out;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = mcp3x0x_adc_conversion(adc, channel->address,
+                       channel->differential, device_index);
+
+               if (ret < 0)
+                       goto out;
+
+               *val = ret;
+               ret = IIO_VAL_INT;
+               break;
+
+       case IIO_CHAN_INFO_SCALE:
+               /*
+                * Digital output code = (resolution * Vin) / Vref
+                * Get regulator output voltage in uV.
+                */
+               ret = regulator_get_voltage(adc->reg);
+               if (ret < 0)
+                       goto out;
+
+               /* convert regulator output voltage to mV */
+               *val  = ret / 1000;
+               *val2 = -1;
+               if (device_index == mcp3001 || device_index == mcp3002 ||
+                       device_index == mcp3004 || device_index == mcp3008)
+                       *val2 = 10;
+               else if (device_index == mcp3201 || device_index == mcp3202 ||
+                       device_index == mcp3204 || device_index == mcp3208)
+                       *val2 = 12;
+               else
+                       goto out;
+
+               ret = IIO_VAL_FRACTIONAL_LOG2;
+               break;
+
+       default:
+               break;
+       }
+
+out:
+       mutex_unlock(&adc->lock);
+
+       return ret;
+}
+
+static int mcp3x0x_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct mcp3x0x *adc;
+       const struct mcp3X0X_chip_info *chip_info;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       adc = iio_priv(indio_dev);
+       adc->spi = spi;
+
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &mcp3x0x_info;
+
+       chip_info = &mcp3X0X_chip_infos[spi_get_device_id(spi)->driver_data];
+       indio_dev->channels = chip_info->channels;
+       indio_dev->num_channels = chip_info->num_channels;
+
+       adc->transfer[0].tx_buf = &adc->tx_buf;
+       adc->transfer[0].len = sizeof(adc->tx_buf);
+       adc->transfer[1].rx_buf = adc->rx_buf;
+       adc->transfer[1].len = sizeof(adc->rx_buf);
+
+       spi_message_init_with_transfers(&adc->msg, adc->transfer,
+                                       ARRAY_SIZE(adc->transfer));
+
+       adc->reg = devm_regulator_get(&spi->dev, "vref");
+       if (IS_ERR(adc->reg))
+               return PTR_ERR(adc->reg);
+
+       ret = regulator_enable(adc->reg);
+       if (ret < 0)
+               return ret;
+
+       mutex_init(&adc->lock);
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0)
+               goto reg_disable;
+
+       return 0;
+
+reg_disable:
+       regulator_disable(adc->reg);
+
+       return ret;
+}
+
+static int mcp3x0x_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct mcp3x0x *adc = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+       regulator_disable(adc->reg);
+
+       return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id mcp3x0x_dt_ids[] = {
+       {
+               .compatible = "mcp3001",
+               .data = &mcp3X0X_chip_infos[mcp3001],
+       }, {
+               .compatible = "mcp3002",
+               .data = &mcp3X0X_chip_infos[mcp3002],
+       }, {
+               .compatible = "mcp3004",
+               .data = &mcp3X0X_chip_infos[mcp3004],
+       }, {
+               .compatible = "mcp3008",
+               .data = &mcp3X0X_chip_infos[mcp3004],
+       }, {
+               .compatible = "mcp3201",
+               .data = &mcp3X0X_chip_infos[mcp3201],
+       }, {
+               .compatible = "mcp3202",
+               .data = &mcp3X0X_chip_infos[mcp3202],
+       }, {
+               .compatible = "mcp3204",
+               .data = &mcp3X0X_chip_infos[mcp3204],
+       }, {
+               .compatible = "mcp3008",
+               .data = &mcp3X0X_chip_infos[mcp3208],
+       }, {
+       }
+};
+MODULE_DEVICE_TABLE(of, mcp3x0x_dt_ids);
+#endif
+
+static const struct spi_device_id mcp3x0x_id[] = {
+       { "mcp3001", mcp3001 },
+       { "mcp3002", mcp3002 },
+       { "mcp3004", mcp3004 },
+       { "mcp3008", mcp3008 },
+       { "mcp3201", mcp3201 },
+       { "mcp3202", mcp3202 },
+       { "mcp3204", mcp3204 },
+       { "mcp3208", mcp3208 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, mcp3x0x_id);
+
+static struct spi_driver mcp3x0x_driver = {
+       .driver = {
+               .name = "mcp3x0x",
+               .owner = THIS_MODULE,
+       },
+       .probe = mcp3x0x_probe,
+       .remove = mcp3x0x_remove,
+       .id_table = mcp3x0x_id,
+};
+module_spi_driver(mcp3x0x_driver);
+
+MODULE_AUTHOR("Allan Bendorff Jensen <[email protected]>");
+MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08");
+MODULE_LICENSE("GPL v2");


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to