From dbdc025bb239ce62c9b4d28c459a98f22ce9ec0a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 4 Jun 2012 11:36:28 +0200 Subject: 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 Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 64c88e5..103349f 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 bd801c0..c38fa2a 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 0000000..a626f03 --- /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 0000000..8ab1d26 --- /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 0000000..276af02 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 0000000..8fce84f --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 0000000..5dfb445 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 0000000..cdbc5bf --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#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 "); +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 0000000..49f557f --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 0000000..dfd68ce --- /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 0000000..242bdc7 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 "); +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 0000000..5dca302 --- /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 0000000..6a7d6a4 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 0000000..6948d75 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 0000000..ffce304 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "); +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 0000000..2bd2e37 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 "); +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 0000000..92c77c8 --- /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 + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 3c8e5ec..04cd6ec 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -29,7 +29,6 @@ source "drivers/staging/iio/accel/Kconfig" source "drivers/staging/iio/adc/Kconfig" source "drivers/staging/iio/addac/Kconfig" source "drivers/staging/iio/cdc/Kconfig" -source "drivers/staging/iio/dac/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index 6a46d5a..fa6937d 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -17,7 +17,6 @@ obj-y += accel/ obj-y += adc/ obj-y += addac/ obj-y += cdc/ -obj-y += dac/ obj-y += frequency/ obj-y += gyro/ obj-y += impedance-analyzer/ diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig deleted file mode 100644 index a626f03..0000000 --- a/drivers/staging/iio/dac/Kconfig +++ /dev/null @@ -1,121 +0,0 @@ -# -# 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/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile deleted file mode 100644 index 8ab1d26..0000000 --- a/drivers/staging/iio/dac/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# 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/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c deleted file mode 100644 index 276af02..0000000 --- a/drivers/staging/iio/dac/ad5064.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 "); -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/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c deleted file mode 100644 index 8fce84f..0000000 --- a/drivers/staging/iio/dac/ad5360.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 "); -MODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5380.c b/drivers/staging/iio/dac/ad5380.c deleted file mode 100644 index 5dfb445..0000000 --- a/drivers/staging/iio/dac/ad5380.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 "); -MODULE_DESCRIPTION("Analog Devices AD5380/81/82/83/84/90/91/92 DAC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c deleted file mode 100644 index ea2f83b..0000000 --- a/drivers/staging/iio/dac/ad5421.c +++ /dev/null @@ -1,544 +0,0 @@ -/* - * AD5421 Digital to analog converters driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include "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 "); -MODULE_DESCRIPTION("Analog Devices AD5421 DAC"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:ad5421"); diff --git a/drivers/staging/iio/dac/ad5421.h b/drivers/staging/iio/dac/ad5421.h deleted file mode 100644 index cd2bb84..0000000 --- a/drivers/staging/iio/dac/ad5421.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __IIO_DAC_AD5421_H__ -#define __IIO_DAC_AD5421_H__ - -/* - * TODO: This file needs to go into include/linux/iio - */ - -/** - * enum ad5421_current_range - Current range the AD5421 is configured for. - * @AD5421_CURRENT_RANGE_4mA_20mA: 4 mA to 20 mA (RANGE1,0 pins = 00) - * @AD5421_CURRENT_RANGE_3mA8_21mA: 3.8 mA to 21 mA (RANGE1,0 pins = x1) - * @AD5421_CURRENT_RANGE_3mA2_24mA: 3.2 mA to 24 mA (RANGE1,0 pins = 10) - */ - -enum ad5421_current_range { - AD5421_CURRENT_RANGE_4mA_20mA, - AD5421_CURRENT_RANGE_3mA8_21mA, - AD5421_CURRENT_RANGE_3mA2_24mA, -}; - -/** - * struct ad5421_platform_data - AD5421 DAC driver platform data - * @external_vref: whether an external reference voltage is used or not - * @current_range: Current range the AD5421 is configured for - */ - -struct ad5421_platform_data { - bool external_vref; - enum ad5421_current_range current_range; -}; - -#endif diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c deleted file mode 100644 index 49f557f..0000000 --- a/drivers/staging/iio/dac/ad5446.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * AD5446 SPI DAC driver - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 "); -MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h deleted file mode 100644 index dfd68ce..0000000 --- a/drivers/staging/iio/dac/ad5446.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c deleted file mode 100644 index 1289e9b..0000000 --- a/drivers/staging/iio/dac/ad5504.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * AD5504, AD5501 High Voltage Digital to Analog Converter - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "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 "); -MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5504.h b/drivers/staging/iio/dac/ad5504.h deleted file mode 100644 index d4980bf..0000000 --- a/drivers/staging/iio/dac/ad5504.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * AD5504 SPI DAC driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#ifndef SPI_AD5504_H_ -#define SPI_AD5504_H_ - -/* - * TODO: struct ad5504_platform_data needs to go into include/linux/iio - */ - -struct ad5504_platform_data { - u16 vref_mv; -}; - -#endif /* SPI_AD5504_H_ */ diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h deleted file mode 100644 index 5dca302..0000000 --- a/drivers/staging/iio/dac/ad5624r.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c deleted file mode 100644 index 6a7d6a4..0000000 --- a/drivers/staging/iio/dac/ad5624r_spi.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver - * - * Copyright 2010-2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c deleted file mode 100644 index 6948d75..0000000 --- a/drivers/staging/iio/dac/ad5686.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * AD5686R, AD5685R, AD5684R Digital to analog converters driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 "); -MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5764.c b/drivers/staging/iio/dac/ad5764.c deleted file mode 100644 index ffce304..0000000 --- a/drivers/staging/iio/dac/ad5764.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Analog devices AD5764, AD5764R, AD5744, AD5744R quad-channel - * Digital to Analog Converters driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#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 "); -MODULE_DESCRIPTION("Analog Devices AD5744/AD5744R/AD5764/AD5764R DAC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c deleted file mode 100644 index 5de28c2..0000000 --- a/drivers/staging/iio/dac/ad5791.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * AD5760, AD5780, AD5781, AD5790, AD5791 Voltage Output Digital to Analog - * Converter - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "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 "); -MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5791.h b/drivers/staging/iio/dac/ad5791.h deleted file mode 100644 index 87a6c92..0000000 --- a/drivers/staging/iio/dac/ad5791.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * AD5791 SPI DAC driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#ifndef SPI_AD5791_H_ -#define SPI_AD5791_H_ - -/* - * TODO: struct ad5791_platform_data needs to go into include/linux/iio - */ - -/** - * struct ad5791_platform_data - platform specific information - * @vref_pos_mv: Vdd Positive Analog Supply Volatge (mV) - * @vref_neg_mv: Vdd Negative Analog Supply Volatge (mV) - * @use_rbuf_gain2: ext. amplifier connected in gain of two configuration - */ - -struct ad5791_platform_data { - u16 vref_pos_mv; - u16 vref_neg_mv; - bool use_rbuf_gain2; -}; - -#endif /* SPI_AD5791_H_ */ diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c deleted file mode 100644 index 403e06f..0000000 --- a/drivers/staging/iio/dac/max517.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * max517.c - Support for Maxim MAX517, MAX518 and MAX519 - * - * Copyright (C) 2010, 2011 Roland Stigge - * - * 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 -#include -#include -#include -#include -#include - -#include -#include - -#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 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 "); -MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/dac/max517.h b/drivers/staging/iio/dac/max517.h deleted file mode 100644 index 8106cf2..0000000 --- a/drivers/staging/iio/dac/max517.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * MAX517 DAC driver - * - * Copyright 2011 Roland Stigge - * - * 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_ */ diff --git a/include/linux/iio/dac/ad5421.h b/include/linux/iio/dac/ad5421.h new file mode 100644 index 0000000..8fd8f05 --- /dev/null +++ b/include/linux/iio/dac/ad5421.h @@ -0,0 +1,28 @@ +#ifndef __IIO_DAC_AD5421_H__ +#define __IIO_DAC_AD5421_H__ + +/** + * enum ad5421_current_range - Current range the AD5421 is configured for. + * @AD5421_CURRENT_RANGE_4mA_20mA: 4 mA to 20 mA (RANGE1,0 pins = 00) + * @AD5421_CURRENT_RANGE_3mA8_21mA: 3.8 mA to 21 mA (RANGE1,0 pins = x1) + * @AD5421_CURRENT_RANGE_3mA2_24mA: 3.2 mA to 24 mA (RANGE1,0 pins = 10) + */ + +enum ad5421_current_range { + AD5421_CURRENT_RANGE_4mA_20mA, + AD5421_CURRENT_RANGE_3mA8_21mA, + AD5421_CURRENT_RANGE_3mA2_24mA, +}; + +/** + * struct ad5421_platform_data - AD5421 DAC driver platform data + * @external_vref: whether an external reference voltage is used or not + * @current_range: Current range the AD5421 is configured for + */ + +struct ad5421_platform_data { + bool external_vref; + enum ad5421_current_range current_range; +}; + +#endif diff --git a/include/linux/iio/dac/ad5504.h b/include/linux/iio/dac/ad5504.h new file mode 100644 index 0000000..4389537 --- /dev/null +++ b/include/linux/iio/dac/ad5504.h @@ -0,0 +1,16 @@ +/* + * AD5504 SPI DAC driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef SPI_AD5504_H_ +#define SPI_AD5504_H_ + +struct ad5504_platform_data { + u16 vref_mv; +}; + +#endif /* SPI_AD5504_H_ */ diff --git a/include/linux/iio/dac/ad5791.h b/include/linux/iio/dac/ad5791.h new file mode 100644 index 0000000..45ee281 --- /dev/null +++ b/include/linux/iio/dac/ad5791.h @@ -0,0 +1,25 @@ +/* + * AD5791 SPI DAC driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef SPI_AD5791_H_ +#define SPI_AD5791_H_ + +/** + * struct ad5791_platform_data - platform specific information + * @vref_pos_mv: Vdd Positive Analog Supply Volatge (mV) + * @vref_neg_mv: Vdd Negative Analog Supply Volatge (mV) + * @use_rbuf_gain2: ext. amplifier connected in gain of two configuration + */ + +struct ad5791_platform_data { + u16 vref_pos_mv; + u16 vref_neg_mv; + bool use_rbuf_gain2; +}; + +#endif /* SPI_AD5791_H_ */ diff --git a/include/linux/iio/dac/max517.h b/include/linux/iio/dac/max517.h new file mode 100644 index 0000000..f6d1d25 --- /dev/null +++ b/include/linux/iio/dac/max517.h @@ -0,0 +1,15 @@ +/* + * MAX517 DAC driver + * + * Copyright 2011 Roland Stigge + * + * Licensed under the GPL-2 or later. + */ +#ifndef IIO_DAC_MAX517_H_ +#define IIO_DAC_MAX517_H_ + +struct max517_platform_data { + u16 vref_mv[2]; +}; + +#endif /* IIO_DAC_MAX517_H_ */ -- cgit v0.10.2