summary refs log tree commit diff
path: root/drivers/iio
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2012-06-04 11:36:28 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-05 14:02:25 +0900
commitdbdc025bb239ce62c9b4d28c459a98f22ce9ec0a (patch)
tree2858c04b9d18852c1a4f4ca1c60c8e00b6180470 /drivers/iio
parent20374d1a36df3e20cd6742ba376684e5506254a8 (diff)
downloadlinux-dbdc025bb239ce62c9b4d28c459a98f22ce9ec0a.tar.gz
staging:iio: Move DAC drivers out of staging
The IIO DAC drivers are in a reasonably good shape. They all make use of channel
spec and non of them provides non-documented sysfs attributes. Code style should
be OK as well, both checkpatch and coccicheck only report trivial issues.

So lets move the whole folder out of staging.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/dac/Kconfig121
-rw-r--r--drivers/iio/dac/Makefile15
-rw-r--r--drivers/iio/dac/ad5064.c538
-rw-r--r--drivers/iio/dac/ad5360.c570
-rw-r--r--drivers/iio/dac/ad5380.c657
-rw-r--r--drivers/iio/dac/ad5421.c544
-rw-r--r--drivers/iio/dac/ad5446.c381
-rw-r--r--drivers/iio/dac/ad5446.h89
-rw-r--r--drivers/iio/dac/ad5504.c393
-rw-r--r--drivers/iio/dac/ad5624r.h79
-rw-r--r--drivers/iio/dac/ad5624r_spi.c324
-rw-r--r--drivers/iio/dac/ad5686.c418
-rw-r--r--drivers/iio/dac/ad5764.c382
-rw-r--r--drivers/iio/dac/ad5791.c485
-rw-r--r--drivers/iio/dac/max517.c243
17 files changed, 5241 insertions, 0 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 64c88e5cda4d..103349f2b3b5 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -52,5 +52,6 @@ source "drivers/iio/adc/Kconfig"
 source "drivers/iio/amplifiers/Kconfig"
 source "drivers/iio/light/Kconfig"
 source "drivers/iio/frequency/Kconfig"
+source "drivers/iio/dac/Kconfig"
 
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index bd801c0bbc2f..c38fa2a40af2 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -13,3 +13,4 @@ obj-y += adc/
 obj-y += amplifiers/
 obj-y += light/
 obj-y += frequency/
