The AD5694/AD5694R/AD5695R/AD5696/AD5696R are a family of 4 channel DAC
s with 12-bit, 14-bit and 16-bit precision respectively. The devices have
either no built-in reference, or built-in 2.5V reference.

The AD5671R/AD5675R are similar, except that they have 8 instead of 4
channels.

These devices are similar to AD5672R/AD5676/AD5676R and
AD5684/AD5684R/AD5684/AD5685R/AD5686/AD5686R, except that they use i2c
instead of spi. In order to add support in the previously existing driver,
three modules were created. One baseline module that has all the
chip-logic and then one module for SPI and one for I2C.

Datasheets:
http://www.analog.com/media/en/technical-documentation/data-sheets/AD5671R_5675R.pdf
http://www.analog.com/media/en/technical-documentation/data-sheets/AD5696R_5695R_5694R.pdf

Signed-off-by: Stefan Popa <stefan.p...@analog.com>
---
 MAINTAINERS                  |   8 ++
 drivers/iio/dac/Kconfig      |  27 ++++--
 drivers/iio/dac/ad5686-spi.c |  93 ++++++++++++++++++
 drivers/iio/dac/ad5686.c     | 222 +++++++++++++------------------------------
 drivers/iio/dac/ad5686.h     | 114 ++++++++++++++++++++++
 drivers/iio/dac/ad5696-i2c.c |  98 +++++++++++++++++++
 6 files changed, 400 insertions(+), 162 deletions(-)
 create mode 100644 drivers/iio/dac/ad5686-spi.c
 create mode 100644 drivers/iio/dac/ad5686.h
 create mode 100644 drivers/iio/dac/ad5696-i2c.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 473ac00..002cb01 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -791,6 +791,14 @@ M: Michael Hanselmann <linux-ker...@hansmi.ch>
 S:     Supported
 F:     drivers/macintosh/ams/
 
+ANALOG DEVICES INC AD5686 DRIVER
+M:     Stefan Popa <stefan.p...@analog.com>
+L:     linux...@vger.kernel.org
+W:     http://ez.analog.com/community/linux-device-drivers
+S:     Supported
+F:     drivers/iio/dac/ad5686*
+F:     drivers/iio/dac/ad5696*
+
 ANALOG DEVICES INC AD9389B DRIVER
 M:     Hans Verkuil <hans.verk...@cisco.com>
 L:     linux-me...@vger.kernel.org
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index 965d5c0..dab0b8a 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -131,15 +131,30 @@ config LTC2632
          module will be called ltc2632.
 
 config AD5686
-       tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
+       tristate
+
+config AD5686_SPI
+       tristate "Analog Devices AD5686 and similar multi-channel DACs (SPI)"
        depends on SPI
+       select AD5686
        help
-         Say yes here to build support for Analog Devices AD5686R, AD5685R,
-         AD5684R, AD5791 Voltage Output Digital to
-         Analog Converter.
+       Say yes here to build support for Analog Devices AD5672R, AD5676,
+       AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R.
+       Voltage Output Digital to Analog Converter.
 
-         To compile this driver as a module, choose M here: the
-         module will be called ad5686.
+       To compile this driver as a module, choose M here: the
+       module will be called ad5686.
+
+config AD5696_I2C
+       tristate "Analog Devices AD5696 and similar multi-channel DACs (I2C)"
+       depends on I2C
+       select AD5686
+       help
+       Say yes here to build support for Analog Devices AD5671R, AD5675R,
+       AD5694, AD5694R, AD5695R, AD5696, AD5696R Voltage Output Digital to
+       Analog Converter.
+       To compile this driver as a module, choose M here: the module will be
+       called ad5696.
 
 config AD5755
        tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC 
