diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 15:39:02 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 15:39:02 +0200 |
commit | aa77677e0a288e08073620db5d2a31df83ca4788 (patch) | |
tree | 0d14b995a21c43f365d66b9ad101a334109fc4e4 /drivers/staging/iio/dac | |
parent | efb8d21b2c6db3497655cc6a033ae8a9883e4063 (diff) | |
parent | 43a3beb6da994549ec28a9f31727b997a025f958 (diff) | |
download | op-kernel-dev-aa77677e0a288e08073620db5d2a31df83ca4788.zip op-kernel-dev-aa77677e0a288e08073620db5d2a31df83ca4788.tar.gz |
Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
* 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1519 commits)
staging: et131x: Remove redundant check and return statement
staging: et131x: Mainly whitespace changes to appease checkpatch
staging: et131x: Remove last of the forward declarations
staging: et131x: Remove even more forward declarations
staging: et131x: Remove yet more forward declarations
staging: et131x: Remove more forward declarations
staging: et131x: Remove forward declaration of et131x_adapter_setup
staging: et131x: Remove some forward declarations
staging: et131x: Remove unused rx_ring.recv_packet_pool
staging: et131x: Remove call to find pci pm capability
staging: et131x: Remove redundant et131x_reset_recv() call
staging: et131x: Remove unused rx_ring.recv_buffer_pool
Staging: bcm: Fix three initialization errors in InterfaceDld.c
Staging: bcm: Fix coding style issues in InterfaceDld.c
staging:iio:dac: Add AD5360 driver
staging:iio:trigger:bfin-timer: Fix compile error
Staging: vt6655: add some range checks before memcpy()
Staging: vt6655: whitespace fixes to iotcl.c
Staging: vt6656: add some range checks before memcpy()
Staging: vt6656: whitespace cleanups in ioctl.c
...
Fix up conflicts in:
- drivers/{Kconfig,Makefile}, drivers/staging/{Kconfig,Makefile}:
vg driver movement
- drivers/staging/brcm80211/brcmfmac/{dhd_linux.c,mac80211_if.c}:
driver removal vs now stale changes
- drivers/staging/rtl8192e/r8192E_core.c:
driver removal vs now stale changes
- drivers/staging/et131x/et131*:
driver consolidation into one file, tried to do fixups
Diffstat (limited to 'drivers/staging/iio/dac')
-rw-r--r-- | drivers/staging/iio/dac/Kconfig | 27 | ||||
-rw-r--r-- | drivers/staging/iio/dac/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5064.c | 463 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5360.c | 581 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5446.c | 72 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5504.c | 94 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5624r_spi.c | 83 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5686.c | 133 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5791.c | 262 | ||||
-rw-r--r-- | drivers/staging/iio/dac/ad5791.h | 6 | ||||
-rw-r--r-- | drivers/staging/iio/dac/dac.h | 2 | ||||
-rw-r--r-- | drivers/staging/iio/dac/max517.c | 34 |
12 files changed, 1392 insertions, 367 deletions
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig index 7ddae35..fac8549 100644 --- a/drivers/staging/iio/dac/Kconfig +++ b/drivers/staging/iio/dac/Kconfig @@ -1,14 +1,35 @@ # # DAC drivers # -comment "Digital to analog convertors" +menu "Digital to analog converters" + +config AD5064 + tristate "Analog Devices AD5064/64-1/44/24 DAC driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD5064, AD5064-1, + AD5044, AD5024 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 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 convertors (DAC). This driver uses the common SPI interface. + AD5664R converters (DAC). This driver uses the common SPI interface. config AD5446 tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver" @@ -62,3 +83,5 @@ config MAX517 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 index 7f4f2ed..07b6f5e 100644 --- a/drivers/staging/iio/dac/Makefile +++ b/drivers/staging/iio/dac/Makefile @@ -2,7 +2,9 @@ # Makefile for industrial I/O DAC drivers # +obj-$(CONFIG_AD5360) += ad5360.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_AD5791) += ad5791.o diff --git a/drivers/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c new file mode 100644 index 0000000..24279f2 --- /dev/null +++ b/drivers/staging/iio/dac/ad5064.c @@ -0,0 +1,463 @@ +/* + * AD5064, AD5064-1, AD5044, AD5024 Digital to analog converters driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/regulator/consumer.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "dac.h" + +#define AD5064_DAC_CHANNELS 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_DAISY_CHAIN_ENABLE 0x8 + +#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 + * @channel: channel specification +*/ + +struct ad5064_chip_info { + bool shared_vref; + struct iio_chan_spec channel[AD5064_DAC_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) + * @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_DAC_CHANNELS]; + bool pwr_down[AD5064_DAC_CHANNELS]; + u8 pwr_down_mode[AD5064_DAC_CHANNELS]; + unsigned int dac_cache[AD5064_DAC_CHANNELS]; + + /* + * 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_AD5044, + ID_AD5064, + ID_AD5064_1, +}; + +#define AD5064_CHANNEL(chan, bits) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (chan), \ + .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE), \ + .address = AD5064_ADDR_DAC(chan), \ + .scan_type = IIO_ST('u', (bits), 16, 20 - (bits)) \ +} + +static const struct ad5064_chip_info ad5064_chip_info_tbl[] = { + [ID_AD5024] = { + .shared_vref = false, + .channel[0] = AD5064_CHANNEL(0, 12), + .channel[1] = AD5064_CHANNEL(1, 12), + .channel[2] = AD5064_CHANNEL(2, 12), + .channel[3] = AD5064_CHANNEL(3, 12), + }, + [ID_AD5044] = { + .shared_vref = false, + .channel[0] = AD5064_CHANNEL(0, 14), + .channel[1] = AD5064_CHANNEL(1, 14), + .channel[2] = AD5064_CHANNEL(2, 14), + .channel[3] = AD5064_CHANNEL(3, 14), + }, + [ID_AD5064] = { + .shared_vref = false, + .channel[0] = AD5064_CHANNEL(0, 16), + .channel[1] = AD5064_CHANNEL(1, 16), + .channel[2] = AD5064_CHANNEL(2, 16), + .channel[3] = AD5064_CHANNEL(3, 16), + }, + [ID_AD5064_1] = { + .shared_vref = true, + .channel[0] = AD5064_CHANNEL(0, 16), + .channel[1] = AD5064_CHANNEL(1, 16), + .channel[2] = AD5064_CHANNEL(2, 16), + .channel[3] = AD5064_CHANNEL(3, 16), + }, +}; + +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 ad5064_powerdown_modes[][15] = { + [AD5064_LDAC_PWRDN_NONE] = "", + [AD5064_LDAC_PWRDN_1K] = "1kohm_to_gnd", + [AD5064_LDAC_PWRDN_100K] = "100kohm_to_gnd", + [AD5064_LDAC_PWRDN_3STATE] = "three_state", +}; + +static ssize_t ad5064_read_powerdown_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5064_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%s\n", + ad5064_powerdown_modes[st->pwr_down_mode[this_attr->address]]); +} + +static ssize_t ad5064_write_powerdown_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5064_state *st = iio_priv(indio_dev); + unsigned int mode, i; + int ret; + + mode = 0; + + for (i = 1; i < ARRAY_SIZE(ad5064_powerdown_modes); ++i) { + if (sysfs_streq(buf, ad5064_powerdown_modes[i])) { + mode = i; + break; + } + } + if (mode == 0) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + st->pwr_down_mode[this_attr->address] = mode; + + ret = ad5064_sync_powerdown_mode(st, this_attr->address); + mutex_unlock(&indio_dev->mlock); + + return ret ? ret : len; +} + +static ssize_t ad5064_read_dac_powerdown(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5064_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + return sprintf(buf, "%d\n", st->pwr_down[this_attr->address]); +} + +static ssize_t ad5064_write_dac_powerdown(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5064_state *st = iio_priv(indio_dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + bool pwr_down; + int ret; + + ret = strtobool(buf, &pwr_down); + if (ret) + return ret; + + mutex_lock(&indio_dev->mlock); + st->pwr_down[this_attr->address] = pwr_down; + + ret = ad5064_sync_powerdown_mode(st, this_attr->address); + mutex_unlock(&indio_dev->mlock); + return ret ? ret : len; +} + +static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, + "1kohm_to_gnd 100kohm_to_gnd three_state"); + +#define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_chan) \ + IIO_DEVICE_ATTR(out_voltage##_chan##_powerdown_mode, \ + S_IRUGO | S_IWUSR, \ + ad5064_read_powerdown_mode, \ + ad5064_write_powerdown_mode, _chan); + +#define IIO_DEV_ATTR_DAC_POWERDOWN(_chan) \ + IIO_DEVICE_ATTR(out_voltage##_chan##_powerdown, \ + S_IRUGO | S_IWUSR, \ + ad5064_read_dac_powerdown, \ + ad5064_write_dac_powerdown, _chan) + +static IIO_DEV_ATTR_DAC_POWERDOWN(0); +static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(0); +static IIO_DEV_ATTR_DAC_POWERDOWN(1); +static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(1); +static IIO_DEV_ATTR_DAC_POWERDOWN(2); +static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(2); +static IIO_DEV_ATTR_DAC_POWERDOWN(3); +static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(3); + +static struct attribute *ad5064_attributes[] = { + &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage1_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage2_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage3_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown_mode.dev_attr.attr, + &iio_dev_attr_out_voltage1_powerdown_mode.dev_attr.attr, + &iio_dev_attr_out_voltage2_powerdown_mode.dev_attr.attr, + &iio_dev_attr_out_voltage3_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad5064_attribute_group = { + .attrs = ad5064_attributes, +}; + +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); + unsigned long scale_uv; + unsigned int vref; + + switch (m) { + case 0: + *val = st->dac_cache[chan->channel]; + return IIO_VAL_INT; + case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + vref = st->chip_info->shared_vref ? 0 : chan->channel; + scale_uv = regulator_get_voltage(st->vref_reg[vref].consumer); + 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 0: + 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, + .attrs = &ad5064_attribute_group, + .driver_module = THIS_MODULE, +}; + +static inline unsigned int ad5064_num_vref(struct ad5064_state *st) +{ + return st->chip_info->shared_vref ? 1 : AD5064_DAC_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_allocate_device(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) + goto error_free; + + ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg); + if (ret) + goto error_free_reg; + + for (i = 0; i < AD5064_DAC_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->channel; + indio_dev->num_channels = AD5064_DAC_CHANNELS; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_disable_reg; + + return 0; + +error_disable_reg: + regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); +error_free_reg: + regulator_bulk_free(ad5064_num_vref(st), st->vref_reg); +error_free: + iio_free_device(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); + + regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg); + regulator_bulk_free(ad5064_num_vref(st), st->vref_reg); + + iio_free_device(indio_dev); + + return 0; +} + +static const struct spi_device_id ad5064_id[] = { + {"ad5024", ID_AD5024}, + {"ad5044", ID_AD5044}, + {"ad5064", ID_AD5064}, + {"ad5064-1", ID_AD5064_1}, + {} +}; +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, +}; + +static __init int ad5064_spi_init(void) +{ + return spi_register_driver(&ad5064_driver); +} +module_init(ad5064_spi_init); + +static __exit void ad5064_spi_exit(void) +{ + spi_unregister_driver(&ad5064_driver); +} +module_exit(ad5064_spi_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD5064/64-1/44/24 DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c new file mode 100644 index 0000000..72d0f3f --- /dev/null +++ b/drivers/staging/iio/dac/ad5360.c @@ -0,0 +1,581 @@ +/* + * Analog devices AD5360, AD5361, AD5362, AD5363, AD5370, AD5371, AD5373 + * multi-channel Digital to Analog Converters driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/regulator/consumer.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "dac.h" + +#define AD5360_CMD(x) ((x) << 22) +#define AD5360_ADDR(x) ((x) << 16) + +#define AD5360_READBACK_TYPE(x) ((x) << 13) +#define AD5360_READBACK_ADDR(x) ((x) << 7) + +#define AD5360_CHAN_ADDR(chan) ((chan) + 0x8) + +#define AD5360_CMD_WRITE_DATA 0x3 +#define AD5360_CMD_WRITE_OFFSET 0x2 +#define AD5360_CMD_WRITE_GAIN 0x1 +#define AD5360_CMD_SPECIAL_FUNCTION 0x0 + +/* Special function register addresses */ +#define AD5360_REG_SF_NOP 0x0 +#define AD5360_REG_SF_CTRL 0x1 +#define AD5360_REG_SF_OFS(x) (0x2 + (x)) +#define AD5360_REG_SF_READBACK 0x5 + +#define AD5360_SF_CTRL_PWR_DOWN BIT(0) + +#define AD5360_READBACK_X1A 0x0 +#define AD5360_READBACK_X1B 0x1 +#define AD5360_READBACK_OFFSET 0x2 +#define AD5360_READBACK_GAIN 0x3 +#define AD5360_READBACK_SF 0x4 + + +/** + * struct ad5360_chip_info - chip specific information + * @channel_template: channel specification template + * @num_channels: number of channels + * @channels_per_group: number of channels per group + * @num_vrefs: number of vref supplies for the chip +*/ + +struct ad5360_chip_info { + struct iio_chan_spec channel_template; + unsigned int num_channels; + unsigned int channels_per_group; + unsigned int num_vrefs; +}; + +/** + * struct ad5360_state - driver instance specific data + * @spi: spi_device + * @chip_info: chip model specific constants, available modes etc + * @vref_reg: vref supply regulators + * @ctrl: control register cache + * @data: spi transfer buffers + */ + +struct ad5360_state { + struct spi_device *spi; + const struct ad5360_chip_info *chip_info; + struct regulator_bulk_data vref_reg[3]; + unsigned int ctrl; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + union { + __be32 d32; + u8 d8[4]; + } data[2] ____cacheline_aligned; +}; + +enum ad5360_type { + ID_AD5360, + ID_AD5361, + ID_AD5362, + ID_AD5363, + ID_AD5370, + ID_AD5371, + ID_AD5372, + ID_AD5373, +}; + +#define AD5360_CHANNEL(bits) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .info_mask = (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | \ + (1 << IIO_CHAN_INFO_OFFSET_SEPARATE) | \ + (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \ + (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), \ + .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_get_drvdata(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_get_drvdata(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 0: + 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 (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + 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 (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + 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 (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + 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 long scale_uv; + unsigned int ofs_index; + int ret; + + switch (m) { + case 0: + 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 (1 << IIO_CHAN_INFO_SCALE_SEPARATE): + /* 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 (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): + ret = ad5360_read(indio_dev, AD5360_READBACK_OFFSET, + chan->address); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE): + ret = ad5360_read(indio_dev, AD5360_READBACK_GAIN, + chan->address); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): + 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(sizeof(struct iio_chan_spec), + st->chip_info->num_channels, 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_allocate_device(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_free_device(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_free_device(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, +}; + +static __init int ad5360_spi_init(void) +{ + return spi_register_driver(&ad5360_driver); +} +module_init(ad5360_spi_init); + +static __exit void ad5360_spi_exit(void) +{ + spi_unregister_driver(&ad5360_driver); +} +module_exit(ad5360_spi_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD5360/61/62/63/70/71/72/73 DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c index e8a9d0b..e1c204d 100644 --- a/drivers/staging/iio/dac/ad5446.c +++ b/drivers/staging/iio/dac/ad5446.c @@ -16,6 +16,7 @@ #include <linux/spi/spi.h> #include <linux/regulator/consumer.h> #include <linux/err.h> +#include <linux/module.h> #include "../iio.h" #include "../sysfs.h" @@ -67,8 +68,8 @@ static ssize_t ad5446_write(struct device *dev, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); int ret; long val; @@ -81,11 +82,11 @@ static ssize_t ad5446_write(struct device *dev, goto error_ret; } - mutex_lock(&dev_info->mlock); + mutex_lock(&indio_dev->mlock); st->cached_val = val; st->chip_info->store_sample(st, val); ret = spi_sync(st->spi, &st->msg); - mutex_unlock(&dev_info->mlock); + mutex_unlock(&indio_dev->mlock); error_ret: return ret ? ret : len; @@ -97,21 +98,21 @@ static ssize_t ad5446_show_scale(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); /* Corresponds to Vref / 2^(bits) */ unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); } -static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0); +static IIO_DEVICE_ATTR(out_voltage_scale, S_IRUGO, ad5446_show_scale, NULL, 0); static ssize_t ad5446_write_powerdown_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); if (sysfs_streq(buf, "1kohm_to_gnd")) st->pwr_down_mode = MODE_PWRDWN_1k; @@ -128,8 +129,8 @@ static ssize_t ad5446_write_powerdown_mode(struct device *dev, static ssize_t ad5446_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; @@ -140,8 +141,8 @@ static ssize_t ad5446_read_dac_powerdown(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); return sprintf(buf, "%d\n", st->pwr_down); } @@ -150,8 +151,8 @@ static ssize_t ad5446_write_dac_powerdown(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); unsigned long readin; int ret; @@ -162,7 +163,7 @@ static ssize_t ad5446_write_dac_powerdown(struct device *dev, if (readin > 1) ret = -EINVAL; - mutex_lock(&dev_info->mlock); + mutex_lock(&indio_dev->mlock); st->pwr_down = readin; if (st->pwr_down) @@ -171,28 +172,28 @@ static ssize_t ad5446_write_dac_powerdown(struct device *dev, st->chip_info->store_sample(st, st->cached_val); ret = spi_sync(st->spi, &st->msg); - mutex_unlock(&dev_info->mlock); + mutex_unlock(&indio_dev->mlock); return ret ? ret : len; } -static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR, ad5446_read_powerdown_mode, ad5446_write_powerdown_mode, 0); -static IIO_CONST_ATTR(out_powerdown_mode_available, +static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, "1kohm_to_gnd 100kohm_to_gnd three_state"); -static IIO_DEVICE_ATTR(out0_powerdown, S_IRUGO | S_IWUSR, +static IIO_DEVICE_ATTR(out_voltage0_powerdown, S_IRUGO | S_IWUSR, ad5446_read_dac_powerdown, ad5446_write_dac_powerdown, 0); static struct attribute *ad5446_attributes[] = { - &iio_dev_attr_out0_raw.dev_attr.attr, - &iio_dev_attr_out_scale.dev_attr.attr, - &iio_dev_attr_out0_powerdown.dev_attr.attr, - &iio_dev_attr_out_powerdown_mode.dev_attr.attr, - &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, + &iio_dev_attr_out_voltage0_raw.dev_attr.attr, + &iio_dev_attr_out_voltage_scale.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, NULL, }; @@ -200,16 +201,18 @@ static mode_t ad5446_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct ad5446_state *st = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ad5446_state *st = iio_priv(indio_dev); mode_t mode = attr->mode; if (!st->chip_info->store_pwr_down && - (attr == &iio_dev_attr_out0_powerdown.dev_attr.attr || - attr == &iio_dev_attr_out_powerdown_mode.dev_attr.attr || + (attr == &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr || + attr == &iio_dev_attr_out_voltage_powerdown_mode. + dev_attr.attr || attr == - &iio_const_attr_out_powerdown_mode_available.dev_attr.attr)) + &iio_const_attr_out_voltage_powerdown_mode_available. + dev_attr.attr)) mode = 0; return mode; @@ -421,13 +424,14 @@ 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); - struct regulator *reg = st->reg; iio_device_unregister(indio_dev); - if (!IS_ERR(reg)) { - regulator_disable(reg); - regulator_put(reg); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); } + iio_free_device(indio_dev); + return 0; } diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c index 1915f45..60dd640 100644 --- a/drivers/staging/iio/dac/ad5504.c +++ b/drivers/staging/iio/dac/ad5504.c @@ -7,7 +7,6 @@ */ #include <linux/interrupt.h> -#include <linux/gpio.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/kernel.h> @@ -15,6 +14,7 @@ #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #include "../iio.h" #include "../sysfs.h" @@ -168,10 +168,10 @@ static ssize_t ad5504_show_scale(struct device *dev, return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); } -static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5504_show_scale, NULL, 0); +static IIO_DEVICE_ATTR(out_voltage_scale, S_IRUGO, ad5504_show_scale, NULL, 0); #define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr) \ - IIO_DEVICE_ATTR(out##_num##_raw, \ + IIO_DEVICE_ATTR(out_voltage##_num##_raw, \ S_IRUGO | S_IWUSR, _show, _store, _addr) static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5504_read_dac, @@ -183,17 +183,16 @@ static IIO_DEV_ATTR_OUT_RW_RAW(2, ad5504_read_dac, static IIO_DEV_ATTR_OUT_RW_RAW(3, ad5504_read_dac, ad5504_write_dac, AD5504_ADDR_DAC3); -static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | +static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR, ad5504_read_powerdown_mode, ad5504_write_powerdown_mode, 0); -static IIO_CONST_ATTR(out_powerdown_mode_available, +static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, "20kohm_to_gnd three_state"); #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ - IIO_DEVICE_ATTR(out##_num##_powerdown, \ + IIO_DEVICE_ATTR(out_voltage##_num##_powerdown, \ S_IRUGO | S_IWUSR, _show, _store, _addr) - static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5504_read_dac_powerdown, ad5504_write_dac_powerdown, 0); static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5504_read_dac_powerdown, @@ -204,17 +203,17 @@ static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5504_read_dac_powerdown, ad5504_write_dac_powerdown, 3); static struct attribute *ad5504_attributes[] = { - &iio_dev_attr_out0_raw.dev_attr.attr, - &iio_dev_attr_out1_raw.dev_attr.attr, - &iio_dev_attr_out2_raw.dev_attr.attr, - &iio_dev_attr_out3_raw.dev_attr.attr, - &iio_dev_attr_out0_powerdown.dev_attr.attr, - &iio_dev_attr_out1_powerdown.dev_attr.attr, - &iio_dev_attr_out2_powerdown.dev_attr.attr, - &iio_dev_attr_out3_powerdown.dev_attr.attr, - &iio_dev_attr_out_powerdown_mode.dev_attr.attr, - &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, - &iio_dev_attr_out_scale.dev_attr.attr, + &iio_dev_attr_out_voltage0_raw.dev_attr.attr, + &iio_dev_attr_out_voltage1_raw.dev_attr.attr, + &iio_dev_attr_out_voltage2_raw.dev_attr.attr, + &iio_dev_attr_out_voltage3_raw.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage1_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage2_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage3_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, + &iio_dev_attr_out_voltage_scale.dev_attr.attr, NULL, }; @@ -223,11 +222,11 @@ static const struct attribute_group ad5504_attribute_group = { }; static struct attribute *ad5501_attributes[] = { - &iio_dev_attr_out0_raw.dev_attr.attr, - &iio_dev_attr_out0_powerdown.dev_attr.attr, - &iio_dev_attr_out_powerdown_mode.dev_attr.attr, - &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, - &iio_dev_attr_out_scale.dev_attr.attr, + &iio_dev_attr_out_voltage0_raw.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, + &iio_dev_attr_out_voltage_scale.dev_attr.attr, NULL, }; @@ -246,12 +245,13 @@ static struct attribute *ad5504_ev_attributes[] = { 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, 0, - IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_TEMP, + iio_push_event(private, + IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), @@ -262,14 +262,12 @@ static irqreturn_t ad5504_event_handler(int irq, void *private) static const struct iio_info ad5504_info = { .attrs = &ad5504_attribute_group, - .num_interrupt_lines = 1, .event_attrs = &ad5504_ev_attribute_group, .driver_module = THIS_MODULE, }; static const struct iio_info ad5501_info = { .attrs = &ad5501_attribute_group, - .num_interrupt_lines = 1, .event_attrs = &ad5504_ev_attribute_group, .driver_module = THIS_MODULE, }; @@ -282,6 +280,11 @@ static int __devinit ad5504_probe(struct spi_device *spi) struct regulator *reg; int ret, voltage_uv = 0; + indio_dev = iio_allocate_device(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); @@ -291,11 +294,6 @@ static int __devinit ad5504_probe(struct spi_device *spi) voltage_uv = regulator_get_voltage(reg); } - indio_dev = iio_allocate_device(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_disable_reg; - } spi_set_drvdata(spi, indio_dev); st = iio_priv(indio_dev); if (voltage_uv) @@ -315,10 +313,6 @@ static int __devinit ad5504_probe(struct spi_device *spi) indio_dev->info = &ad5504_info; indio_dev->modes = INDIO_DIRECT_MODE; - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_dev; - if (spi->irq) { ret = request_threaded_irq(spi->irq, NULL, @@ -327,22 +321,26 @@ static int __devinit ad5504_probe(struct spi_device *spi) spi_get_device_id(st->spi)->name, indio_dev); if (ret) - goto error_unreg_iio_device; + goto error_disable_reg; } + ret = iio_device_register(indio_dev); + if (ret) + goto error_free_irq; + return 0; -error_unreg_iio_device: - iio_device_unregister(indio_dev); -error_free_dev: - iio_free_device(indio_dev); +error_free_irq: + free_irq(spi->irq, indio_dev); error_disable_reg: if (!IS_ERR(reg)) - regulator_disable(st->reg); + regulator_disable(reg); error_put_reg: if (!IS_ERR(reg)) regulator_put(reg); + iio_free_device(indio_dev); +error_ret: return ret; } @@ -350,16 +348,16 @@ 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); - struct regulator *reg = st->reg; - if (spi->irq) - free_irq(spi->irq, indio_dev); iio_device_unregister(indio_dev); + if (spi->irq) + free_irq(spi->irq, indio_dev); - if (!IS_ERR(reg)) { - regulator_disable(reg); - regulator_put(reg); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); } + iio_free_device(indio_dev); return 0; } diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c index a5b3776..284d8790 100644 --- a/drivers/staging/iio/dac/ad5624r_spi.c +++ b/drivers/staging/iio/dac/ad5624r_spi.c @@ -7,7 +7,6 @@ */ #include <linux/interrupt.h> -#include <linux/gpio.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/kernel.h> @@ -15,6 +14,7 @@ #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #include "../iio.h" #include "../sysfs.h" @@ -172,22 +172,22 @@ static ssize_t ad5624r_show_scale(struct device *dev, return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); } -static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5624r_show_scale, NULL, 0); +static IIO_DEVICE_ATTR(out_voltage_scale, S_IRUGO, ad5624r_show_scale, NULL, 0); static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0); static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1); static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); -static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | +static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR, ad5624r_read_powerdown_mode, ad5624r_write_powerdown_mode, 0); -static IIO_CONST_ATTR(out_powerdown_mode_available, +static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, "1kohm_to_gnd 100kohm_to_gnd three_state"); #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ - IIO_DEVICE_ATTR(out##_num##_powerdown, \ + IIO_DEVICE_ATTR(out_voltage##_num##_powerdown, \ S_IRUGO | S_IWUSR, _show, _store, _addr) static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5624r_read_dac_powerdown, @@ -200,17 +200,17 @@ static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5624r_read_dac_powerdown, ad5624r_write_dac_powerdown, 3); static struct attribute *ad5624r_attributes[] = { - &iio_dev_attr_out0_raw.dev_attr.attr, - &iio_dev_attr_out1_raw.dev_attr.attr, - &iio_dev_attr_out2_raw.dev_attr.attr, - &iio_dev_attr_out3_raw.dev_attr.attr, - &iio_dev_attr_out0_powerdown.dev_attr.attr, - &iio_dev_attr_out1_powerdown.dev_attr.attr, - &iio_dev_attr_out2_powerdown.dev_attr.attr, - &iio_dev_attr_out3_powerdown.dev_attr.attr, - &iio_dev_attr_out_powerdown_mode.dev_attr.attr, - &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, - &iio_dev_attr_out_scale.dev_attr.attr, + &iio_dev_attr_out_voltage0_raw.dev_attr.attr, + &iio_dev_attr_out_voltage1_raw.dev_attr.attr, + &iio_dev_attr_out_voltage2_raw.dev_attr.attr, + &iio_dev_attr_out_voltage3_raw.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage1_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage2_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage3_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, + &iio_dev_attr_out_voltage_scale.dev_attr.attr, NULL, }; @@ -227,24 +227,23 @@ static int __devinit ad5624r_probe(struct spi_device *spi) { struct ad5624r_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_allocate_device(sizeof(*st)); if (indio_dev == NULL) { ret = -ENOMEM; - goto error_disable_reg; + goto error_ret; } st = iio_priv(indio_dev); - st->reg = reg; + 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]; @@ -261,25 +260,25 @@ static int __devinit ad5624r_probe(struct spi_device *spi) indio_dev->info = &ad5624r_info; indio_dev->modes = INDIO_DIRECT_MODE; - ret = iio_device_register(indio_dev); - if (ret) - goto error_free_dev; - ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, !!voltage_uv, 16); if (ret) - goto error_free_dev; + goto error_disable_reg; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_disable_reg; return 0; -error_free_dev: - iio_free_device(indio_dev); error_disable_reg: - if (!IS_ERR(reg)) - regulator_disable(reg); + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); error_put_reg: - if (!IS_ERR(reg)) - regulator_put(reg); + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + iio_free_device(indio_dev); +error_ret: return ret; } @@ -288,13 +287,13 @@ 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); - struct regulator *reg = st->reg; iio_device_unregister(indio_dev); - if (!IS_ERR(reg)) { - regulator_disable(reg); - regulator_put(reg); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); } + iio_free_device(indio_dev); return 0; } diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c index fd67cfa..48389e1 100644 --- a/drivers/staging/iio/dac/ad5686.c +++ b/drivers/staging/iio/dac/ad5686.c @@ -7,9 +7,9 @@ */ #include <linux/interrupt.h> -#include <linux/gpio.h> #include <linux/fs.h> #include <linux/device.h> +#include <linux/module.h> #include <linux/kernel.h> #include <linux/spi/spi.h> #include <linux/slab.h> @@ -25,10 +25,7 @@ #define AD5686_ADDR(x) ((x) << 16) #define AD5686_CMD(x) ((x) << 20) -#define AD5686_ADDR_DAC0 0x1 -#define AD5686_ADDR_DAC1 0x2 -#define AD5686_ADDR_DAC2 0x4 -#define AD5686_ADDR_DAC3 0x8 +#define AD5686_ADDR_DAC(chan) (0x1 << (chan)) #define AD5686_ADDR_ALL_DAC 0xF #define AD5686_CMD_NOOP 0x0 @@ -96,63 +93,35 @@ enum ad5686_supported_device_ids { ID_AD5685, ID_AD5686, }; - +#define AD5868_CHANNEL(chan, bits, shift) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = chan, \ + .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED), \ + .address = AD5686_ADDR_DAC(chan), \ + .scan_type = IIO_ST('u', bits, 16, shift) \ +} static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { [ID_AD5684] = { - .channel[0] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC0, - 0, IIO_ST('u', 12, 16, 4), 0), - .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC1, - 1, IIO_ST('u', 12, 16, 4), 0), - .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC2, - 2, IIO_ST('u', 12, 16, 4), 0), - .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC3, - 3, IIO_ST('u', 12, 16, 4), 0), + .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] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC0, - 0, IIO_ST('u', 14, 16, 2), 0), - .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC1, - 1, IIO_ST('u', 14, 16, 2), 0), - .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC2, - 2, IIO_ST('u', 14, 16, 2), 0), - .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC3, - 3, IIO_ST('u', 14, 16, 2), 0), + .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] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC0, - 0, IIO_ST('u', 16, 16, 0), 0), - .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC1, - 1, IIO_ST('u', 16, 16, 0), 0), - .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC2, - 2, IIO_ST('u', 16, 16, 0), 0), - .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, - (1 << IIO_CHAN_INFO_SCALE_SHARED), - AD5686_ADDR_DAC3, - 3, IIO_ST('u', 16, 16, 0), 0), + .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, }, }; @@ -274,11 +243,12 @@ static ssize_t ad5686_write_dac_powerdown(struct device *dev, return ret ? ret : len; } -static IIO_CONST_ATTR(out_powerdown_mode_available, +static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, "1kohm_to_gnd 100kohm_to_gnd three_state"); -#define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_num) \ - IIO_DEVICE_ATTR(out##_num##_powerdown_mode, S_IRUGO | S_IWUSR, \ +#define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_num) \ + IIO_DEVICE_ATTR(out_voltage##_num##_powerdown_mode, \ + S_IRUGO | S_IWUSR, \ ad5686_read_powerdown_mode, \ ad5686_write_powerdown_mode, _num) @@ -287,8 +257,9 @@ static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(1); static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(2); static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(3); -#define IIO_DEV_ATTR_DAC_POWERDOWN(_num) \ - IIO_DEVICE_ATTR(out##_num##_powerdown, S_IRUGO | S_IWUSR, \ +#define IIO_DEV_ATTR_DAC_POWERDOWN(_num) \ + IIO_DEVICE_ATTR(out_voltage##_num##_powerdown, \ + S_IRUGO | S_IWUSR, \ ad5686_read_dac_powerdown, \ ad5686_write_dac_powerdown, _num) @@ -298,15 +269,15 @@ static IIO_DEV_ATTR_DAC_POWERDOWN(2); static IIO_DEV_ATTR_DAC_POWERDOWN(3); static struct attribute *ad5686_attributes[] = { - &iio_dev_attr_out0_powerdown.dev_attr.attr, - &iio_dev_attr_out1_powerdown.dev_attr.attr, - &iio_dev_attr_out2_powerdown.dev_attr.attr, - &iio_dev_attr_out3_powerdown.dev_attr.attr, - &iio_dev_attr_out0_powerdown_mode.dev_attr.attr, - &iio_dev_attr_out1_powerdown_mode.dev_attr.attr, - &iio_dev_attr_out2_powerdown_mode.dev_attr.attr, - &iio_dev_attr_out3_powerdown_mode.dev_attr.attr, - &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage1_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage2_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage3_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown_mode.dev_attr.attr, + &iio_dev_attr_out_voltage1_powerdown_mode.dev_attr.attr, + &iio_dev_attr_out_voltage2_powerdown_mode.dev_attr.attr, + &iio_dev_attr_out_voltage3_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, NULL, }; @@ -356,7 +327,7 @@ static int ad5686_write_raw(struct iio_dev *indio_dev, switch (mask) { case 0: - if (val > (1 << chan->scan_type.realbits)) + if (val > (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; mutex_lock(&indio_dev->mlock); @@ -420,16 +391,16 @@ static int __devinit ad5686_probe(struct spi_device *spi) indio_dev->channels = st->chip_info->channel; indio_dev->num_channels = AD5686_DAC_CHANNELS; - ret = iio_device_register(indio_dev); - if (ret) - goto error_disable_reg; - 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: @@ -439,10 +410,7 @@ error_put_reg: if (!IS_ERR(st->reg)) regulator_put(st->reg); - if (regdone) - iio_device_unregister(indio_dev); - else - iio_free_device(indio_dev); + iio_free_device(indio_dev); return ret; } @@ -451,14 +419,13 @@ 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); - struct regulator *reg = st->reg; - - if (!IS_ERR(reg)) { - regulator_disable(reg); - regulator_put(reg); - } iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + iio_free_device(indio_dev); return 0; } diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c index 64770d2..6fbca8d 100644 --- a/drivers/staging/iio/dac/ad5791.c +++ b/drivers/staging/iio/dac/ad5791.c @@ -7,7 +7,6 @@ */ #include <linux/interrupt.h> -#include <linux/gpio.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/kernel.h> @@ -15,6 +14,7 @@ #include <linux/slab.h> #include <linux/sysfs.h> #include <linux/regulator/consumer.h> +#include <linux/module.h> #include "../iio.h" #include "../sysfs.h" @@ -71,48 +71,23 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) return ret; } -static ssize_t ad5791_write_dac(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5791_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - long readin; - int ret; - - ret = strict_strtol(buf, 10, &readin); - if (ret) - return ret; - - readin += (1 << (st->chip_info->bits - 1)); - readin &= AD5791_RES_MASK(st->chip_info->bits); - readin <<= st->chip_info->left_shift; - - ret = ad5791_spi_write(st->spi, this_attr->address, readin); - return ret ? ret : len; +#define AD5791_CHAN(bits, shift) { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .address = AD5791_ADDR_DAC0, \ + .channel = 0, \ + .info_mask = (1 << IIO_CHAN_INFO_SCALE_SHARED) | \ + (1 << IIO_CHAN_INFO_OFFSET_SHARED), \ + .scan_type = IIO_ST('u', bits, 24, shift) \ } -static ssize_t ad5791_read_dac(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5791_state *st = iio_priv(indio_dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - int ret; - int val; - - ret = ad5791_spi_read(st->spi, this_attr->address, &val); - if (ret) - return ret; - - val &= AD5791_DAC_MASK; - val >>= st->chip_info->left_shift; - val -= (1 << (st->chip_info->bits - 1)); - - return sprintf(buf, "%d\n", val); -} +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 ssize_t ad5791_read_powerdown_mode(struct device *dev, struct device_attribute *attr, char *buf) @@ -183,58 +158,24 @@ static ssize_t ad5791_write_dac_powerdown(struct device *dev, return ret ? ret : len; } -static ssize_t ad5791_show_scale(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5791_state *st = iio_priv(indio_dev); - /* Corresponds to Vref / 2^(bits) */ - unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; - - return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); -} -static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5791_show_scale, NULL, 0); - -static ssize_t ad5791_show_name(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct ad5791_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); -} -static IIO_DEVICE_ATTR(name, S_IRUGO, ad5791_show_name, NULL, 0); - -#define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr) \ - IIO_DEVICE_ATTR(out##_num##_raw, \ - S_IRUGO | S_IWUSR, _show, _store, _addr) - -static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5791_read_dac, - ad5791_write_dac, AD5791_ADDR_DAC0); - -static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | +static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR, ad5791_read_powerdown_mode, ad5791_write_powerdown_mode, 0); -static IIO_CONST_ATTR(out_powerdown_mode_available, +static IIO_CONST_ATTR(out_voltage_powerdown_mode_available, "6kohm_to_gnd three_state"); #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ - IIO_DEVICE_ATTR(out##_num##_powerdown, \ + IIO_DEVICE_ATTR(out_voltage##_num##_powerdown, \ S_IRUGO | S_IWUSR, _show, _store, _addr) static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5791_read_dac_powerdown, ad5791_write_dac_powerdown, 0); static struct attribute *ad5791_attributes[] = { - &iio_dev_attr_out0_raw.dev_attr.attr, - &iio_dev_attr_out0_powerdown.dev_attr.attr, - &iio_dev_attr_out_powerdown_mode.dev_attr.attr, - &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, - &iio_dev_attr_out_scale.dev_attr.attr, - &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr, + &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr, + &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr, NULL, }; @@ -263,31 +204,78 @@ static int ad5780_get_lin_comp(unsigned int span) else return AD5780_LINCOMP_10_20; } - static const struct ad5791_chip_info ad5791_chip_info_tbl[] = { [ID_AD5760] = { - .bits = 16, - .left_shift = 4, .get_lin_comp = ad5780_get_lin_comp, }, [ID_AD5780] = { - .bits = 18, - .left_shift = 2, .get_lin_comp = ad5780_get_lin_comp, }, [ID_AD5781] = { - .bits = 18, - .left_shift = 2, .get_lin_comp = ad5791_get_lin_comp, }, [ID_AD5791] = { - .bits = 20, - .left_shift = 0, .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 0: + 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 (1 << IIO_CHAN_INFO_SCALE_SHARED): + *val = 0; + *val2 = (((u64)st->vref_mv) * 1000000ULL) >> chan->scan_type.realbits; + return IIO_VAL_INT_PLUS_MICRO; + case (1 << IIO_CHAN_INFO_OFFSET_SHARED): + 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 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 0: + 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, .attrs = &ad5791_attribute_group, .driver_module = THIS_MODULE, }; @@ -296,50 +284,52 @@ static int __devinit ad5791_probe(struct spi_device *spi) { struct ad5791_platform_data *pdata = spi->dev.platform_data; struct iio_dev *indio_dev; - struct regulator *reg_vdd, *reg_vss; struct ad5791_state *st; int ret, pos_voltage_uv = 0, neg_voltage_uv = 0; - reg_vdd = regulator_get(&spi->dev, "vdd"); - if (!IS_ERR(reg_vdd)) { - ret = regulator_enable(reg_vdd); + indio_dev = iio_allocate_device(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(reg_vdd); + pos_voltage_uv = regulator_get_voltage(st->reg_vdd); } - reg_vss = regulator_get(&spi->dev, "vss"); - if (!IS_ERR(reg_vss)) { - ret = regulator_enable(reg_vss); + 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(reg_vss); + neg_voltage_uv = regulator_get_voltage(st->reg_vss); } - indio_dev = iio_allocate_device(sizeof(*st)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_disable_reg_neg; - } - st = iio_priv(indio_dev); st->pwr_down = true; st->spi = spi; - if (!IS_ERR(reg_vss) && !IS_ERR(reg_vdd)) - st->vref_mv = (pos_voltage_uv - neg_voltage_uv) / 1000; - else if (pdata) - st->vref_mv = pdata->vref_pos_mv - pdata->vref_neg_mv; - else + 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_free_dev; + goto error_disable_reg_neg; - st->chip_info = - &ad5791_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + 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)) @@ -349,39 +339,37 @@ static int __devinit ad5791_probe(struct spi_device *spi) ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); if (ret) - goto error_free_dev; - - st->reg_vdd = reg_vdd; - st->reg_vss = reg_vss; + 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_free_dev; + goto error_disable_reg_neg; return 0; -error_free_dev: - iio_free_device(indio_dev); - error_disable_reg_neg: - if (!IS_ERR(reg_vss)) - regulator_disable(reg_vss); + if (!IS_ERR(st->reg_vss)) + regulator_disable(st->reg_vss); error_put_reg_neg: - if (!IS_ERR(reg_vss)) - regulator_put(reg_vss); + if (!IS_ERR(st->reg_vss)) + regulator_put(st->reg_vss); - if (!IS_ERR(reg_vdd)) - regulator_disable(reg_vdd); + if (!IS_ERR(st->reg_vdd)) + regulator_disable(st->reg_vdd); error_put_reg_pos: - if (!IS_ERR(reg_vdd)) - regulator_put(reg_vdd); - + if (!IS_ERR(st->reg_vdd)) + regulator_put(st->reg_vdd); + iio_free_device(indio_dev); error_ret: + return ret; } @@ -389,20 +377,18 @@ 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); - struct regulator *reg_vdd = st->reg_vdd; - struct regulator *reg_vss = st->reg_vss; iio_device_unregister(indio_dev); - if (!IS_ERR(st->reg_vdd)) { - regulator_disable(reg_vdd); - regulator_put(reg_vdd); + regulator_disable(st->reg_vdd); + regulator_put(st->reg_vdd); } if (!IS_ERR(st->reg_vss)) { - regulator_disable(reg_vss); - regulator_put(reg_vss); + regulator_disable(st->reg_vss); + regulator_put(st->reg_vss); } + iio_free_device(indio_dev); return 0; } diff --git a/drivers/staging/iio/dac/ad5791.h b/drivers/staging/iio/dac/ad5791.h index c807f26..fd7edbd 100644 --- a/drivers/staging/iio/dac/ad5791.h +++ b/drivers/staging/iio/dac/ad5791.h @@ -68,14 +68,10 @@ struct ad5791_platform_data { /** * struct ad5791_chip_info - chip specific information - * @bits: accuracy of the DAC in bits - * @left_shift: number of bits the datum must be shifted * @get_lin_comp: function pointer to the device specific function */ struct ad5791_chip_info { - u8 bits; - u8 left_shift; int (*get_lin_comp) (unsigned int span); }; @@ -86,6 +82,7 @@ struct ad5791_chip_info { * @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 */ @@ -95,6 +92,7 @@ struct ad5791_state { 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; diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h index 1d82f35..0754d71 100644 --- a/drivers/staging/iio/dac/dac.h +++ b/drivers/staging/iio/dac/dac.h @@ -3,4 +3,4 @@ */ #define IIO_DEV_ATTR_OUT_RAW(_num, _store, _addr) \ - IIO_DEVICE_ATTR(out##_num##_raw, S_IWUSR, NULL, _store, _addr) + IIO_DEVICE_ATTR(out_voltage##_num##_raw, S_IWUSR, NULL, _store, _addr) diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c index ed5d351..adfbd20 100644 --- a/drivers/staging/iio/dac/max517.c +++ b/drivers/staging/iio/dac/max517.c @@ -26,6 +26,7 @@ #include <linux/err.h> #include "../iio.h" +#include "../sysfs.h" #include "dac.h" #include "max517.h" @@ -58,8 +59,8 @@ static ssize_t max517_set_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count, int channel) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct max517_data *data = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct max517_data *data = iio_priv(indio_dev); struct i2c_client *client = data->client; u8 outbuf[4]; /* 1x or 2x command + value */ int outbuf_size = 0; @@ -119,15 +120,16 @@ static ssize_t max517_set_value_both(struct device *dev, { return max517_set_value(dev, attr, buf, count, 3); } -static IIO_DEVICE_ATTR_NAMED(out1and2_raw, out1&2_raw, S_IWUSR, NULL, - max517_set_value_both, -1); +static IIO_DEVICE_ATTR_NAMED(out_voltage1and2_raw, + out_voltage1&2_raw, S_IWUSR, NULL, + max517_set_value_both, -1); static ssize_t max517_show_scale(struct device *dev, struct device_attribute *attr, char *buf, int channel) { - struct iio_dev *dev_info = dev_get_drvdata(dev); - struct max517_data *data = iio_priv(dev_info); + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct max517_data *data = iio_priv(indio_dev); /* Corresponds to Vref / 2^(bits) */ unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8; @@ -140,7 +142,8 @@ static ssize_t max517_show_scale1(struct device *dev, { return max517_show_scale(dev, attr, buf, 1); } -static IIO_DEVICE_ATTR(out1_scale, S_IRUGO, max517_show_scale1, NULL, 0); +static IIO_DEVICE_ATTR(out_voltage1_scale, S_IRUGO, + max517_show_scale1, NULL, 0); static ssize_t max517_show_scale2(struct device *dev, struct device_attribute *attr, @@ -148,12 +151,13 @@ static ssize_t max517_show_scale2(struct device *dev, { return max517_show_scale(dev, attr, buf, 2); } -static IIO_DEVICE_ATTR(out2_scale, S_IRUGO, max517_show_scale2, NULL, 0); +static IIO_DEVICE_ATTR(out_voltage2_scale, S_IRUGO, + max517_show_scale2, NULL, 0); /* On MAX517 variant, we have one output */ static struct attribute *max517_attributes[] = { - &iio_dev_attr_out1_raw.dev_attr.attr, - &iio_dev_attr_out1_scale.dev_attr.attr, + &iio_dev_attr_out_voltage1_raw.dev_attr.attr, + &iio_dev_attr_out_voltage1_scale.dev_attr.attr, NULL }; @@ -163,11 +167,11 @@ static struct attribute_group max517_attribute_group = { /* On MAX518 and MAX519 variant, we have two outputs */ static struct attribute *max518_attributes[] = { - &iio_dev_attr_out1_raw.dev_attr.attr, - &iio_dev_attr_out1_scale.dev_attr.attr, - &iio_dev_attr_out2_raw.dev_attr.attr, - &iio_dev_attr_out2_scale.dev_attr.attr, - &iio_dev_attr_out1and2_raw.dev_attr.attr, + &iio_dev_attr_out_voltage1_raw.dev_attr.attr, + &iio_dev_attr_out_voltage1_scale.dev_attr.attr, + &iio_dev_attr_out_voltage2_raw.dev_attr.attr, + &iio_dev_attr_out_voltage2_scale.dev_attr.attr, + &iio_dev_attr_out_voltage1and2_raw.dev_attr.attr, NULL }; |