+obj-y += dac/
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
new file mode 100644
index 000000000000..a626f03871ec
--- /dev/null
+++ b/drivers/iio/dac/Kconfig
@@ -0,0 +1,121 @@
+#
+# DAC drivers
+#
+menu "Digital to analog converters"
+
+config AD5064
+	tristate "Analog Devices AD5064/64-1/65/44/45/24/25, AD5628/48/66/68 DAC driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
+	  AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648, AD5666, AD5668 Digital
+	  to Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5064.
+
+config AD5360
+	tristate "Analog Devices Analog Devices AD5360/61/62/63/70/71/73 DAC driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5360, AD5361,
+	  AD5362, AD5363, AD5370, AD5371, AD5373 multi-channel
+	  Digital to Analog Converters (DAC).
+
+	  To compile this driver as module choose M here: the module will be called
+	  ad5360.
+
+config AD5380
+	tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver"
+	depends on (SPI_MASTER || I2C)
+	select REGMAP_I2C if I2C
+	select REGMAP_SPI if SPI_MASTER
+	help
+	  Say yes here to build support for Analog Devices AD5380, AD5381,
+	  AD5382, AD5383, AD5384, AD5390, AD5391, AD5392 multi-channel
+	  Digital to Analog Converters (DAC).
+
+	  To compile this driver as module choose M here: the module will be called
+	  ad5380.
+
+config AD5421
+	tristate "Analog Devices AD5421 DAC driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5421 loop-powered
+	  digital-to-analog convertors (DAC).
+
+	  To compile this driver as module choose M here: the module will be called
+	  ad5421.
+
+config AD5624R_SPI
+	tristate "Analog Devices AD5624/44/64R DAC spi driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5624R, AD5644R and
+	  AD5664R converters (DAC). This driver uses the common SPI interface.
+
+config AD5446
+	tristate "Analog Devices AD5446 and similar single channel DACs driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5444, AD5446,
+	  AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620,
+	  AD5621, AD5640, AD5660, AD5662 DACs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5446.
+
+config AD5504
+	tristate "Analog Devices AD5504/AD5501 DAC SPI driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5504, AD5501,
+	  High Voltage Digital to Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5504.
+
+config AD5764
+	tristate "Analog Devices AD5764/64R/44/44R DAC driver"
+	depends on SPI_MASTER
+	help
+	  Say yes here to build support for Analog Devices AD5764, AD5764R, AD5744,
+	  AD5744R Digital to Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5764.
+
+config AD5791
+	tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5760, AD5780,
+	  AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to
+	  Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5791.
+
+config AD5686
+	tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver"
+	depends on SPI
+	help
+	  Say yes here to build support for Analog Devices AD5686R, AD5685R,
+	  AD5684R, AD5791 Voltage Output Digital to
+	  Analog Converter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad5686.
+
+config MAX517
+	tristate "Maxim MAX517/518/519 DAC driver"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Maxim chips MAX517,
+	  MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called max517.
+
+endmenu
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
new file mode 100644
index 000000000000..8ab1d264aab7
--- /dev/null
+++ b/drivers/iio/dac/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for industrial I/O DAC drivers
+#
+
+obj-$(CONFIG_AD5360) += ad5360.o
+obj-$(CONFIG_AD5380) += ad5380.o
+obj-$(CONFIG_AD5421) += ad5421.o
+obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
+obj-$(CONFIG_AD5064) += ad5064.o
+obj-$(CONFIG_AD5504) += ad5504.o
+obj-$(CONFIG_AD5446) += ad5446.o
+obj-$(CONFIG_AD5764) += ad5764.o
+obj-$(CONFIG_AD5791) += ad5791.o
+obj-$(CONFIG_AD5686) += ad5686.o
+obj-$(CONFIG_MAX517) += max517.o
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
new file mode 100644
index 000000000000..276af02520af
--- /dev/null
+++ b/drivers/iio/dac/ad5064.c
@@ -0,0 +1,538 @@
+/*
+ * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648,
+ * AD5666, AD5668 Digital to analog converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.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>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5064_MAX_DAC_CHANNELS			8
+#define AD5064_MAX_VREFS			4
+
+#define AD5064_ADDR(x)				((x) << 20)
+#define AD5064_CMD(x)				((x) << 24)
+
+#define AD5064_ADDR_DAC(chan)			(chan)
+#define AD5064_ADDR_ALL_DAC			0xF
+
+#define AD5064_CMD_WRITE_INPUT_N		0x0
+#define AD5064_CMD_UPDATE_DAC_N			0x1
+#define AD5064_CMD_WRITE_INPUT_N_UPDATE_ALL	0x2
+#define AD5064_CMD_WRITE_INPUT_N_UPDATE_N	0x3
+#define AD5064_CMD_POWERDOWN_DAC		0x4
+#define AD5064_CMD_CLEAR			0x5
+#define AD5064_CMD_LDAC_MASK			0x6
+#define AD5064_CMD_RESET			0x7
+#define AD5064_CMD_CONFIG			0x8
+
+#define AD5064_CONFIG_DAISY_CHAIN_ENABLE	BIT(1)
+#define AD5064_CONFIG_INT_VREF_ENABLE		BIT(0)
+
+#define AD5064_LDAC_PWRDN_NONE			0x0
+#define AD5064_LDAC_PWRDN_1K			0x1
+#define AD5064_LDAC_PWRDN_100K			0x2
+#define AD5064_LDAC_PWRDN_3STATE		0x3
+
+/**
+ * struct ad5064_chip_info - chip specific information
+ * @shared_vref:	whether the vref supply is shared between channels
+ * @internal_vref:	internal reference voltage. 0 if the chip has no internal
+ *			vref.
+ * @channel:		channel specification
+ * @num_channels:	number of channels
+ */
+
+struct ad5064_chip_info {
+	bool shared_vref;
+	unsigned long internal_vref;
+	const struct iio_chan_spec *channels;
+	unsigned int num_channels;
+};
+
+/**
+ * struct ad5064_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @vref_reg:		vref supply regulators
+ * @pwr_down:		whether channel is powered down
+ * @pwr_down_mode:	channel's current power down mode
+ * @dac_cache:		current DAC raw value (chip does not support readback)
+ * @use_internal_vref:	set to true if the internal reference voltage should be
+ *			used.
+ * @data:		spi transfer buffers
+ */
+
+struct ad5064_state {
+	struct spi_device		*spi;
+	const struct ad5064_chip_info	*chip_info;
+	struct regulator_bulk_data	vref_reg[AD5064_MAX_VREFS];
+	bool				pwr_down[AD5064_MAX_DAC_CHANNELS];
+	u8				pwr_down_mode[AD5064_MAX_DAC_CHANNELS];
+	unsigned int			dac_cache[AD5064_MAX_DAC_CHANNELS];
+	bool				use_internal_vref;
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	__be32 data ____cacheline_aligned;
+};
+
+enum ad5064_type {
+	ID_AD5024,
+	ID_AD5025,
+	ID_AD5044,
+	ID_AD5045,
+	ID_AD5064,
+	ID_AD5064_1,
+	ID_AD5065,
+	ID_AD5628_1,
+	ID_AD5628_2,
+	ID_AD5648_1,
+	ID_AD5648_2,
+	ID_AD5666_1,
+	ID_AD5666_2,
+	ID_AD5668_1,
+	ID_AD5668_2,
+};
+
+static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd,
+	unsigned int addr, unsigned int val, unsigned int shift)
+{
+	val <<= shift;
+
+	st->data = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val);
+
+	return spi_write(st->spi, &st->data, sizeof(st->data));
+}
+
+static int ad5064_sync_powerdown_mode(struct ad5064_state *st,
+	unsigned int channel)
+{
+	unsigned int val;
+	int ret;
+
+	val = (0x1 << channel);
+
+	if (st->pwr_down[channel])
+		val |= st->pwr_down_mode[channel] << 8;
+
+	ret = ad5064_spi_write(st, AD5064_CMD_POWERDOWN_DAC, 0, val, 0);
+
+	return ret;
+}
+
+static const char * const ad5064_powerdown_modes[] = {
+	"1kohm_to_gnd",
+	"100kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5064_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode[chan->channel] - 1;
+}
+
+static int ad5064_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->pwr_down_mode[chan->channel] = mode + 1;
+
+	ret = ad5064_sync_powerdown_mode(st, chan->channel);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static const struct iio_enum ad5064_powerdown_mode_enum = {
+	.items = ad5064_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5064_powerdown_modes),
+	.get = ad5064_get_powerdown_mode,
+	.set = ad5064_set_powerdown_mode,
+};
+
+static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down[chan->channel]);
+}
+
+static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	bool pwr_down;
+	int ret;
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->pwr_down[chan->channel] = pwr_down;
+
+	ret = ad5064_sync_powerdown_mode(st, chan->channel);
+	mutex_unlock(&indio_dev->mlock);
+	return ret ? ret : len;
+}
+
+static int ad5064_get_vref(struct ad5064_state *st,
+	struct iio_chan_spec const *chan)
+{
+	unsigned int i;
+
+	if (st->use_internal_vref)
+		return st->chip_info->internal_vref;
+
+	i = st->chip_info->shared_vref ? 0 : chan->channel;
+	return regulator_get_voltage(st->vref_reg[i].consumer);
+}
+
+static int ad5064_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	int scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		*val = st->dac_cache[chan->channel];
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = ad5064_get_vref(st, chan);
+		if (scale_uv < 0)
+			return scale_uv;
+
+		scale_uv = (scale_uv * 100) >> chan->scan_type.realbits;
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int ad5064_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	struct ad5064_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val > (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		mutex_lock(&indio_dev->mlock);
+		ret = ad5064_spi_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N,
+				chan->address, val, chan->scan_type.shift);
+		if (ret == 0)
+			st->dac_cache[chan->channel] = val;
+		mutex_unlock(&indio_dev->mlock);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct iio_info ad5064_info = {
+	.read_raw = ad5064_read_raw,
+	.write_raw = ad5064_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5064_read_dac_powerdown,
+		.write = ad5064_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", false, &ad5064_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5064_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5064_CHANNEL(chan, bits) {				\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = (chan),					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+	IIO_CHAN_INFO_SCALE_SEPARATE_BIT,			\
+	.address = AD5064_ADDR_DAC(chan),			\
+	.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)),	\
+	.ext_info = ad5064_ext_info,				\
+}
+
+#define DECLARE_AD5064_CHANNELS(name, bits) \
+const struct iio_chan_spec name[] = { \
+	AD5064_CHANNEL(0, bits), \
+	AD5064_CHANNEL(1, bits), \
+	AD5064_CHANNEL(2, bits), \
+	AD5064_CHANNEL(3, bits), \
+	AD5064_CHANNEL(4, bits), \
+	AD5064_CHANNEL(5, bits), \
+	AD5064_CHANNEL(6, bits), \
+	AD5064_CHANNEL(7, bits), \
+}
+
+static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
+static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
+static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
+
+static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
+	[ID_AD5024] = {
+		.shared_vref = false,
+		.channels = ad5024_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5025] = {
+		.shared_vref = false,
+		.channels = ad5024_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5044] = {
+		.shared_vref = false,
+		.channels = ad5044_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5045] = {
+		.shared_vref = false,
+		.channels = ad5044_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5064] = {
+		.shared_vref = false,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5064_1] = {
+		.shared_vref = true,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5065] = {
+		.shared_vref = false,
+		.channels = ad5064_channels,
+		.num_channels = 2,
+	},
+	[ID_AD5628_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5024_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5628_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5024_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5648_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5044_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5648_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5044_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5666_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5666_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5064_channels,
+		.num_channels = 4,
+	},
+	[ID_AD5668_1] = {
+		.shared_vref = true,
+		.internal_vref = 2500000,
+		.channels = ad5064_channels,
+		.num_channels = 8,
+	},
+	[ID_AD5668_2] = {
+		.shared_vref = true,
+		.internal_vref = 5000000,
+		.channels = ad5064_channels,
+		.num_channels = 8,
+	},
+};
+
+static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
+{
+	return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels;
+}
+
+static const char * const ad5064_vref_names[] = {
+	"vrefA",
+	"vrefB",
+	"vrefC",
+	"vrefD",
+};
+
+static const char * const ad5064_vref_name(struct ad5064_state *st,
+	unsigned int vref)
+{
+	return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref];
+}
+
+static int __devinit ad5064_probe(struct spi_device *spi)
+{
+	enum ad5064_type type = spi_get_device_id(spi)->driver_data;
+	struct iio_dev *indio_dev;
+	struct ad5064_state *st;
+	unsigned int i;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL)
+		return  -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->chip_info = &ad5064_chip_info_tbl[type];
+	st->spi = spi;
+
+	for (i = 0; i < ad5064_num_vref(st); ++i)
+		st->vref_reg[i].supply = ad5064_vref_name(st, i);
+
+	ret = regulator_bulk_get(&st->spi->dev, ad5064_num_vref(st),
+		st->vref_reg);
+	if (ret) {
+		if (!st->chip_info->internal_vref)
+			goto error_free;
+		st->use_internal_vref = true;
+		ret = ad5064_spi_write(st, AD5064_CMD_CONFIG, 0,
+			AD5064_CONFIG_INT_VREF_ENABLE, 0);
+		if (ret) {
+			dev_err(&spi->dev, "Failed to enable internal vref: %d\n",
+				ret);
+			goto error_free;
+		}
+	} else {
+		ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
+		if (ret)
+			goto error_free_reg;
+	}
+
+	for (i = 0; i < st->chip_info->num_channels; ++i) {
+		st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K;
+		st->dac_cache[i] = 0x8000;
+	}
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5064_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->chip_info->channels;
+	indio_dev->num_channels = st->chip_info->num_channels;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	return 0;
+
+error_disable_reg:
+	if (!st->use_internal_vref)
+		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
+error_free_reg:
+	if (!st->use_internal_vref)
+		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+
+static int __devexit ad5064_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5064_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	if (!st->use_internal_vref) {
+		regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
+		regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
+	}
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5064_id[] = {
+	{"ad5024", ID_AD5024},
+	{"ad5025", ID_AD5025},
+	{"ad5044", ID_AD5044},
+	{"ad5045", ID_AD5045},
+	{"ad5064", ID_AD5064},
+	{"ad5064-1", ID_AD5064_1},
+	{"ad5065", ID_AD5065},
+	{"ad5628-1", ID_AD5628_1},
+	{"ad5628-2", ID_AD5628_2},
+	{"ad5648-1", ID_AD5648_1},
+	{"ad5648-2", ID_AD5648_2},
+	{"ad5666-1", ID_AD5666_1},
+	{"ad5666-2", ID_AD5666_2},
+	{"ad5668-1", ID_AD5668_1},
+	{"ad5668-2", ID_AD5668_2},
+	{"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5064_id);
+
+static struct spi_driver ad5064_driver = {
+	.driver = {
+		   .name = "ad5064",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5064_probe,
+	.remove = __devexit_p(ad5064_remove),
+	.id_table = ad5064_id,
+};
+module_spi_driver(ad5064_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5024/25/44/45/64/64-1/65, AD5628/48/66/68 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c
new file mode 100644
index 000000000000..8fce84fe70b1
--- /dev/null
+++ b/drivers/iio/dac/ad5360.c
@@ -0,0 +1,570 @@
+/*
+ * Analog devices AD5360, AD5361, AD5362, AD5363, AD5370, AD5371, AD5373
+ * multi-channel Digital to Analog Converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.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>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5360_CMD(x)				((x) << 22)
+#define AD5360_ADDR(x)				((x) << 16)
+
+#define AD5360_READBACK_TYPE(x)			((x) << 13)
+#define AD5360_READBACK_ADDR(x)			((x) << 7)
+
+#define AD5360_CHAN_ADDR(chan)			((chan) + 0x8)
+
+#define AD5360_CMD_WRITE_DATA			0x3
+#define AD5360_CMD_WRITE_OFFSET			0x2
+#define AD5360_CMD_WRITE_GAIN			0x1
+#define AD5360_CMD_SPECIAL_FUNCTION		0x0
+
+/* Special function register addresses */
+#define AD5360_REG_SF_NOP			0x0
+#define AD5360_REG_SF_CTRL			0x1
+#define AD5360_REG_SF_OFS(x)			(0x2 + (x))
+#define AD5360_REG_SF_READBACK			0x5
+
+#define AD5360_SF_CTRL_PWR_DOWN			BIT(0)
+
+#define AD5360_READBACK_X1A			0x0
+#define AD5360_READBACK_X1B			0x1
+#define AD5360_READBACK_OFFSET			0x2
+#define AD5360_READBACK_GAIN			0x3
+#define AD5360_READBACK_SF			0x4
+
+
+/**
+ * struct ad5360_chip_info - chip specific information
+ * @channel_template:	channel specification template
+ * @num_channels:	number of channels
+ * @channels_per_group:	number of channels per group
+ * @num_vrefs:		number of vref supplies for the chip
+*/
+
+struct ad5360_chip_info {
+	struct iio_chan_spec	channel_template;
+	unsigned int		num_channels;
+	unsigned int		channels_per_group;
+	unsigned int		num_vrefs;
+};
+
+/**
+ * struct ad5360_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @vref_reg:		vref supply regulators
+ * @ctrl:		control register cache
+ * @data:		spi transfer buffers
+ */
+
+struct ad5360_state {
+	struct spi_device		*spi;
+	const struct ad5360_chip_info	*chip_info;
+	struct regulator_bulk_data	vref_reg[3];
+	unsigned int			ctrl;
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	union {
+		__be32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+enum ad5360_type {
+	ID_AD5360,
+	ID_AD5361,
+	ID_AD5362,
+	ID_AD5363,
+	ID_AD5370,
+	ID_AD5371,
+	ID_AD5372,
+	ID_AD5373,
+};
+
+#define AD5360_CHANNEL(bits) {					\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,	\
+	.scan_type = IIO_ST('u', (bits), 16, 16 - (bits))	\
+}
+
+static const struct ad5360_chip_info ad5360_chip_info_tbl[] = {
+	[ID_AD5360] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 16,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5361] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 16,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5362] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 8,
+		.channels_per_group = 4,
+		.num_vrefs = 2,
+	},
+	[ID_AD5363] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 8,
+		.channels_per_group = 4,
+		.num_vrefs = 2,
+	},
+	[ID_AD5370] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 40,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5371] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 40,
+		.channels_per_group = 8,
+		.num_vrefs = 3,
+	},
+	[ID_AD5372] = {
+		.channel_template = AD5360_CHANNEL(16),
+		.num_channels = 32,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+	[ID_AD5373] = {
+		.channel_template = AD5360_CHANNEL(14),
+		.num_channels = 32,
+		.channels_per_group = 8,
+		.num_vrefs = 2,
+	},
+};
+
+static unsigned int ad5360_get_channel_vref_index(struct ad5360_state *st,
+	unsigned int channel)
+{
+	unsigned int i;
+
+	/* The first groups have their own vref, while the remaining groups
+	 * share the last vref */
+	i = channel / st->chip_info->channels_per_group;
+	if (i >= st->chip_info->num_vrefs)
+		i = st->chip_info->num_vrefs - 1;
+
+	return i;
+}
+
+static int ad5360_get_channel_vref(struct ad5360_state *st,
+	unsigned int channel)
+{
+	unsigned int i = ad5360_get_channel_vref_index(st, channel);
+
+	return regulator_get_voltage(st->vref_reg[i].consumer);
+}
+
+
+static int ad5360_write_unlocked(struct iio_dev *indio_dev,
+	unsigned int cmd, unsigned int addr, unsigned int val,
+	unsigned int shift)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+
+	val <<= shift;
+	val |= AD5360_CMD(cmd) | AD5360_ADDR(addr);
+	st->data[0].d32 = cpu_to_be32(val);
+
+	return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5360_write(struct iio_dev *indio_dev, unsigned int cmd,
+	unsigned int addr, unsigned int val, unsigned int shift)
+{
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad5360_write_unlocked(indio_dev, cmd, addr, val, shift);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5360_read(struct iio_dev *indio_dev, unsigned int type,
+	unsigned int addr)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.rx_buf = &st->data[1].d8[1],
+			.len = 3,
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->data[0].d32 = cpu_to_be32(AD5360_CMD(AD5360_CMD_SPECIAL_FUNCTION) |
+		AD5360_ADDR(AD5360_REG_SF_READBACK) |
+		AD5360_READBACK_TYPE(type) |
+		AD5360_READBACK_ADDR(addr));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret >= 0)
+		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static ssize_t ad5360_read_dac_powerdown(struct device *dev,
+					   struct device_attribute *attr,
+					   char *buf)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	struct ad5360_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN));
+}
+
+static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
+	unsigned int clr)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	unsigned int ret;
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->ctrl |= set;
+	st->ctrl &= ~clr;
+
+	ret = ad5360_write_unlocked(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
+			AD5360_REG_SF_CTRL, st->ctrl, 0);
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static ssize_t ad5360_write_dac_powerdown(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+	bool pwr_down;
+	int ret;
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (pwr_down)
+		ret = ad5360_update_ctrl(indio_dev, AD5360_SF_CTRL_PWR_DOWN, 0);
+	else
+		ret = ad5360_update_ctrl(indio_dev, 0, AD5360_SF_CTRL_PWR_DOWN);
+
+	return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(out_voltage_powerdown,
+			S_IRUGO | S_IWUSR,
+			ad5360_read_dac_powerdown,
+			ad5360_write_dac_powerdown, 0);
+
+static struct attribute *ad5360_attributes[] = {
+	&iio_dev_attr_out_voltage_powerdown.dev_attr.attr,
+	NULL,
+};
+
+static const struct attribute_group ad5360_attribute_group = {
+	.attrs = ad5360_attributes,
+};
+
+static int ad5360_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	int max_val = (1 << chan->scan_type.realbits);
+	unsigned int ofs_index;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5360_write(indio_dev, AD5360_CMD_WRITE_DATA,
+				 chan->address, val, chan->scan_type.shift);
+
+	case IIO_CHAN_INFO_CALIBBIAS:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5360_write(indio_dev, AD5360_CMD_WRITE_OFFSET,
+				 chan->address, val, chan->scan_type.shift);
+
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5360_write(indio_dev, AD5360_CMD_WRITE_GAIN,
+				 chan->address, val, chan->scan_type.shift);
+
+	case IIO_CHAN_INFO_OFFSET:
+		if (val <= -max_val || val > 0)
+			return -EINVAL;
+
+		val = -val;
+
+		/* offset is supposed to have the same scale as raw, but it
+		 * is always 14bits wide, so on a chip where the raw value has
+		 * more bits, we need to shift offset. */
+		val >>= (chan->scan_type.realbits - 14);
+
+		/* There is one DAC offset register per vref. Changing one
+		 * channels offset will also change the offset for all other
+		 * channels which share the same vref supply. */
+		ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
+		return ad5360_write(indio_dev, AD5360_CMD_SPECIAL_FUNCTION,
+				 AD5360_REG_SF_OFS(ofs_index), val, 0);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int ad5360_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	unsigned int ofs_index;
+	int scale_uv;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5360_read(indio_dev, AD5360_READBACK_X1A,
+			chan->address);
+		if (ret < 0)
+			return ret;
+		*val = ret >> chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		/* vout = 4 * vref * dac_code */
+		scale_uv = ad5360_get_channel_vref(st, chan->channel) * 4 * 100;
+		if (scale_uv < 0)
+			return scale_uv;
+
+		scale_uv >>= (chan->scan_type.realbits);
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET,
+			chan->address);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN,
+			chan->address);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_OFFSET:
+		ofs_index = ad5360_get_channel_vref_index(st, chan->channel);
+		ret = ad5360_read(indio_dev, AD5360_READBACK_SF,
+			AD5360_REG_SF_OFS(ofs_index));
+		if (ret < 0)
+			return ret;
+
+		ret <<= (chan->scan_type.realbits - 14);
+		*val = -ret;
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5360_info = {
+	.read_raw = ad5360_read_raw,
+	.write_raw = ad5360_write_raw,
+	.attrs = &ad5360_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static const char * const ad5360_vref_name[] = {
+	 "vref0", "vref1", "vref2"
+};
+
+static int __devinit ad5360_alloc_channels(struct iio_dev *indio_dev)
+{
+	struct ad5360_state *st = iio_priv(indio_dev);
+	struct iio_chan_spec *channels;
+	unsigned int i;
+
+	channels = kcalloc(st->chip_info->num_channels,
+			   sizeof(struct iio_chan_spec), GFP_KERNEL);
+
+	if (!channels)
+		return -ENOMEM;
+
+	for (i = 0; i < st->chip_info->num_channels; ++i) {
+		channels[i] = st->chip_info->channel_template;
+		channels[i].channel = i;
+		channels[i].address = AD5360_CHAN_ADDR(i);
+	}
+
+	indio_dev->channels = channels;
+
+	return 0;
+}
+
+static int __devinit ad5360_probe(struct spi_device *spi)
+{
+	enum ad5360_type type = spi_get_device_id(spi)->driver_data;
+	struct iio_dev *indio_dev;
+	struct ad5360_state *st;
+	unsigned int i;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(&spi->dev, "Failed to allocate iio device\n");
+		return  -ENOMEM;
+	}
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->chip_info = &ad5360_chip_info_tbl[type];
+	st->spi = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5360_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->num_channels = st->chip_info->num_channels;
+
+	ret = ad5360_alloc_channels(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to allocate channel spec: %d\n", ret);
+		goto error_free;
+	}
+
+	for (i = 0; i < st->chip_info->num_vrefs; ++i)
+		st->vref_reg[i].supply = ad5360_vref_name[i];
+
+	ret = regulator_bulk_get(&st->spi->dev, st->chip_info->num_vrefs,
+		st->vref_reg);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to request vref regulators: %d\n", ret);
+		goto error_free_channels;
+	}
+
+	ret = regulator_bulk_enable(st->chip_info->num_vrefs, st->vref_reg);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to enable vref regulators: %d\n", ret);
+		goto error_free_reg;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	return 0;
+
+error_disable_reg:
+	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
+error_free_reg:
+	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
+error_free_channels:
+	kfree(indio_dev->channels);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5360_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5360_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	kfree(indio_dev->channels);
+
+	regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
+	regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5360_ids[] = {
+	{ "ad5360", ID_AD5360 },
+	{ "ad5361", ID_AD5361 },
+	{ "ad5362", ID_AD5362 },
+	{ "ad5363", ID_AD5363 },
+	{ "ad5370", ID_AD5370 },
+	{ "ad5371", ID_AD5371 },
+	{ "ad5372", ID_AD5372 },
+	{ "ad5373", ID_AD5373 },
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5360_ids);
+
+static struct spi_driver ad5360_driver = {
+	.driver = {
+		   .name = "ad5360",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5360_probe,
+	.remove = __devexit_p(ad5360_remove),
+	.id_table = ad5360_ids,
+};
+module_spi_driver(ad5360_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c
new file mode 100644
index 000000000000..5dfb4451728f
--- /dev/null
+++ b/drivers/iio/dac/ad5380.c
@@ -0,0 +1,657 @@
+/*
+ * Analog devices AD5380, AD5381, AD5382, AD5383, AD5390, AD5391, AD5392
+ * multi-channel Digital to Analog Converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5380_REG_DATA(x)	(((x) << 2) | 3)
+#define AD5380_REG_OFFSET(x)	(((x) << 2) | 2)
+#define AD5380_REG_GAIN(x)	(((x) << 2) | 1)
+#define AD5380_REG_SF_PWR_DOWN	(8 << 2)
+#define AD5380_REG_SF_PWR_UP	(9 << 2)
+#define AD5380_REG_SF_CTRL	(12 << 2)
+
+#define AD5380_CTRL_PWR_DOWN_MODE_OFFSET	13
+#define AD5380_CTRL_INT_VREF_2V5		BIT(12)
+#define AD5380_CTRL_INT_VREF_EN			BIT(10)
+
+/**
+ * struct ad5380_chip_info - chip specific information
+ * @channel_template:	channel specification template
+ * @num_channels:	number of channels
+ * @int_vref:		internal vref in uV
+*/
+
+struct ad5380_chip_info {
+	struct iio_chan_spec	channel_template;
+	unsigned int		num_channels;
+	unsigned int		int_vref;
+};
+
+/**
+ * struct ad5380_state - driver instance specific data
+ * @regmap:		regmap instance used by the device
+ * @chip_info:		chip model specific constants, available modes etc
+ * @vref_reg:		vref supply regulator
+ * @vref:		actual reference voltage used in uA
+ * @pwr_down:		whether the chip is currently in power down mode
+ */
+
+struct ad5380_state {
+	struct regmap			*regmap;
+	const struct ad5380_chip_info	*chip_info;
+	struct regulator		*vref_reg;
+	int				vref;
+	bool				pwr_down;
+};
+
+enum ad5380_type {
+	ID_AD5380_3,
+	ID_AD5380_5,
+	ID_AD5381_3,
+	ID_AD5381_5,
+	ID_AD5382_3,
+	ID_AD5382_5,
+	ID_AD5383_3,
+	ID_AD5383_5,
+	ID_AD5390_3,
+	ID_AD5390_5,
+	ID_AD5391_3,
+	ID_AD5391_5,
+	ID_AD5392_3,
+	ID_AD5392_5,
+};
+
+static ssize_t ad5380_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5380_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	bool pwr_down;
+	int ret;
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+
+	if (pwr_down)
+		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_DOWN, 0);
+	else
+		ret = regmap_write(st->regmap, AD5380_REG_SF_PWR_UP, 0);
+
+	st->pwr_down = pwr_down;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static const char * const ad5380_powerdown_modes[] = {
+	"100kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5380_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	unsigned int mode;
+	int ret;
+
+	ret = regmap_read(st->regmap, AD5380_REG_SF_CTRL, &mode);
+	if (ret)
+		return ret;
+
+	mode = (mode >> AD5380_CTRL_PWR_DOWN_MODE_OFFSET) & 1;
+
+	return mode;
+}
+
+static int ad5380_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	int ret;
+
+	ret = regmap_update_bits(st->regmap, AD5380_REG_SF_CTRL,
+		1 << AD5380_CTRL_PWR_DOWN_MODE_OFFSET,
+		mode << AD5380_CTRL_PWR_DOWN_MODE_OFFSET);
+
+	return ret;
+}
+
+static const struct iio_enum ad5380_powerdown_mode_enum = {
+	.items = ad5380_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5380_powerdown_modes),
+	.get = ad5380_get_powerdown_mode,
+	.set = ad5380_set_powerdown_mode,
+};
+
+static unsigned int ad5380_info_to_reg(struct iio_chan_spec const *chan,
+	long info)
+{
+	switch (info) {
+	case 0:
+		return AD5380_REG_DATA(chan->address);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		return AD5380_REG_OFFSET(chan->address);
+	case IIO_CHAN_INFO_CALIBSCALE:
+		return AD5380_REG_GAIN(chan->address);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int ad5380_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+	const unsigned int max_val = (1 << chan->scan_type.realbits);
+	struct ad5380_state *st = iio_priv(indio_dev);
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return regmap_write(st->regmap,
+			ad5380_info_to_reg(chan, info),
+			val << chan->scan_type.shift);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		val += (1 << chan->scan_type.realbits) / 2;
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return regmap_write(st->regmap,
+			AD5380_REG_OFFSET(chan->address),
+			val << chan->scan_type.shift);
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int ad5380_read_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	int ret;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_CALIBSCALE:
+		ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
+					val);
+		if (ret)
+			return ret;
+		*val >>= chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		ret = regmap_read(st->regmap, AD5380_REG_OFFSET(chan->address),
+					val);
+		if (ret)
+			return ret;
+		*val >>= chan->scan_type.shift;
+		val -= (1 << chan->scan_type.realbits) / 2;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = ((2 * st->vref) >> chan->scan_type.realbits) * 100;
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5380_info = {
+	.read_raw = ad5380_read_raw,
+	.write_raw = ad5380_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static struct iio_chan_spec_ext_info ad5380_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5380_read_dac_powerdown,
+		.write = ad5380_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5380_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5380_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5380_CHANNEL(_bits) {					\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |		\
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
+	.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)),	\
+	.ext_info = ad5380_ext_info,				\
+}
+
+static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
+	[ID_AD5380_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 40,
+		.int_vref = 1250000,
+	},
+	[ID_AD5380_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 40,
+		.int_vref = 2500000,
+	},
+	[ID_AD5381_3] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 1250000,
+	},
+	[ID_AD5381_5] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 2500000,
+	},
+	[ID_AD5382_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 32,
+		.int_vref = 1250000,
+	},
+	[ID_AD5382_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 32,
+		.int_vref = 2500000,
+	},
+	[ID_AD5383_3] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 32,
+		.int_vref = 1250000,
+	},
+	[ID_AD5383_5] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 32,
+		.int_vref = 2500000,
+	},
+	[ID_AD5390_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 16,
+		.int_vref = 1250000,
+	},
+	[ID_AD5390_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 16,
+		.int_vref = 2500000,
+	},
+	[ID_AD5391_3] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 1250000,
+	},
+	[ID_AD5391_5] = {
+		.channel_template = AD5380_CHANNEL(12),
+		.num_channels = 16,
+		.int_vref = 2500000,
+	},
+	[ID_AD5392_3] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 8,
+		.int_vref = 1250000,
+	},
+	[ID_AD5392_5] = {
+		.channel_template = AD5380_CHANNEL(14),
+		.num_channels = 8,
+		.int_vref = 2500000,
+	},
+};
+
+static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev)
+{
+	struct ad5380_state *st = iio_priv(indio_dev);
+	struct iio_chan_spec *channels;
+	unsigned int i;
+
+	channels = kcalloc(st->chip_info->num_channels,
+			   sizeof(struct iio_chan_spec), GFP_KERNEL);
+
+	if (!channels)
+		return -ENOMEM;
+
+	for (i = 0; i < st->chip_info->num_channels; ++i) {
+		channels[i] = st->chip_info->channel_template;
+		channels[i].channel = i;
+		channels[i].address = i;
+	}
+
+	indio_dev->channels = channels;
+
+	return 0;
+}
+
+static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap,
+	enum ad5380_type type, const char *name)
+{
+	struct iio_dev *indio_dev;
+	struct ad5380_state *st;
+	unsigned int ctrl = 0;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(dev, "Failed to allocate iio device\n");
+		ret = -ENOMEM;
+		goto error_regmap_exit;
+	}
+
+	st = iio_priv(indio_dev);
+	dev_set_drvdata(dev, indio_dev);
+
+	st->chip_info = &ad5380_chip_info_tbl[type];
+	st->regmap = regmap;
+
+	indio_dev->dev.parent = dev;
+	indio_dev->name = name;
+	indio_dev->info = &ad5380_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->num_channels = st->chip_info->num_channels;
+
+	ret = ad5380_alloc_channels(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to allocate channel spec: %d\n", ret);
+		goto error_free;
+	}
+
+	if (st->chip_info->int_vref == 2500000)
+		ctrl |= AD5380_CTRL_INT_VREF_2V5;
+
+	st->vref_reg = regulator_get(dev, "vref");
+	if (!IS_ERR(st->vref_reg)) {
+		ret = regulator_enable(st->vref_reg);
+		if (ret) {
+			dev_err(dev, "Failed to enable vref regulators: %d\n",
+				ret);
+			goto error_free_reg;
+		}
+
+		st->vref = regulator_get_voltage(st->vref_reg);
+	} else {
+		st->vref = st->chip_info->int_vref;
+		ctrl |= AD5380_CTRL_INT_VREF_EN;
+	}
+
+	ret = regmap_write(st->regmap, AD5380_REG_SF_CTRL, ctrl);
+	if (ret) {
+		dev_err(dev, "Failed to write to device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register iio device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->vref_reg))
+		regulator_disable(st->vref_reg);
+error_free_reg:
+	if (!IS_ERR(st->vref_reg))
+		regulator_put(st->vref_reg);
+
+	kfree(indio_dev->channels);
+error_free:
+	iio_device_free(indio_dev);
+error_regmap_exit:
+	regmap_exit(regmap);
+
+	return ret;
+}
+
+static int __devexit ad5380_remove(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ad5380_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	kfree(indio_dev->channels);
+
+	if (!IS_ERR(st->vref_reg)) {
+		regulator_disable(st->vref_reg);
+		regulator_put(st->vref_reg);
+	}
+
+	regmap_exit(st->regmap);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static bool ad5380_reg_false(struct device *dev, unsigned int reg)
+{
+	return false;
+}
+
+static const struct regmap_config ad5380_regmap_config = {
+	.reg_bits = 10,
+	.val_bits = 14,
+
+	.max_register = AD5380_REG_DATA(40),
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = ad5380_reg_false,
+	.readable_reg = ad5380_reg_false,
+};
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static int __devinit ad5380_spi_probe(struct spi_device *spi)
+{
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct regmap *regmap;
+
+	regmap = regmap_init_spi(spi, &ad5380_regmap_config);
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return ad5380_probe(&spi->dev, regmap, id->driver_data, id->name);
+}
+
+static int __devexit ad5380_spi_remove(struct spi_device *spi)
+{
+	return ad5380_remove(&spi->dev);
+}
+
+static const struct spi_device_id ad5380_spi_ids[] = {
+	{ "ad5380-3", ID_AD5380_3 },
+	{ "ad5380-5", ID_AD5380_5 },
+	{ "ad5381-3", ID_AD5381_3 },
+	{ "ad5381-5", ID_AD5381_5 },
+	{ "ad5382-3", ID_AD5382_3 },
+	{ "ad5382-5", ID_AD5382_5 },
+	{ "ad5383-3", ID_AD5383_3 },
+	{ "ad5383-5", ID_AD5383_5 },
+	{ "ad5384-3", ID_AD5380_3 },
+	{ "ad5384-5", ID_AD5380_5 },
+	{ "ad5390-3", ID_AD5390_3 },
+	{ "ad5390-5", ID_AD5390_5 },
+	{ "ad5391-3", ID_AD5391_3 },
+	{ "ad5391-5", ID_AD5391_5 },
+	{ "ad5392-3", ID_AD5392_3 },
+	{ "ad5392-5", ID_AD5392_5 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ad5380_spi_ids);
+
+static struct spi_driver ad5380_spi_driver = {
+	.driver = {
+		   .name = "ad5380",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5380_spi_probe,
+	.remove = __devexit_p(ad5380_spi_remove),
+	.id_table = ad5380_spi_ids,
+};
+
+static inline int ad5380_spi_register_driver(void)
+{
+	return spi_register_driver(&ad5380_spi_driver);
+}
+
+static inline void ad5380_spi_unregister_driver(void)
+{
+	spi_unregister_driver(&ad5380_spi_driver);
+}
+
+#else
+
+static inline int ad5380_spi_register_driver(void)
+{
+	return 0;
+}
+
+static inline void ad5380_spi_unregister_driver(void)
+{
+}
+
+#endif
+
+#if IS_ENABLED(CONFIG_I2C)
+
+static int __devinit ad5380_i2c_probe(struct i2c_client *i2c,
+	const struct i2c_device_id *id)
+{
+	struct regmap *regmap;
+
+	regmap = regmap_init_i2c(i2c, &ad5380_regmap_config);
+
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	return ad5380_probe(&i2c->dev, regmap, id->driver_data, id->name);
+}
+
+static int __devexit ad5380_i2c_remove(struct i2c_client *i2c)
+{
+	return ad5380_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id ad5380_i2c_ids[] = {
+	{ "ad5380-3", ID_AD5380_3 },
+	{ "ad5380-5", ID_AD5380_5 },
+	{ "ad5381-3", ID_AD5381_3 },
+	{ "ad5381-5", ID_AD5381_5 },
+	{ "ad5382-3", ID_AD5382_3 },
+	{ "ad5382-5", ID_AD5382_5 },
+	{ "ad5383-3", ID_AD5383_3 },
+	{ "ad5383-5", ID_AD5383_5 },
+	{ "ad5384-3", ID_AD5380_3 },
+	{ "ad5384-5", ID_AD5380_5 },
+	{ "ad5390-3", ID_AD5390_3 },
+	{ "ad5390-5", ID_AD5390_5 },
+	{ "ad5391-3", ID_AD5391_3 },
+	{ "ad5391-5", ID_AD5391_5 },
+	{ "ad5392-3", ID_AD5392_3 },
+	{ "ad5392-5", ID_AD5392_5 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad5380_i2c_ids);
+
+static struct i2c_driver ad5380_i2c_driver = {
+	.driver = {
+		   .name = "ad5380",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5380_i2c_probe,
+	.remove = __devexit_p(ad5380_i2c_remove),
+	.id_table = ad5380_i2c_ids,
+};
+
+static inline int ad5380_i2c_register_driver(void)
+{
+	return i2c_add_driver(&ad5380_i2c_driver);
+}
+
+static inline void ad5380_i2c_unregister_driver(void)
+{
+	i2c_del_driver(&ad5380_i2c_driver);
+}
+
+#else
+
+static inline int ad5380_i2c_register_driver(void)
+{
+	return 0;
+}
+
+static inline void ad5380_i2c_unregister_driver(void)
+{
+}
+
+#endif
+
+static int __init ad5380_spi_init(void)
+{
+	int ret;
+
+	ret = ad5380_spi_register_driver();
+	if (ret)
+		return ret;
+
+	ret = ad5380_i2c_register_driver();
+	if (ret) {
+		ad5380_spi_unregister_driver();
+		return ret;
+	}
+
+	return 0;
+}
+module_init(ad5380_spi_init);
+
+static void __exit ad5380_spi_exit(void)
+{
+	ad5380_i2c_unregister_driver();
+	ad5380_spi_unregister_driver();
+
+}
+module_exit(ad5380_spi_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c
new file mode 100644
index 000000000000..cdbc5bf25c31
--- /dev/null
+++ b/drivers/iio/dac/ad5421.c
@@ -0,0 +1,544 @@
+/*
+ * AD5421 Digital to analog converters  driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/dac/ad5421.h>
+
+
+#define AD5421_REG_DAC_DATA		0x1
+#define AD5421_REG_CTRL			0x2
+#define AD5421_REG_OFFSET		0x3
+#define AD5421_REG_GAIN			0x4
+/* load dac and fault shared the same register number. Writing to it will cause
+ * a dac load command, reading from it will return the fault status register */
+#define AD5421_REG_LOAD_DAC		0x5
+#define AD5421_REG_FAULT		0x5
+#define AD5421_REG_FORCE_ALARM_CURRENT	0x6
+#define AD5421_REG_RESET		0x7
+#define AD5421_REG_START_CONVERSION	0x8
+#define AD5421_REG_NOOP			0x9
+
+#define AD5421_CTRL_WATCHDOG_DISABLE	BIT(12)
+#define AD5421_CTRL_AUTO_FAULT_READBACK	BIT(11)
+#define AD5421_CTRL_MIN_CURRENT		BIT(9)
+#define AD5421_CTRL_ADC_SOURCE_TEMP	BIT(8)
+#define AD5421_CTRL_ADC_ENABLE		BIT(7)
+#define AD5421_CTRL_PWR_DOWN_INT_VREF	BIT(6)
+
+#define AD5421_FAULT_SPI			BIT(15)
+#define AD5421_FAULT_PEC			BIT(14)
+#define AD5421_FAULT_OVER_CURRENT		BIT(13)
+#define AD5421_FAULT_UNDER_CURRENT		BIT(12)
+#define AD5421_FAULT_TEMP_OVER_140		BIT(11)
+#define AD5421_FAULT_TEMP_OVER_100		BIT(10)
+#define AD5421_FAULT_UNDER_VOLTAGE_6V		BIT(9)
+#define AD5421_FAULT_UNDER_VOLTAGE_12V		BIT(8)
+
+/* These bits will cause the fault pin to go high */
+#define AD5421_FAULT_TRIGGER_IRQ \
+	(AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \
+	AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140)
+
+/**
+ * struct ad5421_state - driver instance specific data
+ * @spi:		spi_device
+ * @ctrl:		control register cache
+ * @current_range:	current range which the device is configured for
+ * @data:		spi transfer buffers
+ * @fault_mask:		software masking of events
+ */
+struct ad5421_state {
+	struct spi_device		*spi;
+	unsigned int			ctrl;
+	enum ad5421_current_range	current_range;
+	unsigned int			fault_mask;
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+static const struct iio_chan_spec ad5421_channels[] = {
+	{
+		.type = IIO_CURRENT,
+		.indexed = 1,
+		.output = 1,
+		.channel = 0,
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+			IIO_CHAN_INFO_SCALE_SHARED_BIT |
+			IIO_CHAN_INFO_OFFSET_SHARED_BIT |
+			IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+			IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+		.scan_type = IIO_ST('u', 16, 16, 0),
+		.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
+			IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
+	},
+	{
+		.type = IIO_TEMP,
+		.channel = -1,
+		.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
+	},
+};
+
+static int ad5421_write_unlocked(struct iio_dev *indio_dev,
+	unsigned int reg, unsigned int val)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+
+	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
+
+	return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg,
+	unsigned int val)
+{
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	ret = ad5421_write_unlocked(indio_dev, reg, val);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.rx_buf = &st->data[1].d8[1],
+			.len = 3,
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret >= 0)
+		ret = be32_to_cpu(st->data[1].d32) & 0xffff;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
+	unsigned int clr)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int ret;
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->ctrl &= ~clr;
+	st->ctrl |= set;
+
+	ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl);
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static irqreturn_t ad5421_fault_handler(int irq, void *data)
+{
+	struct iio_dev *indio_dev = data;
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int fault;
+	unsigned int old_fault = 0;
+	unsigned int events;
+
+	fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
+	if (!fault)
+		return IRQ_NONE;
+
+	/* If we had a fault, this might mean that the DAC has lost its state
+	 * and has been reset. Make sure that the control register actually
+	 * contains what we expect it to contain. Otherwise the watchdog might
+	 * be enabled and we get watchdog timeout faults, which will render the
+	 * DAC unusable. */
+	ad5421_update_ctrl(indio_dev, 0, 0);
+
+
+	/* The fault pin stays high as long as a fault condition is present and
+	 * it is not possible to mask fault conditions. For certain fault
+	 * conditions for example like over-temperature it takes some time
+	 * until the fault condition disappears. If we would exit the interrupt
+	 * handler immediately after handling the event it would be entered
+	 * again instantly. Thus we fall back to polling in case we detect that
+	 * a interrupt condition is still present.
+	 */
+	do {
+		/* 0xffff is a invalid value for the register and will only be
+		 * read if there has been a communication error */
+		if (fault == 0xffff)
+			fault = 0;
+
+		/* we are only interested in new events */
+		events = (old_fault ^ fault) & fault;
+		events &= st->fault_mask;
+
+		if (events & AD5421_FAULT_OVER_CURRENT) {
+			iio_push_event(indio_dev,
+				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
+					0,
+					IIO_EV_TYPE_THRESH,
+					IIO_EV_DIR_RISING),
+			iio_get_time_ns());
+		}
+
+		if (events & AD5421_FAULT_UNDER_CURRENT) {
+			iio_push_event(indio_dev,
+				IIO_UNMOD_EVENT_CODE(IIO_CURRENT,
+					0,
+					IIO_EV_TYPE_THRESH,
+					IIO_EV_DIR_FALLING),
+				iio_get_time_ns());
+		}
+
+		if (events & AD5421_FAULT_TEMP_OVER_140) {
+			iio_push_event(indio_dev,
+				IIO_UNMOD_EVENT_CODE(IIO_TEMP,
+					0,
+					IIO_EV_TYPE_MAG,
+					IIO_EV_DIR_RISING),
+				iio_get_time_ns());
+		}
+
+		old_fault = fault;
+		fault = ad5421_read(indio_dev, AD5421_REG_FAULT);
+
+		/* still active? go to sleep for some time */
+		if (fault & AD5421_FAULT_TRIGGER_IRQ)
+			msleep(1000);
+
+	} while (fault & AD5421_FAULT_TRIGGER_IRQ);
+
+
+	return IRQ_HANDLED;
+}
+
+static void ad5421_get_current_min_max(struct ad5421_state *st,
+	unsigned int *min, unsigned int *max)
+{
+	/* The current range is configured using external pins, which are
+	 * usually hard-wired and not run-time switchable. */
+	switch (st->current_range) {
+	case AD5421_CURRENT_RANGE_4mA_20mA:
+		*min = 4000;
+		*max = 20000;
+		break;
+	case AD5421_CURRENT_RANGE_3mA8_21mA:
+		*min = 3800;
+		*max = 21000;
+		break;
+	case AD5421_CURRENT_RANGE_3mA2_24mA:
+		*min = 3200;
+		*max = 24000;
+		break;
+	default:
+		*min = 0;
+		*max = 1;
+		break;
+	}
+}
+
+static inline unsigned int ad5421_get_offset(struct ad5421_state *st)
+{
+	unsigned int min, max;
+
+	ad5421_get_current_min_max(st, &min, &max);
+	return (min * (1 << 16)) / (max - min);
+}
+
+static inline unsigned int ad5421_get_scale(struct ad5421_state *st)
+{
+	unsigned int min, max;
+
+	ad5421_get_current_min_max(st, &min, &max);
+	return ((max - min) * 1000) / (1 << 16);
+}
+
+static int ad5421_read_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int *val, int *val2, long m)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	int ret;
+
+	if (chan->type != IIO_CURRENT)
+		return -EINVAL;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = ad5421_get_scale(st);
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = ad5421_get_offset(st);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		ret = ad5421_read(indio_dev, AD5421_REG_OFFSET);
+		if (ret < 0)
+			return ret;
+		*val = ret - 32768;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		ret = ad5421_read(indio_dev, AD5421_REG_GAIN);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static int ad5421_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	const unsigned int max_val = 1 << 16;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		val += 32768;
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5421_write(indio_dev, AD5421_REG_GAIN, val);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int ad5421_write_event_config(struct iio_dev *indio_dev,
+	u64 event_code, int state)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int mask;
+
+	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
+	case IIO_CURRENT:
+		if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
+			IIO_EV_DIR_RISING)
+			mask = AD5421_FAULT_OVER_CURRENT;
+		else
+			mask = AD5421_FAULT_UNDER_CURRENT;
+		break;
+	case IIO_TEMP:
+		mask = AD5421_FAULT_TEMP_OVER_140;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&indio_dev->mlock);
+	if (state)
+		st->fault_mask |= mask;
+	else
+		st->fault_mask &= ~mask;
+	mutex_unlock(&indio_dev->mlock);
+
+	return 0;
+}
+
+static int ad5421_read_event_config(struct iio_dev *indio_dev,
+	u64 event_code)
+{
+	struct ad5421_state *st = iio_priv(indio_dev);
+	unsigned int mask;
+
+	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
+	case IIO_CURRENT:
+		if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
+			IIO_EV_DIR_RISING)
+			mask = AD5421_FAULT_OVER_CURRENT;
+		else
+			mask = AD5421_FAULT_UNDER_CURRENT;
+		break;
+	case IIO_TEMP:
+		mask = AD5421_FAULT_TEMP_OVER_140;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return (bool)(st->fault_mask & mask);
+}
+
+static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code,
+	int *val)
+{
+	int ret;
+
+	switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
+	case IIO_CURRENT:
+		ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		break;
+	case IIO_TEMP:
+		*val = 140000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct iio_info ad5421_info = {
+	.read_raw =		ad5421_read_raw,
+	.write_raw =		ad5421_write_raw,
+	.read_event_config =	ad5421_read_event_config,
+	.write_event_config =	ad5421_write_event_config,
+	.read_event_value =	ad5421_read_event_value,
+	.driver_module =	THIS_MODULE,
+};
+
+static int __devinit ad5421_probe(struct spi_device *spi)
+{
+	struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev);
+	struct iio_dev *indio_dev;
+	struct ad5421_state *st;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(&spi->dev, "Failed to allocate iio device\n");
+		return  -ENOMEM;
+	}
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->spi = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = "ad5421";
+	indio_dev->info = &ad5421_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = ad5421_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ad5421_channels);
+
+	st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE |
+			AD5421_CTRL_AUTO_FAULT_READBACK;
+
+	if (pdata) {
+		st->current_range = pdata->current_range;
+		if (pdata->external_vref)
+			st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF;
+	} else {
+		st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
+	}
+
+	/* write initial ctrl register value */
+	ad5421_update_ctrl(indio_dev, 0, 0);
+
+	if (spi->irq) {
+		ret = request_threaded_irq(spi->irq,
+					   NULL,
+					   ad5421_fault_handler,
+					   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+					   "ad5421 fault",
+					   indio_dev);
+		if (ret)
+			goto error_free;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
+		goto error_free_irq;
+	}
+
+	return 0;
+
+error_free_irq:
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5421_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+
+	iio_device_unregister(indio_dev);
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static struct spi_driver ad5421_driver = {
+	.driver = {
+		   .name = "ad5421",
+		   .owner = THIS_MODULE,
+	},
+	.probe = ad5421_probe,
+	.remove = __devexit_p(ad5421_remove),
+};
+module_spi_driver(ad5421_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5421 DAC");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("spi:ad5421");
diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c
new file mode 100644
index 000000000000..49f557fc673b
--- /dev/null
+++ b/drivers/iio/dac/ad5446.c
@@ -0,0 +1,381 @@
+/*
+ * AD5446 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "ad5446.h"
+
+static int ad5446_write(struct ad5446_state *st, unsigned val)
+{
+	__be16 data = cpu_to_be16(val);
+	return spi_write(st->spi, &data, sizeof(data));
+}
+
+static int ad5660_write(struct ad5446_state *st, unsigned val)
+{
+	uint8_t data[3];
+
+	data[0] = (val >> 16) & 0xFF;
+	data[1] = (val >> 8) & 0xFF;
+	data[2] = val & 0xFF;
+
+	return spi_write(st->spi, data, sizeof(data));
+}
+
+static const char * const ad5446_powerdown_modes[] = {
+	"1kohm_to_gnd", "100kohm_to_gnd", "three_state"
+};
+
+static int ad5446_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode + 1;
+
+	return 0;
+}
+
+static int ad5446_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode - 1;
+}
+
+static const struct iio_enum ad5446_powerdown_mode_enum = {
+	.items = ad5446_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5446_powerdown_modes),
+	.get = ad5446_get_powerdown_mode,
+	.set = ad5446_set_powerdown_mode,
+};
+
+static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
+					   uintptr_t private,
+					   const struct iio_chan_spec *chan,
+					   char *buf)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
+					    uintptr_t private,
+					    const struct iio_chan_spec *chan,
+					    const char *buf, size_t len)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	unsigned int shift;
+	unsigned int val;
+	bool powerdown;
+	int ret;
+
+	ret = strtobool(buf, &powerdown);
+	if (ret)
+		return ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->pwr_down = powerdown;
+
+	if (st->pwr_down) {
+		shift = chan->scan_type.realbits + chan->scan_type.shift;
+		val = st->pwr_down_mode << shift;
+	} else {
+		val = st->cached_val;
+	}
+
+	ret = st->chip_info->write(st, val);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret ? ret : len;
+}
+
+static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
+	{
+		.name = "powerdown",
+		.read = ad5446_read_dac_powerdown,
+		.write = ad5446_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", false, &ad5446_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5446_powerdown_mode_enum),
+	{ },
+};
+
+#define _AD5446_CHANNEL(bits, storage, shift, ext) { \
+	.type = IIO_VOLTAGE, \
+	.indexed = 1, \
+	.output = 1, \
+	.channel = 0, \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+	IIO_CHAN_INFO_SCALE_SHARED_BIT,	\
+	.scan_type = IIO_ST('u', (bits), (storage), (shift)), \
+	.ext_info = (ext), \
+}
+
+#define AD5446_CHANNEL(bits, storage, shift) \
+	_AD5446_CHANNEL(bits, storage, shift, NULL)
+
+#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
+	_AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
+
+static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
+	[ID_AD5444] = {
+		.channel = AD5446_CHANNEL(12, 16, 2),
+		.write = ad5446_write,
+	},
+	[ID_AD5446] = {
+		.channel = AD5446_CHANNEL(14, 16, 0),
+		.write = ad5446_write,
+	},
+	[ID_AD5541A] = {
+		.channel = AD5446_CHANNEL(16, 16, 0),
+		.write = ad5446_write,
+	},
+	[ID_AD5512A] = {
+		.channel = AD5446_CHANNEL(12, 16, 4),
+		.write = ad5446_write,
+	},
+	[ID_AD5553] = {
+		.channel = AD5446_CHANNEL(14, 16, 0),
+		.write = ad5446_write,
+	},
+	[ID_AD5601] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
+		.write = ad5446_write,
+	},
+	[ID_AD5611] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
+		.write = ad5446_write,
+	},
+	[ID_AD5621] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+		.write = ad5446_write,
+	},
+	[ID_AD5620_2500] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+		.int_vref_mv = 2500,
+		.write = ad5446_write,
+	},
+	[ID_AD5620_1250] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+		.int_vref_mv = 1250,
+		.write = ad5446_write,
+	},
+	[ID_AD5640_2500] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
+		.int_vref_mv = 2500,
+		.write = ad5446_write,
+	},
+	[ID_AD5640_1250] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
+		.int_vref_mv = 1250,
+		.write = ad5446_write,
+	},
+	[ID_AD5660_2500] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+		.int_vref_mv = 2500,
+		.write = ad5660_write,
+	},
+	[ID_AD5660_1250] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+		.int_vref_mv = 1250,
+		.write = ad5660_write,
+	},
+	[ID_AD5662] = {
+		.channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+		.write = ad5660_write,
+	},
+};
+
+static int ad5446_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		*val = st->cached_val;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5446_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5446_state *st = iio_priv(indio_dev);
+	int ret = 0;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		val <<= chan->scan_type.shift;
+		mutex_lock(&indio_dev->mlock);
+		st->cached_val = val;
+		if (!st->pwr_down)
+			ret = st->chip_info->write(st, val);
+		mutex_unlock(&indio_dev->mlock);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct iio_info ad5446_info = {
+	.read_raw = ad5446_read_raw,
+	.write_raw = ad5446_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5446_probe(struct spi_device *spi)
+{
+	struct ad5446_state *st;
+	struct iio_dev *indio_dev;
+	struct regulator *reg;
+	int ret, voltage_uv = 0;
+
+	reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(reg)) {
+		ret = regulator_enable(reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(reg);
+	}
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_disable_reg;
+	}
+	st = iio_priv(indio_dev);
+	st->chip_info =
+		&ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+	spi_set_drvdata(spi, indio_dev);
+	st->reg = reg;
+	st->spi = spi;
+
+	/* Establish that the iio_dev is a child of the spi device */
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5446_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = &st->chip_info->channel;
+	indio_dev->num_channels = 1;
+
+	st->pwr_down_mode = MODE_PWRDWN_1k;
+
+	if (st->chip_info->int_vref_mv)
+		st->vref_mv = st->chip_info->int_vref_mv;
+	else if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else
+		dev_warn(&spi->dev, "reference voltage unspecified\n");
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_device;
+
+	return 0;
+
+error_free_device:
+	iio_device_free(indio_dev);
+error_disable_reg:
+	if (!IS_ERR(reg))
+		regulator_disable(reg);
+error_put_reg:
+	if (!IS_ERR(reg))
+		regulator_put(reg);
+
+	return ret;
+}
+
+static int ad5446_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5446_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5446_id[] = {
+	{"ad5444", ID_AD5444},
+	{"ad5446", ID_AD5446},
+	{"ad5512a", ID_AD5512A},
+	{"ad5541a", ID_AD5541A},
+	{"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
+	{"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
+	{"ad5553", ID_AD5553},
+	{"ad5601", ID_AD5601},
+	{"ad5611", ID_AD5611},
+	{"ad5621", ID_AD5621},
+	{"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */
+	{"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */
+	{"ad5640-2500", ID_AD5640_2500},
+	{"ad5640-1250", ID_AD5640_1250},
+	{"ad5660-2500", ID_AD5660_2500},
+	{"ad5660-1250", ID_AD5660_1250},
+	{"ad5662", ID_AD5662},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5446_id);
+
+static struct spi_driver ad5446_driver = {
+	.driver = {
+		.name	= "ad5446",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad5446_probe,
+	.remove		= __devexit_p(ad5446_remove),
+	.id_table	= ad5446_id,
+};
+module_spi_driver(ad5446_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5446.h b/drivers/iio/dac/ad5446.h
new file mode 100644
index 000000000000..dfd68ce7427e
--- /dev/null
+++ b/drivers/iio/dac/ad5446.h
@@ -0,0 +1,89 @@
+/*
+ * AD5446 SPI DAC driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DAC_AD5446_H_
+#define IIO_DAC_AD5446_H_
+
+/* DAC Control Bits */
+
+#define AD5446_LOAD		(0x0 << 14) /* Load and update */
+#define AD5446_SDO_DIS		(0x1 << 14) /* Disable SDO */
+#define AD5446_NOP		(0x2 << 14) /* No operation */
+#define AD5446_CLK_RISING	(0x3 << 14) /* Clock data on rising edge */
+
+#define AD5620_LOAD		(0x0 << 14) /* Load and update Norm Operation*/
+#define AD5620_PWRDWN_1k	(0x1 << 14) /* Power-down: 1kOhm to GND */
+#define AD5620_PWRDWN_100k	(0x2 << 14) /* Power-down: 100kOhm to GND */
+#define AD5620_PWRDWN_TRISTATE	(0x3 << 14) /* Power-down: Three-state */
+
+#define AD5660_LOAD		(0x0 << 16) /* Load and update Norm Operation*/
+#define AD5660_PWRDWN_1k	(0x1 << 16) /* Power-down: 1kOhm to GND */
+#define AD5660_PWRDWN_100k	(0x2 << 16) /* Power-down: 100kOhm to GND */
+#define AD5660_PWRDWN_TRISTATE	(0x3 << 16) /* Power-down: Three-state */
+
+#define MODE_PWRDWN_1k		0x1
+#define MODE_PWRDWN_100k	0x2
+#define MODE_PWRDWN_TRISTATE	0x3
+
+/**
+ * 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
+ */
+
+struct ad5446_state {
+	struct spi_device		*spi;
+	const struct ad5446_chip_info	*chip_info;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			cached_val;
+	unsigned			pwr_down_mode;
+	unsigned			pwr_down;
+};
+
+/**
+ * struct ad5446_chip_info - chip specific information
+ * @channel:		channel spec for the DAC
+ * @int_vref_mv:	AD5620/40/60: the internal reference voltage
+ * @write:		chip specific helper function to write to the register
+ */
+
+struct ad5446_chip_info {
+	struct iio_chan_spec	channel;
+	u16			int_vref_mv;
+	int			(*write)(struct ad5446_state *st, unsigned val);
+};
+
+/**
+ * ad5446_supported_device_ids:
+ * The AD5620/40/60 parts are available in different fixed internal reference
+ * voltage options. The actual part numbers may look differently
+ * (and a bit cryptic), however this style is used to make clear which
+ * parts are supported here.
+ */
+
+enum ad5446_supported_device_ids {
+	ID_AD5444,
+	ID_AD5446,
+	ID_AD5541A,
+	ID_AD5512A,
+	ID_AD5553,
+	ID_AD5601,
+	ID_AD5611,
+	ID_AD5621,
+	ID_AD5620_2500,
+	ID_AD5620_1250,
+	ID_AD5640_2500,
+	ID_AD5640_1250,
+	ID_AD5660_2500,
+	ID_AD5660_1250,
+	ID_AD5662,
+};
+
+#endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c
new file mode 100644
index 000000000000..242bdc7d0044
--- /dev/null
+++ b/drivers/iio/dac/ad5504.c
@@ -0,0 +1,393 @@
+/*
+ * AD5504, AD5501 High Voltage Digital to Analog Converter
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/dac/ad5504.h>
+
+#define AD5505_BITS			12
+#define AD5504_RES_MASK			((1 << (AD5505_BITS)) - 1)
+
+#define AD5504_CMD_READ			(1 << 15)
+#define AD5504_CMD_WRITE		(0 << 15)
+#define AD5504_ADDR(addr)		((addr) << 12)
+
+/* Registers */
+#define AD5504_ADDR_NOOP		0
+#define AD5504_ADDR_DAC(x)		((x) + 1)
+#define AD5504_ADDR_ALL_DAC		5
+#define AD5504_ADDR_CTRL		7
+
+/* Control Register */
+#define AD5504_DAC_PWR(ch)		((ch) << 2)
+#define AD5504_DAC_PWRDWN_MODE(mode)	((mode) << 6)
+#define AD5504_DAC_PWRDN_20K		0
+#define AD5504_DAC_PWRDN_3STATE		1
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @us:			spi_device
+ * @reg:		supply regulator
+ * @vref_mv:		actual reference voltage used
+ * @pwr_down_mask	power down mask
+ * @pwr_down_mode	current power down mode
+ */
+
+struct ad5504_state {
+	struct spi_device		*spi;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			pwr_down_mask;
+	unsigned			pwr_down_mode;
+};
+
+/**
+ * ad5504_supported_device_ids:
+ */
+
+enum ad5504_supported_device_ids {
+	ID_AD5504,
+	ID_AD5501,
+};
+
+static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val)
+{
+	u16 tmp = cpu_to_be16(AD5504_CMD_WRITE |
+			      AD5504_ADDR(addr) |
+			      (val & AD5504_RES_MASK));
+
+	return spi_write(spi, (u8 *)&tmp, 2);
+}
+
+static int ad5504_spi_read(struct spi_device *spi, u8 addr)
+{
+	u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr));
+	u16 val;
+	int ret;
+	struct spi_transfer	t = {
+			.tx_buf		= &tmp,
+			.rx_buf		= &val,
+			.len		= 2,
+		};
+	struct spi_message	m;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t, &m);
+	ret = spi_sync(spi, &m);
+
+	if (ret < 0)
+		return ret;
+
+	return be16_to_cpu(val) & AD5504_RES_MASK;
+}
+
+static int ad5504_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5504_spi_read(st->spi, chan->address);
+		if (ret < 0)
+			return ret;
+
+		*val = ret;
+
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5504_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		return ad5504_spi_write(st->spi, chan->address, val);
+	default:
+		ret = -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const char * const ad5504_powerdown_modes[] = {
+	"20kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5504_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode;
+}
+
+static int ad5504_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode;
+
+	return 0;
+}
+
+static const struct iio_enum ad5504_powerdown_mode_enum = {
+	.items = ad5504_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5504_powerdown_modes),
+	.get = ad5504_get_powerdown_mode,
+	.set = ad5504_set_powerdown_mode,
+};
+
+static ssize_t ad5504_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n",
+			!(st->pwr_down_mask & (1 << chan->channel)));
+}
+
+static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	size_t len)
+{
+	bool pwr_down;
+	int ret;
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (pwr_down)
+		st->pwr_down_mask |= (1 << chan->channel);
+	else
+		st->pwr_down_mask &= ~(1 << chan->channel);
+
+	ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL,
+				AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) |
+				AD5504_DAC_PWR(st->pwr_down_mask));
+
+	/* writes to the CTRL register must be followed by a NOOP */
+	ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0);
+
+	return ret ? ret : len;
+}
+
+static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000");
+static IIO_CONST_ATTR(temp0_thresh_rising_en, "1");
+
+static struct attribute *ad5504_ev_attributes[] = {
+	&iio_const_attr_temp0_thresh_rising_value.dev_attr.attr,
+	&iio_const_attr_temp0_thresh_rising_en.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute_group ad5504_ev_attribute_group = {
+	.attrs = ad5504_ev_attributes,
+	.name = "events",
+};
+
+static irqreturn_t ad5504_event_handler(int irq, void *private)
+{
+	iio_push_event(private,
+		       IIO_UNMOD_EVENT_CODE(IIO_TEMP,
+					    0,
+					    IIO_EV_TYPE_THRESH,
+					    IIO_EV_DIR_RISING),
+		       iio_get_time_ns());
+
+	return IRQ_HANDLED;
+}
+
+static const struct iio_info ad5504_info = {
+	.write_raw = ad5504_write_raw,
+	.read_raw = ad5504_read_raw,
+	.event_attrs = &ad5504_ev_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5504_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5504_read_dac_powerdown,
+		.write = ad5504_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5504_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5504_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5504_CHANNEL(_chan) { \
+	.type = IIO_VOLTAGE, \
+	.indexed = 1, \
+	.output = 1, \
+	.channel = (_chan), \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+	.address = AD5504_ADDR_DAC(_chan), \
+	.scan_type = IIO_ST('u', 12, 16, 0), \
+	.ext_info = ad5504_ext_info, \
+}
+
+static const struct iio_chan_spec ad5504_channels[] = {
+	AD5504_CHANNEL(0),
+	AD5504_CHANNEL(1),
+	AD5504_CHANNEL(2),
+	AD5504_CHANNEL(3),
+};
+
+static int __devinit ad5504_probe(struct spi_device *spi)
+{
+	struct ad5504_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct ad5504_state *st;
+	struct regulator *reg;
+	int ret, voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(reg)) {
+		ret = regulator_enable(reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(reg);
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st = iio_priv(indio_dev);
+	if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else if (pdata)
+		st->vref_mv = pdata->vref_mv;
+	else
+		dev_warn(&spi->dev, "reference voltage unspecified\n");
+
+	st->reg = reg;
+	st->spi = spi;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(st->spi)->name;
+	indio_dev->info = &ad5504_info;
+	if (spi_get_device_id(st->spi)->driver_data == ID_AD5501)
+		indio_dev->num_channels = 1;
+	else
+		indio_dev->num_channels = 4;
+	indio_dev->channels = ad5504_channels;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	if (spi->irq) {
+		ret = request_threaded_irq(spi->irq,
+					   NULL,
+					   &ad5504_event_handler,
+					   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					   spi_get_device_id(st->spi)->name,
+					   indio_dev);
+		if (ret)
+			goto error_disable_reg;
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_free_irq;
+
+	return 0;
+
+error_free_irq:
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+error_disable_reg:
+	if (!IS_ERR(reg))
+		regulator_disable(reg);
+error_put_reg:
+	if (!IS_ERR(reg))
+		regulator_put(reg);
+
+	iio_device_free(indio_dev);
+error_ret:
+	return ret;
+}
+
+static int __devexit ad5504_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5504_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (spi->irq)
+		free_irq(spi->irq, indio_dev);
+
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5504_id[] = {
+	{"ad5504", ID_AD5504},
+	{"ad5501", ID_AD5501},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5504_id);
+
+static struct spi_driver ad5504_driver = {
+	.driver = {
+		   .name = "ad5504",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5504_probe,
+	.remove = __devexit_p(ad5504_remove),
+	.id_table = ad5504_id,
+};
+module_spi_driver(ad5504_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5624r.h b/drivers/iio/dac/ad5624r.h
new file mode 100644
index 000000000000..5dca3028cdfd
--- /dev/null
+++ b/drivers/iio/dac/ad5624r.h
@@ -0,0 +1,79 @@
+/*
+ * AD5624R SPI DAC driver
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+#ifndef SPI_AD5624R_H_
+#define SPI_AD5624R_H_
+
+#define AD5624R_DAC_CHANNELS			4
+
+#define AD5624R_ADDR_DAC0			0x0
+#define AD5624R_ADDR_DAC1			0x1
+#define AD5624R_ADDR_DAC2			0x2
+#define AD5624R_ADDR_DAC3			0x3
+#define AD5624R_ADDR_ALL_DAC			0x7
+
+#define AD5624R_CMD_WRITE_INPUT_N		0x0
+#define AD5624R_CMD_UPDATE_DAC_N		0x1
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL	0x2
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N	0x3
+#define AD5624R_CMD_POWERDOWN_DAC		0x4
+#define AD5624R_CMD_RESET			0x5
+#define AD5624R_CMD_LDAC_SETUP			0x6
+#define AD5624R_CMD_INTERNAL_REFER_SETUP	0x7
+
+#define AD5624R_LDAC_PWRDN_NONE			0x0
+#define AD5624R_LDAC_PWRDN_1K			0x1
+#define AD5624R_LDAC_PWRDN_100K			0x2
+#define AD5624R_LDAC_PWRDN_3STATE		0x3
+
+/**
+ * struct ad5624r_chip_info - chip specific information
+ * @channels:		channel spec for the DAC
+ * @int_vref_mv:	AD5620/40/60: the internal reference voltage
+ */
+
+struct ad5624r_chip_info {
+	const struct iio_chan_spec	*channels;
+	u16				int_vref_mv;
+};
+
+/**
+ * struct ad5446_state - driver instance specific data
+ * @indio_dev:		the industrial I/O device
+ * @us:			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
+ */
+
+struct ad5624r_state {
+	struct spi_device		*us;
+	const struct ad5624r_chip_info	*chip_info;
+	struct regulator		*reg;
+	unsigned short			vref_mv;
+	unsigned			pwr_down_mask;
+	unsigned			pwr_down_mode;
+};
+
+/**
+ * ad5624r_supported_device_ids:
+ * The AD5624/44/64 parts are available in different
+ * fixed internal reference voltage options.
+ */
+
+enum ad5624r_supported_device_ids {
+	ID_AD5624R3,
+	ID_AD5644R3,
+	ID_AD5664R3,
+	ID_AD5624R5,
+	ID_AD5644R5,
+	ID_AD5664R5,
+};
+
+#endif /* SPI_AD5624R_H_ */
diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c
new file mode 100644
index 000000000000..6a7d6a48cc6d
--- /dev/null
+++ b/drivers/iio/dac/ad5624r_spi.c
@@ -0,0 +1,324 @@
+/*
+ * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "ad5624r.h"
+
+static int ad5624r_spi_write(struct spi_device *spi,
+			     u8 cmd, u8 addr, u16 val, u8 len)
+{
+	u32 data;
+	u8 msg[3];
+
+	/*
+	 * The input shift register is 24 bits wide. The first two bits are
+	 * don't care bits. The next three are the command bits, C2 to C0,
+	 * followed by the 3-bit DAC address, A2 to A0, and then the
+	 * 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
+	 * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits,
+	 * for the AD5664R, AD5644R, and AD5624R, respectively.
+	 */
+	data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
+	msg[0] = data >> 16;
+	msg[1] = data >> 8;
+	msg[2] = data;
+
+	return spi_write(spi, msg, 3);
+}
+
+static int ad5624r_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val =  scale_uv / 1000;
+		*val2 = (scale_uv % 1000) * 1000;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5624r_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= (1 << chan->scan_type.realbits) || val < 0)
+			return -EINVAL;
+
+		return ad5624r_spi_write(st->us,
+				AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
+				chan->address, val,
+				chan->scan_type.shift);
+	default:
+		ret = -EINVAL;
+	}
+
+	return -EINVAL;
+}
+
+static const char * const ad5624r_powerdown_modes[] = {
+	"1kohm_to_gnd",
+	"100kohm_to_gnd",
+	"three_state"
+};
+
+static int ad5624r_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode;
+}
+
+static int ad5624r_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode;
+
+	return 0;
+}
+
+static const struct iio_enum ad5624r_powerdown_mode_enum = {
+	.items = ad5624r_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5624r_powerdown_modes),
+	.get = ad5624r_get_powerdown_mode,
+	.set = ad5624r_set_powerdown_mode,
+};
+
+static ssize_t ad5624r_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n",
+			!!(st->pwr_down_mask & (1 << chan->channel)));
+}
+
+static ssize_t ad5624r_write_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	size_t len)
+{
+	bool pwr_down;
+	int ret;
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (pwr_down)
+		st->pwr_down_mask |= (1 << chan->channel);
+	else
+		st->pwr_down_mask &= ~(1 << chan->channel);
+
+	ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
+				(st->pwr_down_mode << 4) |
+				st->pwr_down_mask, 16);
+
+	return ret ? ret : len;
+}
+
+static const struct iio_info ad5624r_info = {
+	.write_raw = ad5624r_write_raw,
+	.read_raw = ad5624r_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5624r_read_dac_powerdown,
+		.write = ad5624r_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5624r_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5624r_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5624R_CHANNEL(_chan, _bits) { \
+	.type = IIO_VOLTAGE, \
+	.indexed = 1, \
+	.output = 1, \
+	.channel = (_chan), \
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+		     IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+	.address = (_chan), \
+	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
+	.ext_info = ad5624r_ext_info, \
+}
+
+#define DECLARE_AD5624R_CHANNELS(_name, _bits) \
+	const struct iio_chan_spec _name##_channels[] = { \
+		AD5624R_CHANNEL(0, _bits), \
+		AD5624R_CHANNEL(1, _bits), \
+		AD5624R_CHANNEL(2, _bits), \
+		AD5624R_CHANNEL(3, _bits), \
+}
+
+static DECLARE_AD5624R_CHANNELS(ad5624r, 12);
+static DECLARE_AD5624R_CHANNELS(ad5644r, 14);
+static DECLARE_AD5624R_CHANNELS(ad5664r, 16);
+
+static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = {
+	[ID_AD5624R3] = {
+		.channels = ad5624r_channels,
+		.int_vref_mv = 1250,
+	},
+	[ID_AD5624R5] = {
+		.channels = ad5624r_channels,
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5644R3] = {
+		.channels = ad5644r_channels,
+		.int_vref_mv = 1250,
+	},
+	[ID_AD5644R5] = {
+		.channels = ad5644r_channels,
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5664R3] = {
+		.channels = ad5664r_channels,
+		.int_vref_mv = 1250,
+	},
+	[ID_AD5664R5] = {
+		.channels = ad5664r_channels,
+		.int_vref_mv = 2500,
+	},
+};
+
+static int __devinit ad5624r_probe(struct spi_device *spi)
+{
+	struct ad5624r_state *st;
+	struct iio_dev *indio_dev;
+	int ret, voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	st = iio_priv(indio_dev);
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(st->reg)) {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(st->reg);
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st->chip_info =
+		&ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+	if (voltage_uv)
+		st->vref_mv = voltage_uv / 1000;
+	else
+		st->vref_mv = st->chip_info->int_vref_mv;
+
+	st->us = spi;
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5624r_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->chip_info->channels;
+	indio_dev->num_channels = AD5624R_DAC_CHANNELS;
+
+	ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
+				!!voltage_uv, 16);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->reg))
+		regulator_disable(st->reg);
+error_put_reg:
+	if (!IS_ERR(st->reg))
+		regulator_put(st->reg);
+	iio_device_free(indio_dev);
+error_ret:
+
+	return ret;
+}
+
+static int __devexit ad5624r_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5624r_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5624r_id[] = {
+	{"ad5624r3", ID_AD5624R3},
+	{"ad5644r3", ID_AD5644R3},
+	{"ad5664r3", ID_AD5664R3},
+	{"ad5624r5", ID_AD5624R5},
+	{"ad5644r5", ID_AD5644R5},
+	{"ad5664r5", ID_AD5664R5},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5624r_id);
+
+static struct spi_driver ad5624r_driver = {
+	.driver = {
+		   .name = "ad5624r",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5624r_probe,
+	.remove = __devexit_p(ad5624r_remove),
+	.id_table = ad5624r_id,
+};
+module_spi_driver(ad5624r_driver);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c
new file mode 100644
index 000000000000..6948d75e1036
--- /dev/null
+++ b/drivers/iio/dac/ad5686.c
@@ -0,0 +1,418 @@
+/*
+ * AD5686R, AD5685R, AD5684R Digital to analog converters  driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#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>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5686_DAC_CHANNELS			4
+
+#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
+ * @channel:		channel specification
+*/
+
+struct ad5686_chip_info {
+	u16				int_vref_mv;
+	struct iio_chan_spec		channel[AD5686_DAC_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 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 {
+		u32 d32;
+		u8 d8[4];
+	} data[3] ____cacheline_aligned;
+};
+
+/**
+ * ad5686_supported_device_ids:
+ */
+
+enum ad5686_supported_device_ids {
+	ID_AD5684,
+	ID_AD5685,
+	ID_AD5686,
+};
+static int ad5686_spi_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);
+}
+
+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_message m;
+	int ret;
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	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(st->spi, &m);
+	if (ret < 0)
+		return ret;
+
+	return be32_to_cpu(st->data[2].d32);
+}
+
+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)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1;
+}
+
+static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode &= ~(0x3 << (chan->channel * 2));
+	st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2));
+
+	return 0;
+}
+
+static const struct iio_enum ad5686_powerdown_mode_enum = {
+	.items = ad5686_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5686_powerdown_modes),
+	.get = ad5686_get_powerdown_mode,
+	.set = ad5686_set_powerdown_mode,
+};
+
+static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", !!(st->pwr_down_mask &
+			(0x3 << (chan->channel * 2))));
+}
+
+static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	bool readin;
+	int ret;
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &readin);
+	if (ret)
+		return ret;
+
+	if (readin == true)
+		st->pwr_down_mask |= (0x3 << (chan->channel * 2));
+	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);
+
+	return ret ? ret : len;
+}
+
+static int ad5686_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&indio_dev->mlock);
+		ret = ad5686_spi_read(st, chan->address);
+		mutex_unlock(&indio_dev->mlock);
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return IIO_VAL_INT;
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		scale_uv = (st->vref_mv * 100000)
+			>> (chan->scan_type.realbits);
+		*val =  scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	}
+	return -EINVAL;
+}
+
+static int ad5686_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val,
+			       int val2,
+			       long mask)
+{
+	struct ad5686_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		if (val > (1 << chan->scan_type.realbits) || val < 0)
+			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);
+		mutex_unlock(&indio_dev->mlock);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct iio_info ad5686_info = {
+	.read_raw = ad5686_read_raw,
+	.write_raw = ad5686_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static const struct iio_chan_spec_ext_info ad5686_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = ad5686_read_dac_powerdown,
+		.write = ad5686_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", false, &ad5686_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5686_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5868_CHANNEL(chan, bits, shift) {			\
+		.type = IIO_VOLTAGE,				\
+		.indexed = 1,					\
+		.output = 1,					\
+		.channel = chan,				\
+		.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT,			\
+		.address = AD5686_ADDR_DAC(chan),			\
+		.scan_type = IIO_ST('u', bits, 16, shift),	\
+		.ext_info = ad5686_ext_info,			\
+}
+
+static const struct ad5686_chip_info ad5686_chip_info_tbl[] = {
+	[ID_AD5684] = {
+		.channel[0] = AD5868_CHANNEL(0, 12, 4),
+		.channel[1] = AD5868_CHANNEL(1, 12, 4),
+		.channel[2] = AD5868_CHANNEL(2, 12, 4),
+		.channel[3] = AD5868_CHANNEL(3, 12, 4),
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5685] = {
+		.channel[0] = AD5868_CHANNEL(0, 14, 2),
+		.channel[1] = AD5868_CHANNEL(1, 14, 2),
+		.channel[2] = AD5868_CHANNEL(2, 14, 2),
+		.channel[3] = AD5868_CHANNEL(3, 14, 2),
+		.int_vref_mv = 2500,
+	},
+	[ID_AD5686] = {
+		.channel[0] = AD5868_CHANNEL(0, 16, 0),
+		.channel[1] = AD5868_CHANNEL(1, 16, 0),
+		.channel[2] = AD5868_CHANNEL(2, 16, 0),
+		.channel[3] = AD5868_CHANNEL(3, 16, 0),
+		.int_vref_mv = 2500,
+	},
+};
+
+
+static int __devinit ad5686_probe(struct spi_device *spi)
+{
+	struct ad5686_state *st;
+	struct iio_dev *indio_dev;
+	int ret, regdone = 0, voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL)
+		return  -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->reg = regulator_get(&spi->dev, "vcc");
+	if (!IS_ERR(st->reg)) {
+		ret = regulator_enable(st->reg);
+		if (ret)
+			goto error_put_reg;
+
+		voltage_uv = regulator_get_voltage(st->reg);
+	}
+
+	st->chip_info =
+		&ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+	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->info = &ad5686_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = st->chip_info->channel;
+	indio_dev->num_channels = AD5686_DAC_CHANNELS;
+
+	regdone = 1;
+	ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0,
+				!!voltage_uv, 0);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg;
+
+	return 0;
+
+error_disable_reg:
+	if (!IS_ERR(st->reg))
+		regulator_disable(st->reg);
+error_put_reg:
+	if (!IS_ERR(st->reg))
+		regulator_put(st->reg);
+
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5686_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5686_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg)) {
+		regulator_disable(st->reg);
+		regulator_put(st->reg);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5686_id[] = {
+	{"ad5684", ID_AD5684},
+	{"ad5685", ID_AD5685},
+	{"ad5686", ID_AD5686},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5686_id);
+
+static struct spi_driver ad5686_driver = {
+	.driver = {
+		   .name = "ad5686",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5686_probe,
+	.remove = __devexit_p(ad5686_remove),
+	.id_table = ad5686_id,
+};
+module_spi_driver(ad5686_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c
new file mode 100644
index 000000000000..ffce30447445
--- /dev/null
+++ b/drivers/iio/dac/ad5764.c
@@ -0,0 +1,382 @@
+/*
+ * Analog devices AD5764, AD5764R, AD5744, AD5744R quad-channel
+ * Digital to Analog Converters driver
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/err.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>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AD5764_REG_SF_NOP			0x0
+#define AD5764_REG_SF_CONFIG			0x1
+#define AD5764_REG_SF_CLEAR			0x4
+#define AD5764_REG_SF_LOAD			0x5
+#define AD5764_REG_DATA(x)			((2 << 3) | (x))
+#define AD5764_REG_COARSE_GAIN(x)		((3 << 3) | (x))
+#define AD5764_REG_FINE_GAIN(x)			((4 << 3) | (x))
+#define AD5764_REG_OFFSET(x)			((5 << 3) | (x))
+
+#define AD5764_NUM_CHANNELS 4
+
+/**
+ * struct ad5764_chip_info - chip specific information
+ * @int_vref:	Value of the internal reference voltage in uV - 0 if external
+ *		reference voltage is used
+ * @channel	channel specification
+*/
+
+struct ad5764_chip_info {
+	unsigned long int_vref;
+	const struct iio_chan_spec *channels;
+};
+
+/**
+ * struct ad5764_state - driver instance specific data
+ * @spi:		spi_device
+ * @chip_info:		chip info
+ * @vref_reg:		vref supply regulators
+ * @data:		spi transfer buffers
+ */
+
+struct ad5764_state {
+	struct spi_device		*spi;
+	const struct ad5764_chip_info	*chip_info;
+	struct regulator_bulk_data	vref_reg[2];
+
+	/*
+	 * DMA (thus cache coherency maintenance) requires the
+	 * transfer buffers to live in their own cache lines.
+	 */
+	union {
+		__be32 d32;
+		u8 d8[4];
+	} data[2] ____cacheline_aligned;
+};
+
+enum ad5764_type {
+	ID_AD5744,
+	ID_AD5744R,
+	ID_AD5764,
+	ID_AD5764R,
+};
+
+#define AD5764_CHANNEL(_chan, _bits) {				\
+	.type = IIO_VOLTAGE,					\
+	.indexed = 1,						\
+	.output = 1,						\
+	.channel = (_chan),					\
+	.address = (_chan),					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_OFFSET_SHARED_BIT |		\
+		IIO_CHAN_INFO_SCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |		\
+		IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,		\
+	.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits))	\
+}
+
+#define DECLARE_AD5764_CHANNELS(_name, _bits) \
+const struct iio_chan_spec _name##_channels[] = { \
+	AD5764_CHANNEL(0, (_bits)), \
+	AD5764_CHANNEL(1, (_bits)), \
+	AD5764_CHANNEL(2, (_bits)), \
+	AD5764_CHANNEL(3, (_bits)), \
+};
+
+static DECLARE_AD5764_CHANNELS(ad5764, 16);
+static DECLARE_AD5764_CHANNELS(ad5744, 14);
+
+static const struct ad5764_chip_info ad5764_chip_infos[] = {
+	[ID_AD5744] = {
+		.int_vref = 0,
+		.channels = ad5744_channels,
+	},
+	[ID_AD5744R] = {
+		.int_vref = 5000000,
+		.channels = ad5744_channels,
+	},
+	[ID_AD5764] = {
+		.int_vref = 0,
+		.channels = ad5764_channels,
+	},
+	[ID_AD5764R] = {
+		.int_vref = 5000000,
+		.channels = ad5764_channels,
+	},
+};
+
+static int ad5764_write(struct iio_dev *indio_dev, unsigned int reg,
+	unsigned int val)
+{
+	struct ad5764_state *st = iio_priv(indio_dev);
+	int ret;
+
+	mutex_lock(&indio_dev->mlock);
+	st->data[0].d32 = cpu_to_be32((reg << 16) | val);
+
+	ret = spi_write(st->spi, &st->data[0].d8[1], 3);
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5764_read(struct iio_dev *indio_dev, unsigned int reg,
+	unsigned int *val)
+{
+	struct ad5764_state *st = iio_priv(indio_dev);
+	struct spi_message m;
+	int ret;
+	struct spi_transfer t[] = {
+		{
+			.tx_buf = &st->data[0].d8[1],
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.rx_buf = &st->data[1].d8[1],
+			.len = 3,
+		},
+	};
+
+	spi_message_init(&m);
+	spi_message_add_tail(&t[0], &m);
+	spi_message_add_tail(&t[1], &m);
+
+	mutex_lock(&indio_dev->mlock);
+
+	st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16));
+
+	ret = spi_sync(st->spi, &m);
+	if (ret >= 0)
+		*val = be32_to_cpu(st->data[1].d32) & 0xffff;
+
+	mutex_unlock(&indio_dev->mlock);
+
+	return ret;
+}
+
+static int ad5764_chan_info_to_reg(struct iio_chan_spec const *chan, long info)
+{
+	switch (info) {
+	case 0:
+		return AD5764_REG_DATA(chan->address);
+	case IIO_CHAN_INFO_CALIBBIAS:
+		return AD5764_REG_OFFSET(chan->address);
+	case IIO_CHAN_INFO_CALIBSCALE:
+		return AD5764_REG_FINE_GAIN(chan->address);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int ad5764_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long info)
+{
+	const int max_val = (1 << chan->scan_type.realbits);
+	unsigned int reg;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+		val <<= chan->scan_type.shift;
+		break;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		if (val >= 128 || val < -128)
+			return -EINVAL;
+		break;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		if (val >= 32 || val < -32)
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	reg = ad5764_chan_info_to_reg(chan, info);
+	return ad5764_write(indio_dev, reg, (u16)val);
+}
+
+static int ad5764_get_channel_vref(struct ad5764_state *st,
+	unsigned int channel)
+{
+	if (st->chip_info->int_vref)
+		return st->chip_info->int_vref;
+	else
+		return regulator_get_voltage(st->vref_reg[channel / 2].consumer);
+}
+
+static int ad5764_read_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int *val, int *val2, long info)
+{
+	struct ad5764_state *st = iio_priv(indio_dev);
+	unsigned long scale_uv;
+	unsigned int reg;
+	int vref;
+	int ret;
+
+	switch (info) {
+	case IIO_CHAN_INFO_RAW:
+		reg = AD5764_REG_DATA(chan->address);
+		ret = ad5764_read(indio_dev, reg, val);
+		if (ret < 0)
+			return ret;
+		*val >>= chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBBIAS:
+		reg = AD5764_REG_OFFSET(chan->address);
+		ret = ad5764_read(indio_dev, reg, val);
+		if (ret < 0)
+			return ret;
+		*val = sign_extend32(*val, 7);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_CALIBSCALE:
+		reg = AD5764_REG_FINE_GAIN(chan->address);
+		ret = ad5764_read(indio_dev, reg, val);
+		if (ret < 0)
+			return ret;
+		*val = sign_extend32(*val, 5);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		/* vout = 4 * vref + ((dac_code / 65535) - 0.5) */
+		vref = ad5764_get_channel_vref(st, chan->channel);
+		if (vref < 0)
+			return vref;
+
+		scale_uv = (vref * 4 * 100) >> chan->scan_type.realbits;
+		*val = scale_uv / 100000;
+		*val2 = (scale_uv % 100000) * 10;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		*val = -(1 << chan->scan_type.realbits) / 2;
+		return IIO_VAL_INT;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info ad5764_info = {
+	.read_raw = ad5764_read_raw,
+	.write_raw = ad5764_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5764_probe(struct spi_device *spi)
+{
+	enum ad5764_type type = spi_get_device_id(spi)->driver_data;
+	struct iio_dev *indio_dev;
+	struct ad5764_state *st;
+	int ret;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		dev_err(&spi->dev, "Failed to allocate iio device\n");
+		return -ENOMEM;
+	}
+
+	st = iio_priv(indio_dev);
+	spi_set_drvdata(spi, indio_dev);
+
+	st->spi = spi;
+	st->chip_info = &ad5764_chip_infos[type];
+
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->name = spi_get_device_id(spi)->name;
+	indio_dev->info = &ad5764_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->num_channels = AD5764_NUM_CHANNELS;
+	indio_dev->channels = st->chip_info->channels;
+
+	if (st->chip_info->int_vref == 0) {
+		st->vref_reg[0].supply = "vrefAB";
+		st->vref_reg[1].supply = "vrefCD";
+
+		ret = regulator_bulk_get(&st->spi->dev,
+			ARRAY_SIZE(st->vref_reg), st->vref_reg);
+		if (ret) {
+			dev_err(&spi->dev, "Failed to request vref regulators: %d\n",
+				ret);
+			goto error_free;
+		}
+
+		ret = regulator_bulk_enable(ARRAY_SIZE(st->vref_reg),
+			st->vref_reg);
+		if (ret) {
+			dev_err(&spi->dev, "Failed to enable vref regulators: %d\n",
+				ret);
+			goto error_free_reg;
+		}
+	}
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register iio device: %d\n", ret);
+		goto error_disable_reg;
+	}
+
+	return 0;
+
+error_disable_reg:
+	if (st->chip_info->int_vref == 0)
+		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+error_free_reg:
+	if (st->chip_info->int_vref == 0)
+		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+error_free:
+	iio_device_free(indio_dev);
+
+	return ret;
+}
+
+static int __devexit ad5764_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5764_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	if (st->chip_info->int_vref == 0) {
+		regulator_bulk_disable(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+		regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
+	}
+
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5764_ids[] = {
+	{ "ad5744", ID_AD5744 },
+	{ "ad5744r", ID_AD5744R },
+	{ "ad5764", ID_AD5764 },
+	{ "ad5764r", ID_AD5764R },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ad5764_ids);
+
+static struct spi_driver ad5764_driver = {
+	.driver = {
+		.name = "ad5764",
+		.owner = THIS_MODULE,
+	},
+	.probe = ad5764_probe,
+	.remove = __devexit_p(ad5764_remove),
+	.id_table = ad5764_ids,
+};
+module_spi_driver(ad5764_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c
new file mode 100644
index 000000000000..2bd2e37280ff
--- /dev/null
+++ b/drivers/iio/dac/ad5791.c
@@ -0,0 +1,485 @@
+/*
+ * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog
+ * Converter
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/regulator/consumer.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/dac/ad5791.h>
+
+#define AD5791_RES_MASK(x)		((1 << (x)) - 1)
+#define AD5791_DAC_MASK			AD5791_RES_MASK(20)
+#define AD5791_DAC_MSB			(1 << 19)
+
+#define AD5791_CMD_READ			(1 << 23)
+#define AD5791_CMD_WRITE		(0 << 23)
+#define AD5791_ADDR(addr)		((addr) << 20)
+
+/* Registers */
+#define AD5791_ADDR_NOOP		0
+#define AD5791_ADDR_DAC0		1
+#define AD5791_ADDR_CTRL		2
+#define AD5791_ADDR_CLRCODE		3
+#define AD5791_ADDR_SW_CTRL		4
+
+/* Control Register */
+#define AD5791_CTRL_RBUF		(1 << 1)
+#define AD5791_CTRL_OPGND		(1 << 2)
+#define AD5791_CTRL_DACTRI		(1 << 3)
+#define AD5791_CTRL_BIN2SC		(1 << 4)
+#define AD5791_CTRL_SDODIS		(1 << 5)
+#define AD5761_CTRL_LINCOMP(x)		((x) << 6)
+
+#define AD5791_LINCOMP_0_10		0
+#define AD5791_LINCOMP_10_12		1
+#define AD5791_LINCOMP_12_16		2
+#define AD5791_LINCOMP_16_19		3
+#define AD5791_LINCOMP_19_20		12
+
+#define AD5780_LINCOMP_0_10		0
+#define AD5780_LINCOMP_10_20		12
+
+/* Software Control Register */
+#define AD5791_SWCTRL_LDAC		(1 << 0)
+#define AD5791_SWCTRL_CLR		(1 << 1)
+#define AD5791_SWCTRL_RESET		(1 << 2)
+
+#define AD5791_DAC_PWRDN_6K		0
+#define AD5791_DAC_PWRDN_3STATE		1
+
+/**
+ * struct ad5791_chip_info - chip specific information
+ * @get_lin_comp:	function pointer to the device specific function
+ */
+
+struct ad5791_chip_info {
+	int (*get_lin_comp)	(unsigned int span);
+};
+
+/**
+ * struct ad5791_state - driver instance specific data
+ * @us:			spi_device
+ * @reg_vdd:		positive supply regulator
+ * @reg_vss:		negative supply regulator
+ * @chip_info:		chip model specific constants
+ * @vref_mv:		actual reference voltage used
+ * @vref_neg_mv:	voltage of the negative supply
+ * @pwr_down_mode	current power down mode
+ */
+
+struct ad5791_state {
+	struct spi_device		*spi;
+	struct regulator		*reg_vdd;
+	struct regulator		*reg_vss;
+	const struct ad5791_chip_info	*chip_info;
+	unsigned short			vref_mv;
+	unsigned int			vref_neg_mv;
+	unsigned			ctrl;
+	unsigned			pwr_down_mode;
+	bool				pwr_down;
+};
+
+/**
+ * ad5791_supported_device_ids:
+ */
+
+enum ad5791_supported_device_ids {
+	ID_AD5760,
+	ID_AD5780,
+	ID_AD5781,
+	ID_AD5791,
+};
+
+static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val)
+{
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data;
+
+	data.d32 = cpu_to_be32(AD5791_CMD_WRITE |
+			      AD5791_ADDR(addr) |
+			      (val & AD5791_DAC_MASK));
+
+	return spi_write(spi, &data.d8[1], 3);
+}
+
+static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
+{
+	union {
+		u32 d32;
+		u8 d8[4];
+	} data[3];
+	int ret;
+	struct spi_message msg;
+	struct spi_transfer xfers[] = {
+		{
+			.tx_buf = &data[0].d8[1],
+			.bits_per_word = 8,
+			.len = 3,
+			.cs_change = 1,
+		}, {
+			.tx_buf = &data[1].d8[1],
+			.rx_buf = &data[2].d8[1],
+			.bits_per_word = 8,
+			.len = 3,
+		},
+	};
+
+	data[0].d32 = cpu_to_be32(AD5791_CMD_READ |
+			      AD5791_ADDR(addr));
+	data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP));
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfers[0], &msg);
+	spi_message_add_tail(&xfers[1], &msg);
+	ret = spi_sync(spi, &msg);
+
+	*val = be32_to_cpu(data[2].d32);
+
+	return ret;
+}
+
+static const char * const ad5791_powerdown_modes[] = {
+	"6kohm_to_gnd",
+	"three_state",
+};
+
+static int ad5791_get_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	return st->pwr_down_mode;
+}
+
+static int ad5791_set_powerdown_mode(struct iio_dev *indio_dev,
+	const struct iio_chan_spec *chan, unsigned int mode)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	st->pwr_down_mode = mode;
+
+	return 0;
+}
+
+static const struct iio_enum ad5791_powerdown_mode_enum = {
+	.items = ad5791_powerdown_modes,
+	.num_items = ARRAY_SIZE(ad5791_powerdown_modes),
+	.get = ad5791_get_powerdown_mode,
+	.set = ad5791_set_powerdown_mode,
+};
+
+static ssize_t ad5791_read_dac_powerdown(struct iio_dev *indio_dev,
+	uintptr_t private, const struct iio_chan_spec *chan, char *buf)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev,
+	 uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+	 size_t len)
+{
+	bool pwr_down;
+	int ret;
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	ret = strtobool(buf, &pwr_down);
+	if (ret)
+		return ret;
+
+	if (!pwr_down) {
+		st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
+	} else {
+		if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K)
+			st->ctrl |= AD5791_CTRL_OPGND;
+		else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE)
+			st->ctrl |= AD5791_CTRL_DACTRI;
+	}
+	st->pwr_down = pwr_down;
+
+	ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl);
+
+	return ret ? ret : len;
+}
+
+static int ad5791_get_lin_comp(unsigned int span)
+{
+	if (span <= 10000)
+		return AD5791_LINCOMP_0_10;
+	else if (span <= 12000)
+		return AD5791_LINCOMP_10_12;
+	else if (span <= 16000)
+		return AD5791_LINCOMP_12_16;
+	else if (span <= 19000)
+		return AD5791_LINCOMP_16_19;
+	else
+		return AD5791_LINCOMP_19_20;
+}
+
+static int ad5780_get_lin_comp(unsigned int span)
+{
+	if (span <= 10000)
+		return AD5780_LINCOMP_0_10;
+	else
+		return AD5780_LINCOMP_10_20;
+}
+static const struct ad5791_chip_info ad5791_chip_info_tbl[] = {
+	[ID_AD5760] = {
+		.get_lin_comp = ad5780_get_lin_comp,
+	},
+	[ID_AD5780] = {
+		.get_lin_comp = ad5780_get_lin_comp,
+	},
+	[ID_AD5781] = {
+		.get_lin_comp = ad5791_get_lin_comp,
+	},
+	[ID_AD5791] = {
+		.get_lin_comp = ad5791_get_lin_comp,
+	},
+};
+
+static int ad5791_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+	u64 val64;
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ad5791_spi_read(st->spi, chan->address, val);
+		if (ret)
+			return ret;
+		*val &= AD5791_DAC_MASK;
+		*val >>= chan->scan_type.shift;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		*val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits;
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_OFFSET:
+		val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits);
+		do_div(val64, st->vref_mv);
+		*val = -val64;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+
+};
+
+static const struct iio_chan_spec_ext_info ad5791_ext_info[] = {
+	{
+		.name = "powerdown",
+		.shared = true,
+		.read = ad5791_read_dac_powerdown,
+		.write = ad5791_write_dac_powerdown,
+	},
+	IIO_ENUM("powerdown_mode", true, &ad5791_powerdown_mode_enum),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &ad5791_powerdown_mode_enum),
+	{ },
+};
+
+#define AD5791_CHAN(bits, shift) {			\
+	.type = IIO_VOLTAGE,				\
+	.output = 1,					\
+	.indexed = 1,					\
+	.address = AD5791_ADDR_DAC0,			\
+	.channel = 0,					\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+		IIO_CHAN_INFO_SCALE_SHARED_BIT |	\
+		IIO_CHAN_INFO_OFFSET_SHARED_BIT,	\
+	.scan_type = IIO_ST('u', bits, 24, shift),	\
+	.ext_info = ad5791_ext_info,			\
+}
+
+static const struct iio_chan_spec ad5791_channels[] = {
+	[ID_AD5760] = AD5791_CHAN(16, 4),
+	[ID_AD5780] = AD5791_CHAN(18, 2),
+	[ID_AD5781] = AD5791_CHAN(18, 2),
+	[ID_AD5791] = AD5791_CHAN(20, 0)
+};
+
+static int ad5791_write_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan,
+			    int val,
+			    int val2,
+			    long mask)
+{
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		val &= AD5791_RES_MASK(chan->scan_type.realbits);
+		val <<= chan->scan_type.shift;
+
+		return ad5791_spi_write(st->spi, chan->address, val);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info ad5791_info = {
+	.read_raw = &ad5791_read_raw,
+	.write_raw = &ad5791_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+static int __devinit ad5791_probe(struct spi_device *spi)
+{
+	struct ad5791_platform_data *pdata = spi->dev.platform_data;
+	struct iio_dev *indio_dev;
+	struct ad5791_state *st;
+	int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
+
+	indio_dev = iio_device_alloc(sizeof(*st));
+	if (indio_dev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+	st = iio_priv(indio_dev);
+	st->reg_vdd = regulator_get(&spi->dev, "vdd");
+	if (!IS_ERR(st->reg_vdd)) {
+		ret = regulator_enable(st->reg_vdd);
+		if (ret)
+			goto error_put_reg_pos;
+
+		pos_voltage_uv = regulator_get_voltage(st->reg_vdd);
+	}
+
+	st->reg_vss = regulator_get(&spi->dev, "vss");
+	if (!IS_ERR(st->reg_vss)) {
+		ret = regulator_enable(st->reg_vss);
+		if (ret)
+			goto error_put_reg_neg;
+
+		neg_voltage_uv = regulator_get_voltage(st->reg_vss);
+	}
+
+	st->pwr_down = true;
+	st->spi = spi;
+
+	if (!IS_ERR(st->reg_vss) && !IS_ERR(st->reg_vdd)) {
+		st->vref_mv = (pos_voltage_uv + neg_voltage_uv) / 1000;
+		st->vref_neg_mv = neg_voltage_uv / 1000;
+	} else if (pdata) {
+		st->vref_mv = pdata->vref_pos_mv + pdata->vref_neg_mv;
+		st->vref_neg_mv = pdata->vref_neg_mv;
+	} else {
+		dev_warn(&spi->dev, "reference voltage unspecified\n");
+	}
+
+	ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET);
+	if (ret)
+		goto error_disable_reg_neg;
+
+	st->chip_info =	&ad5791_chip_info_tbl[spi_get_device_id(spi)
+					      ->driver_data];
+
+
+	st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv))
+		  | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) |
+		  AD5791_CTRL_BIN2SC;
+
+	ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl |
+		AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI);
+	if (ret)
+		goto error_disable_reg_neg;
+
+	spi_set_drvdata(spi, indio_dev);
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->info = &ad5791_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels
+		= &ad5791_channels[spi_get_device_id(spi)->driver_data];
+	indio_dev->num_channels = 1;
+	indio_dev->name = spi_get_device_id(st->spi)->name;
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto error_disable_reg_neg;
+
+	return 0;
+
+error_disable_reg_neg:
+	if (!IS_ERR(st->reg_vss))
+		regulator_disable(st->reg_vss);
+error_put_reg_neg:
+	if (!IS_ERR(st->reg_vss))
+		regulator_put(st->reg_vss);
+
+	if (!IS_ERR(st->reg_vdd))
+		regulator_disable(st->reg_vdd);
+error_put_reg_pos:
+	if (!IS_ERR(st->reg_vdd))
+		regulator_put(st->reg_vdd);
+	iio_device_free(indio_dev);
+error_ret:
+
+	return ret;
+}
+
+static int __devexit ad5791_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct ad5791_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	if (!IS_ERR(st->reg_vdd)) {
+		regulator_disable(st->reg_vdd);
+		regulator_put(st->reg_vdd);
+	}
+
+	if (!IS_ERR(st->reg_vss)) {
+		regulator_disable(st->reg_vss);
+		regulator_put(st->reg_vss);
+	}
+	iio_device_free(indio_dev);
+
+	return 0;
+}
+
+static const struct spi_device_id ad5791_id[] = {
+	{"ad5760", ID_AD5760},
+	{"ad5780", ID_AD5780},
+	{"ad5781", ID_AD5781},
+	{"ad5790", ID_AD5791},
+	{"ad5791", ID_AD5791},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, ad5791_id);
+
+static struct spi_driver ad5791_driver = {
+	.driver = {
+		   .name = "ad5791",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = ad5791_probe,
+	.remove = __devexit_p(ad5791_remove),
+	.id_table = ad5791_id,
+};
+module_spi_driver(ad5791_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c
new file mode 100644
index 000000000000..92c77c82026c
--- /dev/null
+++ b/drivers/iio/dac/max517.c
@@ -0,0 +1,243 @@
+/*
+ *  max517.c - Support for Maxim MAX517, MAX518 and MAX519
+ *
+ *  Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/dac/max517.h>
+
+#define MAX517_DRV_NAME	"max517"
+
+/* Commands */
+#define COMMAND_CHANNEL0	0x00
+#define COMMAND_CHANNEL1	0x01 /* for MAX518 and MAX519 */
+#define COMMAND_PD		0x08 /* Power Down */
+
+enum max517_device_ids {
+	ID_MAX517,
+	ID_MAX518,
+	ID_MAX519,
+};
+
+struct max517_data {
+	struct iio_dev		*indio_dev;
+	struct i2c_client	*client;
+	unsigned short		vref_mv[2];
+};
+
+/*
+ * channel: bit 0: channel 1
+ *          bit 1: channel 2
+ * (this way, it's possible to set both channels at once)
+ */
+static int max517_set_value(struct iio_dev *indio_dev,
+	long val, int channel)
+{
+	struct max517_data *data = iio_priv(indio_dev);
+	struct i2c_client *client = data->client;
+	u8 outbuf[2];
+	int res;
+
+	if (val < 0 || val > 255)
+		return -EINVAL;
+
+	outbuf[0] = channel;
+	outbuf[1] = val;
+
+	res = i2c_master_send(client, outbuf, 2);
+	if (res < 0)
+		return res;
+	else if (res != 2)
+		return -EIO;
+	else
+		return 0;
+}
+
+static int max517_read_raw(struct iio_dev *indio_dev,
+			   struct iio_chan_spec const *chan,
+			   int *val,
+			   int *val2,
+			   long m)
+{
+	struct max517_data *data = iio_priv(indio_dev);
+	unsigned int scale_uv;
+
+	switch (m) {
+	case IIO_CHAN_INFO_SCALE:
+		/* Corresponds to Vref / 2^(bits) */
+		scale_uv = (data->vref_mv[chan->channel] * 1000) >> 8;
+		*val =  scale_uv / 1000000;
+		*val2 = scale_uv % 1000000;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int max517_write_raw(struct iio_dev *indio_dev,
+	struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = max517_set_value(indio_dev, val, chan->channel);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max517_suspend(struct device *dev)
+{
+	u8 outbuf = COMMAND_PD;
+
+	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
+}
+
+static int max517_resume(struct device *dev)
+{
+	u8 outbuf = 0;
+
+	return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
+}
+
+static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
+#define MAX517_PM_OPS (&max517_pm_ops)
+#else
+#define MAX517_PM_OPS NULL
+#endif
+
+static const struct iio_info max517_info = {
+	.read_raw = max517_read_raw,
+	.write_raw = max517_write_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define MAX517_CHANNEL(chan) {				\
+	.type = IIO_VOLTAGE,				\
+	.indexed = 1,					\
+	.output = 1,					\
+	.channel = (chan),				\
+	.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |	\
+	IIO_CHAN_INFO_SCALE_SEPARATE_BIT,		\
+	.scan_type = IIO_ST('u', 8, 8, 0),		\
+}
+
+static const struct iio_chan_spec max517_channels[] = {
+	MAX517_CHANNEL(0),
+	MAX517_CHANNEL(1)
+};
+
+static int max517_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct max517_data *data;
+	struct iio_dev *indio_dev;
+	struct max517_platform_data *platform_data = client->dev.platform_data;
+	int err;
+
+	indio_dev = iio_device_alloc(sizeof(*data));
+	if (indio_dev == NULL) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	/* establish that the iio_dev is a child of the i2c device */
+	indio_dev->dev.parent = &client->dev;
+
+	/* reduced channel set for MAX517 */
+	if (id->driver_data == ID_MAX517)
+		indio_dev->num_channels = 1;
+	else
+		indio_dev->num_channels = 2;
+	indio_dev->channels = max517_channels;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &max517_info;
+
+	/*
+	 * Reference voltage on MAX518 and default is 5V, else take vref_mv
+	 * from platform_data
+	 */
+	if (id->driver_data == ID_MAX518 || !platform_data) {
+		data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */
+	} else {
+		data->vref_mv[0] = platform_data->vref_mv[0];
+		data->vref_mv[1] = platform_data->vref_mv[1];
+	}
+
+	err = iio_device_register(indio_dev);
+	if (err)
+		goto exit_free_device;
+
+	dev_info(&client->dev, "DAC registered\n");
+
+	return 0;
+
+exit_free_device:
+	iio_device_free(indio_dev);
+exit:
+	return err;
+}
+
+static int max517_remove(struct i2c_client *client)
+{
+	iio_device_unregister(i2c_get_clientdata(client));
+	iio_device_free(i2c_get_clientdata(client));
+
+	return 0;
+}
+
+static const struct i2c_device_id max517_id[] = {
+	{ "max517", ID_MAX517 },
+	{ "max518", ID_MAX518 },
+	{ "max519", ID_MAX519 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max517_id);
+
+static struct i2c_driver max517_driver = {
+	.driver = {
+		.name	= MAX517_DRV_NAME,
+		.pm		= MAX517_PM_OPS,
+	},
+	.probe		= max517_probe,
+	.remove		= max517_remove,
+	.id_table	= max517_id,
+};
+module_i2c_driver(max517_driver);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC");
+MODULE_LICENSE("GPL");