driver"
diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c
new file mode 100644
index 0000000..d68579b
--- /dev/null
+++ b/drivers/iio/dac/ad5686-spi.c
@@ -0,0 +1,93 @@
+/*
+ * AD5672R, AD5676, AD5676R, AD5684, AD5684R, AD5684R, AD5685R, AD5686, AD5686R
+ * Digital to analog converters driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include "ad5686.h"
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+static int ad5686_spi_write(struct ad5686_state *st,
+                           u8 cmd, u8 addr, u16 val)
+{
+       struct spi_device *spi = to_spi_device(st->dev);
+
+       st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
+                                     AD5686_ADDR(addr) |
+                                     val);
+
+       return spi_write(spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
+{
+       struct spi_transfer t[] = {
+               {
+                       .tx_buf = &st->data[0].d8[1],
+                       .len = 3,
+                       .cs_change = 1,
+               }, {
+                       .tx_buf = &st->data[1].d8[1],
+                       .rx_buf = &st->data[2].d8[1],
+                       .len = 3,
+               },
+       };
+       struct spi_device *spi = to_spi_device(st->dev);
+       int ret;
+
+       st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
+                                     AD5686_ADDR(addr));
+       st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
+
+       ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
+       if (ret < 0)
+               return ret;
+
+       return be32_to_cpu(st->data[2].d32);
+}
+
+static int ad5686_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+
+       return ad5686_probe(&spi->dev, id->driver_data, id->name,
+                           ad5686_spi_write, ad5686_spi_read);
+}
+
+static int ad5686_spi_remove(struct spi_device *spi)
+{
+       return ad5686_remove(&spi->dev);
+}
+
+static const struct spi_device_id ad5686_spi_id[] = {
+       {"ad5672r", ID_AD5672R},
+       {"ad5676", ID_AD5676},
+       {"ad5676r", ID_AD5676R},
+       {"ad5684", ID_AD5684},
+       {"ad5684r", ID_AD5684R},
+       {"ad5685r", ID_AD5685R},
+       {"ad5686", ID_AD5686},
+       {"ad5686r", ID_AD5686R},
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ad5686_spi_id);
+
+static struct spi_driver ad5686_spi_driver = {
+       .driver = {
+               .name = "ad5686",
+       },
+       .probe = ad5686_spi_probe,
+       .remove = ad5686_spi_remove,
+       .id_table = ad5686_spi_id,
+};
+
+module_spi_driver(ad5686_spi_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.p...@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
index 5fb0179..e4ea0dc 100644
--- a/drivers/iio/dac/ad5686.c
+++ b/drivers/iio/dac/ad5686.c
@@ -11,7 +11,6 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/spi/spi.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include <linux/regulator/consumer.h>
@@ -19,128 +18,28 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 
-#define AD5686_ADDR(x)                         ((x) << 16)
-#define AD5686_CMD(x)                          ((x) << 20)
-
-#define AD5686_ADDR_DAC(chan)                  (0x1 << (chan))
-#define AD5686_ADDR_ALL_DAC                    0xF
-
-#define AD5686_CMD_NOOP                                0x0
-#define AD5686_CMD_WRITE_INPUT_N               0x1
-#define AD5686_CMD_UPDATE_DAC_N                        0x2
-#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N      0x3
-#define AD5686_CMD_POWERDOWN_DAC               0x4
-#define AD5686_CMD_LDAC_MASK                   0x5
-#define AD5686_CMD_RESET                       0x6
-#define AD5686_CMD_INTERNAL_REFER_SETUP                0x7
-#define AD5686_CMD_DAISY_CHAIN_ENABLE          0x8
-#define AD5686_CMD_READBACK_ENABLE             0x9
-
-#define AD5686_LDAC_PWRDN_NONE                 0x0
-#define AD5686_LDAC_PWRDN_1K                   0x1
-#define AD5686_LDAC_PWRDN_100K                 0x2
-#define AD5686_LDAC_PWRDN_3STATE               0x3
-
-/**
- * struct ad5686_chip_info - chip specific information
- * @int_vref_mv:       AD5620/40/60: the internal reference voltage
- * @num_channels:      number of channels
- * @channel:           channel specification
-*/
-
-struct ad5686_chip_info {
-       u16                             int_vref_mv;
-       unsigned int                    num_channels;
-       struct iio_chan_spec            *channels;
-};
-
-/**
- * struct ad5446_state - driver instance specific data
- * @spi:               spi_device
- * @chip_info:         chip model specific constants, available modes etc
- * @reg:               supply regulator
- * @vref_mv:           actual reference voltage used
- * @pwr_down_mask:     power down mask
- * @pwr_down_mode:     current power down mode
- * @data:              spi transfer buffers
- */
+#include "ad5686.h"
 
