diff options
Diffstat (limited to 'drivers/staging/iio/dac/ad5446.c')
-rw-r--r-- | drivers/staging/iio/dac/ad5446.c | 193 |
1 files changed, 178 insertions, 15 deletions
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c index 0f87ecac82f..8623a72e046 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}, |