From 8341dc04dfb33fbae71727ae648e20c51abc40e3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 16 Oct 2012 17:29:00 +0100 Subject: iio:dac: Add support for the ad5449 This patch adds support for the AD5415, AD5426, AD5429, AD5432, AD5439, AD5443 and AD5449 single and dual channel DACs. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- include/linux/platform_data/ad5449.h | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 include/linux/platform_data/ad5449.h (limited to 'include/linux/platform_data') diff --git a/include/linux/platform_data/ad5449.h b/include/linux/platform_data/ad5449.h new file mode 100644 index 00000000000..bd712bd4b94 --- /dev/null +++ b/include/linux/platform_data/ad5449.h @@ -0,0 +1,40 @@ +/* + * AD5415, AD5426, AD5429, AD5432, AD5439, AD5443, AD5449 Digital to Analog + * Converter driver. + * + * Copyright 2012 Analog Devices Inc. + * Author: Lars-Peter Clausen + * + * Licensed under the GPL-2. + */ + +#ifndef __LINUX_PLATFORM_DATA_AD5449_H__ +#define __LINUX_PLATFORM_DATA_AD5449_H__ + +/** + * enum ad5449_sdo_mode - AD5449 SDO pin configuration + * @AD5449_SDO_DRIVE_FULL: Drive the SDO pin with full strength. + * @AD5449_SDO_DRIVE_WEAK: Drive the SDO pin with not full strength. + * @AD5449_SDO_OPEN_DRAIN: Operate the SDO pin in open-drain mode. + * @AD5449_SDO_DISABLED: Disable the SDO pin, in this mode it is not possible to + * read back from the device. + */ +enum ad5449_sdo_mode { + AD5449_SDO_DRIVE_FULL = 0x0, + AD5449_SDO_DRIVE_WEAK = 0x1, + AD5449_SDO_OPEN_DRAIN = 0x2, + AD5449_SDO_DISABLED = 0x3, +}; + +/** + * struct ad5449_platform_data - Platform data for the ad5449 DAC driver + * @sdo_mode: SDO pin mode + * @hardware_clear_to_midscale: Whether asserting the hardware CLR pin sets the + * outputs to midscale (true) or to zero scale(false). + */ +struct ad5449_platform_data { + enum ad5449_sdo_mode sdo_mode; + bool hardware_clear_to_midscale; +}; + +#endif -- cgit v1.2.3-70-g09d2 From 5e3b08749951e5746d3e747f1ffae37eff2d08d5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 29 Oct 2012 09:31:12 +0100 Subject: staging: drm/omap: add support for ARCH_MULTIPLATFORM Remove usage of plat/cpu.h and get information from platform data instead. This enables omapdrm to be built with ARCH_MULTIPLATFORM. Signed-off-by: Rob Clark Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/drm.c | 7 +++++++ drivers/staging/omapdrm/Kconfig | 2 +- drivers/staging/omapdrm/omap_dmm_tiler.h | 1 - drivers/staging/omapdrm/omap_drv.c | 6 +++++- drivers/staging/omapdrm/omap_drv.h | 2 ++ include/linux/platform_data/omap_drm.h | 1 + 6 files changed, 16 insertions(+), 3 deletions(-) (limited to 'include/linux/platform_data') diff --git a/arch/arm/mach-omap2/drm.c b/arch/arm/mach-omap2/drm.c index 72e0f01b715..49a7ffb716a 100644 --- a/arch/arm/mach-omap2/drm.c +++ b/arch/arm/mach-omap2/drm.c @@ -23,15 +23,20 @@ #include #include #include +#include #include #include +#include #if defined(CONFIG_DRM_OMAP) || (CONFIG_DRM_OMAP_MODULE) +static struct omap_drm_platform_data platform_data; + static struct platform_device omap_drm_device = { .dev = { .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &platform_data, }, .name = "omapdrm", .id = 0, @@ -52,6 +57,8 @@ static int __init omap_init_drm(void) oh->name); } + platform_data.omaprev = GET_OMAP_REVISION(); + return platform_device_register(&omap_drm_device); } diff --git a/drivers/staging/omapdrm/Kconfig b/drivers/staging/omapdrm/Kconfig index 81a7cba4a0c..b724a413143 100644 --- a/drivers/staging/omapdrm/Kconfig +++ b/drivers/staging/omapdrm/Kconfig @@ -2,7 +2,7 @@ config DRM_OMAP tristate "OMAP DRM" depends on DRM && !CONFIG_FB_OMAP2 - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM select DRM_KMS_HELPER select OMAP2_DSS select FB_SYS_FILLRECT diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.h b/drivers/staging/omapdrm/omap_dmm_tiler.h index c0271a2ac87..4fdd61e54bd 100644 --- a/drivers/staging/omapdrm/omap_dmm_tiler.h +++ b/drivers/staging/omapdrm/omap_dmm_tiler.h @@ -16,7 +16,6 @@ #ifndef OMAP_DMM_TILER_H #define OMAP_DMM_TILER_H -#include #include "omap_drv.h" #include "tcm.h" diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 09653b88e0e..6ae2f763b27 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -417,13 +417,14 @@ static void omap_modeset_free(struct drm_device *dev) static int ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file_priv) { + struct omap_drm_private *priv = dev->dev_private; struct drm_omap_param *args = data; DBG("%p: param=%llu", dev, args->param); switch (args->param) { case OMAP_PARAM_CHIPSET_ID: - args->value = GET_OMAP_TYPE; + args->value = priv->omaprev; break; default: DBG("unknown parameter %lld", args->param); @@ -555,6 +556,7 @@ struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = { */ static int dev_load(struct drm_device *dev, unsigned long flags) { + struct omap_drm_platform_data *pdata = dev->dev->platform_data; struct omap_drm_private *priv; int ret; @@ -566,6 +568,8 @@ static int dev_load(struct drm_device *dev, unsigned long flags) return -ENOMEM; } + priv->omaprev = pdata->omaprev; + dev->dev_private = priv; priv->wq = alloc_ordered_workqueue("omapdrm", 0); diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 9dc72d143ff..8f7c447930f 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h @@ -40,6 +40,8 @@ #define MAX_MAPPERS 2 struct omap_drm_private { + uint32_t omaprev; + unsigned int num_crtcs; struct drm_crtc *crtcs[8]; diff --git a/include/linux/platform_data/omap_drm.h b/include/linux/platform_data/omap_drm.h index 3da73bdc203..f4e4a237ebd 100644 --- a/include/linux/platform_data/omap_drm.h +++ b/include/linux/platform_data/omap_drm.h @@ -46,6 +46,7 @@ struct omap_kms_platform_data { }; struct omap_drm_platform_data { + uint32_t omaprev; struct omap_kms_platform_data *kms_pdata; }; -- cgit v1.2.3-70-g09d2 From 4eb3ccf157639a9d9c7829de94017c46c73d9cc4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 5 Nov 2012 09:56:00 +0000 Subject: staging:iio: Move the ad7887 driver out of staging The driver does not expose any custom API to userspace and none of the standard static code checker tools report any issues, so move it out of staging. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 13 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7887.c | 378 +++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/Kconfig | 13 -- drivers/staging/iio/adc/Makefile | 2 - drivers/staging/iio/adc/ad7887.c | 378 ----------------------------------- drivers/staging/iio/adc/ad7887.h | 31 --- include/linux/platform_data/ad7887.h | 26 +++ 8 files changed, 418 insertions(+), 424 deletions(-) create mode 100644 drivers/iio/adc/ad7887.c delete mode 100644 drivers/staging/iio/adc/ad7887.c delete mode 100644 drivers/staging/iio/adc/ad7887.h create mode 100644 include/linux/platform_data/ad7887.h (limited to 'include/linux/platform_data') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 49275812033..706386ba02e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -45,6 +45,19 @@ config AD7476 To compile this driver as a module, choose M here: the module will be called ad7476. +config AD7887 + tristate "Analog Devices AD7887 ADC driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices + AD7887 SPI analog to digital converter (ADC). + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called ad7887. + config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 900995d5e17..034eacb8f7c 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o +obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c new file mode 100644 index 00000000000..fd62309b4d3 --- /dev/null +++ b/drivers/iio/adc/ad7887.c @@ -0,0 +1,378 @@ +/* + * AD7887 SPI ADC driver + * + * Copyright 2010-2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */ +#define AD7887_DUAL (1 << 4) /* dual-channel mode */ +#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */ +#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */ +#define AD7887_PM_MODE1 (0) /* CS based shutdown */ +#define AD7887_PM_MODE2 (1) /* full on */ +#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */ +#define AD7887_PM_MODE4 (3) /* standby mode */ + +enum ad7887_channels { + AD7887_CH0, + AD7887_CH0_CH1, + AD7887_CH1, +}; + +#define RES_MASK(bits) ((1 << (bits)) - 1) + +/** + * struct ad7887_chip_info - chip specifc information + * @int_vref_mv: the internal reference voltage + * @channel: channel specification + */ +struct ad7887_chip_info { + u16 int_vref_mv; + struct iio_chan_spec channel[3]; +}; + +struct ad7887_state { + struct spi_device *spi; + const struct ad7887_chip_info *chip_info; + struct regulator *reg; + struct spi_transfer xfer[4]; + struct spi_message msg[3]; + struct spi_message *ring_msg; + unsigned char tx_cmd_buf[4]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * Buffer needs to be large enough to hold two 16 bit samples and a + * 64 bit aligned 64 bit timestamp. + */ + unsigned char data[ALIGN(4, sizeof(s64)) + sizeof(s64)] + ____cacheline_aligned; +}; + +enum ad7887_supported_device_ids { + ID_AD7887 +}; + +static int ad7887_ring_preenable(struct iio_dev *indio_dev) +{ + struct ad7887_state *st = iio_priv(indio_dev); + int ret; + + ret = iio_sw_buffer_preenable(indio_dev); + if (ret < 0) + return ret; + + /* We know this is a single long so can 'cheat' */ + switch (*indio_dev->active_scan_mask) { + case (1 << 0): + st->ring_msg = &st->msg[AD7887_CH0]; + break; + case (1 << 1): + st->ring_msg = &st->msg[AD7887_CH1]; + /* Dummy read: push CH1 setting down to hardware */ + spi_sync(st->spi, st->ring_msg); + break; + case ((1 << 1) | (1 << 0)): + st->ring_msg = &st->msg[AD7887_CH0_CH1]; + break; + } + + return 0; +} + +static int ad7887_ring_postdisable(struct iio_dev *indio_dev) +{ + struct ad7887_state *st = iio_priv(indio_dev); + + /* dummy read: restore default CH0 settin */ + return spi_sync(st->spi, &st->msg[AD7887_CH0]); +} + +/** + * ad7887_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad7887_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7887_state *st = iio_priv(indio_dev); + s64 time_ns; + int b_sent; + + b_sent = spi_sync(st->spi, st->ring_msg); + if (b_sent) + goto done; + + time_ns = iio_get_time_ns(); + + if (indio_dev->scan_timestamp) + memcpy(st->data + indio_dev->scan_bytes - sizeof(s64), + &time_ns, sizeof(time_ns)); + + iio_push_to_buffer(indio_dev->buffer, st->data); +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = { + .preenable = &ad7887_ring_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &ad7887_ring_postdisable, +}; + +static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch) +{ + int ret = spi_sync(st->spi, &st->msg[ch]); + if (ret) + return ret; + + return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1]; +} + +static int ad7887_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + int ret; + struct ad7887_state *st = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + if (iio_buffer_enabled(indio_dev)) + ret = -EBUSY; + else + ret = ad7887_scan_direct(st, chan->address); + mutex_unlock(&indio_dev->mlock); + + if (ret < 0) + return ret; + *val = ret >> chan->scan_type.shift; + *val &= RES_MASK(chan->scan_type.realbits); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (st->reg) { + *val = regulator_get_voltage(st->reg); + if (*val < 0) + return *val; + *val /= 1000; + } else { + *val = st->chip_info->int_vref_mv; + } + + *val2 = chan->scan_type.realbits; + + return IIO_VAL_FRACTIONAL_LOG2; + } + return -EINVAL; +} + + +static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { + /* + * More devices added in future + */ + [ID_AD7887] = { + .channel[0] = { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 1, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = 1, + .scan_index = 1, + .scan_type = IIO_ST('u', 12, 16, 0), + }, + .channel[1] = { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT, + .address = 0, + .scan_index = 0, + .scan_type = IIO_ST('u', 12, 16, 0), + }, + .channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2), + .int_vref_mv = 2500, + }, +}; + +static const struct iio_info ad7887_info = { + .read_raw = &ad7887_read_raw, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad7887_probe(struct spi_device *spi) +{ + struct ad7887_platform_data *pdata = spi->dev.platform_data; + struct ad7887_state *st; + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + uint8_t mode; + int ret; + + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + + if (!pdata || !pdata->use_onchip_ref) { + st->reg = regulator_get(&spi->dev, "vref"); + if (IS_ERR(st->reg)) { + ret = PTR_ERR(st->reg); + goto error_free; + } + + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + } + + st->chip_info = + &ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + spi_set_drvdata(spi, indio_dev); + st->spi = spi; + + /* Estabilish 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 = &ad7887_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + /* Setup default message */ + + mode = AD7887_PM_MODE4; + if (!pdata || !pdata->use_onchip_ref) + mode |= AD7887_REF_DIS; + if (pdata && pdata->en_dual) + mode |= AD7887_DUAL; + + st->tx_cmd_buf[0] = AD7887_CH_AIN0 | mode; + + st->xfer[0].rx_buf = &st->data[0]; + st->xfer[0].tx_buf = &st->tx_cmd_buf[0]; + st->xfer[0].len = 2; + + spi_message_init(&st->msg[AD7887_CH0]); + spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]); + + if (pdata && pdata->en_dual) { + st->tx_cmd_buf[2] = AD7887_CH_AIN1 | mode; + + st->xfer[1].rx_buf = &st->data[0]; + st->xfer[1].tx_buf = &st->tx_cmd_buf[2]; + st->xfer[1].len = 2; + + st->xfer[2].rx_buf = &st->data[2]; + st->xfer[2].tx_buf = &st->tx_cmd_buf[0]; + st->xfer[2].len = 2; + + spi_message_init(&st->msg[AD7887_CH0_CH1]); + spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]); + spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]); + + st->xfer[3].rx_buf = &st->data[2]; + st->xfer[3].tx_buf = &st->tx_cmd_buf[2]; + st->xfer[3].len = 2; + + spi_message_init(&st->msg[AD7887_CH1]); + spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]); + + indio_dev->channels = st->chip_info->channel; + indio_dev->num_channels = 3; + } else { + indio_dev->channels = &st->chip_info->channel[1]; + indio_dev->num_channels = 2; + } + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &ad7887_trigger_handler, &ad7887_ring_setup_ops); + if (ret) + goto error_disable_reg; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_unregister_ring; + + return 0; +error_unregister_ring: + iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: + if (st->reg) + regulator_disable(st->reg); +error_put_reg: + if (st->reg) + regulator_put(st->reg); +error_free: + iio_device_free(indio_dev); + + return ret; +} + +static int __devexit ad7887_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad7887_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + if (st->reg) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad7887_id[] = { + {"ad7887", ID_AD7887}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7887_id); + +static struct spi_driver ad7887_driver = { + .driver = { + .name = "ad7887", + .owner = THIS_MODULE, + }, + .probe = ad7887_probe, + .remove = __devexit_p(ad7887_remove), + .id_table = ad7887_id, +}; +module_spi_driver(ad7887_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7887 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 71a515d0a6d..eba64fb64d8 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -68,19 +68,6 @@ config AD799X_RING_BUFFER Say yes here to include ring buffer support in the AD799X ADC driver. -config AD7887 - tristate "Analog Devices AD7887 ADC driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices - AD7887 SPI analog to digital converter (ADC). - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad7887. - config AD7780 tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 8036fd14f68..c56b41ee285 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -17,8 +17,6 @@ ad799x-y := ad799x_core.o ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o obj-$(CONFIG_AD799X) += ad799x.o -obj-$(CONFIG_AD7887) += ad7887.o - ad7298-y := ad7298_core.o ad7298-$(CONFIG_IIO_BUFFER) += ad7298_ring.o obj-$(CONFIG_AD7298) += ad7298.o diff --git a/drivers/staging/iio/adc/ad7887.c b/drivers/staging/iio/adc/ad7887.c deleted file mode 100644 index 72cfe191cd8..00000000000 --- a/drivers/staging/iio/adc/ad7887.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * AD7887 SPI ADC driver - * - * Copyright 2010-2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "ad7887.h" - -#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */ -#define AD7887_DUAL (1 << 4) /* dual-channel mode */ -#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */ -#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */ -#define AD7887_PM_MODE1 (0) /* CS based shutdown */ -#define AD7887_PM_MODE2 (1) /* full on */ -#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */ -#define AD7887_PM_MODE4 (3) /* standby mode */ - -enum ad7887_channels { - AD7887_CH0, - AD7887_CH0_CH1, - AD7887_CH1, -}; - -#define RES_MASK(bits) ((1 << (bits)) - 1) - -/** - * struct ad7887_chip_info - chip specifc information - * @int_vref_mv: the internal reference voltage - * @channel: channel specification - */ -struct ad7887_chip_info { - u16 int_vref_mv; - struct iio_chan_spec channel[3]; -}; - -struct ad7887_state { - struct spi_device *spi; - const struct ad7887_chip_info *chip_info; - struct regulator *reg; - struct spi_transfer xfer[4]; - struct spi_message msg[3]; - struct spi_message *ring_msg; - unsigned char tx_cmd_buf[4]; - - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - * Buffer needs to be large enough to hold two 16 bit samples and a - * 64 bit aligned 64 bit timestamp. - */ - unsigned char data[ALIGN(4, sizeof(s64)) + sizeof(s64)] - ____cacheline_aligned; -}; - -enum ad7887_supported_device_ids { - ID_AD7887 -}; - -static int ad7887_ring_preenable(struct iio_dev *indio_dev) -{ - struct ad7887_state *st = iio_priv(indio_dev); - int ret; - - ret = iio_sw_buffer_preenable(indio_dev); - if (ret < 0) - return ret; - - /* We know this is a single long so can 'cheat' */ - switch (*indio_dev->active_scan_mask) { - case (1 << 0): - st->ring_msg = &st->msg[AD7887_CH0]; - break; - case (1 << 1): - st->ring_msg = &st->msg[AD7887_CH1]; - /* Dummy read: push CH1 setting down to hardware */ - spi_sync(st->spi, st->ring_msg); - break; - case ((1 << 1) | (1 << 0)): - st->ring_msg = &st->msg[AD7887_CH0_CH1]; - break; - } - - return 0; -} - -static int ad7887_ring_postdisable(struct iio_dev *indio_dev) -{ - struct ad7887_state *st = iio_priv(indio_dev); - - /* dummy read: restore default CH0 settin */ - return spi_sync(st->spi, &st->msg[AD7887_CH0]); -} - -/** - * ad7887_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - **/ -static irqreturn_t ad7887_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct ad7887_state *st = iio_priv(indio_dev); - s64 time_ns; - int b_sent; - - b_sent = spi_sync(st->spi, st->ring_msg); - if (b_sent) - goto done; - - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(st->data + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - - iio_push_to_buffer(indio_dev->buffer, st->data); -done: - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = { - .preenable = &ad7887_ring_preenable, - .postenable = &iio_triggered_buffer_postenable, - .predisable = &iio_triggered_buffer_predisable, - .postdisable = &ad7887_ring_postdisable, -}; - -static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch) -{ - int ret = spi_sync(st->spi, &st->msg[ch]); - if (ret) - return ret; - - return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1]; -} - -static int ad7887_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - int ret; - struct ad7887_state *st = iio_priv(indio_dev); - - switch (m) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad7887_scan_direct(st, chan->address); - mutex_unlock(&indio_dev->mlock); - - if (ret < 0) - return ret; - *val = ret >> chan->scan_type.shift; - *val &= RES_MASK(chan->scan_type.realbits); - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - if (st->reg) { - *val = regulator_get_voltage(st->reg); - if (*val < 0) - return *val; - *val /= 1000; - } else { - *val = st->chip_info->int_vref_mv; - } - - *val2 = chan->scan_type.realbits; - - return IIO_VAL_FRACTIONAL_LOG2; - } - return -EINVAL; -} - - -static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { - /* - * More devices added in future - */ - [ID_AD7887] = { - .channel[0] = { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 1, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = 1, - .scan_index = 1, - .scan_type = IIO_ST('u', 12, 16, 0), - }, - .channel[1] = { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT, - .address = 0, - .scan_index = 0, - .scan_type = IIO_ST('u', 12, 16, 0), - }, - .channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2), - .int_vref_mv = 2500, - }, -}; - -static const struct iio_info ad7887_info = { - .read_raw = &ad7887_read_raw, - .driver_module = THIS_MODULE, -}; - -static int __devinit ad7887_probe(struct spi_device *spi) -{ - struct ad7887_platform_data *pdata = spi->dev.platform_data; - struct ad7887_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); - uint8_t mode; - int ret; - - if (indio_dev == NULL) - return -ENOMEM; - - st = iio_priv(indio_dev); - - if (!pdata || !pdata->use_onchip_ref) { - st->reg = regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) { - ret = PTR_ERR(st->reg); - goto error_free; - } - - ret = regulator_enable(st->reg); - if (ret) - goto error_put_reg; - } - - st->chip_info = - &ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - - spi_set_drvdata(spi, indio_dev); - st->spi = spi; - - /* Estabilish 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 = &ad7887_info; - indio_dev->modes = INDIO_DIRECT_MODE; - - /* Setup default message */ - - mode = AD7887_PM_MODE4; - if (!pdata || !pdata->use_onchip_ref) - mode |= AD7887_REF_DIS; - if (pdata && pdata->en_dual) - mode |= AD7887_DUAL; - - st->tx_cmd_buf[0] = AD7887_CH_AIN0 | mode; - - st->xfer[0].rx_buf = &st->data[0]; - st->xfer[0].tx_buf = &st->tx_cmd_buf[0]; - st->xfer[0].len = 2; - - spi_message_init(&st->msg[AD7887_CH0]); - spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]); - - if (pdata && pdata->en_dual) { - st->tx_cmd_buf[2] = AD7887_CH_AIN1 | mode; - - st->xfer[1].rx_buf = &st->data[0]; - st->xfer[1].tx_buf = &st->tx_cmd_buf[2]; - st->xfer[1].len = 2; - - st->xfer[2].rx_buf = &st->data[2]; - st->xfer[2].tx_buf = &st->tx_cmd_buf[0]; - st->xfer[2].len = 2; - - spi_message_init(&st->msg[AD7887_CH0_CH1]); - spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]); - spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]); - - st->xfer[3].rx_buf = &st->data[2]; - st->xfer[3].tx_buf = &st->tx_cmd_buf[2]; - st->xfer[3].len = 2; - - spi_message_init(&st->msg[AD7887_CH1]); - spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]); - - indio_dev->channels = st->chip_info->channel; - indio_dev->num_channels = 3; - } else { - indio_dev->channels = &st->chip_info->channel[1]; - indio_dev->num_channels = 2; - } - - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - &ad7887_trigger_handler, &ad7887_ring_setup_ops); - if (ret) - goto error_disable_reg; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_unregister_ring; - - return 0; -error_unregister_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - if (st->reg) - regulator_disable(st->reg); -error_put_reg: - if (st->reg) - regulator_put(st->reg); -error_free: - iio_device_free(indio_dev); - - return ret; -} - -static int __devexit ad7887_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad7887_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - if (st->reg) { - regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); - - return 0; -} - -static const struct spi_device_id ad7887_id[] = { - {"ad7887", ID_AD7887}, - {} -}; -MODULE_DEVICE_TABLE(spi, ad7887_id); - -static struct spi_driver ad7887_driver = { - .driver = { - .name = "ad7887", - .owner = THIS_MODULE, - }, - .probe = ad7887_probe, - .remove = __devexit_p(ad7887_remove), - .id_table = ad7887_id, -}; -module_spi_driver(ad7887_driver); - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7887 ADC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h deleted file mode 100644 index 16c2d05e5e0..00000000000 --- a/drivers/staging/iio/adc/ad7887.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * AD7887 SPI ADC driver - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ -#ifndef IIO_ADC_AD7887_H_ -#define IIO_ADC_AD7887_H_ - -/* - * TODO: struct ad7887_platform_data needs to go into include/linux/iio - */ - - -/** - * struct ad7887_platform_data - AD7887 ADC driver platform data - * @en_dual: Whether to use dual channel mode. If set to true AIN1 becomes the - * second input channel, and Vref is internally connected to Vdd. If set to - * false the device is used in single channel mode and AIN1/Vref is used as - * VREF input. - * @use_onchip_ref: Whether to use the onchip reference. If set to true the - * internal 2.5V reference is used. If set to false a external reference is - * used. - */ -struct ad7887_platform_data { - bool en_dual; - bool use_onchip_ref; -}; - -#endif /* IIO_ADC_AD7887_H_ */ diff --git a/include/linux/platform_data/ad7887.h b/include/linux/platform_data/ad7887.h new file mode 100644 index 00000000000..1e06eac3174 --- /dev/null +++ b/include/linux/platform_data/ad7887.h @@ -0,0 +1,26 @@ +/* + * AD7887 SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ +#ifndef IIO_ADC_AD7887_H_ +#define IIO_ADC_AD7887_H_ + +/** + * struct ad7887_platform_data - AD7887 ADC driver platform data + * @en_dual: Whether to use dual channel mode. If set to true AIN1 becomes the + * second input channel, and Vref is internally connected to Vdd. If set to + * false the device is used in single channel mode and AIN1/Vref is used as + * VREF input. + * @use_onchip_ref: Whether to use the onchip reference. If set to true the + * internal 2.5V reference is used. If set to false a external reference is + * used. + */ +struct ad7887_platform_data { + bool en_dual; + bool use_onchip_ref; +}; + +#endif /* IIO_ADC_AD7887_H_ */ -- cgit v1.2.3-70-g09d2 From 709ab36e9559ff5c7df6e6f2d9e3c4a4410f8d49 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 17 Nov 2012 11:42:59 +0000 Subject: staging:iio: Move the ad7298 driver out of staging The driver does not expose any custom API to userspace and none of the standard static code checker tools report any issues, so move it out of staging. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 12 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7298.c | 408 +++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/Kconfig | 12 -- drivers/staging/iio/adc/Makefile | 2 - drivers/staging/iio/adc/ad7298.c | 408 ----------------------------------- drivers/staging/iio/adc/ad7298.h | 20 -- include/linux/platform_data/ad7298.h | 20 ++ 8 files changed, 441 insertions(+), 442 deletions(-) create mode 100644 drivers/iio/adc/ad7298.c delete mode 100644 drivers/staging/iio/adc/ad7298.c delete mode 100644 drivers/staging/iio/adc/ad7298.h create mode 100644 include/linux/platform_data/ad7298.h (limited to 'include/linux/platform_data') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index ef5200a6850..cd5eed60be2 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -18,6 +18,18 @@ config AD7266 Say yes here to build support for Analog Devices AD7265 and AD7266 ADCs. +config AD7298 + tristate "Analog Devices AD7298 ADC driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices AD7298 + 8 Channel ADC with temperature sensor. + + To compile this driver as a module, choose M here: the + module will be called ad7298. + config AD7791 tristate "Analog Devices AD7791 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 54ac7bbcd01..3256dc64a46 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7266) += ad7266.o +obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AD7887) += ad7887.o diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c new file mode 100644 index 00000000000..441a9a265c1 --- /dev/null +++ b/drivers/iio/adc/ad7298.c @@ -0,0 +1,408 @@ +/* + * AD7298 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define AD7298_WRITE (1 << 15) /* write to the control register */ +#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */ +#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */ +#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */ +#define AD7298_EXTREF (1 << 2) /* external reference enable */ +#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */ +#define AD7298_PDD (1 << 0) /* partial power down enable */ + +#define AD7298_MAX_CHAN 8 +#define AD7298_BITS 12 +#define AD7298_STORAGE_BITS 16 +#define AD7298_INTREF_mV 2500 + +#define AD7298_CH_TEMP 9 + +#define RES_MASK(bits) ((1 << (bits)) - 1) + +struct ad7298_state { + struct spi_device *spi; + struct regulator *reg; + unsigned ext_ref; + struct spi_transfer ring_xfer[10]; + struct spi_transfer scan_single_xfer[3]; + struct spi_message ring_msg; + struct spi_message scan_single_msg; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + unsigned short rx_buf[12] ____cacheline_aligned; + unsigned short tx_buf[2]; +}; + +#define AD7298_V_CHAN(index) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = index, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT, \ + .address = index, \ + .scan_index = index, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec ad7298_channels[] = { + { + .type = IIO_TEMP, + .indexed = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, + .address = AD7298_CH_TEMP, + .scan_index = -1, + .scan_type = { + .sign = 's', + .realbits = 32, + .storagebits = 32, + }, + }, + AD7298_V_CHAN(0), + AD7298_V_CHAN(1), + AD7298_V_CHAN(2), + AD7298_V_CHAN(3), + AD7298_V_CHAN(4), + AD7298_V_CHAN(5), + AD7298_V_CHAN(6), + AD7298_V_CHAN(7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +/** + * ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask + **/ +static int ad7298_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *active_scan_mask) +{ + struct ad7298_state *st = iio_priv(indio_dev); + int i, m; + unsigned short command; + int scan_count; + + /* Now compute overall size */ + scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength); + + command = AD7298_WRITE | st->ext_ref; + + for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1) + if (test_bit(i, active_scan_mask)) + command |= m; + + st->tx_buf[0] = cpu_to_be16(command); + + /* build spi ring message */ + st->ring_xfer[0].tx_buf = &st->tx_buf[0]; + st->ring_xfer[0].len = 2; + st->ring_xfer[0].cs_change = 1; + st->ring_xfer[1].tx_buf = &st->tx_buf[1]; + st->ring_xfer[1].len = 2; + st->ring_xfer[1].cs_change = 1; + + spi_message_init(&st->ring_msg); + spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); + spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg); + + for (i = 0; i < scan_count; i++) { + st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i]; + st->ring_xfer[i + 2].len = 2; + st->ring_xfer[i + 2].cs_change = 1; + spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg); + } + /* make sure last transfer cs_change is not set */ + st->ring_xfer[i + 1].cs_change = 0; + + return 0; +} + +/** + * ad7298_trigger_handler() bh of trigger launched polling to ring buffer + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + **/ +static irqreturn_t ad7298_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7298_state *st = iio_priv(indio_dev); + s64 time_ns = 0; + int b_sent; + + b_sent = spi_sync(st->spi, &st->ring_msg); + if (b_sent) + goto done; + + if (indio_dev->scan_timestamp) { + time_ns = iio_get_time_ns(); + memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64), + &time_ns, sizeof(time_ns)); + } + + iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf); + +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) +{ + int ret; + st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref | + (AD7298_CH(0) >> ch)); + + ret = spi_sync(st->spi, &st->scan_single_msg); + if (ret) + return ret; + + return be16_to_cpu(st->rx_buf[0]); +} + +static int ad7298_scan_temp(struct ad7298_state *st, int *val) +{ + int ret; + __be16 buf; + + buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | + AD7298_TAVG | st->ext_ref); + + ret = spi_write(st->spi, (u8 *)&buf, 2); + if (ret) + return ret; + + buf = cpu_to_be16(0); + + ret = spi_write(st->spi, (u8 *)&buf, 2); + if (ret) + return ret; + + usleep_range(101, 1000); /* sleep > 100us */ + + ret = spi_read(st->spi, (u8 *)&buf, 2); + if (ret) + return ret; + + *val = sign_extend32(be16_to_cpu(buf), 11); + + return 0; +} + +static int ad7298_get_ref_voltage(struct ad7298_state *st) +{ + int vref; + + if (st->ext_ref) { + vref = regulator_get_voltage(st->reg); + if (vref < 0) + return vref; + + return vref / 1000; + } else { + return AD7298_INTREF_mV; + } +} + +static int ad7298_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + int ret; + struct ad7298_state *st = iio_priv(indio_dev); + + switch (m) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { + ret = -EBUSY; + } else { + if (chan->address == AD7298_CH_TEMP) + ret = ad7298_scan_temp(st, val); + else + ret = ad7298_scan_direct(st, chan->address); + } + mutex_unlock(&indio_dev->mlock); + + if (ret < 0) + return ret; + + if (chan->address != AD7298_CH_TEMP) + *val = ret & RES_MASK(AD7298_BITS); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + *val = ad7298_get_ref_voltage(st); + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_TEMP: + *val = ad7298_get_ref_voltage(st); + *val2 = 10; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + *val = 1093 - 2732500 / ad7298_get_ref_voltage(st); + return IIO_VAL_INT; + } + return -EINVAL; +} + +static const struct iio_info ad7298_info = { + .read_raw = &ad7298_read_raw, + .update_scan_mode = ad7298_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad7298_probe(struct spi_device *spi) +{ + struct ad7298_platform_data *pdata = spi->dev.platform_data; + struct ad7298_state *st; + struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); + int ret; + + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + + if (pdata && pdata->ext_ref) + st->ext_ref = AD7298_EXTREF; + + if (st->ext_ref) { + st->reg = regulator_get(&spi->dev, "vref"); + if (IS_ERR(st->reg)) { + ret = PTR_ERR(st->reg); + goto error_free; + } + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + } + + spi_set_drvdata(spi, indio_dev); + + st->spi = spi; + + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad7298_channels; + indio_dev->num_channels = ARRAY_SIZE(ad7298_channels); + indio_dev->info = &ad7298_info; + + /* Setup default message */ + + st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; + st->scan_single_xfer[0].len = 2; + st->scan_single_xfer[0].cs_change = 1; + st->scan_single_xfer[1].tx_buf = &st->tx_buf[1]; + st->scan_single_xfer[1].len = 2; + st->scan_single_xfer[1].cs_change = 1; + st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; + st->scan_single_xfer[2].len = 2; + + spi_message_init(&st->scan_single_msg); + spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg); + spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg); + spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg); + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &ad7298_trigger_handler, NULL); + if (ret) + goto error_disable_reg; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_cleanup_ring; + + return 0; + +error_cleanup_ring: + iio_triggered_buffer_cleanup(indio_dev); +error_disable_reg: + if (st->ext_ref) + regulator_disable(st->reg); +error_put_reg: + if (st->ext_ref) + regulator_put(st->reg); +error_free: + iio_device_free(indio_dev); + + return ret; +} + +static int __devexit ad7298_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad7298_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + if (st->ext_ref) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad7298_id[] = { + {"ad7298", 0}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7298_id); + +static struct spi_driver ad7298_driver = { + .driver = { + .name = "ad7298", + .owner = THIS_MODULE, + }, + .probe = ad7298_probe, + .remove = __devexit_p(ad7298_remove), + .id_table = ad7298_id, +}; +module_spi_driver(ad7298_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7298 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 5086a46b8e9..dc8582b95b6 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -10,18 +10,6 @@ config AD7291 Say yes here to build support for Analog Devices AD7291 8 Channel ADC with temperature sensor. -config AD7298 - tristate "Analog Devices AD7298 ADC driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices AD7298 - 8 Channel ADC with temperature sensor. - - To compile this driver as a module, choose M here: the - module will be called ad7298. - config AD7606 tristate "Analog Devices AD7606 ADC driver" depends on GPIOLIB diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 4beaa588256..7281451a613 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -12,8 +12,6 @@ ad799x-y := ad799x_core.o ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o obj-$(CONFIG_AD799X) += ad799x.o -obj-$(CONFIG_AD7298) += ad7298.o - obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7780) += ad7780.o obj-$(CONFIG_AD7793) += ad7793.o diff --git a/drivers/staging/iio/adc/ad7298.c b/drivers/staging/iio/adc/ad7298.c deleted file mode 100644 index 2742a9de05d..00000000000 --- a/drivers/staging/iio/adc/ad7298.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * AD7298 SPI ADC driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "ad7298.h" - -#define AD7298_WRITE (1 << 15) /* write to the control register */ -#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */ -#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */ -#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */ -#define AD7298_EXTREF (1 << 2) /* external reference enable */ -#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */ -#define AD7298_PDD (1 << 0) /* partial power down enable */ - -#define AD7298_MAX_CHAN 8 -#define AD7298_BITS 12 -#define AD7298_STORAGE_BITS 16 -#define AD7298_INTREF_mV 2500 - -#define AD7298_CH_TEMP 9 - -#define RES_MASK(bits) ((1 << (bits)) - 1) - -struct ad7298_state { - struct spi_device *spi; - struct regulator *reg; - unsigned ext_ref; - struct spi_transfer ring_xfer[10]; - struct spi_transfer scan_single_xfer[3]; - struct spi_message ring_msg; - struct spi_message scan_single_msg; - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - unsigned short rx_buf[12] ____cacheline_aligned; - unsigned short tx_buf[2]; -}; - -#define AD7298_V_CHAN(index) \ - { \ - .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = index, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SHARED_BIT, \ - .address = index, \ - .scan_index = index, \ - .scan_type = { \ - .sign = 'u', \ - .realbits = 12, \ - .storagebits = 16, \ - .endianness = IIO_BE, \ - }, \ - } - -static const struct iio_chan_spec ad7298_channels[] = { - { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, - .address = AD7298_CH_TEMP, - .scan_index = -1, - .scan_type = { - .sign = 's', - .realbits = 32, - .storagebits = 32, - }, - }, - AD7298_V_CHAN(0), - AD7298_V_CHAN(1), - AD7298_V_CHAN(2), - AD7298_V_CHAN(3), - AD7298_V_CHAN(4), - AD7298_V_CHAN(5), - AD7298_V_CHAN(6), - AD7298_V_CHAN(7), - IIO_CHAN_SOFT_TIMESTAMP(8), -}; - -/** - * ad7298_update_scan_mode() setup the spi transfer buffer for the new scan mask - **/ -static int ad7298_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *active_scan_mask) -{ - struct ad7298_state *st = iio_priv(indio_dev); - int i, m; - unsigned short command; - int scan_count; - - /* Now compute overall size */ - scan_count = bitmap_weight(active_scan_mask, indio_dev->masklength); - - command = AD7298_WRITE | st->ext_ref; - - for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1) - if (test_bit(i, active_scan_mask)) - command |= m; - - st->tx_buf[0] = cpu_to_be16(command); - - /* build spi ring message */ - st->ring_xfer[0].tx_buf = &st->tx_buf[0]; - st->ring_xfer[0].len = 2; - st->ring_xfer[0].cs_change = 1; - st->ring_xfer[1].tx_buf = &st->tx_buf[1]; - st->ring_xfer[1].len = 2; - st->ring_xfer[1].cs_change = 1; - - spi_message_init(&st->ring_msg); - spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); - spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg); - - for (i = 0; i < scan_count; i++) { - st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i]; - st->ring_xfer[i + 2].len = 2; - st->ring_xfer[i + 2].cs_change = 1; - spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg); - } - /* make sure last transfer cs_change is not set */ - st->ring_xfer[i + 1].cs_change = 0; - - return 0; -} - -/** - * ad7298_trigger_handler() bh of trigger launched polling to ring buffer - * - * Currently there is no option in this driver to disable the saving of - * timestamps within the ring. - **/ -static irqreturn_t ad7298_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct ad7298_state *st = iio_priv(indio_dev); - s64 time_ns = 0; - int b_sent; - - b_sent = spi_sync(st->spi, &st->ring_msg); - if (b_sent) - goto done; - - if (indio_dev->scan_timestamp) { - time_ns = iio_get_time_ns(); - memcpy((u8 *)st->rx_buf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - } - - iio_push_to_buffers(indio_dev, (u8 *)st->rx_buf); - -done: - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) -{ - int ret; - st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref | - (AD7298_CH(0) >> ch)); - - ret = spi_sync(st->spi, &st->scan_single_msg); - if (ret) - return ret; - - return be16_to_cpu(st->rx_buf[0]); -} - -static int ad7298_scan_temp(struct ad7298_state *st, int *val) -{ - int ret; - __be16 buf; - - buf = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | - AD7298_TAVG | st->ext_ref); - - ret = spi_write(st->spi, (u8 *)&buf, 2); - if (ret) - return ret; - - buf = cpu_to_be16(0); - - ret = spi_write(st->spi, (u8 *)&buf, 2); - if (ret) - return ret; - - usleep_range(101, 1000); /* sleep > 100us */ - - ret = spi_read(st->spi, (u8 *)&buf, 2); - if (ret) - return ret; - - *val = sign_extend32(be16_to_cpu(buf), 11); - - return 0; -} - -static int ad7298_get_ref_voltage(struct ad7298_state *st) -{ - int vref; - - if (st->ext_ref) { - vref = regulator_get_voltage(st->reg); - if (vref < 0) - return vref; - - return vref / 1000; - } else { - return AD7298_INTREF_mV; - } -} - -static int ad7298_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - int ret; - struct ad7298_state *st = iio_priv(indio_dev); - - switch (m) { - case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { - ret = -EBUSY; - } else { - if (chan->address == AD7298_CH_TEMP) - ret = ad7298_scan_temp(st, val); - else - ret = ad7298_scan_direct(st, chan->address); - } - mutex_unlock(&indio_dev->mlock); - - if (ret < 0) - return ret; - - if (chan->address != AD7298_CH_TEMP) - *val = ret & RES_MASK(AD7298_BITS); - - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_VOLTAGE: - *val = ad7298_get_ref_voltage(st); - *val2 = chan->scan_type.realbits; - return IIO_VAL_FRACTIONAL_LOG2; - case IIO_TEMP: - *val = ad7298_get_ref_voltage(st); - *val2 = 10; - return IIO_VAL_FRACTIONAL; - default: - return -EINVAL; - } - case IIO_CHAN_INFO_OFFSET: - *val = 1093 - 2732500 / ad7298_get_ref_voltage(st); - return IIO_VAL_INT; - } - return -EINVAL; -} - -static const struct iio_info ad7298_info = { - .read_raw = &ad7298_read_raw, - .update_scan_mode = ad7298_update_scan_mode, - .driver_module = THIS_MODULE, -}; - -static int __devinit ad7298_probe(struct spi_device *spi) -{ - struct ad7298_platform_data *pdata = spi->dev.platform_data; - struct ad7298_state *st; - struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st)); - int ret; - - if (indio_dev == NULL) - return -ENOMEM; - - st = iio_priv(indio_dev); - - if (pdata && pdata->ext_ref) - st->ext_ref = AD7298_EXTREF; - - if (st->ext_ref) { - st->reg = regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) { - ret = PTR_ERR(st->reg); - goto error_free; - } - ret = regulator_enable(st->reg); - if (ret) - goto error_put_reg; - } - - spi_set_drvdata(spi, indio_dev); - - st->spi = spi; - - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->dev.parent = &spi->dev; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = ad7298_channels; - indio_dev->num_channels = ARRAY_SIZE(ad7298_channels); - indio_dev->info = &ad7298_info; - - /* Setup default message */ - - st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; - st->scan_single_xfer[0].len = 2; - st->scan_single_xfer[0].cs_change = 1; - st->scan_single_xfer[1].tx_buf = &st->tx_buf[1]; - st->scan_single_xfer[1].len = 2; - st->scan_single_xfer[1].cs_change = 1; - st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; - st->scan_single_xfer[2].len = 2; - - spi_message_init(&st->scan_single_msg); - spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg); - spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg); - spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg); - - ret = iio_triggered_buffer_setup(indio_dev, NULL, - &ad7298_trigger_handler, NULL); - if (ret) - goto error_disable_reg; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_cleanup_ring; - - return 0; - -error_cleanup_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - if (st->ext_ref) - regulator_disable(st->reg); -error_put_reg: - if (st->ext_ref) - regulator_put(st->reg); -error_free: - iio_device_free(indio_dev); - - return ret; -} - -static int __devexit ad7298_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad7298_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - if (st->ext_ref) { - regulator_disable(st->reg); - regulator_put(st->reg); - } - iio_device_free(indio_dev); - - return 0; -} - -static const struct spi_device_id ad7298_id[] = { - {"ad7298", 0}, - {} -}; -MODULE_DEVICE_TABLE(spi, ad7298_id); - -static struct spi_driver ad7298_driver = { - .driver = { - .name = "ad7298", - .owner = THIS_MODULE, - }, - .probe = ad7298_probe, - .remove = __devexit_p(ad7298_remove), - .id_table = ad7298_id, -}; -module_spi_driver(ad7298_driver); - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7298 ADC"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h deleted file mode 100644 index c8ac969ec01..00000000000 --- a/drivers/staging/iio/adc/ad7298.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * AD7298 SPI ADC driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#ifndef IIO_ADC_AD7298_H_ -#define IIO_ADC_AD7298_H_ - -/** - * struct ad7298_platform_data - Platform data for the ad7298 ADC driver - * @ext_ref: Whether to use an external reference voltage. - **/ -struct ad7298_platform_data { - bool ext_ref; -}; - -#endif /* IIO_ADC_AD7298_H_ */ diff --git a/include/linux/platform_data/ad7298.h b/include/linux/platform_data/ad7298.h new file mode 100644 index 00000000000..fbf8adf1363 --- /dev/null +++ b/include/linux/platform_data/ad7298.h @@ -0,0 +1,20 @@ +/* + * AD7298 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef __LINUX_PLATFORM_DATA_AD7298_H__ +#define __LINUX_PLATFORM_DATA_AD7298_H__ + +/** + * struct ad7298_platform_data - Platform data for the ad7298 ADC driver + * @ext_ref: Whether to use an external reference voltage. + **/ +struct ad7298_platform_data { + bool ext_ref; +}; + +#endif /* IIO_ADC_AD7298_H_ */ -- cgit v1.2.3-70-g09d2 From f87f1a2375a51ef8c5048bfce42587dbea1ca627 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 21 Nov 2012 16:27:00 +0000 Subject: staging:iio: Move ad7793 driver out of staging The driver does not expose any custom API to userspace and none of the standard static code checker tools report any issues, so move it out of staging. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7793.c | 691 ++++++++++++++++++++++++++++++++++ drivers/staging/iio/adc/Kconfig | 12 - drivers/staging/iio/adc/Makefile | 1 - drivers/staging/iio/adc/ad7793.c | 692 ----------------------------------- drivers/staging/iio/adc/ad7793.h | 116 ------ include/linux/platform_data/ad7793.h | 112 ++++++ 8 files changed, 816 insertions(+), 821 deletions(-) create mode 100644 drivers/iio/adc/ad7793.c delete mode 100644 drivers/staging/iio/adc/ad7793.c delete mode 100644 drivers/staging/iio/adc/ad7793.h create mode 100644 include/linux/platform_data/ad7793.h (limited to 'include/linux/platform_data') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index cd5eed60be2..408557b0244 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -42,6 +42,18 @@ config AD7791 To compile this driver as a module, choose M here: the module will be called ad7791. +config AD7793 + tristate "Analog Devices AD7793 and similar ADCs driver" + depends on SPI + select AD_SIGMA_DELTA + help + Say yes here to build support for Analog Devices AD7785, AD7792, AD7793, + AD7794 and AD7795 SPI analog to digital converters (ADC). + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called AD7793. + config AD7476 tristate "Analog Devices AD7476 and similar 1-channel ADCs driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 3256dc64a46..78202d9eb96 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AD7298) += ad7298.o obj-$(CONFIG_AD7476) += ad7476.o obj-$(CONFIG_AD7791) += ad7791.o +obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c new file mode 100644 index 00000000000..a109e686b9f --- /dev/null +++ b/drivers/iio/adc/ad7793.c @@ -0,0 +1,691 @@ +/* + * AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver + * + * Copyright 2011-2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Registers */ +#define AD7793_REG_COMM 0 /* Communications Register (WO, 8-bit) */ +#define AD7793_REG_STAT 0 /* Status Register (RO, 8-bit) */ +#define AD7793_REG_MODE 1 /* Mode Register (RW, 16-bit */ +#define AD7793_REG_CONF 2 /* Configuration Register (RW, 16-bit) */ +#define AD7793_REG_DATA 3 /* Data Register (RO, 16-/24-bit) */ +#define AD7793_REG_ID 4 /* ID Register (RO, 8-bit) */ +#define AD7793_REG_IO 5 /* IO Register (RO, 8-bit) */ +#define AD7793_REG_OFFSET 6 /* Offset Register (RW, 16-bit + * (AD7792)/24-bit (AD7793)) */ +#define AD7793_REG_FULLSALE 7 /* Full-Scale Register + * (RW, 16-bit (AD7792)/24-bit (AD7793)) */ + +/* Communications Register Bit Designations (AD7793_REG_COMM) */ +#define AD7793_COMM_WEN (1 << 7) /* Write Enable */ +#define AD7793_COMM_WRITE (0 << 6) /* Write Operation */ +#define AD7793_COMM_READ (1 << 6) /* Read Operation */ +#define AD7793_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */ +#define AD7793_COMM_CREAD (1 << 2) /* Continuous Read of Data Register */ + +/* Status Register Bit Designations (AD7793_REG_STAT) */ +#define AD7793_STAT_RDY (1 << 7) /* Ready */ +#define AD7793_STAT_ERR (1 << 6) /* Error (Overrange, Underrange) */ +#define AD7793_STAT_CH3 (1 << 2) /* Channel 3 */ +#define AD7793_STAT_CH2 (1 << 1) /* Channel 2 */ +#define AD7793_STAT_CH1 (1 << 0) /* Channel 1 */ + +/* Mode Register Bit Designations (AD7793_REG_MODE) */ +#define AD7793_MODE_SEL(x) (((x) & 0x7) << 13) /* Operation Mode Select */ +#define AD7793_MODE_SEL_MASK (0x7 << 13) /* Operation Mode Select mask */ +#define AD7793_MODE_CLKSRC(x) (((x) & 0x3) << 6) /* ADC Clock Source Select */ +#define AD7793_MODE_RATE(x) ((x) & 0xF) /* Filter Update Rate Select */ + +#define AD7793_MODE_CONT 0 /* Continuous Conversion Mode */ +#define AD7793_MODE_SINGLE 1 /* Single Conversion Mode */ +#define AD7793_MODE_IDLE 2 /* Idle Mode */ +#define AD7793_MODE_PWRDN 3 /* Power-Down Mode */ +#define AD7793_MODE_CAL_INT_ZERO 4 /* Internal Zero-Scale Calibration */ +#define AD7793_MODE_CAL_INT_FULL 5 /* Internal Full-Scale Calibration */ +#define AD7793_MODE_CAL_SYS_ZERO 6 /* System Zero-Scale Calibration */ +#define AD7793_MODE_CAL_SYS_FULL 7 /* System Full-Scale Calibration */ + +#define AD7793_CLK_INT 0 /* Internal 64 kHz Clock not + * available at the CLK pin */ +#define AD7793_CLK_INT_CO 1 /* Internal 64 kHz Clock available + * at the CLK pin */ +#define AD7793_CLK_EXT 2 /* External 64 kHz Clock */ +#define AD7793_CLK_EXT_DIV2 3 /* External Clock divided by 2 */ + +/* Configuration Register Bit Designations (AD7793_REG_CONF) */ +#define AD7793_CONF_VBIAS(x) (((x) & 0x3) << 14) /* Bias Voltage + * Generator Enable */ +#define AD7793_CONF_BO_EN (1 << 13) /* Burnout Current Enable */ +#define AD7793_CONF_UNIPOLAR (1 << 12) /* Unipolar/Bipolar Enable */ +#define AD7793_CONF_BOOST (1 << 11) /* Boost Enable */ +#define AD7793_CONF_GAIN(x) (((x) & 0x7) << 8) /* Gain Select */ +#define AD7793_CONF_REFSEL(x) ((x) << 6) /* INT/EXT Reference Select */ +#define AD7793_CONF_BUF (1 << 4) /* Buffered Mode Enable */ +#define AD7793_CONF_CHAN(x) ((x) & 0xf) /* Channel select */ +#define AD7793_CONF_CHAN_MASK 0xf /* Channel select mask */ + +#define AD7793_CH_AIN1P_AIN1M 0 /* AIN1(+) - AIN1(-) */ +#define AD7793_CH_AIN2P_AIN2M 1 /* AIN2(+) - AIN2(-) */ +#define AD7793_CH_AIN3P_AIN3M 2 /* AIN3(+) - AIN3(-) */ +#define AD7793_CH_AIN1M_AIN1M 3 /* AIN1(-) - AIN1(-) */ +#define AD7793_CH_TEMP 6 /* Temp Sensor */ +#define AD7793_CH_AVDD_MONITOR 7 /* AVDD Monitor */ + +#define AD7795_CH_AIN4P_AIN4M 4 /* AIN4(+) - AIN4(-) */ +#define AD7795_CH_AIN5P_AIN5M 5 /* AIN5(+) - AIN5(-) */ +#define AD7795_CH_AIN6P_AIN6M 6 /* AIN6(+) - AIN6(-) */ +#define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */ + +/* ID Register Bit Designations (AD7793_REG_ID) */ +#define AD7785_ID 0xB +#define AD7792_ID 0xA +#define AD7793_ID 0xB +#define AD7794_ID 0xF +#define AD7795_ID 0xF +#define AD7793_ID_MASK 0xF + +/* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */ +#define AD7793_IO_IEXC1_IOUT1_IEXC2_IOUT2 0 /* IEXC1 connect to IOUT1, + * IEXC2 connect to IOUT2 */ +#define AD7793_IO_IEXC1_IOUT2_IEXC2_IOUT1 1 /* IEXC1 connect to IOUT2, + * IEXC2 connect to IOUT1 */ +#define AD7793_IO_IEXC1_IEXC2_IOUT1 2 /* Both current sources + * IEXC1,2 connect to IOUT1 */ +#define AD7793_IO_IEXC1_IEXC2_IOUT2 3 /* Both current sources + * IEXC1,2 connect to IOUT2 */ + +#define AD7793_IO_IXCEN_10uA (1 << 0) /* Excitation Current 10uA */ +#define AD7793_IO_IXCEN_210uA (2 << 0) /* Excitation Current 210uA */ +#define AD7793_IO_IXCEN_1mA (3 << 0) /* Excitation Current 1mA */ + +/* NOTE: + * The AD7792/AD7793 features a dual use data out ready DOUT/RDY output. + * In order to avoid contentions on the SPI bus, it's therefore necessary + * to use spi bus locking. + * + * The DOUT/RDY output must also be wired to an interrupt capable GPIO. + */ + +struct ad7793_chip_info { + unsigned int id; + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; + +struct ad7793_state { + const struct ad7793_chip_info *chip_info; + struct regulator *reg; + u16 int_vref_mv; + u16 mode; + u16 conf; + u32 scale_avail[8][2]; + + struct ad_sigma_delta sd; + +}; + +enum ad7793_supported_device_ids { + ID_AD7785, + ID_AD7792, + ID_AD7793, + ID_AD7794, + ID_AD7795, +}; + +static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd) +{ + return container_of(sd, struct ad7793_state, sd); +} + +static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel) +{ + struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); + + st->conf &= ~AD7793_CONF_CHAN_MASK; + st->conf |= AD7793_CONF_CHAN(channel); + + return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf); +} + +static int ad7793_set_mode(struct ad_sigma_delta *sd, + enum ad_sigma_delta_mode mode) +{ + struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); + + st->mode &= ~AD7793_MODE_SEL_MASK; + st->mode |= AD7793_MODE_SEL(mode); + + return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode); +} + +static const struct ad_sigma_delta_info ad7793_sigma_delta_info = { + .set_channel = ad7793_set_channel, + .set_mode = ad7793_set_mode, + .has_registers = true, + .addr_shift = 3, + .read_mask = BIT(6), +}; + +static const struct ad_sd_calib_data ad7793_calib_arr[6] = { + {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M}, + {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M}, + {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M}, + {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN2P_AIN2M}, + {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN3P_AIN3M}, + {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN3P_AIN3M} +}; + +static int ad7793_calibrate_all(struct ad7793_state *st) +{ + return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr, + ARRAY_SIZE(ad7793_calib_arr)); +} + +static int ad7793_setup(struct iio_dev *indio_dev, + const struct ad7793_platform_data *pdata, + unsigned int vref_mv) +{ + struct ad7793_state *st = iio_priv(indio_dev); + int i, ret = -1; + unsigned long long scale_uv; + u32 id; + + if ((pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT1 || + pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT2) && + ((pdata->exitation_current != AD7793_IX_10uA) && + (pdata->exitation_current != AD7793_IX_210uA))) + return -EINVAL; + + /* reset the serial interface */ + ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret)); + if (ret < 0) + goto out; + usleep_range(500, 2000); /* Wait for at least 500us */ + + /* write/read test for device presence */ + ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id); + if (ret) + goto out; + + id &= AD7793_ID_MASK; + + if (id != st->chip_info->id) { + dev_err(&st->sd.spi->dev, "device ID query failed\n"); + goto out; + } + + st->mode = AD7793_MODE_RATE(1); + st->mode |= AD7793_MODE_CLKSRC(pdata->clock_src); + st->conf = AD7793_CONF_REFSEL(pdata->refsel); + st->conf |= AD7793_CONF_VBIAS(pdata->bias_voltage); + if (pdata->buffered) + st->conf |= AD7793_CONF_BUF; + if (pdata->boost_enable) + st->conf |= AD7793_CONF_BOOST; + if (pdata->burnout_current) + st->conf |= AD7793_CONF_BO_EN; + if (pdata->unipolar) + st->conf |= AD7793_CONF_UNIPOLAR; + + ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE); + if (ret) + goto out; + + ret = ad7793_set_channel(&st->sd, 0); + if (ret) + goto out; + + ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO, 1, + pdata->exitation_current | + (pdata->current_source_direction << 2)); + if (ret) + goto out; + + ret = ad7793_calibrate_all(st); + if (ret) + goto out; + + /* Populate available ADC input ranges */ + for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { + scale_uv = ((u64)vref_mv * 100000000) + >> (st->chip_info->channels[0].scan_type.realbits - + (!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1)); + scale_uv >>= i; + + st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10; + st->scale_avail[i][0] = scale_uv; + } + + return 0; +out: + dev_err(&st->sd.spi->dev, "setup failed\n"); + return ret; +} + +static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19, + 17, 16, 12, 10, 8, 6, 4}; + +static ssize_t ad7793_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7793_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", + sample_freq_avail[AD7793_MODE_RATE(st->mode)]); +} + +static ssize_t ad7793_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7793_state *st = iio_priv(indio_dev); + long lval; + int i, ret; + + mutex_lock(&indio_dev->mlock); + if (iio_buffer_enabled(indio_dev)) { + mutex_unlock(&indio_dev->mlock); + return -EBUSY; + } + mutex_unlock(&indio_dev->mlock); + + ret = kstrtol(buf, 10, &lval); + if (ret) + return ret; + + ret = -EINVAL; + + for (i = 0; i < ARRAY_SIZE(sample_freq_avail); i++) + if (lval == sample_freq_avail[i]) { + mutex_lock(&indio_dev->mlock); + st->mode &= ~AD7793_MODE_RATE(-1); + st->mode |= AD7793_MODE_RATE(i); + ad_sd_write_reg(&st->sd, AD7793_REG_MODE, + sizeof(st->mode), st->mode); + mutex_unlock(&indio_dev->mlock); + ret = 0; + } + + return ret ? ret : len; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ad7793_read_frequency, + ad7793_write_frequency); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( + "470 242 123 62 50 39 33 19 17 16 12 10 8 6 4"); + +static ssize_t ad7793_show_scale_available(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7793_state *st = iio_priv(indio_dev); + int i, len = 0; + + for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) + len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0], + st->scale_avail[i][1]); + + len += sprintf(buf + len, "\n"); + + return len; +} + +static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, + in_voltage-voltage_scale_available, S_IRUGO, + ad7793_show_scale_available, NULL, 0); + +static struct attribute *ad7793_attributes[] = { + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_in_m_in_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group ad7793_attribute_group = { + .attrs = ad7793_attributes, +}; + +static int ad7793_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long m) +{ + struct ad7793_state *st = iio_priv(indio_dev); + int ret; + unsigned long long scale_uv; + bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR); + + switch (m) { + case IIO_CHAN_INFO_RAW: + ret = ad_sigma_delta_single_conversion(indio_dev, chan, val); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + if (chan->differential) { + *val = st-> + scale_avail[(st->conf >> 8) & 0x7][0]; + *val2 = st-> + scale_avail[(st->conf >> 8) & 0x7][1]; + return IIO_VAL_INT_PLUS_NANO; + } else { + /* 1170mV / 2^23 * 6 */ + scale_uv = (1170ULL * 1000000000ULL * 6ULL); + } + break; + case IIO_TEMP: + /* 1170mV / 0.81 mV/C / 2^23 */ + scale_uv = 1444444444444444ULL; + break; + default: + return -EINVAL; + } + + scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1)); + *val = 0; + *val2 = scale_uv; + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + if (!unipolar) + *val = -(1 << (chan->scan_type.realbits - 1)); + else + *val = 0; + + /* Kelvin to Celsius */ + if (chan->type == IIO_TEMP) { + unsigned long long offset; + unsigned int shift; + + shift = chan->scan_type.realbits - (unipolar ? 0 : 1); + offset = 273ULL << shift; + do_div(offset, 1444); + *val -= offset; + } + return IIO_VAL_INT; + } + return -EINVAL; +} + +static int ad7793_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct ad7793_state *st = iio_priv(indio_dev); + int ret, i; + unsigned int tmp; + + mutex_lock(&indio_dev->mlock); + if (iio_buffer_enabled(indio_dev)) { + mutex_unlock(&indio_dev->mlock); + return -EBUSY; + } + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = -EINVAL; + for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) + if (val2 == st->scale_avail[i][1]) { + ret = 0; + tmp = st->conf; + st->conf &= ~AD7793_CONF_GAIN(-1); + st->conf |= AD7793_CONF_GAIN(i); + + if (tmp == st->conf) + break; + + ad_sd_write_reg(&st->sd, AD7793_REG_CONF, + sizeof(st->conf), st->conf); + ad7793_calibrate_all(st); + break; + } + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&indio_dev->mlock); + return ret; +} + +static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_NANO; +} + +static const struct iio_info ad7793_info = { + .read_raw = &ad7793_read_raw, + .write_raw = &ad7793_write_raw, + .write_raw_get_fmt = &ad7793_write_raw_get_fmt, + .attrs = &ad7793_attribute_group, + .validate_trigger = ad_sd_validate_trigger, + .driver_module = THIS_MODULE, +}; + +#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \ +const struct iio_chan_spec _name##_channels[] = { \ + AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \ + AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \ + AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \ + AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \ + AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \ + AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \ + IIO_CHAN_SOFT_TIMESTAMP(6), \ +} + +#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \ +const struct iio_chan_spec _name##_channels[] = { \ + AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \ + AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ + AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \ + AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ + IIO_CHAN_SOFT_TIMESTAMP(9), \ +} + +static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4); +static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0); +static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0); +static DECLARE_AD7795_CHANNELS(ad7794, 16, 32); +static DECLARE_AD7795_CHANNELS(ad7795, 24, 32); + +static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { + [ID_AD7785] = { + .id = AD7785_ID, + .channels = ad7785_channels, + .num_channels = ARRAY_SIZE(ad7785_channels), + }, + [ID_AD7792] = { + .id = AD7792_ID, + .channels = ad7792_channels, + .num_channels = ARRAY_SIZE(ad7792_channels), + }, + [ID_AD7793] = { + .id = AD7793_ID, + .channels = ad7793_channels, + .num_channels = ARRAY_SIZE(ad7793_channels), + }, + [ID_AD7794] = { + .id = AD7794_ID, + .channels = ad7794_channels, + .num_channels = ARRAY_SIZE(ad7794_channels), + }, + [ID_AD7795] = { + .id = AD7795_ID, + .channels = ad7795_channels, + .num_channels = ARRAY_SIZE(ad7795_channels), + }, +}; + +static int ad7793_probe(struct spi_device *spi) +{ + const struct ad7793_platform_data *pdata = spi->dev.platform_data; + struct ad7793_state *st; + struct iio_dev *indio_dev; + int ret, vref_mv = 0; + + if (!pdata) { + dev_err(&spi->dev, "no platform data?\n"); + return -ENODEV; + } + + if (!spi->irq) { + dev_err(&spi->dev, "no IRQ?\n"); + return -ENODEV; + } + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + + ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); + + if (pdata->refsel != AD7793_REFSEL_INTERNAL) { + st->reg = regulator_get(&spi->dev, "refin"); + if (IS_ERR(st->reg)) { + ret = PTR_ERR(st->reg); + goto error_device_free; + } + + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + + vref_mv = regulator_get_voltage(st->reg); + if (vref_mv < 0) { + ret = vref_mv; + goto error_disable_reg; + } + + vref_mv /= 1000; + } else { + vref_mv = 1170; /* Build-in ref */ + } + + st->chip_info = + &ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + spi_set_drvdata(spi, indio_dev); + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; + indio_dev->info = &ad7793_info; + + ret = ad_sd_setup_buffer_and_trigger(indio_dev); + if (ret) + goto error_disable_reg; + + ret = ad7793_setup(indio_dev, pdata, vref_mv); + if (ret) + goto error_remove_trigger; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_remove_trigger; + + return 0; + +error_remove_trigger: + ad_sd_cleanup_buffer_and_trigger(indio_dev); +error_disable_reg: + if (pdata->refsel != AD7793_REFSEL_INTERNAL) + regulator_disable(st->reg); +error_put_reg: + if (pdata->refsel != AD7793_REFSEL_INTERNAL) + regulator_put(st->reg); +error_device_free: + iio_device_free(indio_dev); + + return ret; +} + +static int ad7793_remove(struct spi_device *spi) +{ + const struct ad7793_platform_data *pdata = spi->dev.platform_data; + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad7793_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + ad_sd_cleanup_buffer_and_trigger(indio_dev); + + if (pdata->refsel != AD7793_REFSEL_INTERNAL) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad7793_id[] = { + {"ad7785", ID_AD7785}, + {"ad7792", ID_AD7792}, + {"ad7793", ID_AD7793}, + {"ad7794", ID_AD7794}, + {"ad7795", ID_AD7795}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7793_id); + +static struct spi_driver ad7793_driver = { + .driver = { + .name = "ad7793", + .owner = THIS_MODULE, + }, + .probe = ad7793_probe, + .remove = ad7793_remove, + .id_table = ad7793_id, +}; +module_spi_driver(ad7793_driver); + +MODULE_AUTHOR("Michael Hennerich "); +MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index dc8582b95b6..fb8c239b0c8 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -70,18 +70,6 @@ config AD7780 To compile this driver as a module, choose M here: the module will be called ad7780. -config AD7793 - tristate "Analog Devices AD7793 and similar ADCs driver" - depends on SPI - select AD_SIGMA_DELTA - help - Say yes here to build support for Analog Devices AD7785, AD7792, AD7793, - AD7794 and AD7795 SPI analog to digital converters (ADC). - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called AD7793. - config AD7816 tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver" depends on SPI diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 7281451a613..d285596272a 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_AD799X) += ad799x.o obj-$(CONFIG_AD7291) += ad7291.o obj-$(CONFIG_AD7780) += ad7780.o -obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7816) += ad7816.o obj-$(CONFIG_AD7192) += ad7192.o obj-$(CONFIG_ADT7410) += adt7410.o diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c deleted file mode 100644 index 8928609a182..00000000000 --- a/drivers/staging/iio/adc/ad7793.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver - * - * Copyright 2011-2012 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "ad7793.h" - -/* Registers */ -#define AD7793_REG_COMM 0 /* Communications Register (WO, 8-bit) */ -#define AD7793_REG_STAT 0 /* Status Register (RO, 8-bit) */ -#define AD7793_REG_MODE 1 /* Mode Register (RW, 16-bit */ -#define AD7793_REG_CONF 2 /* Configuration Register (RW, 16-bit) */ -#define AD7793_REG_DATA 3 /* Data Register (RO, 16-/24-bit) */ -#define AD7793_REG_ID 4 /* ID Register (RO, 8-bit) */ -#define AD7793_REG_IO 5 /* IO Register (RO, 8-bit) */ -#define AD7793_REG_OFFSET 6 /* Offset Register (RW, 16-bit - * (AD7792)/24-bit (AD7793)) */ -#define AD7793_REG_FULLSALE 7 /* Full-Scale Register - * (RW, 16-bit (AD7792)/24-bit (AD7793)) */ - -/* Communications Register Bit Designations (AD7793_REG_COMM) */ -#define AD7793_COMM_WEN (1 << 7) /* Write Enable */ -#define AD7793_COMM_WRITE (0 << 6) /* Write Operation */ -#define AD7793_COMM_READ (1 << 6) /* Read Operation */ -#define AD7793_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */ -#define AD7793_COMM_CREAD (1 << 2) /* Continuous Read of Data Register */ - -/* Status Register Bit Designations (AD7793_REG_STAT) */ -#define AD7793_STAT_RDY (1 << 7) /* Ready */ -#define AD7793_STAT_ERR (1 << 6) /* Error (Overrange, Underrange) */ -#define AD7793_STAT_CH3 (1 << 2) /* Channel 3 */ -#define AD7793_STAT_CH2 (1 << 1) /* Channel 2 */ -#define AD7793_STAT_CH1 (1 << 0) /* Channel 1 */ - -/* Mode Register Bit Designations (AD7793_REG_MODE) */ -#define AD7793_MODE_SEL(x) (((x) & 0x7) << 13) /* Operation Mode Select */ -#define AD7793_MODE_SEL_MASK (0x7 << 13) /* Operation Mode Select mask */ -#define AD7793_MODE_CLKSRC(x) (((x) & 0x3) << 6) /* ADC Clock Source Select */ -#define AD7793_MODE_RATE(x) ((x) & 0xF) /* Filter Update Rate Select */ - -#define AD7793_MODE_CONT 0 /* Continuous Conversion Mode */ -#define AD7793_MODE_SINGLE 1 /* Single Conversion Mode */ -#define AD7793_MODE_IDLE 2 /* Idle Mode */ -#define AD7793_MODE_PWRDN 3 /* Power-Down Mode */ -#define AD7793_MODE_CAL_INT_ZERO 4 /* Internal Zero-Scale Calibration */ -#define AD7793_MODE_CAL_INT_FULL 5 /* Internal Full-Scale Calibration */ -#define AD7793_MODE_CAL_SYS_ZERO 6 /* System Zero-Scale Calibration */ -#define AD7793_MODE_CAL_SYS_FULL 7 /* System Full-Scale Calibration */ - -#define AD7793_CLK_INT 0 /* Internal 64 kHz Clock not - * available at the CLK pin */ -#define AD7793_CLK_INT_CO 1 /* Internal 64 kHz Clock available - * at the CLK pin */ -#define AD7793_CLK_EXT 2 /* External 64 kHz Clock */ -#define AD7793_CLK_EXT_DIV2 3 /* External Clock divided by 2 */ - -/* Configuration Register Bit Designations (AD7793_REG_CONF) */ -#define AD7793_CONF_VBIAS(x) (((x) & 0x3) << 14) /* Bias Voltage - * Generator Enable */ -#define AD7793_CONF_BO_EN (1 << 13) /* Burnout Current Enable */ -#define AD7793_CONF_UNIPOLAR (1 << 12) /* Unipolar/Bipolar Enable */ -#define AD7793_CONF_BOOST (1 << 11) /* Boost Enable */ -#define AD7793_CONF_GAIN(x) (((x) & 0x7) << 8) /* Gain Select */ -#define AD7793_CONF_REFSEL(x) ((x) << 6) /* INT/EXT Reference Select */ -#define AD7793_CONF_BUF (1 << 4) /* Buffered Mode Enable */ -#define AD7793_CONF_CHAN(x) ((x) & 0xf) /* Channel select */ -#define AD7793_CONF_CHAN_MASK 0xf /* Channel select mask */ - -#define AD7793_CH_AIN1P_AIN1M 0 /* AIN1(+) - AIN1(-) */ -#define AD7793_CH_AIN2P_AIN2M 1 /* AIN2(+) - AIN2(-) */ -#define AD7793_CH_AIN3P_AIN3M 2 /* AIN3(+) - AIN3(-) */ -#define AD7793_CH_AIN1M_AIN1M 3 /* AIN1(-) - AIN1(-) */ -#define AD7793_CH_TEMP 6 /* Temp Sensor */ -#define AD7793_CH_AVDD_MONITOR 7 /* AVDD Monitor */ - -#define AD7795_CH_AIN4P_AIN4M 4 /* AIN4(+) - AIN4(-) */ -#define AD7795_CH_AIN5P_AIN5M 5 /* AIN5(+) - AIN5(-) */ -#define AD7795_CH_AIN6P_AIN6M 6 /* AIN6(+) - AIN6(-) */ -#define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */ - -/* ID Register Bit Designations (AD7793_REG_ID) */ -#define AD7785_ID 0xB -#define AD7792_ID 0xA -#define AD7793_ID 0xB -#define AD7794_ID 0xF -#define AD7795_ID 0xF -#define AD7793_ID_MASK 0xF - -/* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */ -#define AD7793_IO_IEXC1_IOUT1_IEXC2_IOUT2 0 /* IEXC1 connect to IOUT1, - * IEXC2 connect to IOUT2 */ -#define AD7793_IO_IEXC1_IOUT2_IEXC2_IOUT1 1 /* IEXC1 connect to IOUT2, - * IEXC2 connect to IOUT1 */ -#define AD7793_IO_IEXC1_IEXC2_IOUT1 2 /* Both current sources - * IEXC1,2 connect to IOUT1 */ -#define AD7793_IO_IEXC1_IEXC2_IOUT2 3 /* Both current sources - * IEXC1,2 connect to IOUT2 */ - -#define AD7793_IO_IXCEN_10uA (1 << 0) /* Excitation Current 10uA */ -#define AD7793_IO_IXCEN_210uA (2 << 0) /* Excitation Current 210uA */ -#define AD7793_IO_IXCEN_1mA (3 << 0) /* Excitation Current 1mA */ - -/* NOTE: - * The AD7792/AD7793 features a dual use data out ready DOUT/RDY output. - * In order to avoid contentions on the SPI bus, it's therefore necessary - * to use spi bus locking. - * - * The DOUT/RDY output must also be wired to an interrupt capable GPIO. - */ - -struct ad7793_chip_info { - unsigned int id; - const struct iio_chan_spec *channels; - unsigned int num_channels; -}; - -struct ad7793_state { - const struct ad7793_chip_info *chip_info; - struct regulator *reg; - u16 int_vref_mv; - u16 mode; - u16 conf; - u32 scale_avail[8][2]; - - struct ad_sigma_delta sd; - -}; - -enum ad7793_supported_device_ids { - ID_AD7785, - ID_AD7792, - ID_AD7793, - ID_AD7794, - ID_AD7795, -}; - -static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd) -{ - return container_of(sd, struct ad7793_state, sd); -} - -static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel) -{ - struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); - - st->conf &= ~AD7793_CONF_CHAN_MASK; - st->conf |= AD7793_CONF_CHAN(channel); - - return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf); -} - -static int ad7793_set_mode(struct ad_sigma_delta *sd, - enum ad_sigma_delta_mode mode) -{ - struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); - - st->mode &= ~AD7793_MODE_SEL_MASK; - st->mode |= AD7793_MODE_SEL(mode); - - return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode); -} - -static const struct ad_sigma_delta_info ad7793_sigma_delta_info = { - .set_channel = ad7793_set_channel, - .set_mode = ad7793_set_mode, - .has_registers = true, - .addr_shift = 3, - .read_mask = BIT(6), -}; - -static const struct ad_sd_calib_data ad7793_calib_arr[6] = { - {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M}, - {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M}, - {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M}, - {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN2P_AIN2M}, - {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN3P_AIN3M}, - {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN3P_AIN3M} -}; - -static int ad7793_calibrate_all(struct ad7793_state *st) -{ - return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr, - ARRAY_SIZE(ad7793_calib_arr)); -} - -static int ad7793_setup(struct iio_dev *indio_dev, - const struct ad7793_platform_data *pdata, - unsigned int vref_mv) -{ - struct ad7793_state *st = iio_priv(indio_dev); - int i, ret = -1; - unsigned long long scale_uv; - u32 id; - - if ((pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT1 || - pdata->current_source_direction == AD7793_IEXEC1_IEXEC2_IOUT2) && - ((pdata->exitation_current != AD7793_IX_10uA) && - (pdata->exitation_current != AD7793_IX_210uA))) - return -EINVAL; - - /* reset the serial interface */ - ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret)); - if (ret < 0) - goto out; - usleep_range(500, 2000); /* Wait for at least 500us */ - - /* write/read test for device presence */ - ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id); - if (ret) - goto out; - - id &= AD7793_ID_MASK; - - if (id != st->chip_info->id) { - dev_err(&st->sd.spi->dev, "device ID query failed\n"); - goto out; - } - - st->mode = AD7793_MODE_RATE(1); - st->mode |= AD7793_MODE_CLKSRC(pdata->clock_src); - st->conf = AD7793_CONF_REFSEL(pdata->refsel); - st->conf |= AD7793_CONF_VBIAS(pdata->bias_voltage); - if (pdata->buffered) - st->conf |= AD7793_CONF_BUF; - if (pdata->boost_enable) - st->conf |= AD7793_CONF_BOOST; - if (pdata->burnout_current) - st->conf |= AD7793_CONF_BO_EN; - if (pdata->unipolar) - st->conf |= AD7793_CONF_UNIPOLAR; - - ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE); - if (ret) - goto out; - - ret = ad7793_set_channel(&st->sd, 0); - if (ret) - goto out; - - ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO, 1, - pdata->exitation_current | - (pdata->current_source_direction << 2)); - if (ret) - goto out; - - ret = ad7793_calibrate_all(st); - if (ret) - goto out; - - /* Populate available ADC input ranges */ - for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { - scale_uv = ((u64)vref_mv * 100000000) - >> (st->chip_info->channels[0].scan_type.realbits - - (!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1)); - scale_uv >>= i; - - st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10; - st->scale_avail[i][0] = scale_uv; - } - - return 0; -out: - dev_err(&st->sd.spi->dev, "setup failed\n"); - return ret; -} - -static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19, - 17, 16, 12, 10, 8, 6, 4}; - -static ssize_t ad7793_read_frequency(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7793_state *st = iio_priv(indio_dev); - - return sprintf(buf, "%d\n", - sample_freq_avail[AD7793_MODE_RATE(st->mode)]); -} - -static ssize_t ad7793_write_frequency(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7793_state *st = iio_priv(indio_dev); - long lval; - int i, ret; - - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) { - mutex_unlock(&indio_dev->mlock); - return -EBUSY; - } - mutex_unlock(&indio_dev->mlock); - - ret = kstrtol(buf, 10, &lval); - if (ret) - return ret; - - ret = -EINVAL; - - for (i = 0; i < ARRAY_SIZE(sample_freq_avail); i++) - if (lval == sample_freq_avail[i]) { - mutex_lock(&indio_dev->mlock); - st->mode &= ~AD7793_MODE_RATE(-1); - st->mode |= AD7793_MODE_RATE(i); - ad_sd_write_reg(&st->sd, AD7793_REG_MODE, - sizeof(st->mode), st->mode); - mutex_unlock(&indio_dev->mlock); - ret = 0; - } - - return ret ? ret : len; -} - -static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, - ad7793_read_frequency, - ad7793_write_frequency); - -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( - "470 242 123 62 50 39 33 19 17 16 12 10 8 6 4"); - -static ssize_t ad7793_show_scale_available(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct ad7793_state *st = iio_priv(indio_dev); - int i, len = 0; - - for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) - len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0], - st->scale_avail[i][1]); - - len += sprintf(buf + len, "\n"); - - return len; -} - -static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, - in_voltage-voltage_scale_available, S_IRUGO, - ad7793_show_scale_available, NULL, 0); - -static struct attribute *ad7793_attributes[] = { - &iio_dev_attr_sampling_frequency.dev_attr.attr, - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_in_m_in_scale_available.dev_attr.attr, - NULL -}; - -static const struct attribute_group ad7793_attribute_group = { - .attrs = ad7793_attributes, -}; - -static int ad7793_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long m) -{ - struct ad7793_state *st = iio_priv(indio_dev); - int ret; - unsigned long long scale_uv; - bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR); - - switch (m) { - case IIO_CHAN_INFO_RAW: - ret = ad_sigma_delta_single_conversion(indio_dev, chan, val); - if (ret < 0) - return ret; - - return IIO_VAL_INT; - - case IIO_CHAN_INFO_SCALE: - switch (chan->type) { - case IIO_VOLTAGE: - if (chan->differential) { - *val = st-> - scale_avail[(st->conf >> 8) & 0x7][0]; - *val2 = st-> - scale_avail[(st->conf >> 8) & 0x7][1]; - return IIO_VAL_INT_PLUS_NANO; - } else { - /* 1170mV / 2^23 * 6 */ - scale_uv = (1170ULL * 1000000000ULL * 6ULL); - } - break; - case IIO_TEMP: - /* 1170mV / 0.81 mV/C / 2^23 */ - scale_uv = 1444444444444444ULL; - break; - default: - return -EINVAL; - } - - scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1)); - *val = 0; - *val2 = scale_uv; - return IIO_VAL_INT_PLUS_NANO; - case IIO_CHAN_INFO_OFFSET: - if (!unipolar) - *val = -(1 << (chan->scan_type.realbits - 1)); - else - *val = 0; - - /* Kelvin to Celsius */ - if (chan->type == IIO_TEMP) { - unsigned long long offset; - unsigned int shift; - - shift = chan->scan_type.realbits - (unipolar ? 0 : 1); - offset = 273ULL << shift; - do_div(offset, 1444); - *val -= offset; - } - return IIO_VAL_INT; - } - return -EINVAL; -} - -static int ad7793_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct ad7793_state *st = iio_priv(indio_dev); - int ret, i; - unsigned int tmp; - - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) { - mutex_unlock(&indio_dev->mlock); - return -EBUSY; - } - - switch (mask) { - case IIO_CHAN_INFO_SCALE: - ret = -EINVAL; - for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) - if (val2 == st->scale_avail[i][1]) { - ret = 0; - tmp = st->conf; - st->conf &= ~AD7793_CONF_GAIN(-1); - st->conf |= AD7793_CONF_GAIN(i); - - if (tmp == st->conf) - break; - - ad_sd_write_reg(&st->sd, AD7793_REG_CONF, - sizeof(st->conf), st->conf); - ad7793_calibrate_all(st); - break; - } - break; - default: - ret = -EINVAL; - } - - mutex_unlock(&indio_dev->mlock); - return ret; -} - -static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) -{ - return IIO_VAL_INT_PLUS_NANO; -} - -static const struct iio_info ad7793_info = { - .read_raw = &ad7793_read_raw, - .write_raw = &ad7793_write_raw, - .write_raw_get_fmt = &ad7793_write_raw_get_fmt, - .attrs = &ad7793_attribute_group, - .validate_trigger = ad_sd_validate_trigger, - .driver_module = THIS_MODULE, -}; - -#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \ -const struct iio_chan_spec _name##_channels[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \ - AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \ - AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \ - AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \ - AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \ - AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \ - IIO_CHAN_SOFT_TIMESTAMP(6), \ -} - -#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \ -const struct iio_chan_spec _name##_channels[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \ - AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ - AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \ - AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ - IIO_CHAN_SOFT_TIMESTAMP(9), \ -} - -static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4); -static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0); -static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0); -static DECLARE_AD7795_CHANNELS(ad7794, 16, 32); -static DECLARE_AD7795_CHANNELS(ad7795, 24, 32); - -static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { - [ID_AD7785] = { - .id = AD7785_ID, - .channels = ad7785_channels, - .num_channels = ARRAY_SIZE(ad7785_channels), - }, - [ID_AD7792] = { - .id = AD7792_ID, - .channels = ad7792_channels, - .num_channels = ARRAY_SIZE(ad7792_channels), - }, - [ID_AD7793] = { - .id = AD7793_ID, - .channels = ad7793_channels, - .num_channels = ARRAY_SIZE(ad7793_channels), - }, - [ID_AD7794] = { - .id = AD7794_ID, - .channels = ad7794_channels, - .num_channels = ARRAY_SIZE(ad7794_channels), - }, - [ID_AD7795] = { - .id = AD7795_ID, - .channels = ad7795_channels, - .num_channels = ARRAY_SIZE(ad7795_channels), - }, -}; - -static int ad7793_probe(struct spi_device *spi) -{ - const struct ad7793_platform_data *pdata = spi->dev.platform_data; - struct ad7793_state *st; - struct iio_dev *indio_dev; - int ret, vref_mv = 0; - - if (!pdata) { - dev_err(&spi->dev, "no platform data?\n"); - return -ENODEV; - } - - if (!spi->irq) { - dev_err(&spi->dev, "no IRQ?\n"); - return -ENODEV; - } - - indio_dev = iio_device_alloc(sizeof(*st)); - if (indio_dev == NULL) - return -ENOMEM; - - st = iio_priv(indio_dev); - - ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); - - if (pdata->refsel != AD7793_REFSEL_INTERNAL) { - st->reg = regulator_get(&spi->dev, "refin"); - if (IS_ERR(st->reg)) { - ret = PTR_ERR(st->reg); - goto error_device_free; - } - - ret = regulator_enable(st->reg); - if (ret) - goto error_put_reg; - - vref_mv = regulator_get_voltage(st->reg); - if (vref_mv < 0) { - ret = vref_mv; - goto error_disable_reg; - } - - vref_mv /= 1000; - } else { - vref_mv = 1170; /* Build-in ref */ - } - - st->chip_info = - &ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - - spi_set_drvdata(spi, indio_dev); - - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channels; - indio_dev->num_channels = st->chip_info->num_channels; - indio_dev->info = &ad7793_info; - - ret = ad_sd_setup_buffer_and_trigger(indio_dev); - if (ret) - goto error_disable_reg; - - ret = ad7793_setup(indio_dev, pdata, vref_mv); - if (ret) - goto error_remove_trigger; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_remove_trigger; - - return 0; - -error_remove_trigger: - ad_sd_cleanup_buffer_and_trigger(indio_dev); -error_disable_reg: - if (pdata->refsel != AD7793_REFSEL_INTERNAL) - regulator_disable(st->reg); -error_put_reg: - if (pdata->refsel != AD7793_REFSEL_INTERNAL) - regulator_put(st->reg); -error_device_free: - iio_device_free(indio_dev); - - return ret; -} - -static int ad7793_remove(struct spi_device *spi) -{ - const struct ad7793_platform_data *pdata = spi->dev.platform_data; - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad7793_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - ad_sd_cleanup_buffer_and_trigger(indio_dev); - - if (pdata->refsel != AD7793_REFSEL_INTERNAL) { - regulator_disable(st->reg); - regulator_put(st->reg); - } - - iio_device_free(indio_dev); - - return 0; -} - -static const struct spi_device_id ad7793_id[] = { - {"ad7785", ID_AD7785}, - {"ad7792", ID_AD7792}, - {"ad7793", ID_AD7793}, - {"ad7794", ID_AD7794}, - {"ad7795", ID_AD7795}, - {} -}; -MODULE_DEVICE_TABLE(spi, ad7793_id); - -static struct spi_driver ad7793_driver = { - .driver = { - .name = "ad7793", - .owner = THIS_MODULE, - }, - .probe = ad7793_probe, - .remove = ad7793_remove, - .id_table = ad7793_id, -}; -module_spi_driver(ad7793_driver); - -MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7793.h b/drivers/staging/iio/adc/ad7793.h deleted file mode 100644 index 0e455de215e..00000000000 --- a/drivers/staging/iio/adc/ad7793.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * AD7792/AD7793 SPI ADC driver - * - * Copyright 2011 Analog Devices Inc. - * - * Licensed under the GPL-2. - */ -#ifndef IIO_ADC_AD7793_H_ -#define IIO_ADC_AD7793_H_ - -/* - * TODO: struct ad7793_platform_data needs to go into include/linux/iio - */ - -/** - * enum ad7793_clock_source - AD7793 clock source selection - * @AD7793_CLK_SRC_INT: Internal 64 kHz clock, not available at the CLK pin. - * @AD7793_CLK_SRC_INT_CO: Internal 64 kHz clock, available at the CLK pin. - * @AD7793_CLK_SRC_EXT: Use external clock. - * @AD7793_CLK_SRC_EXT_DIV2: Use external clock divided by 2. - */ -enum ad7793_clock_source { - AD7793_CLK_SRC_INT, - AD7793_CLK_SRC_INT_CO, - AD7793_CLK_SRC_EXT, - AD7793_CLK_SRC_EXT_DIV2, -}; - -/** - * enum ad7793_bias_voltage - AD7793 bias voltage selection - * @AD7793_BIAS_VOLTAGE_DISABLED: Bias voltage generator disabled - * @AD7793_BIAS_VOLTAGE_AIN1: Bias voltage connected to AIN1(-). - * @AD7793_BIAS_VOLTAGE_AIN2: Bias voltage connected to AIN2(-). - * @AD7793_BIAS_VOLTAGE_AIN3: Bias voltage connected to AIN3(-). - * Only valid for AD7795/AD7796. - */ -enum ad7793_bias_voltage { - AD7793_BIAS_VOLTAGE_DISABLED, - AD7793_BIAS_VOLTAGE_AIN1, - AD7793_BIAS_VOLTAGE_AIN2, - AD7793_BIAS_VOLTAGE_AIN3, -}; - -/** - * enum ad7793_refsel - AD7793 reference voltage selection - * @AD7793_REFSEL_REFIN1: External reference applied between REFIN1(+) - * and REFIN1(-). - * @AD7793_REFSEL_REFIN2: External reference applied between REFIN2(+) and - * and REFIN1(-). Only valid for AD7795/AD7796. - * @AD7793_REFSEL_INTERNAL: Internal 1.17 V reference. - */ -enum ad7793_refsel { - AD7793_REFSEL_REFIN1 = 0, - AD7793_REFSEL_REFIN2 = 1, - AD7793_REFSEL_INTERNAL = 2, -}; - -/** - * enum ad7793_current_source_direction - AD7793 excitation current direction - * @AD7793_IEXEC1_IOUT1_IEXEC2_IOUT2: Current source IEXC1 connected to pin - * IOUT1, current source IEXC2 connected to pin IOUT2. - * @AD7793_IEXEC1_IOUT2_IEXEC2_IOUT1: Current source IEXC2 connected to pin - * IOUT1, current source IEXC1 connected to pin IOUT2. - * @AD7793_IEXEC1_IEXEC2_IOUT1: Both current sources connected to pin IOUT1. - * Only valid when the current sources are set to 10 uA or 210 uA. - * @AD7793_IEXEC1_IEXEC2_IOUT2: Both current sources connected to Pin IOUT2. - * Only valid when the current ources are set to 10 uA or 210 uA. - */ -enum ad7793_current_source_direction { - AD7793_IEXEC1_IOUT1_IEXEC2_IOUT2 = 0, - AD7793_IEXEC1_IOUT2_IEXEC2_IOUT1 = 1, - AD7793_IEXEC1_IEXEC2_IOUT1 = 2, - AD7793_IEXEC1_IEXEC2_IOUT2 = 3, -}; - -/** - * enum ad7793_excitation_current - AD7793 excitation current selection - * @AD7793_IX_DISABLED: Excitation current Disabled. - * @AD7793_IX_10uA: Enable 10 micro-ampere excitation current. - * @AD7793_IX_210uA: Enable 210 micro-ampere excitation current. - * @AD7793_IX_1mA: Enable 1 milli-Ampere excitation current. - */ -enum ad7793_excitation_current { - AD7793_IX_DISABLED = 0, - AD7793_IX_10uA = 1, - AD7793_IX_210uA = 2, - AD7793_IX_1mA = 3, -}; - -/** - * struct ad7793_platform_data - AD7793 platform data - * @clock_src: Clock source selection - * @burnout_current: If set to true the 100nA burnout current is enabled. - * @boost_enable: Enable boost for the bias voltage generator. - * @buffered: If set to true configure the device for buffered input mode. - * @unipolar: If set to true sample in unipolar mode, if set to false sample in - * bipolar mode. - * @refsel: Reference voltage selection - * @bias_voltage: Bias voltage selection - * @exitation_current: Excitation current selection - * @current_source_direction: Excitation current direction selection - */ -struct ad7793_platform_data { - enum ad7793_clock_source clock_src; - bool burnout_current; - bool boost_enable; - bool buffered; - bool unipolar; - - enum ad7793_refsel refsel; - enum ad7793_bias_voltage bias_voltage; - enum ad7793_excitation_current exitation_current; - enum ad7793_current_source_direction current_source_direction; -}; - -#endif /* IIO_ADC_AD7793_H_ */ diff --git a/include/linux/platform_data/ad7793.h b/include/linux/platform_data/ad7793.h new file mode 100644 index 00000000000..7ea6751aae6 --- /dev/null +++ b/include/linux/platform_data/ad7793.h @@ -0,0 +1,112 @@ +/* + * AD7792/AD7793 SPI ADC driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ +#ifndef __LINUX_PLATFORM_DATA_AD7793_H__ +#define __LINUX_PLATFORM_DATA_AD7793_H__ + +/** + * enum ad7793_clock_source - AD7793 clock source selection + * @AD7793_CLK_SRC_INT: Internal 64 kHz clock, not available at the CLK pin. + * @AD7793_CLK_SRC_INT_CO: Internal 64 kHz clock, available at the CLK pin. + * @AD7793_CLK_SRC_EXT: Use external clock. + * @AD7793_CLK_SRC_EXT_DIV2: Use external clock divided by 2. + */ +enum ad7793_clock_source { + AD7793_CLK_SRC_INT, + AD7793_CLK_SRC_INT_CO, + AD7793_CLK_SRC_EXT, + AD7793_CLK_SRC_EXT_DIV2, +}; + +/** + * enum ad7793_bias_voltage - AD7793 bias voltage selection + * @AD7793_BIAS_VOLTAGE_DISABLED: Bias voltage generator disabled + * @AD7793_BIAS_VOLTAGE_AIN1: Bias voltage connected to AIN1(-). + * @AD7793_BIAS_VOLTAGE_AIN2: Bias voltage connected to AIN2(-). + * @AD7793_BIAS_VOLTAGE_AIN3: Bias voltage connected to AIN3(-). + * Only valid for AD7795/AD7796. + */ +enum ad7793_bias_voltage { + AD7793_BIAS_VOLTAGE_DISABLED, + AD7793_BIAS_VOLTAGE_AIN1, + AD7793_BIAS_VOLTAGE_AIN2, + AD7793_BIAS_VOLTAGE_AIN3, +}; + +/** + * enum ad7793_refsel - AD7793 reference voltage selection + * @AD7793_REFSEL_REFIN1: External reference applied between REFIN1(+) + * and REFIN1(-). + * @AD7793_REFSEL_REFIN2: External reference applied between REFIN2(+) and + * and REFIN1(-). Only valid for AD7795/AD7796. + * @AD7793_REFSEL_INTERNAL: Internal 1.17 V reference. + */ +enum ad7793_refsel { + AD7793_REFSEL_REFIN1 = 0, + AD7793_REFSEL_REFIN2 = 1, + AD7793_REFSEL_INTERNAL = 2, +}; + +/** + * enum ad7793_current_source_direction - AD7793 excitation current direction + * @AD7793_IEXEC1_IOUT1_IEXEC2_IOUT2: Current source IEXC1 connected to pin + * IOUT1, current source IEXC2 connected to pin IOUT2. + * @AD7793_IEXEC1_IOUT2_IEXEC2_IOUT1: Current source IEXC2 connected to pin + * IOUT1, current source IEXC1 connected to pin IOUT2. + * @AD7793_IEXEC1_IEXEC2_IOUT1: Both current sources connected to pin IOUT1. + * Only valid when the current sources are set to 10 uA or 210 uA. + * @AD7793_IEXEC1_IEXEC2_IOUT2: Both current sources connected to Pin IOUT2. + * Only valid when the current ources are set to 10 uA or 210 uA. + */ +enum ad7793_current_source_direction { + AD7793_IEXEC1_IOUT1_IEXEC2_IOUT2 = 0, + AD7793_IEXEC1_IOUT2_IEXEC2_IOUT1 = 1, + AD7793_IEXEC1_IEXEC2_IOUT1 = 2, + AD7793_IEXEC1_IEXEC2_IOUT2 = 3, +}; + +/** + * enum ad7793_excitation_current - AD7793 excitation current selection + * @AD7793_IX_DISABLED: Excitation current Disabled. + * @AD7793_IX_10uA: Enable 10 micro-ampere excitation current. + * @AD7793_IX_210uA: Enable 210 micro-ampere excitation current. + * @AD7793_IX_1mA: Enable 1 milli-Ampere excitation current. + */ +enum ad7793_excitation_current { + AD7793_IX_DISABLED = 0, + AD7793_IX_10uA = 1, + AD7793_IX_210uA = 2, + AD7793_IX_1mA = 3, +}; + +/** + * struct ad7793_platform_data - AD7793 platform data + * @clock_src: Clock source selection + * @burnout_current: If set to true the 100nA burnout current is enabled. + * @boost_enable: Enable boost for the bias voltage generator. + * @buffered: If set to true configure the device for buffered input mode. + * @unipolar: If set to true sample in unipolar mode, if set to false sample in + * bipolar mode. + * @refsel: Reference voltage selection + * @bias_voltage: Bias voltage selection + * @exitation_current: Excitation current selection + * @current_source_direction: Excitation current direction selection + */ +struct ad7793_platform_data { + enum ad7793_clock_source clock_src; + bool burnout_current; + bool boost_enable; + bool buffered; + bool unipolar; + + enum ad7793_refsel refsel; + enum ad7793_bias_voltage bias_voltage; + enum ad7793_excitation_current exitation_current; + enum ad7793_current_source_direction current_source_direction; +}; + +#endif /* IIO_ADC_AD7793_H_ */ -- cgit v1.2.3-70-g09d2