-struct ad5686_state {
-       struct spi_device               *spi;
-       const struct ad5686_chip_info   *chip_info;
-       struct regulator                *reg;
-       unsigned short                  vref_mv;
-       unsigned                        pwr_down_mask;
-       unsigned                        pwr_down_mode;
-       /*
-        * DMA (thus cache coherency maintenance) requires the
-        * transfer buffers to live in their own cache lines.
-        */
-
-       union {
-               __be32 d32;
-               u8 d8[4];
-       } data[3] ____cacheline_aligned;
+static const char * const ad5686_powerdown_modes[] = {
+       "1kohm_to_gnd",
+       "100kohm_to_gnd",
+       "three_state"
 };
 
-/**
- * ad5686_supported_device_ids:
- */
-
-enum ad5686_supported_device_ids {
-       ID_AD5672R,
-       ID_AD5676,
-       ID_AD5676R,
-       ID_AD5684,
-       ID_AD5684R,
-       ID_AD5685R,
-       ID_AD5686,
-       ID_AD5686R
-};
-static int ad5686_spi_write(struct ad5686_state *st,
-                            u8 cmd, u8 addr, u16 val, u8 shift)
+static int ad5686_write(struct ad5686_state *st,
+                       u8 cmd, u8 addr, u16 val, u8 shift)
 {
        val <<= shift;
 
-       st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
-                             AD5686_ADDR(addr) |
-                             val);
-
-       return spi_write(st->spi, &st->data[0].d8[1], 3);
+       return st->write(st, cmd, addr, val);
 }
 
-static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
+static int ad5686_read(struct ad5686_state *st, u8 addr)
 {
-       struct spi_transfer t[] = {
-               {
-                       .tx_buf = &st->data[0].d8[1],
-                       .len = 3,
-                       .cs_change = 1,
-               }, {
-                       .tx_buf = &st->data[1].d8[1],
-                       .rx_buf = &st->data[2].d8[1],
-                       .len = 3,
-               },
-       };
-       int ret;
 
-       st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) |
-                             AD5686_ADDR(addr));
-       st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
-
-       ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
-       if (ret < 0)
-               return ret;
-
-       return be32_to_cpu(st->data[2].d32);
+       return st->read(st, addr);
 }
 
-static const char * const ad5686_powerdown_modes[] = {
-       "1kohm_to_gnd",
-       "100kohm_to_gnd",
-       "three_state"
-};
-
 static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev,
                                     const struct iio_chan_spec *chan)
 {
@@ -196,8 +95,8 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev 
*indio_dev,
        else
                st->pwr_down_mask &= ~(0x3 << (chan->channel * 2));
 
-       ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0,
-                              st->pwr_down_mask & st->pwr_down_mode, 0);
+       ret = ad5686_write(st, AD5686_CMD_POWERDOWN_DAC, 0,
+                          st->pwr_down_mask & st->pwr_down_mode, 0);
 
        return ret ? ret : len;
 }
