summaryrefslogtreecommitdiff
path: root/drivers/staging/iio/dac/ad5446.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/iio/dac/ad5446.c')
-rw-r--r--drivers/staging/iio/dac/ad5446.c193
1 files changed, 178 insertions, 15 deletions
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
index 0f87ecac82fc..8623a72e046c 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},