summaryrefslogtreecommitdiff
path: root/drivers/staging/iio/dac
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/iio/dac')
-rw-r--r--drivers/staging/iio/dac/Kconfig15
-rw-r--r--drivers/staging/iio/dac/Makefile1
-rw-r--r--drivers/staging/iio/dac/ad5446.c193
-rw-r--r--drivers/staging/iio/dac/ad5446.h24
-rw-r--r--drivers/staging/iio/dac/ad5624r.h89
-rw-r--r--drivers/staging/iio/dac/ad5624r_spi.c247
-rw-r--r--drivers/staging/iio/dac/max517.c298
-rw-r--r--drivers/staging/iio/dac/max517.h19
8 files changed, 750 insertions, 136 deletions
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
index 9191bd2..67defcb 100644
--- a/drivers/staging/iio/dac/Kconfig
+++ b/drivers/staging/iio/dac/Kconfig
@@ -11,11 +11,22 @@ config AD5624R_SPI
AD5664R convertors (DAC). This driver uses the common SPI interface.
config AD5446
- tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5541A/12A DAC SPI driver"
+ tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5444, AD5446,
- AD5620, AD5640, AD5660 and AD5541A, AD5512A DACs.
+ AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621,
+ AD5640, AD5660 DACs.
To compile this driver as a module, choose M here: the
module will be called ad5446.
+
+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.
diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile
index 7cf331b..1197aef 100644
--- a/drivers/staging/iio/dac/Makefile
+++ b/drivers/staging/iio/dac/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
obj-$(CONFIG_AD5446) += ad5446.o
+obj-$(CONFIG_MAX517) += max517.o
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
index 0f87eca..8623a72 100644
--- a/drivers/staging/iio/dac/ad5446.c
+++ b/drivers/staging/iio/dac/ad5446.c
@@ -48,6 +48,20 @@ static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
st->data.d24[2] = val & 0xFF;
}
+static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode)
+{
+ st->data.d16 = cpu_to_be16(mode << 14);
+}
+
+static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode)
+{
+ unsigned val = mode << 16;
+
+ st->data.d24[0] = (val >> 16) & 0xFF;
+ st->data.d24[1] = (val >> 8) & 0xFF;
+ st->data.d24[2] = val & 0xFF;
+}
+
static ssize_t ad5446_write(struct device *dev,
struct device_attribute *attr,
const char *buf,
@@ -68,6 +82,7 @@ static ssize_t ad5446_write(struct device *dev,
}
mutex_lock(&dev_info->mlock);
+ st->cached_val = val;
st->chip_info->store_sample(st, val);
ret = spi_sync(st->spi, &st->msg);
mutex_unlock(&dev_info->mlock);
@@ -102,15 +117,119 @@ static ssize_t ad5446_show_name(struct device *dev,
}
static IIO_DEVICE_ATTR(name, S_IRUGO, ad5446_show_name, NULL, 0);
+static ssize_t ad5446_write_powerdown_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+
+ if (sysfs_streq(buf, "1kohm_to_gnd"))
+ st->pwr_down_mode = MODE_PWRDWN_1k;
+ else if (sysfs_streq(buf, "100kohm_to_gnd"))
+ st->pwr_down_mode = MODE_PWRDWN_100k;
+ else if (sysfs_streq(buf, "three_state"))
+ st->pwr_down_mode = MODE_PWRDWN_TRISTATE;
+ else
+ return -EINVAL;
+
+ return len;
+}
+
+static ssize_t ad5446_read_powerdown_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+
+ char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
+
+ return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
+}
+
+static ssize_t ad5446_read_dac_powerdown(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+
+ return sprintf(buf, "%d\n", st->pwr_down);
+}
+
+static ssize_t ad5446_write_dac_powerdown(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = dev_info->dev_data;
+ unsigned long readin;
+ int ret;
+
+ ret = strict_strtol(buf, 10, &readin);
+ if (ret)
+ return ret;
+
+ if (readin > 1)
+ ret = -EINVAL;
+
+ mutex_lock(&dev_info->mlock);
+ st->pwr_down = readin;
+
+ if (st->pwr_down)
+ st->chip_info->store_pwr_down(st, st->pwr_down_mode);
+ else
+ st->chip_info->store_sample(st, st->cached_val);
+
+ ret = spi_sync(st->spi, &st->msg);
+ mutex_unlock(&dev_info->mlock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | S_IWUSR,
+ ad5446_read_powerdown_mode,
+ ad5446_write_powerdown_mode, 0);
+
+static IIO_CONST_ATTR(out_powerdown_mode_available,
+ "1kohm_to_gnd 100kohm_to_gnd three_state");
+
+static IIO_DEVICE_ATTR(out0_powerdown, S_IRUGO | S_IWUSR,
+ ad5446_read_dac_powerdown,
+ ad5446_write_dac_powerdown, 0);
+
static struct attribute *ad5446_attributes[] = {
&iio_dev_attr_out0_raw.dev_attr.attr,
&iio_dev_attr_out_scale.dev_attr.attr,
+ &iio_dev_attr_out0_powerdown.dev_attr.attr,
+ &iio_dev_attr_out_powerdown_mode.dev_attr.attr,
+ &iio_const_attr_out_powerdown_mode_available.dev_attr.attr,
&iio_dev_attr_name.dev_attr.attr,
NULL,
};
+static mode_t ad5446_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct ad5446_state *st = iio_dev_get_devdata(dev_info);
+
+ mode_t mode = attr->mode;
+
+ if (!st->chip_info->store_pwr_down &&
+ (attr == &iio_dev_attr_out0_powerdown.dev_attr.attr ||
+ attr == &iio_dev_attr_out_powerdown_mode.dev_attr.attr ||
+ attr ==
+ &iio_const_attr_out_powerdown_mode_available.dev_attr.attr))
+ mode = 0;
+
+ return mode;
+}
+
static const struct attribute_group ad5446_attribute_group = {
.attrs = ad5446_attributes,
+ .is_visible = ad5446_attr_is_visible,
};
static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
@@ -132,18 +251,52 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.store_sample = ad5542_store_sample,
},
+ [ID_AD5543] = {
+ .bits = 16,
+ .storagebits = 16,
+ .left_shift = 0,
+ .store_sample = ad5542_store_sample,
+ },
[ID_AD5512A] = {
.bits = 12,
.storagebits = 16,
.left_shift = 4,
.store_sample = ad5542_store_sample,
},
+ [ID_AD5553] = {
+ .bits = 14,
+ .storagebits = 16,
+ .left_shift = 0,
+ .store_sample = ad5542_store_sample,
+ },
+ [ID_AD5601] = {
+ .bits = 8,
+ .storagebits = 16,
+ .left_shift = 6,
+ .store_sample = ad5542_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
+ },
+ [ID_AD5611] = {
+ .bits = 10,
+ .storagebits = 16,
+ .left_shift = 4,
+ .store_sample = ad5542_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
+ },
+ [ID_AD5621] = {
+ .bits = 12,
+ .storagebits = 16,
+ .left_shift = 2,
+ .store_sample = ad5542_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
+ },
[ID_AD5620_2500] = {
.bits = 12,
.storagebits = 16,
.left_shift = 2,
.int_vref_mv = 2500,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5620_1250] = {
.bits = 12,
@@ -151,6 +304,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 2,
.int_vref_mv = 1250,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5640_2500] = {
.bits = 14,
@@ -158,6 +312,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 2500,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5640_1250] = {
.bits = 14,
@@ -165,6 +320,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 1250,
.store_sample = ad5620_store_sample,
+ .store_pwr_down = ad5620_store_pwr_down,
},
[ID_AD5660_2500] = {
.bits = 16,
@@ -172,6 +328,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 2500,
.store_sample = ad5660_store_sample,
+ .store_pwr_down = ad5660_store_pwr_down,
},
[ID_AD5660_1250] = {
.bits = 16,
@@ -179,6 +336,7 @@ static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
.left_shift = 0,
.int_vref_mv = 1250,
.store_sample = ad5660_store_sample,
+ .store_pwr_down = ad5660_store_pwr_down,
},
};
@@ -231,20 +389,20 @@ static int __devinit ad5446_probe(struct spi_device *spi)
spi_message_add_tail(&st->xfer, &st->msg);
switch (spi_get_device_id(spi)->driver_data) {
- case ID_AD5620_2500:
- case ID_AD5620_1250:
- case ID_AD5640_2500:
- case ID_AD5640_1250:
- case ID_AD5660_2500:
- case ID_AD5660_1250:
- st->vref_mv = st->chip_info->int_vref_mv;
- break;
- default:
- if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else
- dev_warn(&spi->dev,
- "reference voltage unspecified\n");
+ case ID_AD5620_2500:
+ case ID_AD5620_1250:
+ case ID_AD5640_2500:
+ case ID_AD5640_1250:
+ case ID_AD5660_2500:
+ case ID_AD5660_1250:
+ st->vref_mv = st->chip_info->int_vref_mv;
+ break;
+ default:
+ if (voltage_uv)
+ st->vref_mv = voltage_uv / 1000;
+ else
+ dev_warn(&spi->dev,
+ "reference voltage unspecified\n");
}
ret = iio_device_register(st->indio_dev);
@@ -283,8 +441,13 @@ static int ad5446_remove(struct spi_device *spi)
static const struct spi_device_id ad5446_id[] = {
{"ad5444", ID_AD5444},
{"ad5446", ID_AD5446},
- {"ad5542a", ID_AD5542A},
{"ad5512a", ID_AD5512A},
+ {"ad5542a", ID_AD5542A},
+ {"ad5543", ID_AD5543},
+ {"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},
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h
index 902542e..7ac63ab8a 100644
--- a/drivers/staging/iio/dac/ad5446.h
+++ b/drivers/staging/iio/dac/ad5446.h
@@ -27,6 +27,10 @@
#define RES_MASK(bits) ((1 << (bits)) - 1)
+#define MODE_PWRDWN_1k 0x1
+#define MODE_PWRDWN_100k 0x2
+#define MODE_PWRDWN_TRISTATE 0x3
+
/**
* struct ad5446_state - driver instance specific data
* @indio_dev: the industrial I/O device
@@ -47,6 +51,9 @@ struct ad5446_state {
struct regulator *reg;
struct work_struct poll_work;
unsigned short vref_mv;
+ unsigned cached_val;
+ unsigned pwr_down_mode;
+ unsigned pwr_down;
struct spi_transfer xfer;
struct spi_message msg;
union {
@@ -62,14 +69,16 @@ struct ad5446_state {
* @left_shift: number of bits the datum must be shifted
* @int_vref_mv: AD5620/40/60: the internal reference voltage
* @store_sample: chip specific helper function to store the datum
+ * @store_sample: chip specific helper function to store the powerpown cmd
*/
struct ad5446_chip_info {
- u8 bits;
- u8 storagebits;
- u8 left_shift;
- u16 int_vref_mv;
- void (*store_sample) (struct ad5446_state *st, unsigned val);
+ u8 bits;
+ u8 storagebits;
+ u8 left_shift;
+ u16 int_vref_mv;
+ void (*store_sample) (struct ad5446_state *st, unsigned val);
+ void (*store_pwr_down) (struct ad5446_state *st, unsigned mode);
};
/**
@@ -84,7 +93,12 @@ enum ad5446_supported_device_ids {
ID_AD5444,
ID_AD5446,
ID_AD5542A,
+ ID_AD5543,
ID_AD5512A,
+ ID_AD5553,
+ ID_AD5601,
+ ID_AD5611,
+ ID_AD5621,
ID_AD5620_2500,
ID_AD5620_1250,
ID_AD5640_2500,
diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h
index ce518be..c16df4e 100644
--- a/drivers/staging/iio/dac/ad5624r.h
+++ b/drivers/staging/iio/dac/ad5624r.h
@@ -1,21 +1,80 @@
+/*
+ * 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_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_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_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
-#endif
+#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
+ * @bits: accuracy of the DAC in bits
+ * @int_vref_mv: AD5620/40/60: the internal reference voltage
+ */
+
+struct ad5624r_chip_info {
+ u8 bits;
+ 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 iio_dev *indio_dev;
+ 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/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
index 2b1c6dd..a945b18 100644
--- a/drivers/staging/iio/dac/ad5624r_spi.c
+++ b/drivers/staging/iio/dac/ad5624r_spi.c
@@ -1,9 +1,9 @@
/*
* AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
*
- * Copyright 2010 Analog Devices Inc.
+ * Copyright 2010-2011 Analog Devices Inc.
*
- * Licensed under the GPL-2 or later.
+ * Licensed under the GPL-2.
*/
#include <linux/interrupt.h>
@@ -14,25 +14,38 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
#include "../iio.h"
#include "../sysfs.h"
#include "dac.h"
#include "ad5624r.h"
-/**
- * struct ad5624r_state - device related storage
- * @indio_dev: associated industrial IO device
- * @us: spi device
- **/
-struct ad5624r_state {
- struct iio_dev *indio_dev;
- struct spi_device *us;
- int data_len;
- int ldac_mode;
- int dac_power_mode[AD5624R_DAC_CHANNELS];
- int internal_ref;
+static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = {
+ [ID_AD5624R3] = {
+ .bits = 12,
+ .int_vref_mv = 1250,
+ },
+ [ID_AD5644R3] = {
+ .bits = 14,
+ .int_vref_mv = 1250,
+ },
+ [ID_AD5664R3] = {
+ .bits = 16,
+ .int_vref_mv = 1250,
+ },
+ [ID_AD5624R5] = {
+ .bits = 12,
+ .int_vref_mv = 2500,
+ },
+ [ID_AD5644R5] = {
+ .bits = 14,
+ .int_vref_mv = 2500,
+ },
+ [ID_AD5664R5] = {
+ .bits = 16,
+ .int_vref_mv = 2500,
+ },
};
static int ad5624r_spi_write(struct spi_device *spi,
@@ -42,11 +55,12 @@ static int ad5624r_spi_write(struct spi_device *spi,
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.
+ * 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;
@@ -63,7 +77,7 @@ static ssize_t ad5624r_write_dac(struct device *dev,
long readin;
int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = strict_strtol(buf, 10, &readin);
@@ -71,138 +85,144 @@ static ssize_t ad5624r_write_dac(struct device *dev,
return ret;
ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
- this_attr->address, readin, st->data_len);
+ this_attr->address, readin,
+ st->chip_info->bits);
return ret ? ret : len;
}
-static ssize_t ad5624r_read_ldac_mode(struct device *dev,
+static ssize_t ad5624r_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
- return sprintf(buf, "%x\n", st->ldac_mode);
+ char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
+
+ return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
}
-static ssize_t ad5624r_write_ldac_mode(struct device *dev,
+static ssize_t ad5624r_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- long readin;
- int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
-
- ret = strict_strtol(buf, 16, &readin);
- if (ret)
- return ret;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
+ int ret;
- ret = ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0,
- readin & 0xF, 16);
- st->ldac_mode = readin & 0xF;
+ if (sysfs_streq(buf, "1kohm_to_gnd"))
+ st->pwr_down_mode = AD5624R_LDAC_PWRDN_1K;
+ else if (sysfs_streq(buf, "100kohm_to_gnd"))
+ st->pwr_down_mode = AD5624R_LDAC_PWRDN_100K;
+ else if (sysfs_streq(buf, "three_state"))
+ st->pwr_down_mode = AD5624R_LDAC_PWRDN_3STATE;
+ else
+ ret = -EINVAL;
return ret ? ret : len;
}
-static ssize_t ad5624r_read_dac_power_mode(struct device *dev,
+static ssize_t ad5624r_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- return sprintf(buf, "%d\n", st->dac_power_mode[this_attr->address]);
+ return sprintf(buf, "%d\n",
+ !!(st->pwr_down_mask & (1 << this_attr->address)));
}
-static ssize_t ad5624r_write_dac_power_mode(struct device *dev,
+static ssize_t ad5624r_write_dac_powerdown(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
long readin;
int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
ret = strict_strtol(buf, 10, &readin);
if (ret)
return ret;
- ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
- ((readin & 0x3) << 4) |
- (1 << this_attr->address), 16);
+ if (readin == 1)
+ st->pwr_down_mask |= (1 << this_attr->address);
+ else if (!readin)
+ st->pwr_down_mask &= ~(1 << this_attr->address);
+ else
+ ret = -EINVAL;
- st->dac_power_mode[this_attr->address] = readin & 0x3;
+ 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 ssize_t ad5624r_read_internal_ref_mode(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t ad5624r_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits;
- return sprintf(buf, "%d\n", st->internal_ref);
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
}
+static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5624r_show_scale, NULL, 0);
-static ssize_t ad5624r_write_internal_ref_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t ad5624r_show_name(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- long readin;
- int ret;
struct iio_dev *indio_dev = dev_get_drvdata(dev);
- struct ad5624r_state *st = indio_dev->dev_data;
-
- ret = strict_strtol(buf, 10, &readin);
- if (ret)
- return ret;
+ struct ad5624r_state *st = iio_dev_get_devdata(indio_dev);
- ret = ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
- !!readin, 16);
-
- st->internal_ref = !!readin;
-
- return ret ? ret : len;
+ return sprintf(buf, "%s\n", spi_get_device_id(st->us)->name);
}
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad5624r_show_name, NULL, 0);
static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0);
static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1);
static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2);
static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3);
-static IIO_DEVICE_ATTR(ldac_mode, S_IRUGO | S_IWUSR, ad5624r_read_ldac_mode,
- ad5624r_write_ldac_mode, 0);
-static IIO_DEVICE_ATTR(internal_ref, S_IRUGO | S_IWUSR,
- ad5624r_read_internal_ref_mode,
- ad5624r_write_internal_ref_mode, 0);
+static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO |
+ S_IWUSR, ad5624r_read_powerdown_mode,
+ ad5624r_write_powerdown_mode, 0);
+
+static IIO_CONST_ATTR(out_powerdown_mode_available,
+ "1kohm_to_gnd 100kohm_to_gnd three_state");
-#define IIO_DEV_ATTR_DAC_POWER_MODE(_num, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dac_power_mode_##_num, S_IRUGO | S_IWUSR, _show, _store, _addr)
+#define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out##_num##_powerdown, \
+ S_IRUGO | S_IWUSR, _show, _store, _addr)
-static IIO_DEV_ATTR_DAC_POWER_MODE(0, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 0);
-static IIO_DEV_ATTR_DAC_POWER_MODE(1, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 1);
-static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 2);
-static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode,
- ad5624r_write_dac_power_mode, 3);
+static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 0);
+static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 1);
+static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 2);
+static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5624r_read_dac_powerdown,
+ ad5624r_write_dac_powerdown, 3);
static struct attribute *ad5624r_attributes[] = {
&iio_dev_attr_out0_raw.dev_attr.attr,
&iio_dev_attr_out1_raw.dev_attr.attr,
&iio_dev_attr_out2_raw.dev_attr.attr,
&iio_dev_attr_out3_raw.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_0.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_1.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_2.dev_attr.attr,
- &iio_dev_attr_dac_power_mode_3.dev_attr.attr,
- &iio_dev_attr_ldac_mode.dev_attr.attr,
- &iio_dev_attr_internal_ref.dev_attr.attr,
+ &iio_dev_attr_out0_powerdown.dev_attr.attr,
+ &iio_dev_attr_out1_powerdown.dev_attr.attr,
+ &iio_dev_attr_out2_powerdown.dev_attr.attr,
+ &iio_dev_attr_out3_powerdown.dev_attr.attr,
+ &iio_dev_attr_out_powerdown_mode.dev_attr.attr,
+ &iio_const_attr_out_powerdown_mode_available.dev_attr.attr,
+ &iio_dev_attr_out_scale.dev_attr.attr,
+ &iio_dev_attr_name.dev_attr.attr,
NULL,
};
@@ -213,7 +233,7 @@ static const struct attribute_group ad5624r_attribute_group = {
static int __devinit ad5624r_probe(struct spi_device *spi)
{
struct ad5624r_state *st;
- int ret = 0;
+ int ret, voltage_uv = 0;
st = kzalloc(sizeof(*st), GFP_KERNEL);
if (st == NULL) {
@@ -222,18 +242,30 @@ static int __devinit ad5624r_probe(struct spi_device *spi)
}
spi_set_drvdata(spi, st);
- st->data_len = spi_get_device_id(spi)->driver_data;
+ 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 =
+ &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;
st->indio_dev = iio_allocate_device();
if (st->indio_dev == NULL) {
ret = -ENOMEM;
- goto error_free_st;
+ goto error_disable_reg;
}
st->indio_dev->dev.parent = &spi->dev;
- st->indio_dev->num_interrupt_lines = 0;
- st->indio_dev->event_attrs = NULL;
-
st->indio_dev->attrs = &ad5624r_attribute_group;
st->indio_dev->dev_data = (void *)(st);
st->indio_dev->driver_module = THIS_MODULE;
@@ -243,14 +275,22 @@ static int __devinit ad5624r_probe(struct spi_device *spi)
if (ret)
goto error_free_dev;
- spi->mode = SPI_MODE_0;
- spi_setup(spi);
+ ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0,
+ !!voltage_uv, 16);
+ if (ret)
+ goto error_free_dev;
return 0;
error_free_dev:
iio_free_device(st->indio_dev);
-error_free_st:
+error_disable_reg:
+ if (!IS_ERR(st->reg))
+ regulator_disable(st->reg);
+error_put_reg:
+ if (!IS_ERR(st->reg))
+ regulator_put(st->reg);
+
kfree(st);
error_ret:
return ret;
@@ -261,15 +301,24 @@ static int __devexit ad5624r_remove(struct spi_device *spi)
struct ad5624r_state *st = spi_get_drvdata(spi);
iio_device_unregister(st->indio_dev);
+
+ if (!IS_ERR(st->reg)) {
+ regulator_disable(st->reg);
+ regulator_put(st->reg);
+ }
+
kfree(st);
return 0;
}
static const struct spi_device_id ad5624r_id[] = {
- {"ad5624r", 12},
- {"ad5644r", 14},
- {"ad5664r", 16},
+ {"ad5624r3", ID_AD5624R3},
+ {"ad5644r3", ID_AD5644R3},
+ {"ad5664r3", ID_AD5664R3},
+ {"ad5624r5", ID_AD5624R5},
+ {"ad5644r5", ID_AD5644R5},
+ {"ad5664r5", ID_AD5664R5},
{}
};
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c
new file mode 100644
index 0000000..7071f713
--- /dev/null
+++ b/drivers/staging/iio/dac/max517.c
@@ -0,0 +1,298 @@
+/*
+ * 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 "../iio.h"
+#include "dac.h"
+
+#include "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 ssize_t max517_set_value(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count, int channel)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max517_data *data = iio_dev_get_devdata(dev_info);
+ struct i2c_client *client = data->client;
+ u8 outbuf[4]; /* 1x or 2x command + value */
+ int outbuf_size = 0;
+ int res;
+ long val;
+
+ res = strict_strtol(buf, 10, &val);
+
+ if (res)
+ return res;
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ if (channel & 1) {
+ outbuf[outbuf_size++] = COMMAND_CHANNEL0;
+ outbuf[outbuf_size++] = val;
+ }
+ if (channel & 2) {
+ outbuf[outbuf_size++] = COMMAND_CHANNEL1;
+ outbuf[outbuf_size++] = val;
+ }
+
+ /*
+ * At this point, there are always 1 or 2 two-byte commands in
+ * outbuf. With 2 commands, the device can set two outputs
+ * simultaneously, latching the values upon the end of the I2C
+ * transfer.
+ */
+
+ res = i2c_master_send(client, outbuf, outbuf_size);
+ if (res < 0)
+ return res;
+
+ return count;
+}
+
+static ssize_t max517_set_value_1(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return max517_set_value(dev, attr, buf, count, 1);
+}
+static IIO_DEV_ATTR_OUT_RAW(1, max517_set_value_1, 0);
+
+static ssize_t max517_set_value_2(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return max517_set_value(dev, attr, buf, count, 2);
+}
+static IIO_DEV_ATTR_OUT_RAW(2, max517_set_value_2, 1);
+
+static ssize_t max517_set_value_both(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return max517_set_value(dev, attr, buf, count, 3);
+}
+static IIO_DEVICE_ATTR_NAMED(out1and2_raw, out1&2_raw, S_IWUSR, NULL,
+ max517_set_value_both, -1);
+
+static ssize_t max517_show_scale(struct device *dev,
+ struct device_attribute *attr,
+ char *buf, int channel)
+{
+ struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct max517_data *data = iio_dev_get_devdata(dev_info);
+ /* Corresponds to Vref / 2^(bits) */
+ unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8;
+
+ return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000);
+}
+
+static ssize_t max517_show_scale1(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return max517_show_scale(dev, attr, buf, 1);
+}
+static IIO_DEVICE_ATTR(out1_scale, S_IRUGO, max517_show_scale1, NULL, 0);
+
+static ssize_t max517_show_scale2(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return max517_show_scale(dev, attr, buf, 2);
+}
+static IIO_DEVICE_ATTR(out2_scale, S_IRUGO, max517_show_scale2, NULL, 0);
+
+/* On MAX517 variant, we have one output */
+static struct attribute *max517_attributes[] = {
+ &iio_dev_attr_out1_raw.dev_attr.attr,
+ &iio_dev_attr_out1_scale.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group max517_attribute_group = {
+ .attrs = max517_attributes,
+};
+
+/* On MAX518 and MAX519 variant, we have two outputs */
+static struct attribute *max518_attributes[] = {
+ &iio_dev_attr_out1_raw.dev_attr.attr,
+ &iio_dev_attr_out1_scale.dev_attr.attr,
+ &iio_dev_attr_out2_raw.dev_attr.attr,
+ &iio_dev_attr_out2_scale.dev_attr.attr,
+ &iio_dev_attr_out1and2_raw.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group max518_attribute_group = {
+ .attrs = max518_attributes,
+};
+
+static int max517_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ u8 outbuf = COMMAND_PD;
+
+ return i2c_master_send(client, &outbuf, 1);
+}
+
+static int max517_resume(struct i2c_client *client)
+{
+ u8 outbuf = 0;
+
+ return i2c_master_send(client, &outbuf, 1);
+}
+
+static int max517_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max517_data *data;
+ struct max517_platform_data *platform_data = client->dev.platform_data;
+ int err;
+
+ data = kzalloc(sizeof(struct max517_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+
+ data->client = client;
+
+ data->indio_dev = iio_allocate_device();
+ if (data->indio_dev == NULL) {
+ err = -ENOMEM;
+ goto exit_free_data;
+ }
+
+ /* establish that the iio_dev is a child of the i2c device */
+ data->indio_dev->dev.parent = &client->dev;
+
+ /* reduced attribute set for MAX517 */
+ if (id->driver_data == ID_MAX517)
+ data->indio_dev->attrs = &max517_attribute_group;
+ else
+ data->indio_dev->attrs = &max518_attribute_group;
+ data->indio_dev->dev_data = (void *)(data);
+ data->indio_dev->driver_module = THIS_MODULE;
+ data->indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /*
+ * 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(data->indio_dev);
+ if (err)
+ goto exit_free_device;
+
+ dev_info(&client->dev, "DAC registered\n");
+
+ return 0;
+
+exit_free_device:
+ iio_free_device(data->indio_dev);
+exit_free_data:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int max517_remove(struct i2c_client *client)
+{
+ struct max517_data *data = i2c_get_clientdata(client);
+
+ iio_free_device(data->indio_dev);
+ kfree(data);
+
+ 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,
+ },
+ .probe = max517_probe,
+ .remove = max517_remove,
+ .suspend = max517_suspend,
+ .resume = max517_resume,
+ .id_table = max517_id,
+};
+
+static int __init max517_init(void)
+{
+ return i2c_add_driver(&max517_driver);
+}
+
+static void __exit max517_exit(void)
+{
+ i2c_del_driver(&max517_driver);
+}
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC");
+MODULE_LICENSE("GPL");
+
+module_init(max517_init);
+module_exit(max517_exit);
diff --git a/drivers/staging/iio/dac/max517.h b/drivers/staging/iio/dac/max517.h
new file mode 100644
index 0000000..8106cf2
--- /dev/null
+++ b/drivers/staging/iio/dac/max517.h
@@ -0,0 +1,19 @@
+/*
+ * MAX517 DAC driver
+ *
+ * Copyright 2011 Roland Stigge <stigge@antcom.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#ifndef IIO_DAC_MAX517_H_
+#define IIO_DAC_MAX517_H_
+
+/*
+ * TODO: struct max517_platform_data needs to go into include/linux/iio
+ */
+
+struct max517_platform_data {
+ u16 vref_mv[2];
+};
+
+#endif /* IIO_DAC_MAX517_H_ */