@@ -214,7 +113,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
        switch (m) {
        case IIO_CHAN_INFO_RAW:
                mutex_lock(&indio_dev->mlock);
-               ret = ad5686_spi_read(st, chan->address);
+               ret = ad5686_read(st, chan->address);
                mutex_unlock(&indio_dev->mlock);
                if (ret < 0)
                        return ret;
@@ -243,11 +142,11 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
                        return -EINVAL;
 
                mutex_lock(&indio_dev->mlock);
-               ret = ad5686_spi_write(st,
-                                AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
-                                chan->address,
-                                val,
-                                chan->scan_type.shift);
+               ret = ad5686_write(st,
+                                  AD5686_CMD_WRITE_INPUT_N_UPDATE_N,
+                                  chan->address,
+                                  val,
+                                  chan->scan_type.shift);
                mutex_unlock(&indio_dev->mlock);
                break;
        default:
@@ -318,11 +217,21 @@ DECLARE_AD5686_CHANNELS(ad5685r_channels, 14, 2);
 DECLARE_AD5686_CHANNELS(ad5686_channels, 16, 0);
 
 static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
+       [ID_AD5671R] = {
+               .channels = ad5672_channels,
+               .int_vref_mv = 2500,
+               .num_channels = 8,
+       },
        [ID_AD5672R] = {
                .channels = ad5672_channels,
                .int_vref_mv = 2500,
                .num_channels = 8,
        },
+       [ID_AD5675R] = {
+               .channels = ad5676_channels,
+               .int_vref_mv = 2500,
+               .num_channels = 8,
+       },
        [ID_AD5676] = {
                .channels = ad5676_channels,
                .num_channels = 8,
@@ -355,22 +264,47 @@ static const struct ad5686_chip_info 
ad5686_chip_info_tbl[] = {
                .int_vref_mv = 2500,
                .num_channels = 4,
        },
+       [ID_AD5694] = {
+               .channels = ad5684_channels,
+               .num_channels = 4,
+       },
+       [ID_AD5694R] = {
+               .channels = ad5684_channels,
+               .int_vref_mv = 2500,
+               .num_channels = 4,
+       },
+       [ID_AD5696] = {
+               .channels = ad5686_channels,
+               .num_channels = 4,
+       },
+       [ID_AD5696R] = {
+               .channels = ad5686_channels,
+               .int_vref_mv = 2500,
+               .num_channels = 4,
+       },
 };
 
-static int ad5686_probe(struct spi_device *spi)
+int ad5686_probe(struct device *dev,
+                enum ad5686_supported_device_ids chip_type,
+                const char *name, ad5686_write_func write,
+                ad5686_read_func read)
 {
        struct ad5686_state *st;
        struct iio_dev *indio_dev;
        int ret, voltage_uv = 0;
 
-       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
        if (indio_dev == NULL)
                return  -ENOMEM;
 
        st = iio_priv(indio_dev);
-       spi_set_drvdata(spi, indio_dev);
+       dev_set_drvdata(dev, indio_dev);
+
+       st->dev = dev;
+       st->write = write;
+       st->read = read;
 
-       st->reg = devm_regulator_get_optional(&spi->dev, "vcc");
+       st->reg = devm_regulator_get_optional(dev, "vcc");
        if (!IS_ERR(st->reg)) {
                ret = regulator_enable(st->reg);
                if (ret)
@@ -383,28 +317,25 @@ static int ad5686_probe(struct spi_device *spi)
                voltage_uv = ret;
        }
 
-       st->chip_info =
-               &ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+       st->chip_info = &ad5686_chip_info_tbl[chip_type];
 
        if (voltage_uv)
                st->vref_mv = voltage_uv / 1000;
        else
                st->vref_mv = st->chip_info->int_vref_mv;
 
-       st->spi = spi;
-
        /* Set all the power down mode for all channels to 1K pulldown */
        st->pwr_down_mode = 0x55;
 
-       indio_dev->dev.parent = &spi->dev;
-       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->dev.parent = dev;
+       indio_dev->name = name;
        indio_dev->info = &ad5686_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = st->chip_info->channels;
        indio_dev->num_channels = st->chip_info->num_channels;
 
-       ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
-                               !!voltage_uv, 0);
+       ret = ad5686_write(st, AD5686_CMD_INTERNAL_REFER_SETUP,
+                          0, !!voltage_uv, 0);
        if (ret)
                goto error_disable_reg;
 
@@ -419,10 +350,11 @@ static int ad5686_probe(struct spi_device *spi)
                regulator_disable(st->reg);
        return ret;
 }
+EXPORT_SYMBOL_GPL(ad5686_probe);
 
