diff options
Diffstat (limited to 'drivers/staging/iio/adc')
-rw-r--r-- | drivers/staging/iio/adc/Kconfig | 35 | ||||
-rw-r--r-- | drivers/staging/iio/adc/Makefile | 8 | ||||
-rw-r--r-- | drivers/staging/iio/adc/ad7476.h | 77 | ||||
-rw-r--r-- | drivers/staging/iio/adc/ad7476_core.c | 293 | ||||
-rw-r--r-- | drivers/staging/iio/adc/ad7476_ring.c | 207 | ||||
-rw-r--r-- | drivers/staging/iio/adc/ad799x.h | 159 | ||||
-rw-r--r-- | drivers/staging/iio/adc/ad799x_core.c | 923 | ||||
-rw-r--r-- | drivers/staging/iio/adc/ad799x_ring.c | 240 | ||||
-rw-r--r-- | drivers/staging/iio/adc/adc.h | 19 | ||||
-rw-r--r-- | drivers/staging/iio/adc/max1363_core.c | 208 | ||||
-rw-r--r-- | drivers/staging/iio/adc/max1363_ring.c | 22 |
11 files changed, 2115 insertions, 76 deletions
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 0835fbc..acb6767 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -26,3 +26,38 @@ config MAX1363_RING_BUFFER help Say yes here to include ring buffer support in the MAX1363 ADC driver. + +config AD799X + tristate "Analog Devices AD799x ADC driver" + depends on I2C + select IIO_TRIGGER if IIO_RING_BUFFER + select AD799X_RING_BUFFER + help + Say yes here to build support for Analog Devices: + ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 + i2c analog to digital convertors (ADC). Provides direct access + via sysfs. + +config AD799X_RING_BUFFER + bool "Analog Devices AD799x: use ring buffer" + depends on AD799X + select IIO_RING_BUFFER + select IIO_SW_RING + help + Say yes here to include ring buffer support in the AD799X + ADC driver. + +config AD7476 + tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver" + depends on SPI + select IIO_RING_BUFFER + select IIO_SW_RING + select IIO_TRIGGER + help + Say yes here to build support for Analog Devices + AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495 + SPI analog to digital convertors (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 ad7476. diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 688510f..b62c319b 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -6,3 +6,11 @@ max1363-y := max1363_core.o max1363-y += max1363_ring.o obj-$(CONFIG_MAX1363) += max1363.o + +ad799x-y := ad799x_core.o +ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o +obj-$(CONFIG_AD799X) += ad799x.o + +ad7476-y := ad7476_core.o +ad7476-$(CONFIG_IIO_RING_BUFFER) += ad7476_ring.o +obj-$(CONFIG_AD7476) += ad7476.o diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h new file mode 100644 index 0000000..b51b49e --- /dev/null +++ b/drivers/staging/iio/adc/ad7476.h @@ -0,0 +1,77 @@ +/* + * AD7476/5/7/8 (A) SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ +#ifndef IIO_ADC_AD7476_H_ +#define IIO_ADC_AD7476_H_ + +#define RES_MASK(bits) ((1 << (bits)) - 1) + +/* + * TODO: struct ad7476_platform_data needs to go into include/linux/iio + */ + +struct ad7476_platform_data { + u16 vref_mv; +}; + +struct ad7476_chip_info { + u8 bits; + u8 storagebits; + u8 res_shift; + char sign; + u16 int_vref_mv; +}; + +struct ad7476_state { + struct iio_dev *indio_dev; + struct spi_device *spi; + const struct ad7476_chip_info *chip_info; + struct regulator *reg; + struct work_struct poll_work; + atomic_t protect_ring; + u16 int_vref_mv; + struct spi_transfer xfer; + struct spi_message msg; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + unsigned char data[2] ____cacheline_aligned; +}; + +enum ad7476_supported_device_ids { + ID_AD7466, + ID_AD7467, + ID_AD7468, + ID_AD7475, + ID_AD7476, + ID_AD7477, + ID_AD7478, + ID_AD7495 +}; + +#ifdef CONFIG_IIO_RING_BUFFER +int ad7476_scan_from_ring(struct ad7476_state *st); +int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev); +void ad7476_ring_cleanup(struct iio_dev *indio_dev); +#else /* CONFIG_IIO_RING_BUFFER */ +static inline int ad7476_scan_from_ring(struct ad7476_state *st) +{ + return 0; +} + +static inline int +ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void ad7476_ring_cleanup(struct iio_dev *indio_dev) +{ +} +#endif /* CONFIG_IIO_RING_BUFFER */ +#endif /* IIO_ADC_AD7476_H_ */ diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c new file mode 100644 index 0000000..deb68c8 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476_core.c @@ -0,0 +1,293 @@ +/* + * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "../ring_generic.h" +#include "adc.h" + +#include "ad7476.h" + +static int ad7476_scan_direct(struct ad7476_state *st) +{ + int ret; + + ret = spi_sync(st->spi, &st->msg); + if (ret) + return ret; + + return (st->data[0] << 8) | st->data[1]; +} + +static ssize_t ad7476_scan(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7476_state *st = dev_info->dev_data; + int ret; + + mutex_lock(&dev_info->mlock); + if (iio_ring_enabled(dev_info)) + ret = ad7476_scan_from_ring(st); + else + ret = ad7476_scan_direct(st); + mutex_unlock(&dev_info->mlock); + + if (ret < 0) + return ret; + + return sprintf(buf, "%d\n", (ret >> st->chip_info->res_shift) & + RES_MASK(st->chip_info->bits)); +} +static IIO_DEV_ATTR_IN_RAW(0, ad7476_scan, 0); + +static ssize_t ad7476_show_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* Driver currently only support internal vref */ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7476_state *st = iio_dev_get_devdata(dev_info); + /* Corresponds to Vref / 2^(bits) */ + unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; + + return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); +} +static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad7476_show_scale, NULL, 0); + +static ssize_t ad7476_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad7476_state *st = iio_dev_get_devdata(dev_info); + + return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); +} +static IIO_DEVICE_ATTR(name, S_IRUGO, ad7476_show_name, NULL, 0); + +static struct attribute *ad7476_attributes[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + NULL, +}; + +static const struct attribute_group ad7476_attribute_group = { + .attrs = ad7476_attributes, +}; + +static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { + [ID_AD7466] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7467] = { + .bits = 10, + .storagebits = 16, + .res_shift = 2, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7468] = { + .bits = 8, + .storagebits = 16, + .res_shift = 4, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7475] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7476] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7477] = { + .bits = 10, + .storagebits = 16, + .res_shift = 2, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7478] = { + .bits = 8, + .storagebits = 16, + .res_shift = 4, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, + [ID_AD7495] = { + .bits = 12, + .storagebits = 16, + .res_shift = 0, + .int_vref_mv = 2500, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + }, +}; + +static int __devinit ad7476_probe(struct spi_device *spi) +{ + struct ad7476_platform_data *pdata = spi->dev.platform_data; + struct ad7476_state *st; + int ret, voltage_uv = 0; + + st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + st->reg = regulator_get(&spi->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + + voltage_uv = regulator_get_voltage(st->reg); + } + + st->chip_info = + &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + + if (st->chip_info->int_vref_mv) + st->int_vref_mv = st->chip_info->int_vref_mv; + else if (pdata && pdata->vref_mv) + st->int_vref_mv = pdata->vref_mv; + else if (voltage_uv) + st->int_vref_mv = voltage_uv / 1000; + else + dev_warn(&spi->dev, "reference voltage unspecified\n"); + + spi_set_drvdata(spi, st); + + atomic_set(&st->protect_ring, 0); + st->spi = spi; + + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + + /* Estabilish that the iio_dev is a child of the i2c device */ + st->indio_dev->dev.parent = &spi->dev; + st->indio_dev->attrs = &ad7476_attribute_group; + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + + /* Setup default message */ + + st->xfer.rx_buf = &st->data; + st->xfer.len = st->chip_info->storagebits / 8; + + spi_message_init(&st->msg); + spi_message_add_tail(&st->xfer, &st->msg); + + ret = ad7476_register_ring_funcs_and_init(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); + if (ret) + goto error_cleanup_ring; + return 0; + +error_cleanup_ring: + ad7476_ring_cleanup(st->indio_dev); + iio_device_unregister(st->indio_dev); +error_free_device: + iio_free_device(st->indio_dev); +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfree(st); +error_ret: + return ret; +} + +static int ad7476_remove(struct spi_device *spi) +{ + struct ad7476_state *st = spi_get_drvdata(spi); + struct iio_dev *indio_dev = st->indio_dev; + iio_ring_buffer_unregister(indio_dev->ring); + ad7476_ring_cleanup(indio_dev); + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + kfree(st); + return 0; +} + +static const struct spi_device_id ad7476_id[] = { + {"ad7466", ID_AD7466}, + {"ad7467", ID_AD7467}, + {"ad7468", ID_AD7468}, + {"ad7475", ID_AD7475}, + {"ad7476", ID_AD7476}, + {"ad7476a", ID_AD7476}, + {"ad7477", ID_AD7477}, + {"ad7477a", ID_AD7477}, + {"ad7478", ID_AD7478}, + {"ad7478a", ID_AD7478}, + {"ad7495", ID_AD7495}, + {} +}; + +static struct spi_driver ad7476_driver = { + .driver = { + .name = "ad7476", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ad7476_probe, + .remove = __devexit_p(ad7476_remove), + .id_table = ad7476_id, +}; + +static int __init ad7476_init(void) +{ + return spi_register_driver(&ad7476_driver); +} +module_init(ad7476_init); + +static void __exit ad7476_exit(void) +{ + spi_unregister_driver(&ad7476_driver); +} +module_exit(ad7476_exit); + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad7476"); diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c new file mode 100644 index 0000000..85de142 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476_ring.c @@ -0,0 +1,207 @@ +/* + * Copyright 2010 Analog Devices Inc. + * Copyright (C) 2008 Jonathan Cameron + * + * Licensed under the GPL-2 or later. + * + * ad7476_ring.c + */ + +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/spi/spi.h> + +#include "../iio.h" +#include "../ring_generic.h" +#include "../ring_sw.h" +#include "../trigger.h" +#include "../sysfs.h" + +#include "ad7476.h" + +static IIO_SCAN_EL_C(in0, 0, 0, NULL); + +static ssize_t ad7476_show_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct ad7476_state *st = indio_dev->dev_data; + + return sprintf(buf, "%c%d/%d>>%d\n", st->chip_info->sign, + st->chip_info->bits, st->chip_info->storagebits, + st->chip_info->res_shift); +} +static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad7476_show_type, NULL, 0); + +static struct attribute *ad7476_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7476_scan_el_group = { + .name = "scan_elements", + .attrs = ad7476_scan_el_attrs, +}; + +int ad7476_scan_from_ring(struct ad7476_state *st) +{ + struct iio_ring_buffer *ring = st->indio_dev->ring; + int ret; + u8 *ring_data; + + ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); + if (ring_data == NULL) { + ret = -ENOMEM; + goto error_ret; + } + ret = ring->access.read_last(ring, ring_data); + if (ret) + goto error_free_ring_data; + + ret = (ring_data[0] << 8) | ring_data[1]; + +error_free_ring_data: + kfree(ring_data); +error_ret: + return ret; +} + +/** + * ad7476_ring_preenable() setup the parameters of the ring before enabling + * + * The complex nature of the setting of the nuber of bytes per datum is due + * to this driver currently ensuring that the timestamp is stored at an 8 + * byte boundary. + **/ +static int ad7476_ring_preenable(struct iio_dev *indio_dev) +{ + struct ad7476_state *st = indio_dev->dev_data; + size_t d_size; + + if (indio_dev->ring->access.set_bytes_per_datum) { + d_size = st->chip_info->storagebits / 8 + sizeof(s64); + if (d_size % 8) + d_size += 8 - (d_size % 8); + indio_dev->ring->access.set_bytes_per_datum(indio_dev->ring, + d_size); + } + + return 0; +} + +/** + * ad7476_poll_func_th() th of trigger launched polling to ring buffer + * + * As sampling only occurs on i2c comms occuring, leave timestamping until + * then. Some triggers will generate their own time stamp. Currently + * there is no way of notifying them when no one cares. + **/ +static void ad7476_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct ad7476_state *st = indio_dev->dev_data; + + schedule_work(&st->poll_work); + return; +} +/** + * ad7476_poll_bh_to_ring() bh of trigger launched polling to ring buffer + * @work_s: the work struct through which this was scheduled + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + * I think the one copy of this at a time was to avoid problems if the + * trigger was set far too high and the reads then locked up the computer. + **/ +static void ad7476_poll_bh_to_ring(struct work_struct *work_s) +{ + struct ad7476_state *st = container_of(work_s, struct ad7476_state, + poll_work); + struct iio_dev *indio_dev = st->indio_dev; + struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring); + s64 time_ns; + __u8 *rxbuf; + int b_sent; + size_t d_size; + + /* Ensure the timestamp is 8 byte aligned */ + d_size = st->chip_info->storagebits / 8 + sizeof(s64); + if (d_size % sizeof(s64)) + d_size += sizeof(s64) - (d_size % sizeof(s64)); + + /* Ensure only one copy of this function running at a time */ + if (atomic_inc_return(&st->protect_ring) > 1) + return; + + rxbuf = kzalloc(d_size, GFP_KERNEL); + if (rxbuf == NULL) + return; + + b_sent = spi_read(st->spi, rxbuf, st->chip_info->storagebits / 8); + if (b_sent < 0) + goto done; + + time_ns = iio_get_time_ns(); + + memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + + indio_dev->ring->access.store_to(&sw_ring->buf, rxbuf, time_ns); +done: + kfree(rxbuf); + atomic_dec(&st->protect_ring); +} + +int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + struct ad7476_state *st = indio_dev->dev_data; + int ret = 0; + + indio_dev->ring = iio_sw_rb_allocate(indio_dev); + if (!indio_dev->ring) { + ret = -ENOMEM; + goto error_ret; + } + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&indio_dev->ring->access); + ret = iio_alloc_pollfunc(indio_dev, NULL, &ad7476_poll_func_th); + if (ret) + goto error_deallocate_sw_rb; + + /* Ring buffer functions - here trigger setup related */ + + indio_dev->ring->preenable = &ad7476_ring_preenable; + indio_dev->ring->postenable = &iio_triggered_ring_postenable; + indio_dev->ring->predisable = &iio_triggered_ring_predisable; + indio_dev->ring->scan_el_attrs = &ad7476_scan_el_group; + + INIT_WORK(&st->poll_work, &ad7476_poll_bh_to_ring); + + /* Flag that polled ring buffering is possible */ + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; +error_deallocate_sw_rb: + iio_sw_rb_free(indio_dev->ring); +error_ret: + return ret; +} + +void ad7476_ring_cleanup(struct iio_dev *indio_dev) +{ + /* ensure that the trigger has been detached */ + if (indio_dev->trig) { + iio_put_trigger(indio_dev->trig); + iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc); + } + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h new file mode 100644 index 0000000..81a20d5 --- /dev/null +++ b/drivers/staging/iio/adc/ad799x.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * Copyright (C) 2008-2010 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ad799x.h + */ + +#ifndef _AD799X_H_ +#define _AD799X_H_ + +#define AD799X_CHANNEL_SHIFT 4 +#define AD799X_STORAGEBITS 16 +/* + * AD7991, AD7995 and AD7999 defines + */ + +#define AD7991_REF_SEL 0x08 +#define AD7991_FLTR 0x04 +#define AD7991_BIT_TRIAL_DELAY 0x02 +#define AD7991_SAMPLE_DELAY 0x01 + +/* + * AD7992, AD7993, AD7994, AD7997 and AD7998 defines + */ + +#define AD7998_FLTR 0x08 +#define AD7998_ALERT_EN 0x04 +#define AD7998_BUSY_ALERT 0x02 +#define AD7998_BUSY_ALERT_POL 0x01 + +#define AD7998_CONV_RES_REG 0x0 +#define AD7998_ALERT_STAT_REG 0x1 +#define AD7998_CONF_REG 0x2 +#define AD7998_CYCLE_TMR_REG 0x3 +#define AD7998_DATALOW_CH1_REG 0x4 +#define AD7998_DATAHIGH_CH1_REG 0x5 +#define AD7998_HYST_CH1_REG 0x6 +#define AD7998_DATALOW_CH2_REG 0x7 +#define AD7998_DATAHIGH_CH2_REG 0x8 +#define AD7998_HYST_CH2_REG 0x9 +#define AD7998_DATALOW_CH3_REG 0xA +#define AD7998_DATAHIGH_CH3_REG 0xB +#define AD7998_HYST_CH3_REG 0xC +#define AD7998_DATALOW_CH4_REG 0xD +#define AD7998_DATAHIGH_CH4_REG 0xE +#define AD7998_HYST_CH4_REG 0xF + +#define AD7998_CYC_MASK 0x7 +#define AD7998_CYC_DIS 0x0 +#define AD7998_CYC_TCONF_32 0x1 +#define AD7998_CYC_TCONF_64 0x2 +#define AD7998_CYC_TCONF_128 0x3 +#define AD7998_CYC_TCONF_256 0x4 +#define AD7998_CYC_TCONF_512 0x5 +#define AD7998_CYC_TCONF_1024 0x6 +#define AD7998_CYC_TCONF_2048 0x7 + +#define AD7998_ALERT_STAT_CLEAR 0xFF + +/* + * AD7997 and AD7997 defines + */ + +#define AD7997_8_READ_SINGLE 0x80 +#define AD7997_8_READ_SEQUENCE 0x70 + +enum { + ad7991, + ad7995, + ad7999, + ad7992, + ad7993, + ad7994, + ad7997, + ad7998 +}; + +struct ad799x_state; + +/** + * struct ad799x_chip_info - chip specifc information + * @num_inputs: number of physical inputs on chip + * @bits: accuracy of the adc in bits + * @int_vref_mv: the internal reference voltage + * @monitor_mode: whether the chip supports monitor interrupts + * @default_config: device default configuration + * @dev_attrs: pointer to the device attribute group + * @scan_attrs: pointer to the scan element attribute group + * @event_attrs: pointer to the monitor event attribute group + * @ad799x_set_scan_mode: function pointer to the device specific mode function + + */ +struct ad799x_chip_info { + u8 num_inputs; + u8 bits; + u8 storagebits; + char sign; + u16 int_vref_mv; + bool monitor_mode; + u16 default_config; + struct attribute_group *dev_attrs; + struct attribute_group *scan_attrs; + struct attribute_group *event_attrs; + int (*ad799x_set_scan_mode) (struct ad799x_state *st, + unsigned mask); +}; + +struct ad799x_state { + struct iio_dev *indio_dev; + struct i2c_client *client; + const struct ad799x_chip_info *chip_info; + struct work_struct poll_work; + struct work_struct work_thresh; + atomic_t protect_ring; + struct iio_trigger *trig; + struct regulator *reg; + s64 last_timestamp; + u16 int_vref_mv; + unsigned id; + char *name; + u16 config; +}; + +/* + * TODO: struct ad799x_platform_data needs to go into include/linux/iio + */ + +struct ad799x_platform_data { + u16 vref_mv; +}; + +int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask); + +#ifdef CONFIG_AD799X_RING_BUFFER +int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask); +int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev); +void ad799x_ring_cleanup(struct iio_dev *indio_dev); +#else /* CONFIG_AD799X_RING_BUFFER */ +int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask) +{ + return -EINVAL; +} + + +static inline int +ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + return 0; +} + +static inline void ad799x_ring_cleanup(struct iio_dev *indio_dev) +{ +} +#endif /* CONFIG_AD799X_RING_BUFFER */ +#endif /* _AD799X_H_ */ diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c new file mode 100644 index 0000000..6309d52 --- /dev/null +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -0,0 +1,923 @@ +/* + * iio/adc/ad799x.c + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * + * based on iio/adc/max1363 + * Copyright (C) 2008-2010 Jonathan Cameron + * + * based on linux/drivers/i2c/chips/max123x + * Copyright (C) 2002-2004 Stefan Eletzhofer + * + * based on linux/drivers/acron/char/pcf8583.c + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ad799x.c + * + * Support for ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, + * ad7998 and similar chips. + * + */ + +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/i2c.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/err.h> + +#include "../iio.h" +#include "../sysfs.h" + +#include "../ring_generic.h" +#include "adc.h" +#include "ad799x.h" + +/* + * ad799x register access by I2C + */ +static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = swab16((u16)ret); + + return 0; +} + +static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, "I2C read error\n"); + return ret; + } + + *data = (u8)ret; + + return 0; +} + +static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_write_word_data(client, reg, swab16(data)); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data) +{ + struct i2c_client *client = st->client; + int ret = 0; + + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + dev_err(&client->dev, "I2C write error\n"); + + return ret; +} + +static int ad799x_scan_el_set_state(struct iio_scan_el *scan_el, + struct iio_dev *indio_dev, + bool state) +{ + struct ad799x_state *st = indio_dev->dev_data; + return ad799x_set_scan_mode(st, st->indio_dev->ring->scan_mask); +} + +/* Here we claim all are 16 bits. This currently does no harm and saves + * us a lot of scan element listings */ + +#define AD799X_SCAN_EL(number) \ + IIO_SCAN_EL_C(in##number, number, 0, ad799x_scan_el_set_state); + +static AD799X_SCAN_EL(0); +static AD799X_SCAN_EL(1); +static AD799X_SCAN_EL(2); +static AD799X_SCAN_EL(3); +static AD799X_SCAN_EL(4); +static AD799X_SCAN_EL(5); +static AD799X_SCAN_EL(6); +static AD799X_SCAN_EL(7); + +static ssize_t ad799x_show_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *indio_dev = ring->indio_dev; + struct ad799x_state *st = indio_dev->dev_data; + + return sprintf(buf, "%c%d/%d\n", st->chip_info->sign, + st->chip_info->bits, AD799X_STORAGEBITS); +} +static IIO_DEVICE_ATTR(in_type, S_IRUGO, ad799x_show_type, NULL, 0); + +static int ad7991_5_9_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + return i2c_smbus_write_byte(st->client, + st->config | (mask << AD799X_CHANNEL_SHIFT)); +} + +static int ad7992_3_4_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + return ad799x_i2c_write8(st, AD7998_CONF_REG, + st->config | (mask << AD799X_CHANNEL_SHIFT)); +} + +static int ad7997_8_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + return ad799x_i2c_write16(st, AD7998_CONF_REG, + st->config | (mask << AD799X_CHANNEL_SHIFT)); +} + +int ad799x_set_scan_mode(struct ad799x_state *st, unsigned mask) +{ + int ret; + + if (st->chip_info->ad799x_set_scan_mode != NULL) { + ret = st->chip_info->ad799x_set_scan_mode(st, mask); + return (ret > 0) ? 0 : ret; + } + + return 0; +} + +static ssize_t ad799x_read_single_channel(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + int ret = 0, len = 0; + u32 data ; + u16 rxbuf[1]; + u8 cmd; + long mask; + + mutex_lock(&dev_info->mlock); + mask = 1 << this_attr->address; + /* If ring buffer capture is occuring, query the buffer */ + if (iio_ring_enabled(dev_info)) { + data = ret = ad799x_single_channel_from_ring(st, mask); + if (ret < 0) + goto error_ret; + ret = 0; + } else { + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | (mask << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = mask << AD799X_CHANNEL_SHIFT; + break; + case ad7997: + case ad7998: + cmd = (this_attr->address << + AD799X_CHANNEL_SHIFT) | AD7997_8_READ_SINGLE; + break; + default: + cmd = 0; + + } + ret = ad799x_i2c_read16(st, cmd, rxbuf); + if (ret < 0) + goto error_ret; + + data = rxbuf[0]; + } + + /* Pretty print the result */ + len = sprintf(buf, "%u\n", data & ((1 << (st->chip_info->bits)) - 1)); + +error_ret: + mutex_unlock(&dev_info->mlock); + return ret ? ret : len; +} + +static ssize_t ad799x_read_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + + int ret, len = 0; + u8 val; + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val); + if (ret) + return ret; + + val &= AD7998_CYC_MASK; + + switch (val) { + case AD7998_CYC_DIS: + len = sprintf(buf, "0\n"); + break; + case AD7998_CYC_TCONF_32: + len = sprintf(buf, "15625\n"); + break; + case AD7998_CYC_TCONF_64: + len = sprintf(buf, "7812\n"); + break; + case AD7998_CYC_TCONF_128: + len = sprintf(buf, "3906\n"); + break; + case AD7998_CYC_TCONF_256: + len = sprintf(buf, "1953\n"); + break; + case AD7998_CYC_TCONF_512: + len = sprintf(buf, "976\n"); + break; + case AD7998_CYC_TCONF_1024: + len = sprintf(buf, "488\n"); + break; + case AD7998_CYC_TCONF_2048: + len = sprintf(buf, "244\n"); + break; + } + return len; +} + +static ssize_t ad799x_write_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + + long val; + int ret; + u8 t; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&dev_info->mlock); + ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); + if (ret) + goto error_ret_mutex; + /* Wipe the bits clean */ + t &= ~AD7998_CYC_MASK; + + switch (val) { + case 15625: + t |= AD7998_CYC_TCONF_32; + break; + case 7812: + t |= AD7998_CYC_TCONF_64; + break; + case 3906: + t |= AD7998_CYC_TCONF_128; + break; + case 1953: + t |= AD7998_CYC_TCONF_256; + break; + case 976: + t |= AD7998_CYC_TCONF_512; + break; + case 488: + t |= AD7998_CYC_TCONF_1024; + break; + case 244: + t |= AD7998_CYC_TCONF_2048; + break; + case 0: + t |= AD7998_CYC_DIS; + break; + default: + ret = -EINVAL; + goto error_ret_mutex; + } + + ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); + +error_ret_mutex: + mutex_unlock(&dev_info->mlock); + + return ret ? ret : len; +} + + +static ssize_t ad799x_read_channel_config(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + struct iio_event_attr *this_attr = to_iio_event_attr(attr); + + int ret; + u16 val; + ret = ad799x_i2c_read16(st, this_attr->mask, &val); + if (ret) + return ret; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t ad799x_write_channel_config(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t len) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + struct iio_event_attr *this_attr = to_iio_event_attr(attr); + + long val; + int ret; + + ret = strict_strtol(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&dev_info->mlock); + ret = ad799x_i2c_write16(st, this_attr->mask, val); + mutex_unlock(&dev_info->mlock); + + return ret ? ret : len; +} + +static void ad799x_interrupt_bh(struct work_struct *work_s) +{ + struct ad799x_state *st = container_of(work_s, + struct ad799x_state, work_thresh); + u8 status; + int i; + + if (ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status)) + goto err_out; + + if (!status) + goto err_out; + + ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR); + + for (i = 0; i < 8; i++) { + if (status & (1 << i)) + iio_push_event(st->indio_dev, 0, + i & 0x1 ? + IIO_EVENT_CODE_IN_HIGH_THRESH(i >> 1) : + IIO_EVENT_CODE_IN_LOW_THRESH(i >> 1), + st->last_timestamp); + } + +err_out: + enable_irq(st->client->irq); +} + +static int ad799x_interrupt(struct iio_dev *dev_info, + int index, + s64 timestamp, + int no_test) +{ + struct ad799x_state *st = dev_info->dev_data; + + st->last_timestamp = timestamp; + schedule_work(&st->work_thresh); + return 0; +} + +IIO_EVENT_SH(ad799x, &ad799x_interrupt); + +/* Direct read attribtues */ +static IIO_DEV_ATTR_IN_RAW(0, ad799x_read_single_channel, 0); +static IIO_DEV_ATTR_IN_RAW(1, ad799x_read_single_channel, 1); +static IIO_DEV_ATTR_IN_RAW(2, ad799x_read_single_channel, 2); +static IIO_DEV_ATTR_IN_RAW(3, ad799x_read_single_channel, 3); +static IIO_DEV_ATTR_IN_RAW(4, ad799x_read_single_channel, 4); +static IIO_DEV_ATTR_IN_RAW(5, ad799x_read_single_channel, 5); +static IIO_DEV_ATTR_IN_RAW(6, ad799x_read_single_channel, 6); +static IIO_DEV_ATTR_IN_RAW(7, ad799x_read_single_channel, 7); + +static ssize_t ad799x_show_scale(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* Driver currently only support internal vref */ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + + /* Corresponds to Vref / 2^(bits) */ + unsigned int scale_uv = (st->int_vref_mv * 1000) >> st->chip_info->bits; + + return sprintf(buf, "%d.%d\n", scale_uv / 1000, scale_uv % 1000); +} + +static IIO_DEVICE_ATTR(in_scale, S_IRUGO, ad799x_show_scale, NULL, 0); + +static ssize_t ad799x_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *dev_info = dev_get_drvdata(dev); + struct ad799x_state *st = iio_dev_get_devdata(dev_info); + return sprintf(buf, "%s\n", st->client->name); +} + +static IIO_DEVICE_ATTR(name, S_IRUGO, ad799x_show_name, NULL, 0); + +static struct attribute *ad7991_5_9_3_4_device_attrs[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_in2_raw.dev_attr.attr, + &iio_dev_attr_in3_raw.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct attribute_group ad7991_5_9_3_4_dev_attr_group = { + .attrs = ad7991_5_9_3_4_device_attrs, +}; + +static struct attribute *ad7991_5_9_3_4_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7991_5_9_3_4_scan_el_group = { + .name = "scan_elements", + .attrs = ad7991_5_9_3_4_scan_el_attrs, +}; + +static struct attribute *ad7992_device_attrs[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct attribute_group ad7992_dev_attr_group = { + .attrs = ad7992_device_attrs, +}; + +static struct attribute *ad7992_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7992_scan_el_group = { + .name = "scan_elements", + .attrs = ad7992_scan_el_attrs, +}; + +static struct attribute *ad7997_8_device_attrs[] = { + &iio_dev_attr_in0_raw.dev_attr.attr, + &iio_dev_attr_in1_raw.dev_attr.attr, + &iio_dev_attr_in2_raw.dev_attr.attr, + &iio_dev_attr_in3_raw.dev_attr.attr, + &iio_dev_attr_in4_raw.dev_attr.attr, + &iio_dev_attr_in5_raw.dev_attr.attr, + &iio_dev_attr_in6_raw.dev_attr.attr, + &iio_dev_attr_in7_raw.dev_attr.attr, + &iio_dev_attr_name.dev_attr.attr, + &iio_dev_attr_in_scale.dev_attr.attr, + NULL +}; + +static struct attribute_group ad7997_8_dev_attr_group = { + .attrs = ad7997_8_device_attrs, +}; + +static struct attribute *ad7997_8_scan_el_attrs[] = { + &iio_scan_el_in0.dev_attr.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in4.dev_attr.attr, + &iio_const_attr_in4_index.dev_attr.attr, + &iio_scan_el_in5.dev_attr.attr, + &iio_const_attr_in5_index.dev_attr.attr, + &iio_scan_el_in6.dev_attr.attr, + &iio_const_attr_in6_index.dev_attr.attr, + &iio_scan_el_in7.dev_attr.attr, + &iio_const_attr_in7_index.dev_attr.attr, + &iio_dev_attr_in_type.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7997_8_scan_el_group = { + .name = "scan_elements", + .attrs = ad7997_8_scan_el_attrs, +}; + +IIO_EVENT_ATTR_SH(in0_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH1_REG); + +IIO_EVENT_ATTR_SH(in0_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH1_REG); + +IIO_EVENT_ATTR_SH(in0_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH1_REG); + +IIO_EVENT_ATTR_SH(in1_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH2_REG); + +IIO_EVENT_ATTR_SH(in1_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH2_REG); + +IIO_EVENT_ATTR_SH(in1_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH2_REG); + +IIO_EVENT_ATTR_SH(in2_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH3_REG); + +IIO_EVENT_ATTR_SH(in2_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH3_REG); + +IIO_EVENT_ATTR_SH(in2_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH3_REG); + +IIO_EVENT_ATTR_SH(in3_thresh_low_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATALOW_CH4_REG); + +IIO_EVENT_ATTR_SH(in3_thresh_high_value, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_DATAHIGH_CH4_REG); + +IIO_EVENT_ATTR_SH(in3_thresh_both_hyst_raw, + iio_event_ad799x, + ad799x_read_channel_config, + ad799x_write_channel_config, + AD7998_HYST_CH4_REG); + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ad799x_read_frequency, + ad799x_write_frequency); +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0"); + +static struct attribute *ad7993_4_7_8_event_attributes[] = { + &iio_event_attr_in0_thresh_low_value.dev_attr.attr, + &iio_event_attr_in0_thresh_high_value.dev_attr.attr, + &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in1_thresh_low_value.dev_attr.attr, + &iio_event_attr_in1_thresh_high_value.dev_attr.attr, + &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in2_thresh_low_value.dev_attr.attr, + &iio_event_attr_in2_thresh_high_value.dev_attr.attr, + &iio_event_attr_in2_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in3_thresh_low_value.dev_attr.attr, + &iio_event_attr_in3_thresh_high_value.dev_attr.attr, + &iio_event_attr_in3_thresh_both_hyst_raw.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7993_4_7_8_event_attrs_group = { + .attrs = ad7993_4_7_8_event_attributes, +}; + +static struct attribute *ad7992_event_attributes[] = { + &iio_event_attr_in0_thresh_low_value.dev_attr.attr, + &iio_event_attr_in0_thresh_high_value.dev_attr.attr, + &iio_event_attr_in0_thresh_both_hyst_raw.dev_attr.attr, + &iio_event_attr_in1_thresh_low_value.dev_attr.attr, + &iio_event_attr_in1_thresh_high_value.dev_attr.attr, + &iio_event_attr_in1_thresh_both_hyst_raw.dev_attr.attr, + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static struct attribute_group ad7992_event_attrs_group = { + .attrs = ad7992_event_attributes, +}; + +static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { + [ad7991] = { + .num_inputs = 4, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, + }, + [ad7995] = { + .num_inputs = 4, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, + }, + [ad7999] = { + .num_inputs = 4, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .ad799x_set_scan_mode = ad7991_5_9_set_scan_mode, + }, + [ad7992] = { + .num_inputs = 2, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7992_dev_attr_group, + .scan_attrs = &ad7992_scan_el_group, + .event_attrs = &ad7992_event_attrs_group, + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, + }, + [ad7993] = { + .num_inputs = 4, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, + }, + [ad7994] = { + .num_inputs = 4, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7991_5_9_3_4_dev_attr_group, + .scan_attrs = &ad7991_5_9_3_4_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7992_3_4_set_scan_mode, + }, + [ad7997] = { + .num_inputs = 8, + .bits = 10, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 1024, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7997_8_dev_attr_group, + .scan_attrs = &ad7997_8_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7997_8_set_scan_mode, + }, + [ad7998] = { + .num_inputs = 8, + .bits = 12, + .sign = IIO_SCAN_EL_TYPE_UNSIGNED, + .int_vref_mv = 4096, + .monitor_mode = true, + .default_config = AD7998_ALERT_EN, + .dev_attrs = &ad7997_8_dev_attr_group, + .scan_attrs = &ad7997_8_scan_el_group, + .event_attrs = &ad7993_4_7_8_event_attrs_group, + .ad799x_set_scan_mode = ad7997_8_set_scan_mode, + }, +}; + +static int __devinit ad799x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret, regdone = 0; + struct ad799x_platform_data *pdata = client->dev.platform_data; + struct ad799x_state *st = kzalloc(sizeof(*st), GFP_KERNEL); + if (st == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + /* this is only used for device removal purposes */ + i2c_set_clientdata(client, st); + + atomic_set(&st->protect_ring, 0); + st->id = id->driver_data; + st->chip_info = &ad799x_chip_info_tbl[st->id]; + st->config = st->chip_info->default_config; + + /* TODO: Add pdata options for filtering and bit delay */ + + if (pdata) + st->int_vref_mv = pdata->vref_mv; + else + st->int_vref_mv = st->chip_info->int_vref_mv; + + st->reg = regulator_get(&client->dev, "vcc"); + if (!IS_ERR(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + } + st->client = client; + + st->indio_dev = iio_allocate_device(); + if (st->indio_dev == NULL) { + ret = -ENOMEM; + goto error_disable_reg; + } + + /* Estabilish that the iio_dev is a child of the i2c device */ + st->indio_dev->dev.parent = &client->dev; + st->indio_dev->attrs = st->chip_info->dev_attrs; + st->indio_dev->event_attrs = st->chip_info->event_attrs; + + st->indio_dev->dev_data = (void *)(st); + st->indio_dev->driver_module = THIS_MODULE; + st->indio_dev->modes = INDIO_DIRECT_MODE; + st->indio_dev->num_interrupt_lines = 1; + + ret = ad799x_set_scan_mode(st, 0); + if (ret) + goto error_free_device; + + ret = ad799x_register_ring_funcs_and_init(st->indio_dev); + if (ret) + goto error_free_device; + + ret = iio_device_register(st->indio_dev); + if (ret) + goto error_cleanup_ring; + regdone = 1; + + ret = iio_ring_buffer_register(st->indio_dev->ring, 0); + if (ret) + goto error_cleanup_ring; + + if (client->irq > 0 && st->chip_info->monitor_mode) { + INIT_WORK(&st->work_thresh, ad799x_interrupt_bh); + + ret = iio_register_interrupt_line(client->irq, + st->indio_dev, + 0, + IRQF_TRIGGER_FALLING, + client->name); + if (ret) + goto error_cleanup_ring; + + /* + * The event handler list element refer to iio_event_ad799x. + * All event attributes bind to the same event handler. + * So, only register event handler once. + */ + iio_add_event_to_list(&iio_event_ad799x, + &st->indio_dev->interrupts[0]->ev_list); + } + + return 0; +error_cleanup_ring: + ad799x_ring_cleanup(st->indio_dev); +error_free_device: + if (!regdone) + iio_free_device(st->indio_dev); + else + iio_device_unregister(st->indio_dev); +error_disable_reg: + if (!IS_ERR(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR(st->reg)) + regulator_put(st->reg); + kfree(st); +error_ret: + return ret; +} + +static __devexit int ad799x_remove(struct i2c_client *client) +{ + struct ad799x_state *st = i2c_get_clientdata(client); + struct iio_dev *indio_dev = st->indio_dev; + + if (client->irq > 0 && st->chip_info->monitor_mode) + iio_unregister_interrupt_line(indio_dev, 0); + + iio_ring_buffer_unregister(indio_dev->ring); + ad799x_ring_cleanup(indio_dev); + iio_device_unregister(indio_dev); + if (!IS_ERR(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + kfree(st); + + return 0; +} + +static const struct i2c_device_id ad799x_id[] = { + { "ad7991", ad7991 }, + { "ad7995", ad7995 }, + { "ad7999", ad7999 }, + { "ad7992", ad7992 }, + { "ad7993", ad7993 }, + { "ad7994", ad7994 }, + { "ad7997", ad7997 }, + { "ad7998", ad7998 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ad799x_id); + +static struct i2c_driver ad799x_driver = { + .driver = { + .name = "ad799x", + }, + .probe = ad799x_probe, + .remove = __devexit_p(ad799x_remove), + .id_table = ad799x_id, +}; + +static __init int ad799x_init(void) +{ + return i2c_add_driver(&ad799x_driver); +} + +static __exit void ad799x_exit(void) +{ + i2c_del_driver(&ad799x_driver); +} + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_DESCRIPTION("Analog Devices AD799x ADC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:ad799x"); + +module_init(ad799x_init); +module_exit(ad799x_exit); diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c new file mode 100644 index 0000000..975cdcb --- /dev/null +++ b/drivers/staging/iio/adc/ad799x_ring.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc. + * Copyright (C) 2008-2010 Jonathan Cameron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ad799x_ring.c + */ + +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/i2c.h> +#include <linux/bitops.h> + +#include "../iio.h" +#include "../ring_generic.h" +#include "../ring_sw.h" +#include "../trigger.h" +#include "../sysfs.h" + +#include "ad799x.h" + +int ad799x_single_channel_from_ring(struct ad799x_state *st, long mask) +{ + struct iio_ring_buffer *ring = st->indio_dev->ring; + int count = 0, ret; + u16 *ring_data; + + if (!(ring->scan_mask & mask)) { + ret = -EBUSY; + goto error_ret; + } + + ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); + if (ring_data == NULL) { + ret = -ENOMEM; + goto error_ret; + } + ret = ring->access.read_last(ring, (u8 *) ring_data); + if (ret) + goto error_free_ring_data; + /* Need a count of channels prior to this one */ + mask >>= 1; + while (mask) { + if (mask & ring->scan_mask) + count++; + mask >>= 1; + } + + ret = be16_to_cpu(ring_data[count]); + +error_free_ring_data: + kfree(ring_data); +error_ret: + return ret; +} + +/** + * ad799x_ring_preenable() setup the parameters of the ring before enabling + * + * The complex nature of the setting of the nuber of bytes per datum is due + * to this driver currently ensuring that the timestamp is stored at an 8 + * byte boundary. + **/ +static int ad799x_ring_preenable(struct iio_dev *indio_dev) +{ + struct iio_ring_buffer *ring = indio_dev->ring; + struct ad799x_state *st = indio_dev->dev_data; + size_t d_size; + unsigned long numvals; + + /* + * Need to figure out the current mode based upon the requested + * scan mask in iio_dev + */ + + if (st->id == ad7997 || st->id == ad7998) + ad799x_set_scan_mode(st, ring->scan_mask); + + numvals = ring->scan_count; + + if (ring->access.set_bytes_per_datum) { + d_size = numvals*2 + sizeof(s64); + if (d_size % 8) + d_size += 8 - (d_size % 8); + ring->access.set_bytes_per_datum(ring, d_size); + } + + return 0; +} + +/** + * ad799x_poll_func_th() th of trigger launched polling to ring buffer + * + * As sampling only occurs on i2c comms occuring, leave timestamping until + * then. Some triggers will generate their own time stamp. Currently + * there is no way of notifying them when no one cares. + **/ +static void ad799x_poll_func_th(struct iio_dev *indio_dev, s64 time) +{ + struct ad799x_state *st = indio_dev->dev_data; + + schedule_work(&st->poll_work); + + return; +} +/** + * ad799x_poll_bh_to_ring() bh of trigger launched polling to ring buffer + * @work_s: the work struct through which this was scheduled + * + * Currently there is no option in this driver to disable the saving of + * timestamps within the ring. + * I think the one copy of this at a time was to avoid problems if the + * trigger was set far too high and the reads then locked up the computer. + **/ +static void ad799x_poll_bh_to_ring(struct work_struct *work_s) +{ + struct ad799x_state *st = container_of(work_s, struct ad799x_state, + poll_work); + struct iio_dev *indio_dev = st->indio_dev; + struct iio_ring_buffer *ring = indio_dev->ring; + struct iio_sw_ring_buffer *ring_sw = iio_to_sw_ring(indio_dev->ring); + s64 time_ns; + __u8 *rxbuf; + int b_sent; + size_t d_size; + u8 cmd; + + unsigned long numvals = ring->scan_count; + + /* Ensure the timestamp is 8 byte aligned */ + d_size = numvals*2 + sizeof(s64); + + if (d_size % sizeof(s64)) + d_size += sizeof(s64) - (d_size % sizeof(s64)); + + /* Ensure only one copy of this function running at a time */ + if (atomic_inc_return(&st->protect_ring) > 1) + return; + + /* Monitor mode prevents reading. Whilst not currently implemented + * might as well have this test in here in the meantime as it does + * no harm. + */ + if (numvals == 0) + return; + + rxbuf = kmalloc(d_size, GFP_KERNEL); + if (rxbuf == NULL) + return; + + switch (st->id) { + case ad7991: + case ad7995: + case ad7999: + cmd = st->config | (ring->scan_mask << AD799X_CHANNEL_SHIFT); + break; + case ad7992: + case ad7993: + case ad7994: + cmd = (ring->scan_mask << AD799X_CHANNEL_SHIFT) | + AD7998_CONV_RES_REG; + break; + case ad7997: + case ad7998: + cmd = AD7997_8_READ_SEQUENCE | AD7998_CONV_RES_REG; + break; + default: + cmd = 0; + } + + b_sent = i2c_smbus_read_i2c_block_data(st->client, + cmd, numvals*2, rxbuf); + if (b_sent < 0) + goto done; + + time_ns = iio_get_time_ns(); + + memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); + + ring->access.store_to(&ring_sw->buf, rxbuf, time_ns); +done: + kfree(rxbuf); + atomic_dec(&st->protect_ring); +} + + +int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev) +{ + struct ad799x_state *st = indio_dev->dev_data; + int ret = 0; + + indio_dev->ring = iio_sw_rb_allocate(indio_dev); + if (!indio_dev->ring) { + ret = -ENOMEM; + goto error_ret; + } + /* Effectively select the ring buffer implementation */ + iio_ring_sw_register_funcs(&st->indio_dev->ring->access); + ret = iio_alloc_pollfunc(indio_dev, NULL, &ad799x_poll_func_th); + if (ret) + goto error_deallocate_sw_rb; + + /* Ring buffer functions - here trigger setup related */ + + indio_dev->ring->preenable = &ad799x_ring_preenable; + indio_dev->ring->postenable = &iio_triggered_ring_postenable; + indio_dev->ring->predisable = &iio_triggered_ring_predisable; + + INIT_WORK(&st->poll_work, &ad799x_poll_bh_to_ring); + + indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs; + + /* Flag that polled ring buffering is possible */ + indio_dev->modes |= INDIO_RING_TRIGGERED; + return 0; +error_deallocate_sw_rb: + iio_sw_rb_free(indio_dev->ring); +error_ret: + return ret; +} + +void ad799x_ring_cleanup(struct iio_dev *indio_dev) +{ + /* ensure that the trigger has been detached */ + if (indio_dev->trig) { + iio_put_trigger(indio_dev->trig); + iio_trigger_dettach_poll_func(indio_dev->trig, + indio_dev->pollfunc); + } + kfree(indio_dev->pollfunc); + iio_sw_rb_free(indio_dev->ring); +} diff --git a/drivers/staging/iio/adc/adc.h b/drivers/staging/iio/adc/adc.h index 7841e6a..40c5949 100644 --- a/drivers/staging/iio/adc/adc.h +++ b/drivers/staging/iio/adc/adc.h @@ -16,8 +16,8 @@ #define IIO_DEV_ATTR_IN_RAW(_num, _show, _addr) \ IIO_DEVICE_ATTR(in##_num##_raw, S_IRUGO, _show, NULL, _addr) -#define IIO_DEV_ATTR_IN_NAMED_RAW(_name, _show, _addr) \ - IIO_DEVICE_ATTR(in_##_name##_raw, S_IRUGO, _show, NULL, _addr) +#define IIO_DEV_ATTR_IN_NAMED_RAW(_num, _name, _show, _addr) \ + IIO_DEVICE_ATTR(in##_num##_##_name##_raw, S_IRUGO, _show, NULL, _addr) #define IIO_DEV_ATTR_IN_DIFF_RAW(_nump, _numn, _show, _addr) \ IIO_DEVICE_ATTR_NAMED(in##_nump##min##_numn##_raw, \ @@ -27,5 +27,16 @@ NULL, \ _addr) -#define IIO_EVENT_CODE_IN_HIGH_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a) -#define IIO_EVENT_CODE_IN_LOW_THRESH(a) (IIO_EVENT_CODE_ADC_BASE + a + 32) + +#define IIO_CONST_ATTR_IN_NAMED_OFFSET(_num, _name, _string) \ + IIO_CONST_ATTR(in##_num##_##_name##_offset, _string) + +#define IIO_CONST_ATTR_IN_NAMED_SCALE(_num, _name, _string) \ + IIO_CONST_ATTR(in##_num##_##_name##_scale, _string) + +#define IIO_EVENT_CODE_IN_HIGH_THRESH(a) \ + IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, a, IIO_EV_TYPE_THRESH, \ + IIO_EV_DIR_RISING) +#define IIO_EVENT_CODE_IN_LOW_THRESH(a) \ + IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, a, IIO_EV_TYPE_THRESH, \ + IIO_EV_DIR_FALLING) diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 6435e50..dde097a 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -42,11 +42,10 @@ /* Here we claim all are 16 bits. This currently does no harm and saves * us a lot of scan element listings */ -#define MAX1363_SCAN_EL(number) \ - IIO_SCAN_EL_C(in##number, number, IIO_UNSIGNED(16), 0, NULL); +#define MAX1363_SCAN_EL(number) \ + IIO_SCAN_EL_C(in##number, number, 0, NULL); #define MAX1363_SCAN_EL_D(p, n, number) \ - IIO_SCAN_NAMED_EL_C(in##p##m##in##n, in##p-in##n, \ - number, IIO_SIGNED(16), 0, NULL); + IIO_SCAN_NAMED_EL_C(in##p##m##in##n, in##p-in##n, number, 0, NULL); static MAX1363_SCAN_EL(0); static MAX1363_SCAN_EL(1); @@ -148,17 +147,59 @@ const struct max1363_mode return NULL; } -static ssize_t max1363_show_precision(struct device *dev, +static ssize_t max1363_show_precision_u(struct device *dev, struct device_attribute *attr, char *buf) { - struct iio_dev *dev_info = dev_get_drvdata(dev); + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *dev_info = ring->indio_dev; + struct max1363_state *st = iio_dev_get_devdata(dev_info); + return sprintf(buf, "u%d/16\n", st->chip_info->bits); +} + +static ssize_t max1363_show_precision_s(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_ring_buffer *ring = dev_get_drvdata(dev); + struct iio_dev *dev_info = ring->indio_dev; struct max1363_state *st = iio_dev_get_devdata(dev_info); - return sprintf(buf, "%d\n", st->chip_info->bits); + return sprintf(buf, "s%d/16\n", st->chip_info->bits); } -static IIO_DEVICE_ATTR(in_precision, S_IRUGO, max1363_show_precision, - NULL, 0); +#define MAX1363_SCAN_TYPE(n) \ + DEVICE_ATTR(in##n##_type, S_IRUGO, \ + max1363_show_precision_u, NULL); +#define MAX1363_SCAN_TYPE_D(p, n) \ + struct device_attribute dev_attr_in##p##m##in##n##_type = \ + __ATTR(in##p-in##n##_type, S_IRUGO, \ + max1363_show_precision_s, NULL); + +static MAX1363_SCAN_TYPE(0); +static MAX1363_SCAN_TYPE(1); +static MAX1363_SCAN_TYPE(2); +static MAX1363_SCAN_TYPE(3); +static MAX1363_SCAN_TYPE(4); +static MAX1363_SCAN_TYPE(5); +static MAX1363_SCAN_TYPE(6); +static MAX1363_SCAN_TYPE(7); +static MAX1363_SCAN_TYPE(8); +static MAX1363_SCAN_TYPE(9); +static MAX1363_SCAN_TYPE(10); +static MAX1363_SCAN_TYPE(11); + +static MAX1363_SCAN_TYPE_D(0, 1); +static MAX1363_SCAN_TYPE_D(2, 3); +static MAX1363_SCAN_TYPE_D(4, 5); +static MAX1363_SCAN_TYPE_D(6, 7); +static MAX1363_SCAN_TYPE_D(8, 9); +static MAX1363_SCAN_TYPE_D(10, 11); +static MAX1363_SCAN_TYPE_D(1, 0); +static MAX1363_SCAN_TYPE_D(3, 2); +static MAX1363_SCAN_TYPE_D(5, 4); +static MAX1363_SCAN_TYPE_D(7, 6); +static MAX1363_SCAN_TYPE_D(9, 8); +static MAX1363_SCAN_TYPE_D(11, 10); static int max1363_write_basic_config(struct i2c_client *client, unsigned char d1, @@ -345,15 +386,22 @@ static struct attribute_group max1363_dev_attr_group = { }; static struct attribute *max1363_scan_el_attrs[] = { - &iio_scan_el_in0.dev_attr.attr, - &iio_scan_el_in1.dev_attr.attr, - &iio_scan_el_in2.dev_attr.attr, - &iio_scan_el_in3.dev_attr.attr, - &iio_scan_el_in0min1.dev_attr.attr, - &iio_scan_el_in2min3.dev_attr.attr, - &iio_scan_el_in1min0.dev_attr.attr, - &iio_scan_el_in3min2.dev_attr.attr, - &iio_dev_attr_in_precision.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr, + &iio_const_attr_in0min1_index.dev_attr.attr, + &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr, + &iio_const_attr_in2min3_index.dev_attr.attr, + &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr, + &iio_const_attr_in1min0_index.dev_attr.attr, + &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr, + &iio_const_attr_in3min2_index.dev_attr.attr, NULL, }; @@ -419,31 +467,54 @@ static struct attribute_group max1238_dev_attr_group = { }; static struct attribute *max1238_scan_el_attrs[] = { - &iio_scan_el_in0.dev_attr.attr, - &iio_scan_el_in1.dev_attr.attr, - &iio_scan_el_in2.dev_attr.attr, - &iio_scan_el_in3.dev_attr.attr, - &iio_scan_el_in4.dev_attr.attr, - &iio_scan_el_in5.dev_attr.attr, - &iio_scan_el_in6.dev_attr.attr, - &iio_scan_el_in7.dev_attr.attr, - &iio_scan_el_in8.dev_attr.attr, - &iio_scan_el_in9.dev_attr.attr, - &iio_scan_el_in10.dev_attr.attr, - &iio_scan_el_in11.dev_attr.attr, - &iio_scan_el_in0min1.dev_attr.attr, - &iio_scan_el_in2min3.dev_attr.attr, - &iio_scan_el_in4min5.dev_attr.attr, - &iio_scan_el_in6min7.dev_attr.attr, - &iio_scan_el_in8min9.dev_attr.attr, - &iio_scan_el_in10min11.dev_attr.attr, - &iio_scan_el_in1min0.dev_attr.attr, - &iio_scan_el_in3min2.dev_attr.attr, - &iio_scan_el_in5min4.dev_attr.attr, - &iio_scan_el_in7min6.dev_attr.attr, - &iio_scan_el_in9min8.dev_attr.attr, - &iio_scan_el_in11min10.dev_attr.attr, - &iio_dev_attr_in_precision.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in4.dev_attr.attr, &dev_attr_in4_type.attr, + &iio_const_attr_in4_index.dev_attr.attr, + &iio_scan_el_in5.dev_attr.attr, &dev_attr_in5_type.attr, + &iio_const_attr_in5_index.dev_attr.attr, + &iio_scan_el_in6.dev_attr.attr, &dev_attr_in6_type.attr, + &iio_const_attr_in6_index.dev_attr.attr, + &iio_scan_el_in7.dev_attr.attr, &dev_attr_in7_type.attr, + &iio_const_attr_in7_index.dev_attr.attr, + &iio_scan_el_in8.dev_attr.attr, &dev_attr_in8_type.attr, + &iio_const_attr_in8_index.dev_attr.attr, + &iio_scan_el_in9.dev_attr.attr, &dev_attr_in9_type.attr, + &iio_const_attr_in9_index.dev_attr.attr, + &iio_scan_el_in10.dev_attr.attr, &dev_attr_in10_type.attr, + &iio_const_attr_in10_index.dev_attr.attr, + &iio_scan_el_in11.dev_attr.attr, &dev_attr_in11_type.attr, + &iio_const_attr_in11_index.dev_attr.attr, + &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr, + &iio_const_attr_in0min1_index.dev_attr.attr, + &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr, + &iio_const_attr_in2min3_index.dev_attr.attr, + &iio_scan_el_in4min5.dev_attr.attr, &dev_attr_in4min5_type.attr, + &iio_const_attr_in4min5_index.dev_attr.attr, + &iio_scan_el_in6min7.dev_attr.attr, &dev_attr_in6min7_type.attr, + &iio_const_attr_in6min7_index.dev_attr.attr, + &iio_scan_el_in8min9.dev_attr.attr, &dev_attr_in8min9_type.attr, + &iio_const_attr_in8min9_index.dev_attr.attr, + &iio_scan_el_in10min11.dev_attr.attr, &dev_attr_in10min11_type.attr, + &iio_const_attr_in10min11_index.dev_attr.attr, + &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr, + &iio_const_attr_in1min0_index.dev_attr.attr, + &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr, + &iio_const_attr_in3min2_index.dev_attr.attr, + &iio_scan_el_in5min4.dev_attr.attr, &dev_attr_in5min4_type.attr, + &iio_const_attr_in5min4_index.dev_attr.attr, + &iio_scan_el_in7min6.dev_attr.attr, &dev_attr_in7min6_type.attr, + &iio_const_attr_in7min6_index.dev_attr.attr, + &iio_scan_el_in9min8.dev_attr.attr, &dev_attr_in9min8_type.attr, + &iio_const_attr_in9min8_index.dev_attr.attr, + &iio_scan_el_in11min10.dev_attr.attr, &dev_attr_in11min10_type.attr, + &iio_const_attr_in11min10_index.dev_attr.attr, NULL, }; @@ -498,23 +569,39 @@ static struct attribute_group max11608_dev_attr_group = { }; static struct attribute *max11608_scan_el_attrs[] = { - &iio_scan_el_in0.dev_attr.attr, - &iio_scan_el_in1.dev_attr.attr, - &iio_scan_el_in2.dev_attr.attr, - &iio_scan_el_in3.dev_attr.attr, - &iio_scan_el_in4.dev_attr.attr, - &iio_scan_el_in5.dev_attr.attr, - &iio_scan_el_in6.dev_attr.attr, - &iio_scan_el_in7.dev_attr.attr, - &iio_scan_el_in0min1.dev_attr.attr, - &iio_scan_el_in2min3.dev_attr.attr, - &iio_scan_el_in4min5.dev_attr.attr, - &iio_scan_el_in6min7.dev_attr.attr, - &iio_scan_el_in1min0.dev_attr.attr, - &iio_scan_el_in3min2.dev_attr.attr, - &iio_scan_el_in5min4.dev_attr.attr, - &iio_scan_el_in7min6.dev_attr.attr, - &iio_dev_attr_in_precision.dev_attr.attr, + &iio_scan_el_in0.dev_attr.attr, &dev_attr_in0_type.attr, + &iio_const_attr_in0_index.dev_attr.attr, + &iio_scan_el_in1.dev_attr.attr, &dev_attr_in1_type.attr, + &iio_const_attr_in1_index.dev_attr.attr, + &iio_scan_el_in2.dev_attr.attr, &dev_attr_in2_type.attr, + &iio_const_attr_in2_index.dev_attr.attr, + &iio_scan_el_in3.dev_attr.attr, &dev_attr_in3_type.attr, + &iio_const_attr_in3_index.dev_attr.attr, + &iio_scan_el_in4.dev_attr.attr, &dev_attr_in4_type.attr, + &iio_const_attr_in4_index.dev_attr.attr, + &iio_scan_el_in5.dev_attr.attr, &dev_attr_in5_type.attr, + &iio_const_attr_in5_index.dev_attr.attr, + &iio_scan_el_in6.dev_attr.attr, &dev_attr_in6_type.attr, + &iio_const_attr_in6_index.dev_attr.attr, + &iio_scan_el_in7.dev_attr.attr, &dev_attr_in7_type.attr, + &iio_const_attr_in7_index.dev_attr.attr, + &iio_scan_el_in0min1.dev_attr.attr, &dev_attr_in0min1_type.attr, + &iio_const_attr_in0min1_index.dev_attr.attr, + &iio_scan_el_in2min3.dev_attr.attr, &dev_attr_in2min3_type.attr, + &iio_const_attr_in2min3_index.dev_attr.attr, + &iio_scan_el_in4min5.dev_attr.attr, &dev_attr_in4min5_type.attr, + &iio_const_attr_in4min5_index.dev_attr.attr, + &iio_scan_el_in6min7.dev_attr.attr, &dev_attr_in6min7_type.attr, + &iio_const_attr_in6min7_index.dev_attr.attr, + &iio_scan_el_in1min0.dev_attr.attr, &dev_attr_in1min0_type.attr, + &iio_const_attr_in1min0_index.dev_attr.attr, + &iio_scan_el_in3min2.dev_attr.attr, &dev_attr_in3min2_type.attr, + &iio_const_attr_in3min2_index.dev_attr.attr, + &iio_scan_el_in5min4.dev_attr.attr, &dev_attr_in5min4_type.attr, + &iio_const_attr_in5min4_index.dev_attr.attr, + &iio_scan_el_in7min6.dev_attr.attr, &dev_attr_in7min6_type.attr, + &iio_const_attr_in7min6_index.dev_attr.attr, + NULL }; static struct attribute_group max11608_scan_el_group = { @@ -1631,7 +1718,6 @@ static int __devinit max1363_probe(struct i2c_client *client, st->indio_dev->attrs = st->chip_info->dev_attrs; /* Todo: this shouldn't be here. */ - st->indio_dev->scan_el_attrs = st->chip_info->scan_attrs; st->indio_dev->dev_data = (void *)(st); st->indio_dev->driver_module = THIS_MODULE; st->indio_dev->modes = INDIO_DIRECT_MODE; diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c index 786b17a..5532f3e 100644 --- a/drivers/staging/iio/adc/max1363_ring.c +++ b/drivers/staging/iio/adc/max1363_ring.c @@ -30,22 +30,20 @@ /* Todo: test this */ int max1363_single_channel_from_ring(long mask, struct max1363_state *st) { - unsigned long numvals; + struct iio_ring_buffer *ring = st->indio_dev->ring; int count = 0, ret; u8 *ring_data; if (!(st->current_mode->modemask & mask)) { ret = -EBUSY; goto error_ret; } - numvals = hweight_long(st->current_mode->modemask); - ring_data = kmalloc(numvals*2, GFP_KERNEL); + ring_data = kmalloc(ring->access.get_bytes_per_datum(ring), GFP_KERNEL); if (ring_data == NULL) { ret = -ENOMEM; goto error_ret; } - ret = st->indio_dev->ring->access.read_last(st->indio_dev->ring, - ring_data); + ret = ring->access.read_last(ring, ring_data); if (ret) goto error_free_ring_data; /* Need a count of channels prior to this one */ @@ -77,6 +75,7 @@ error_ret: static int max1363_ring_preenable(struct iio_dev *indio_dev) { struct max1363_state *st = indio_dev->dev_data; + struct iio_ring_buffer *ring = indio_dev->ring; size_t d_size; unsigned long numvals; @@ -84,7 +83,7 @@ static int max1363_ring_preenable(struct iio_dev *indio_dev) * Need to figure out the current mode based upon the requested * scan mask in iio_dev */ - st->current_mode = max1363_match_mode(st->indio_dev->scan_mask, + st->current_mode = max1363_match_mode(ring->scan_mask, st->chip_info); if (!st->current_mode) return -EINVAL; @@ -92,14 +91,14 @@ static int max1363_ring_preenable(struct iio_dev *indio_dev) max1363_set_scan_mode(st); numvals = hweight_long(st->current_mode->modemask); - if (indio_dev->ring->access.set_bpd) { + if (ring->access.set_bytes_per_datum) { if (st->chip_info->bits != 8) d_size = numvals*2 + sizeof(s64); else d_size = numvals + sizeof(s64); if (d_size % 8) d_size += 8 - (d_size % 8); - indio_dev->ring->access.set_bpd(indio_dev->ring, d_size); + ring->access.set_bytes_per_datum(ring, d_size); } return 0; @@ -135,7 +134,7 @@ static void max1363_poll_bh_to_ring(struct work_struct *work_s) struct max1363_state *st = container_of(work_s, struct max1363_state, poll_work); struct iio_dev *indio_dev = st->indio_dev; - struct iio_sw_ring_buffer *ring = iio_to_sw_ring(indio_dev->ring); + struct iio_sw_ring_buffer *sw_ring = iio_to_sw_ring(indio_dev->ring); s64 time_ns; __u8 *rxbuf; int b_sent; @@ -175,7 +174,7 @@ static void max1363_poll_bh_to_ring(struct work_struct *work_s) memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); - indio_dev->ring->access.store_to(&ring->buf, rxbuf, time_ns); + indio_dev->ring->access.store_to(&sw_ring->buf, rxbuf, time_ns); done: kfree(rxbuf); atomic_dec(&st->protect_ring); @@ -193,12 +192,13 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev) goto error_ret; } /* Effectively select the ring buffer implementation */ - iio_ring_sw_register_funcs(&st->indio_dev->ring->access); + iio_ring_sw_register_funcs(&indio_dev->ring->access); ret = iio_alloc_pollfunc(indio_dev, NULL, &max1363_poll_func_th); if (ret) goto error_deallocate_sw_rb; /* Ring buffer functions - here trigger setup related */ + indio_dev->ring->scan_el_attrs = st->chip_info->scan_attrs; indio_dev->ring->postenable = &iio_triggered_ring_postenable; indio_dev->ring->preenable = &max1363_ring_preenable; indio_dev->ring->predisable = &iio_triggered_ring_predisable; |