-static int ad5686_remove(struct spi_device *spi)
+int ad5686_remove(struct device *dev)
 {
-       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct ad5686_state *st = iio_priv(indio_dev);
 
        iio_device_unregister(indio_dev);
@@ -431,29 +363,7 @@ static int ad5686_remove(struct spi_device *spi)
 
        return 0;
 }
-
-static const struct spi_device_id ad5686_id[] = {
-       {"ad5672r", ID_AD5672R},
-       {"ad5676", ID_AD5676},
-       {"ad5676r", ID_AD5676R},
-       {"ad5684", ID_AD5684},
-       {"ad5684r", ID_AD5684R},
-       {"ad5685r", ID_AD5685R},
-       {"ad5686", ID_AD5686},
-       {"ad5686r", ID_AD5686R},
-       {}
-};
-MODULE_DEVICE_TABLE(spi, ad5686_id);
-
-static struct spi_driver ad5686_driver = {
-       .driver = {
-                  .name = "ad5686",
-                  },
-       .probe = ad5686_probe,
-       .remove = ad5686_remove,
-       .id_table = ad5686_id,
-};
-module_spi_driver(ad5686_driver);
+EXPORT_SYMBOL_GPL(ad5686_remove);
 
 MODULE_AUTHOR("Michael Hennerich <henner...@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h
new file mode 100644
index 0000000..b2b0110
--- /dev/null
+++ b/drivers/iio/dac/ad5686.h
@@ -0,0 +1,114 @@
+#ifndef __DRIVERS_IIO_DAC_AD5686_H__
+#define __DRIVERS_IIO_DAC_AD5686_H__
+
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+
+#define AD5686_ADDR(x)                         ((x) << 16)
+#define AD5686_CMD(x)                          ((x) << 20)
+
+#define AD5686_ADDR_DAC(chan)                  (0x1 << (chan))
+#define AD5686_ADDR_ALL_DAC                    0xF
+
+#define AD5686_CMD_NOOP                                0x0
+#define AD5686_CMD_WRITE_INPUT_N               0x1
+#define AD5686_CMD_UPDATE_DAC_N                        0x2
+#define AD5686_CMD_WRITE_INPUT_N_UPDATE_N      0x3
+#define AD5686_CMD_POWERDOWN_DAC               0x4
+#define AD5686_CMD_LDAC_MASK                   0x5
+#define AD5686_CMD_RESET                       0x6
+#define AD5686_CMD_INTERNAL_REFER_SETUP                0x7
+#define AD5686_CMD_DAISY_CHAIN_ENABLE          0x8
+#define AD5686_CMD_READBACK_ENABLE             0x9
+
+#define AD5686_LDAC_PWRDN_NONE                 0x0
+#define AD5686_LDAC_PWRDN_1K                   0x1
+#define AD5686_LDAC_PWRDN_100K                 0x2
+#define AD5686_LDAC_PWRDN_3STATE               0x3
+
+/**
+ * ad5686_supported_device_ids:
+ */
+enum ad5686_supported_device_ids {
+       ID_AD5671R,
+       ID_AD5672R,
+       ID_AD5675R,
+       ID_AD5676,
+       ID_AD5676R,
+       ID_AD5684,
+       ID_AD5684R,
+       ID_AD5685R,
+       ID_AD5686,
+       ID_AD5686R,
+       ID_AD5694,
+       ID_AD5694R,
+       ID_AD5695R,
+       ID_AD5696,
+       ID_AD5696R,
+};
+
+struct ad5686_state;
+
+typedef int (*ad5686_write_func)(struct ad5686_state *st,
+                                u8 cmd, u8 addr, u16 val);
+
+typedef int (*ad5686_read_func)(struct ad5686_state *st, u8 addr);
+
+/**
+ * struct ad5686_chip_info - chip specific information
+ * @int_vref_mv:       AD5620/40/60: the internal reference voltage
+ * @num_channels:      number of channels
+ * @channel:           channel specification
+ */
+
+struct ad5686_chip_info {
+       u16                             int_vref_mv;
+       unsigned int                    num_channels;
+       struct iio_chan_spec            *channels;
+};
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @spi:               spi_device
+ * @chip_info:         chip model specific constants, available modes etc
+ * @reg:               supply regulator
+ * @vref_mv:           actual reference voltage used
+ * @pwr_down_mask:     power down mask
+ * @pwr_down_mode:     current power down mode
+ * @data:              spi transfer buffers
+ */
+
+struct ad5686_state {
+       struct device                   *dev;
+       const struct ad5686_chip_info   *chip_info;
+       struct regulator                *reg;
+       unsigned short                  vref_mv;
+       unsigned int                    pwr_down_mask;
+       unsigned int                    pwr_down_mode;
+       ad5686_write_func               write;
+       ad5686_read_func                read;
+
+       /*
+        * DMA (thus cache coherency maintenance) requires the
+        * transfer buffers to live in their own cache lines.
+        */
+
+       union {
+               __be32 d32;
+               __be16 d16;
+               u8 d8[4];
+       } data[3] ____cacheline_aligned;
+};
+
+
+int ad5686_probe(struct device *dev,
+                enum ad5686_supported_device_ids chip_type,
+                const char *name, ad5686_write_func write,
+                ad5686_read_func read);
+
+int ad5686_remove(struct device *dev);
+
+
+#endif /* __DRIVERS_IIO_DAC_AD5686_H__ */
diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c
new file mode 100644
index 0000000..c9187de
--- /dev/null
+++ b/drivers/iio/dac/ad5696-i2c.c
@@ -0,0 +1,98 @@
+/*
+ * AD5671R, AD5675R, AD5694, AD5694R, AD5695R, AD5696, AD5696R
+ * Digital to analog converters driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include "ad5686.h"
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+static int ad5686_i2c_read(struct ad5686_state *st, u8 addr)
+{
+       struct i2c_client *i2c = to_i2c_client(st->dev);
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = i2c->addr,
+                       .flags = i2c->flags,
+                       .len = 3,
+                       .buf = &st->data[0].d8[1],
+               },
+               {
+                       .addr = i2c->addr,
+                       .flags = i2c->flags | I2C_M_RD,
+                       .len = 2,
+                       .buf = (char *)&st->data[0].d16,
+               },
+       };
+       int ret;
+
+       st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP) |
+                                     AD5686_ADDR(addr) |
+                                     0x00);
+
+       ret = i2c_transfer(i2c->adapter, msg, 2);
+       if (ret < 0)
+               return ret;
+
+       return be16_to_cpu(st->data[0].d16);
+}
+
+static int ad5686_i2c_write(struct ad5686_state *st,
+                           u8 cmd, u8 addr, u16 val)
+{
+       struct i2c_client *i2c = to_i2c_client(st->dev);
+       int ret;
+
+       st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr)
+                                     | val);
+
+       ret = i2c_master_send(i2c, &st->data[0].d8[1], 3);
+       if (ret < 0)
+               return ret;
+
+       return (ret != 3) ? -EIO : 0;
+}
+
+static int ad5686_i2c_probe(struct i2c_client *i2c,
+                           const struct i2c_device_id *id)
+{
+       return ad5686_probe(&i2c->dev, id->driver_data, id->name,
+                           ad5686_i2c_write, ad5686_i2c_read);
+}
+
+static int ad5686_i2c_remove(struct i2c_client *i2c)
+{
+       return ad5686_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id ad5686_i2c_id[] = {
+       {"ad5671r", ID_AD5671R},
+       {"ad5675r", ID_AD5675R},
+       {"ad5694", ID_AD5694},
+       {"ad5694r", ID_AD5694R},
+       {"ad5695r", ID_AD5695R},
+       {"ad5696", ID_AD5696},
+       {"ad5696r", ID_AD5696R},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, i2c_device_id);
+
+static struct i2c_driver ad5686_i2c_driver = {
+       .driver = {
+               .name = "ad5696",
+       },
+       .probe = ad5686_i2c_probe,
+       .remove = ad5686_i2c_remove,
+       .id_table = ad5686_i2c_id,
+};
+
+module_i2c_driver(ad5686_i2c_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.p...@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5686 and similar multi-channel DACs");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

Reply via email to