From 8ec4cf5303e03941fa5fd91bbb9c85bd4ae88c47 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 25 Jun 2012 14:52:49 +0200 Subject: [PATCH 1/9] iio:adc: Add AD7265/AD7266 support This patch adds support for the Analog Devices AD7265 and AD7266 Analog-to-Digital converters. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 10 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ad7266.c | 536 +++++++++++++++++++++++++++ include/linux/platform_data/ad7266.h | 54 +++ 4 files changed, 601 insertions(+) create mode 100644 drivers/iio/adc/ad7266.c create mode 100644 include/linux/platform_data/ad7266.h diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 4f7f584cfd61..8a78b4f3ef58 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -3,6 +3,16 @@ # menu "Analog to digital converters" +config AD7266 + tristate "Analog Devices AD7265/AD7266 ADC driver" + depends on SPI_MASTER + select IIO_BUFFER + select IIO_TRIGGER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices AD7265 and AD7266 + ADCs. + config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 175c8d41ea99..52eec254c38c 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -2,4 +2,5 @@ # Makefile for IIO ADC drivers # +obj-$(CONFIG_AD7266) += ad7266.o obj-$(CONFIG_AT91_ADC) += at91_adc.o diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c new file mode 100644 index 000000000000..5c3f1ba5a06d --- /dev/null +++ b/drivers/iio/adc/ad7266.c @@ -0,0 +1,536 @@ +/* + * AD7266/65 SPI ADC driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +struct ad7266_state { + struct spi_device *spi; + struct regulator *reg; + unsigned long vref_uv; + + struct spi_transfer single_xfer[3]; + struct spi_message single_msg; + + enum ad7266_range range; + enum ad7266_mode mode; + bool fixed_addr; + struct gpio gpios[3]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * The buffer needs to be large enough to hold two samples (4 bytes) and + * the naturally aligned timestamp (8 bytes). + */ + uint8_t data[ALIGN(4, sizeof(s64)) + sizeof(s64)] ____cacheline_aligned; +}; + +static int ad7266_wakeup(struct ad7266_state *st) +{ + /* Any read with >= 2 bytes will wake the device */ + return spi_read(st->spi, st->data, 2); +} + +static int ad7266_powerdown(struct ad7266_state *st) +{ + /* Any read with < 2 bytes will powerdown the device */ + return spi_read(st->spi, st->data, 1); +} + +static int ad7266_preenable(struct iio_dev *indio_dev) +{ + struct ad7266_state *st = iio_priv(indio_dev); + int ret; + + ret = ad7266_wakeup(st); + if (ret) + return ret; + + ret = iio_sw_buffer_preenable(indio_dev); + if (ret) + ad7266_powerdown(st); + + return ret; +} + +static int ad7266_postdisable(struct iio_dev *indio_dev) +{ + struct ad7266_state *st = iio_priv(indio_dev); + return ad7266_powerdown(st); +} + +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { + .preenable = &ad7266_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &ad7266_postdisable, +}; + +static irqreturn_t ad7266_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct iio_buffer *buffer = indio_dev->buffer; + struct ad7266_state *st = iio_priv(indio_dev); + int ret; + + ret = spi_read(st->spi, st->data, 4); + if (ret == 0) { + if (indio_dev->scan_timestamp) + ((s64 *)st->data)[1] = pf->timestamp; + iio_push_to_buffer(buffer, (u8 *)st->data, pf->timestamp); + } + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static void ad7266_select_input(struct ad7266_state *st, unsigned int nr) +{ + unsigned int i; + + if (st->fixed_addr) + return; + + switch (st->mode) { + case AD7266_MODE_SINGLE_ENDED: + nr >>= 1; + break; + case AD7266_MODE_PSEUDO_DIFF: + nr |= 1; + break; + case AD7266_MODE_DIFF: + nr &= ~1; + break; + } + + for (i = 0; i < 3; ++i) + gpio_set_value(st->gpios[i].gpio, (bool)(nr & BIT(i))); +} + +static int ad7266_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct ad7266_state *st = iio_priv(indio_dev); + unsigned int nr = find_first_bit(scan_mask, indio_dev->masklength); + + ad7266_select_input(st, nr); + + return 0; +} + +static int ad7266_read_single(struct ad7266_state *st, int *val, + unsigned int address) +{ + int ret; + + ad7266_select_input(st, address); + + ret = spi_sync(st->spi, &st->single_msg); + *val = be16_to_cpu(st->data[address % 2]); + + return ret; +} + +static int ad7266_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long m) +{ + struct ad7266_state *st = iio_priv(indio_dev); + unsigned long scale_uv; + int ret; + + switch (m) { + case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + ret = ad7266_read_single(st, val, chan->address); + if (ret) + return ret; + + *val = (*val >> 2) & 0xfff; + if (chan->scan_type.sign == 's') + *val = sign_extend32(*val, 11); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + scale_uv = (st->vref_uv * 100); + if (st->mode == AD7266_MODE_DIFF) + scale_uv *= 2; + if (st->range == AD7266_RANGE_2VREF) + scale_uv *= 2; + + scale_uv >>= chan->scan_type.realbits; + *val = scale_uv / 100000; + *val2 = (scale_uv % 100000) * 10; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + if (st->range == AD7266_RANGE_2VREF && + st->mode != AD7266_MODE_DIFF) + *val = 2048; + else + *val = 0; + return IIO_VAL_INT; + } + return -EINVAL; +} + +#define AD7266_CHAN(_chan, _sign) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_chan), \ + .address = (_chan), \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT \ + | IIO_CHAN_INFO_SCALE_SHARED_BIT \ + | IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ + .scan_index = (_chan), \ + .scan_type = { \ + .sign = (_sign), \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 2, \ + .endianness = IIO_BE, \ + }, \ +} + +#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_##_name[] = { \ + AD7266_CHAN(0, (_sign)), \ + AD7266_CHAN(1, (_sign)), \ + AD7266_CHAN(2, (_sign)), \ + AD7266_CHAN(3, (_sign)), \ + AD7266_CHAN(4, (_sign)), \ + AD7266_CHAN(5, (_sign)), \ + AD7266_CHAN(6, (_sign)), \ + AD7266_CHAN(7, (_sign)), \ + AD7266_CHAN(8, (_sign)), \ + AD7266_CHAN(9, (_sign)), \ + AD7266_CHAN(10, (_sign)), \ + AD7266_CHAN(11, (_sign)), \ + IIO_CHAN_SOFT_TIMESTAMP(13), \ +} + +#define AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_##_name##_fixed[] = { \ + AD7266_CHAN(0, (_sign)), \ + AD7266_CHAN(1, (_sign)), \ + IIO_CHAN_SOFT_TIMESTAMP(2), \ +} + +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(u, 'u'); +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS(s, 's'); +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(u, 'u'); +static AD7266_DECLARE_SINGLE_ENDED_CHANNELS_FIXED(s, 's'); + +#define AD7266_CHAN_DIFF(_chan, _sign) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (_chan) * 2, \ + .channel2 = (_chan) * 2 + 1, \ + .address = (_chan), \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT \ + | IIO_CHAN_INFO_SCALE_SHARED_BIT \ + | IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ + .scan_index = (_chan), \ + .scan_type = { \ + .sign = _sign, \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 2, \ + .endianness = IIO_BE, \ + }, \ + .differential = 1, \ +} + +#define AD7266_DECLARE_DIFF_CHANNELS(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_diff_##_name[] = { \ + AD7266_CHAN_DIFF(0, (_sign)), \ + AD7266_CHAN_DIFF(1, (_sign)), \ + AD7266_CHAN_DIFF(2, (_sign)), \ + AD7266_CHAN_DIFF(3, (_sign)), \ + AD7266_CHAN_DIFF(4, (_sign)), \ + AD7266_CHAN_DIFF(5, (_sign)), \ + IIO_CHAN_SOFT_TIMESTAMP(6), \ +} + +static AD7266_DECLARE_DIFF_CHANNELS(s, 's'); +static AD7266_DECLARE_DIFF_CHANNELS(u, 'u'); + +#define AD7266_DECLARE_DIFF_CHANNELS_FIXED(_name, _sign) \ +const struct iio_chan_spec ad7266_channels_diff_fixed_##_name[] = { \ + AD7266_CHAN_DIFF(0, (_sign)), \ + AD7266_CHAN_DIFF(1, (_sign)), \ + IIO_CHAN_SOFT_TIMESTAMP(2), \ +} + +static AD7266_DECLARE_DIFF_CHANNELS_FIXED(s, 's'); +static AD7266_DECLARE_DIFF_CHANNELS_FIXED(u, 'u'); + +static const struct iio_info ad7266_info = { + .read_raw = &ad7266_read_raw, + .update_scan_mode = &ad7266_update_scan_mode, + .driver_module = THIS_MODULE, +}; + +static unsigned long ad7266_available_scan_masks[] = { + 0x003, + 0x00c, + 0x030, + 0x0c0, + 0x300, + 0xc00, + 0x000, +}; + +static unsigned long ad7266_available_scan_masks_diff[] = { + 0x003, + 0x00c, + 0x030, + 0x000, +}; + +static unsigned long ad7266_available_scan_masks_fixed[] = { + 0x003, + 0x000, +}; + +struct ad7266_chan_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; + unsigned long *scan_masks; +}; + +#define AD7266_CHAN_INFO_INDEX(_differential, _signed, _fixed) \ + (((_differential) << 2) | ((_signed) << 1) | ((_fixed) << 0)) + +static const struct ad7266_chan_info ad7266_chan_infos[] = { + [AD7266_CHAN_INFO_INDEX(0, 0, 0)] = { + .channels = ad7266_channels_u, + .num_channels = ARRAY_SIZE(ad7266_channels_u), + .scan_masks = ad7266_available_scan_masks, + }, + [AD7266_CHAN_INFO_INDEX(0, 0, 1)] = { + .channels = ad7266_channels_u_fixed, + .num_channels = ARRAY_SIZE(ad7266_channels_u_fixed), + .scan_masks = ad7266_available_scan_masks_fixed, + }, + [AD7266_CHAN_INFO_INDEX(0, 1, 0)] = { + .channels = ad7266_channels_s, + .num_channels = ARRAY_SIZE(ad7266_channels_s), + .scan_masks = ad7266_available_scan_masks, + }, + [AD7266_CHAN_INFO_INDEX(0, 1, 1)] = { + .channels = ad7266_channels_s_fixed, + .num_channels = ARRAY_SIZE(ad7266_channels_s_fixed), + .scan_masks = ad7266_available_scan_masks_fixed, + }, + [AD7266_CHAN_INFO_INDEX(1, 0, 0)] = { + .channels = ad7266_channels_diff_u, + .num_channels = ARRAY_SIZE(ad7266_channels_diff_u), + .scan_masks = ad7266_available_scan_masks_diff, + }, + [AD7266_CHAN_INFO_INDEX(1, 0, 1)] = { + .channels = ad7266_channels_diff_fixed_u, + .num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_u), + .scan_masks = ad7266_available_scan_masks_fixed, + }, + [AD7266_CHAN_INFO_INDEX(1, 1, 0)] = { + .channels = ad7266_channels_diff_s, + .num_channels = ARRAY_SIZE(ad7266_channels_diff_s), + .scan_masks = ad7266_available_scan_masks_diff, + }, + [AD7266_CHAN_INFO_INDEX(1, 1, 1)] = { + .channels = ad7266_channels_diff_fixed_s, + .num_channels = ARRAY_SIZE(ad7266_channels_diff_fixed_s), + .scan_masks = ad7266_available_scan_masks_fixed, + }, +}; + +static void __devinit ad7266_init_channels(struct iio_dev *indio_dev) +{ + struct ad7266_state *st = iio_priv(indio_dev); + bool is_differential, is_signed; + const struct ad7266_chan_info *chan_info; + int i; + + is_differential = st->mode != AD7266_MODE_SINGLE_ENDED; + is_signed = (st->range == AD7266_RANGE_2VREF) | + (st->mode == AD7266_MODE_DIFF); + + i = AD7266_CHAN_INFO_INDEX(is_differential, is_signed, st->fixed_addr); + chan_info = &ad7266_chan_infos[i]; + + indio_dev->channels = chan_info->channels; + indio_dev->num_channels = chan_info->num_channels; + indio_dev->available_scan_masks = chan_info->scan_masks; + indio_dev->masklength = chan_info->num_channels - 1; +} + +static const char * const ad7266_gpio_labels[] = { + "AD0", "AD1", "AD2", +}; + +static int __devinit ad7266_probe(struct spi_device *spi) +{ + struct ad7266_platform_data *pdata = spi->dev.platform_data; + struct iio_dev *indio_dev; + struct ad7266_state *st; + unsigned int i; + int ret; + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->reg = regulator_get(&spi->dev, "vref"); + if (!IS_ERR_OR_NULL(st->reg)) { + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + + st->vref_uv = regulator_get_voltage(st->reg); + } else { + /* Use internal reference */ + st->vref_uv = 2500000; + } + + if (pdata) { + st->fixed_addr = pdata->fixed_addr; + st->mode = pdata->mode; + st->range = pdata->range; + + if (!st->fixed_addr) { + for (i = 0; i < ARRAY_SIZE(st->gpios); ++i) { + st->gpios[i].gpio = pdata->addr_gpios[i]; + st->gpios[i].flags = GPIOF_OUT_INIT_LOW; + st->gpios[i].label = ad7266_gpio_labels[i]; + } + ret = gpio_request_array(st->gpios, + ARRAY_SIZE(st->gpios)); + if (ret) + goto error_disable_reg; + } + } else { + st->fixed_addr = true; + st->range = AD7266_RANGE_VREF; + st->mode = AD7266_MODE_DIFF; + } + + spi_set_drvdata(spi, indio_dev); + st->spi = spi; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ad7266_info; + + ad7266_init_channels(indio_dev); + + /* wakeup */ + st->single_xfer[0].rx_buf = &st->data; + st->single_xfer[0].len = 2; + st->single_xfer[0].cs_change = 1; + /* conversion */ + st->single_xfer[1].rx_buf = &st->data; + st->single_xfer[1].len = 4; + st->single_xfer[1].cs_change = 1; + /* powerdown */ + st->single_xfer[2].tx_buf = &st->data; + st->single_xfer[2].len = 1; + + spi_message_init(&st->single_msg); + spi_message_add_tail(&st->single_xfer[0], &st->single_msg); + spi_message_add_tail(&st->single_xfer[1], &st->single_msg); + spi_message_add_tail(&st->single_xfer[2], &st->single_msg); + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &ad7266_trigger_handler, &iio_triggered_buffer_setup_ops); + if (ret) + goto error_free_gpios; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_buffer_cleanup; + + return 0; + +error_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); +error_free_gpios: + if (!st->fixed_addr) + gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios)); +error_disable_reg: + if (!IS_ERR_OR_NULL(st->reg)) + regulator_disable(st->reg); +error_put_reg: + if (!IS_ERR_OR_NULL(st->reg)) + regulator_put(st->reg); + + iio_device_free(indio_dev); + + return ret; +} + +static int __devexit ad7266_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad7266_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + if (!st->fixed_addr) + gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios)); + if (!IS_ERR_OR_NULL(st->reg)) { + regulator_disable(st->reg); + regulator_put(st->reg); + } + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad7266_id[] = { + {"ad7265", 0}, + {"ad7266", 0}, + { } +}; +MODULE_DEVICE_TABLE(spi, ad7266_id); + +static struct spi_driver ad7266_driver = { + .driver = { + .name = "ad7266", + .owner = THIS_MODULE, + }, + .probe = ad7266_probe, + .remove = __devexit_p(ad7266_remove), + .id_table = ad7266_id, +}; +module_spi_driver(ad7266_driver); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("Analog Devices AD7266/65 ADC"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/platform_data/ad7266.h b/include/linux/platform_data/ad7266.h new file mode 100644 index 000000000000..eabfdcb26992 --- /dev/null +++ b/include/linux/platform_data/ad7266.h @@ -0,0 +1,54 @@ +/* + * AD7266/65 SPI ADC driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef __IIO_ADC_AD7266_H__ +#define __IIO_ADC_AD7266_H__ + +/** + * enum ad7266_range - AD7266 reference voltage range + * @AD7266_RANGE_VREF: Device is configured for input range 0V - VREF + * (RANGE pin set to low) + * @AD7266_RANGE_2VREF: Device is configured for input range 0V - 2VREF + * (RANGE pin set to high) + */ +enum ad7266_range { + AD7266_RANGE_VREF, + AD7266_RANGE_2VREF, +}; + +/** + * enum ad7266_mode - AD7266 sample mode + * @AD7266_MODE_DIFF: Device is configured for full differential mode + * (SGL/DIFF pin set to low, AD0 pin set to low) + * @AD7266_MODE_PSEUDO_DIFF: Device is configured for pseudo differential mode + * (SGL/DIFF pin set to low, AD0 pin set to high) + * @AD7266_MODE_SINGLE_ENDED: Device is configured for single-ended mode + * (SGL/DIFF pin set to high) + */ +enum ad7266_mode { + AD7266_MODE_DIFF, + AD7266_MODE_PSEUDO_DIFF, + AD7266_MODE_SINGLE_ENDED, +}; + +/** + * struct ad7266_platform_data - Platform data for the AD7266 driver + * @range: Reference voltage range the device is configured for + * @mode: Sample mode the device is configured for + * @fixed_addr: Whether the address pins are hard-wired + * @addr_gpios: GPIOs used for controlling the address pins, only used if + * fixed_addr is set to false. + */ +struct ad7266_platform_data { + enum ad7266_range range; + enum ad7266_mode mode; + bool fixed_addr; + unsigned int addr_gpios[3]; +}; + +#endif From 6a17a0768f77626046aa441843b318a00bac3800 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 26 Jun 2012 11:04:36 +0200 Subject: [PATCH 2/9] iio:dac:ad5064: Add support for the ad5629r and ad5669r The ad5629r and ad5669r are the I2C variants of the ad5628 and ad5668. Since the ad5064 driver currently only supports SPI based devices the major part of this patch focuses on adding support for I2C based devices. Adding support for the actual parts boils down to adding entries for them to the device id table. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/dac/Kconfig | 8 +- drivers/iio/dac/ad5064.c | 200 +++++++++++++++++++++++++++++++++------ 2 files changed, 173 insertions(+), 35 deletions(-) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index afd207e171cf..1be15fa9d618 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -4,12 +4,12 @@ menu "Digital to analog converters" config AD5064 - tristate "Analog Devices AD5064/64-1/65/44/45/24/25, AD5628/48/66/68 DAC driver" - depends on SPI + tristate "Analog Devices AD5064 and similar multi-channel DAC driver" + depends on (SPI_MASTER || I2C) help Say yes here to build support for Analog Devices AD5024, AD5025, AD5044, - AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648, AD5666, AD5668 Digital - to Analog Converter. + AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5629R, AD5648, AD5666, AD5668, + AD5669R Digital to Analog Converter. To compile this driver as a module, choose M here: the module will be called ad5064. diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index 276af02520af..aa739c497f2b 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -1,6 +1,6 @@ /* - * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648, - * AD5666, AD5668 Digital to analog converters driver + * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5629R, + * AD5648, AD5666, AD5668, AD5669R Digital to analog converters driver * * Copyright 2011 Analog Devices Inc. * @@ -12,9 +12,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -62,9 +64,14 @@ struct ad5064_chip_info { unsigned int num_channels; }; +struct ad5064_state; + +typedef int (*ad5064_write_func)(struct ad5064_state *st, unsigned int cmd, + unsigned int addr, unsigned int val); + /** * struct ad5064_state - driver instance specific data - * @spi: spi_device + * @dev: the device for this driver instance * @chip_info: chip model specific constants, available modes etc * @vref_reg: vref supply regulators * @pwr_down: whether channel is powered down @@ -72,11 +79,12 @@ struct ad5064_chip_info { * @dac_cache: current DAC raw value (chip does not support readback) * @use_internal_vref: set to true if the internal reference voltage should be * used. - * @data: spi transfer buffers + * @write: register write callback + * @data: i2c/spi transfer buffers */ struct ad5064_state { - struct spi_device *spi; + struct device *dev; const struct ad5064_chip_info *chip_info; struct regulator_bulk_data vref_reg[AD5064_MAX_VREFS]; bool pwr_down[AD5064_MAX_DAC_CHANNELS]; @@ -84,11 +92,16 @@ struct ad5064_state { unsigned int dac_cache[AD5064_MAX_DAC_CHANNELS]; bool use_internal_vref; + ad5064_write_func write; + /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. */ - __be32 data ____cacheline_aligned; + union { + u8 i2c[3]; + __be32 spi; + } data ____cacheline_aligned; }; enum ad5064_type { @@ -109,14 +122,31 @@ enum ad5064_type { ID_AD5668_2, }; +static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd, + unsigned int addr, unsigned int val) +{ + struct i2c_client *i2c = to_i2c_client(st->dev); + + st->data.i2c[0] = (cmd << 4) | addr; + put_unaligned_be16(val, &st->data.i2c[1]); + return i2c_master_send(i2c, st->data.i2c, 3); +} + static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd, + unsigned int addr, unsigned int val) +{ + struct spi_device *spi = to_spi_device(st->dev); + + st->data.spi = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val); + return spi_write(spi, &st->data.spi, sizeof(st->data.spi)); +} + +static int ad5064_write(struct ad5064_state *st, unsigned int cmd, unsigned int addr, unsigned int val, unsigned int shift) { val <<= shift; - st->data = cpu_to_be32(AD5064_CMD(cmd) | AD5064_ADDR(addr) | val); - - return spi_write(st->spi, &st->data, sizeof(st->data)); + return st->write(st, cmd, addr, val); } static int ad5064_sync_powerdown_mode(struct ad5064_state *st, @@ -130,7 +160,7 @@ static int ad5064_sync_powerdown_mode(struct ad5064_state *st, if (st->pwr_down[channel]) val |= st->pwr_down_mode[channel] << 8; - ret = ad5064_spi_write(st, AD5064_CMD_POWERDOWN_DAC, 0, val, 0); + ret = ad5064_write(st, AD5064_CMD_POWERDOWN_DAC, 0, val, 0); return ret; } @@ -251,7 +281,7 @@ static int ad5064_write_raw(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&indio_dev->mlock); - ret = ad5064_spi_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, + ret = ad5064_write(st, AD5064_CMD_WRITE_INPUT_N_UPDATE_N, chan->address, val, chan->scan_type.shift); if (ret == 0) st->dac_cache[chan->channel] = val; @@ -413,9 +443,9 @@ static const char * const ad5064_vref_name(struct ad5064_state *st, return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref]; } -static int __devinit ad5064_probe(struct spi_device *spi) +static int __devinit ad5064_probe(struct device *dev, enum ad5064_type type, + const char *name, ad5064_write_func write) { - enum ad5064_type type = spi_get_device_id(spi)->driver_data; struct iio_dev *indio_dev; struct ad5064_state *st; unsigned int i; @@ -426,24 +456,25 @@ static int __devinit ad5064_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); + dev_set_drvdata(dev, indio_dev); st->chip_info = &ad5064_chip_info_tbl[type]; - st->spi = spi; + st->dev = dev; + st->write = write; for (i = 0; i < ad5064_num_vref(st); ++i) st->vref_reg[i].supply = ad5064_vref_name(st, i); - ret = regulator_bulk_get(&st->spi->dev, ad5064_num_vref(st), + ret = regulator_bulk_get(dev, ad5064_num_vref(st), st->vref_reg); if (ret) { if (!st->chip_info->internal_vref) goto error_free; st->use_internal_vref = true; - ret = ad5064_spi_write(st, AD5064_CMD_CONFIG, 0, + ret = ad5064_write(st, AD5064_CMD_CONFIG, 0, AD5064_CONFIG_INT_VREF_ENABLE, 0); if (ret) { - dev_err(&spi->dev, "Failed to enable internal vref: %d\n", + dev_err(dev, "Failed to enable internal vref: %d\n", ret); goto error_free; } @@ -458,8 +489,8 @@ static int __devinit ad5064_probe(struct spi_device *spi) st->dac_cache[i] = 0x8000; } - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = dev; + indio_dev->name = name; indio_dev->info = &ad5064_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = st->chip_info->channels; @@ -483,10 +514,9 @@ static int __devinit ad5064_probe(struct spi_device *spi) return ret; } - -static int __devexit ad5064_remove(struct spi_device *spi) +static int __devexit ad5064_remove(struct device *dev) { - struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5064_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); @@ -501,7 +531,22 @@ static int __devexit ad5064_remove(struct spi_device *spi) return 0; } -static const struct spi_device_id ad5064_id[] = { +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static int __devinit ad5064_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); + + return ad5064_probe(&spi->dev, id->driver_data, id->name, + ad5064_spi_write); +} + +static int __devexit ad5064_spi_remove(struct spi_device *spi) +{ + return ad5064_remove(&spi->dev); +} + +static const struct spi_device_id ad5064_spi_ids[] = { {"ad5024", ID_AD5024}, {"ad5025", ID_AD5025}, {"ad5044", ID_AD5044}, @@ -520,19 +565,112 @@ static const struct spi_device_id ad5064_id[] = { {"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */ {} }; -MODULE_DEVICE_TABLE(spi, ad5064_id); +MODULE_DEVICE_TABLE(spi, ad5064_spi_ids); -static struct spi_driver ad5064_driver = { +static struct spi_driver ad5064_spi_driver = { .driver = { .name = "ad5064", .owner = THIS_MODULE, }, - .probe = ad5064_probe, - .remove = __devexit_p(ad5064_remove), - .id_table = ad5064_id, + .probe = ad5064_spi_probe, + .remove = __devexit_p(ad5064_spi_remove), + .id_table = ad5064_spi_ids, }; -module_spi_driver(ad5064_driver); + +static int __init ad5064_spi_register_driver(void) +{ + return spi_register_driver(&ad5064_spi_driver); +} + +static void __exit ad5064_spi_unregister_driver(void) +{ + spi_unregister_driver(&ad5064_spi_driver); +} + +#else + +static inline int ad5064_spi_register_driver(void) { return 0; } +static inline void ad5064_spi_unregister_driver(void) { } + +#endif + +#if IS_ENABLED(CONFIG_I2C) + +static int __devinit ad5064_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return ad5064_probe(&i2c->dev, id->driver_data, id->name, + ad5064_i2c_write); +} + +static int __devexit ad5064_i2c_remove(struct i2c_client *i2c) +{ + return ad5064_remove(&i2c->dev); +} + +static const struct i2c_device_id ad5064_i2c_ids[] = { + {"ad5629-1", ID_AD5628_1}, + {"ad5629-2", ID_AD5628_2}, + {"ad5629-3", ID_AD5628_2}, /* similar enough to ad5629-2 */ + {"ad5669-1", ID_AD5668_1}, + {"ad5669-2", ID_AD5668_2}, + {"ad5669-3", ID_AD5668_2}, /* similar enough to ad5669-2 */ + {} +}; +MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids); + +static struct i2c_driver ad5064_i2c_driver = { + .driver = { + .name = "ad5064", + .owner = THIS_MODULE, + }, + .probe = ad5064_i2c_probe, + .remove = __devexit_p(ad5064_i2c_remove), + .id_table = ad5064_i2c_ids, +}; + +static int __init ad5064_i2c_register_driver(void) +{ + return i2c_add_driver(&ad5064_i2c_driver); +} + +static void __exit ad5064_i2c_unregister_driver(void) +{ + i2c_del_driver(&ad5064_i2c_driver); +} + +#else + +static inline int ad5064_i2c_register_driver(void) { return 0; } +static inline void ad5064_i2c_unregister_driver(void) { } + +#endif + +static int __init ad5064_init(void) +{ + int ret; + + ret = ad5064_spi_register_driver(); + if (ret) + return ret; + + ret = ad5064_i2c_register_driver(); + if (ret) { + ad5064_spi_unregister_driver(); + return ret; + } + + return 0; +} +module_init(ad5064_init); + +static void __exit ad5064_exit(void) +{ + ad5064_i2c_unregister_driver(); + ad5064_spi_unregister_driver(); +} +module_exit(ad5064_exit); MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_DESCRIPTION("Analog Devices AD5024/25/44/45/64/64-1/65, AD5628/48/66/68 DAC"); +MODULE_DESCRIPTION("Analog Devices AD5024 and similar multi-channel DACs"); MODULE_LICENSE("GPL v2"); From 314be14bb89369b2164125b0ec3b24d85b407b62 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Tue, 1 May 2012 21:04:24 +0100 Subject: [PATCH 3/9] iio: Rename _st_ functions to loose the bit that meant the staging version. These were originally introduced when the plan was to have parallel IIO cores in and out of staging with a slow move between them. Now we have reached the point where the whole core has moved, they need clearing up! Signed-off-by: Jonathan Cameron --- drivers/iio/inkern.c | 33 +++++++++++++++----------------- drivers/staging/iio/iio_hwmon.c | 12 ++++++------ include/linux/iio/consumer.h | 34 ++++++++++++++++----------------- 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index d4760bd1e9b1..9a46ca61ef02 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -92,8 +92,7 @@ int iio_map_array_unregister(struct iio_dev *indio_dev, EXPORT_SYMBOL_GPL(iio_map_array_unregister); static const struct iio_chan_spec -*iio_chan_spec_from_name(const struct iio_dev *indio_dev, - const char *name) +*iio_chan_spec_from_name(const struct iio_dev *indio_dev, const char *name) { int i; const struct iio_chan_spec *chan = NULL; @@ -108,8 +107,7 @@ static const struct iio_chan_spec } -struct iio_channel *iio_st_channel_get(const char *name, - const char *channel_name) +struct iio_channel *iio_channel_get(const char *name, const char *channel_name) { struct iio_map_internal *c_i = NULL, *c = NULL; struct iio_channel *channel; @@ -145,16 +143,16 @@ struct iio_channel *iio_st_channel_get(const char *name, return channel; } -EXPORT_SYMBOL_GPL(iio_st_channel_get); +EXPORT_SYMBOL_GPL(iio_channel_get); -void iio_st_channel_release(struct iio_channel *channel) +void iio_channel_release(struct iio_channel *channel) { iio_device_put(channel->indio_dev); kfree(channel); } -EXPORT_SYMBOL_GPL(iio_st_channel_release); +EXPORT_SYMBOL_GPL(iio_channel_release); -struct iio_channel *iio_st_channel_get_all(const char *name) +struct iio_channel *iio_channel_get_all(const char *name) { struct iio_channel *chans; struct iio_map_internal *c = NULL; @@ -217,9 +215,9 @@ struct iio_channel *iio_st_channel_get_all(const char *name) return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(iio_st_channel_get_all); +EXPORT_SYMBOL_GPL(iio_channel_get_all); -void iio_st_channel_release_all(struct iio_channel *channels) +void iio_channel_release_all(struct iio_channel *channels) { struct iio_channel *chan = &channels[0]; @@ -229,9 +227,9 @@ void iio_st_channel_release_all(struct iio_channel *channels) } kfree(channels); } -EXPORT_SYMBOL_GPL(iio_st_channel_release_all); +EXPORT_SYMBOL_GPL(iio_channel_release_all); -int iio_st_read_channel_raw(struct iio_channel *chan, int *val) +int iio_read_channel_raw(struct iio_channel *chan, int *val) { int val2, ret; @@ -248,9 +246,9 @@ int iio_st_read_channel_raw(struct iio_channel *chan, int *val) return ret; } -EXPORT_SYMBOL_GPL(iio_st_read_channel_raw); +EXPORT_SYMBOL_GPL(iio_read_channel_raw); -int iio_st_read_channel_scale(struct iio_channel *chan, int *val, int *val2) +int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) { int ret; @@ -269,10 +267,9 @@ int iio_st_read_channel_scale(struct iio_channel *chan, int *val, int *val2) return ret; } -EXPORT_SYMBOL_GPL(iio_st_read_channel_scale); +EXPORT_SYMBOL_GPL(iio_read_channel_scale); -int iio_st_get_channel_type(struct iio_channel *chan, - enum iio_chan_type *type) +int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type) { int ret = 0; /* Need to verify underlying driver has not gone away */ @@ -289,4 +286,4 @@ int iio_st_get_channel_type(struct iio_channel *chan, return ret; } -EXPORT_SYMBOL_GPL(iio_st_get_channel_type); +EXPORT_SYMBOL_GPL(iio_get_channel_type); diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c index b03554fee443..27d27ec9521f 100644 --- a/drivers/staging/iio/iio_hwmon.c +++ b/drivers/staging/iio/iio_hwmon.c @@ -51,12 +51,12 @@ static ssize_t iio_hwmon_read_val(struct device *dev, * No locking between this pair, so theoretically possible * the scale has changed. */ - ret = iio_st_read_channel_raw(&state->channels[sattr->index], + ret = iio_read_channel_raw(&state->channels[sattr->index], &val); if (ret < 0) return ret; - ret = iio_st_read_channel_scale(&state->channels[sattr->index], + ret = iio_read_channel_scale(&state->channels[sattr->index], &scaleint, &scalepart); if (ret < 0) return ret; @@ -106,7 +106,7 @@ static int __devinit iio_hwmon_probe(struct platform_device *pdev) goto error_ret; } - st->channels = iio_st_channel_get_all(dev_name(&pdev->dev)); + st->channels = iio_channel_get_all(dev_name(&pdev->dev)); if (IS_ERR(st->channels)) { ret = PTR_ERR(st->channels); goto error_free_state; @@ -130,7 +130,7 @@ static int __devinit iio_hwmon_probe(struct platform_device *pdev) } sysfs_attr_init(&a->dev_attr.attr); - ret = iio_st_get_channel_type(&st->channels[i], &type); + ret = iio_get_channel_type(&st->channels[i], &type); if (ret < 0) { kfree(a); goto error_free_attrs; @@ -186,7 +186,7 @@ static int __devinit iio_hwmon_probe(struct platform_device *pdev) iio_hwmon_free_attrs(st); kfree(st->attrs); error_release_channels: - iio_st_channel_release_all(st->channels); + iio_channel_release_all(st->channels); error_free_state: kfree(st); error_ret: @@ -201,7 +201,7 @@ static int __devexit iio_hwmon_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &st->attr_group); iio_hwmon_free_attrs(st); kfree(st->attrs); - iio_st_channel_release_all(st->channels); + iio_channel_release_all(st->channels); return 0; } diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index 1a15e560a5a1..e2657e6d4d26 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -33,17 +33,17 @@ struct iio_channel { * side. This typically describes the channels use within * the consumer. E.g. 'battery_voltage' */ -struct iio_channel *iio_st_channel_get(const char *name, - const char *consumer_channel); +struct iio_channel *iio_channel_get(const char *name, + const char *consumer_channel); /** - * iio_st_channel_release() - release channels obtained via iio_st_channel_get + * iio_channel_release() - release channels obtained via iio_channel_get * @chan: The channel to be released. */ -void iio_st_channel_release(struct iio_channel *chan); +void iio_channel_release(struct iio_channel *chan); /** - * iio_st_channel_get_all() - get all channels associated with a client + * iio_channel_get_all() - get all channels associated with a client * @name: name of consumer device. * * Returns an array of iio_channel structures terminated with one with @@ -51,37 +51,37 @@ void iio_st_channel_release(struct iio_channel *chan); * This function is used by fairly generic consumers to get all the * channels registered as having this consumer. */ -struct iio_channel *iio_st_channel_get_all(const char *name); +struct iio_channel *iio_channel_get_all(const char *name); /** - * iio_st_channel_release_all() - reverse iio_st_get_all + * iio_channel_release_all() - reverse iio_channel_get_all * @chan: Array of channels to be released. */ -void iio_st_channel_release_all(struct iio_channel *chan); +void iio_channel_release_all(struct iio_channel *chan); /** - * iio_st_read_channel_raw() - read from a given channel + * iio_read_channel_raw() - read from a given channel * @channel: The channel being queried. * @val: Value read back. * * Note raw reads from iio channels are in adc counts and hence * scale will need to be applied if standard units required. */ -int iio_st_read_channel_raw(struct iio_channel *chan, - int *val); +int iio_read_channel_raw(struct iio_channel *chan, + int *val); /** - * iio_st_get_channel_type() - get the type of a channel + * iio_get_channel_type() - get the type of a channel * @channel: The channel being queried. * @type: The type of the channel. * * returns the enum iio_chan_type of the channel */ -int iio_st_get_channel_type(struct iio_channel *channel, - enum iio_chan_type *type); +int iio_get_channel_type(struct iio_channel *channel, + enum iio_chan_type *type); /** - * iio_st_read_channel_scale() - read the scale value for a channel + * iio_read_channel_scale() - read the scale value for a channel * @channel: The channel being queried. * @val: First part of value read back. * @val2: Second part of value read back. @@ -90,7 +90,7 @@ int iio_st_get_channel_type(struct iio_channel *channel, * as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val * + val2/1e6 */ -int iio_st_read_channel_scale(struct iio_channel *chan, int *val, - int *val2); +int iio_read_channel_scale(struct iio_channel *chan, int *val, + int *val2); #endif From 13d947db1c8e4e5c2114e809beef97ddf41b7006 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 5 May 2012 09:16:08 +0100 Subject: [PATCH 4/9] staging:iio:accel drop sysfs interface for resetting devices. There is no reason why userspace should want to do this manually. Hence, lets drop this abi. Signed-off-by: Jonathan Cameron Acked-by: Michael Hennerich --- drivers/staging/iio/accel/adis16201_core.c | 27 -------------------- drivers/staging/iio/accel/adis16203_core.c | 28 --------------------- drivers/staging/iio/accel/adis16204_core.c | 20 --------------- drivers/staging/iio/accel/adis16209_core.c | 29 ---------------------- drivers/staging/iio/accel/adis16220_core.c | 24 ------------------ drivers/staging/iio/accel/adis16240_core.c | 20 --------------- 6 files changed, 148 deletions(-) diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c index 02b340919c0e..204106b72d24 100644 --- a/drivers/staging/iio/accel/adis16201_core.c +++ b/drivers/staging/iio/accel/adis16201_core.c @@ -159,21 +159,6 @@ static int adis16201_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16201_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - int ret; - bool res; - - if (len < 1) - return -EINVAL; - ret = strtobool(buf, &res); - if (ret || !res) - return ret; - return adis16201_reset(dev_to_iio_dev(dev)); -} - int adis16201_set_irq(struct iio_dev *indio_dev, bool enable) { int ret = 0; @@ -507,19 +492,7 @@ static struct iio_chan_spec adis16201_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(7) }; -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16201_write_reset, 0); - -static struct attribute *adis16201_attributes[] = { - &iio_dev_attr_reset.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16201_attribute_group = { - .attrs = adis16201_attributes, -}; - static const struct iio_info adis16201_info = { - .attrs = &adis16201_attribute_group, .read_raw = &adis16201_read_raw, .write_raw = &adis16201_write_raw, .driver_module = THIS_MODULE, diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c index 15d46bfd1b42..22085e9dfd16 100644 --- a/drivers/staging/iio/accel/adis16203_core.c +++ b/drivers/staging/iio/accel/adis16203_core.c @@ -178,22 +178,6 @@ static int adis16203_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16203_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - if (len < 1) - return -EINVAL; - switch (buf[0]) { - case '1': - case 'y': - case 'Y': - return adis16203_reset(indio_dev); - } - return -EINVAL; -} - int adis16203_set_irq(struct iio_dev *indio_dev, bool enable) { int ret = 0; @@ -444,19 +428,7 @@ static struct iio_chan_spec adis16203_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(5), }; -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16203_write_reset, 0); - -static struct attribute *adis16203_attributes[] = { - &iio_dev_attr_reset.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16203_attribute_group = { - .attrs = adis16203_attributes, -}; - static const struct iio_info adis16203_info = { - .attrs = &adis16203_attribute_group, .read_raw = &adis16203_read_raw, .write_raw = &adis16203_write_raw, .driver_module = THIS_MODULE, diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c index 457982bf7eac..685fa925d9df 100644 --- a/drivers/staging/iio/accel/adis16204_core.c +++ b/drivers/staging/iio/accel/adis16204_core.c @@ -207,23 +207,6 @@ static int adis16204_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16204_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - - if (len < 1) - return -EINVAL; - switch (buf[0]) { - case '1': - case 'y': - case 'Y': - return adis16204_reset(indio_dev); - } - return -EINVAL; -} - int adis16204_set_irq(struct iio_dev *indio_dev, bool enable) { int ret = 0; @@ -310,8 +293,6 @@ static IIO_DEV_ATTR_ACCEL_XYPEAK(adis16204_read_14bit_signed, ADIS16204_XY_PEAK_OUT); static IIO_CONST_ATTR(in_accel_xy_scale, "0.017125"); -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16204_write_reset, 0); - enum adis16204_channel { in_supply, in_aux, @@ -520,7 +501,6 @@ static struct iio_chan_spec adis16204_channels[] = { }; static struct attribute *adis16204_attributes[] = { - &iio_dev_attr_reset.dev_attr.attr, &iio_dev_attr_in_accel_xy.dev_attr.attr, &iio_dev_attr_in_accel_xypeak.dev_attr.attr, &iio_const_attr_in_accel_xy_scale.dev_attr.attr, diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c index 6fc426e27e4e..494570508c36 100644 --- a/drivers/staging/iio/accel/adis16209_core.c +++ b/drivers/staging/iio/accel/adis16209_core.c @@ -153,23 +153,6 @@ static int adis16209_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16209_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - - if (len < 1) - return -EINVAL; - switch (buf[0]) { - case '1': - case 'y': - case 'Y': - return adis16209_reset(indio_dev); - } - return -EINVAL; -} - int adis16209_set_irq(struct iio_dev *indio_dev, bool enable) { int ret = 0; @@ -519,19 +502,7 @@ static struct iio_chan_spec adis16209_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(8) }; -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16209_write_reset, 0); - -static struct attribute *adis16209_attributes[] = { - &iio_dev_attr_reset.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16209_attribute_group = { - .attrs = adis16209_attributes, -}; - static const struct iio_info adis16209_info = { - .attrs = &adis16209_attribute_group, .read_raw = &adis16209_read_raw, .write_raw = &adis16209_write_raw, .driver_module = THIS_MODULE, diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c index af5c57637166..575f1af25d5d 100644 --- a/drivers/staging/iio/accel/adis16220_core.c +++ b/drivers/staging/iio/accel/adis16220_core.c @@ -204,26 +204,6 @@ static int adis16220_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16220_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - bool val; - int ret; - - ret = strtobool(buf, &val); - if (ret) - return ret; - if (!val) - return -EINVAL; - - ret = adis16220_reset(indio_dev); - if (ret) - return ret; - return len; -} - static ssize_t adis16220_write_capture(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -454,9 +434,6 @@ static struct bin_attribute adc2_bin = { .size = ADIS16220_CAPTURE_SIZE, }; -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, - adis16220_write_reset, 0); - #define IIO_DEV_ATTR_CAPTURE(_store) \ IIO_DEVICE_ATTR(capture, S_IWUSR, NULL, _store, 0) @@ -611,7 +588,6 @@ static const struct iio_chan_spec adis16220_channels[] = { }; static struct attribute *adis16220_attributes[] = { - &iio_dev_attr_reset.dev_attr.attr, &iio_dev_attr_capture.dev_attr.attr, &iio_dev_attr_capture_count.dev_attr.attr, NULL diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index 1a51f03d3d76..b30b7874ffb0 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -199,23 +199,6 @@ static int adis16240_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16240_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - - if (len < 1) - return -EINVAL; - switch (buf[0]) { - case '1': - case 'y': - case 'Y': - return adis16240_reset(indio_dev); - } - return -EINVAL; -} - int adis16240_set_irq(struct iio_dev *indio_dev, bool enable) { int ret = 0; @@ -329,8 +312,6 @@ static IIO_DEVICE_ATTR(in_accel_xyz_squared_peak_raw, S_IRUGO, adis16240_read_12bit_signed, NULL, ADIS16240_XYZPEAK_OUT); -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16240_write_reset, 0); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("4096"); enum adis16240_chan { @@ -559,7 +540,6 @@ static struct iio_chan_spec adis16240_channels[] = { static struct attribute *adis16240_attributes[] = { &iio_dev_attr_in_accel_xyz_squared_peak_raw.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_reset.dev_attr.attr, NULL }; From 15a1a7530c3c411adbd9aed05f7bb43fbe9816c4 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 5 May 2012 09:19:09 +0100 Subject: [PATCH 5/9] staging:iio:gyro:adis16260 drop sysfs interface for manual device reset. There is no reason for userspace to do this, so lets drop this abi. Signed-off-by: Jonathan Cameron Acked-by: Michael Hennerich --- drivers/staging/iio/gyro/adis16260_core.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index fdb84cc3d7c9..f16b3938928f 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -233,22 +233,6 @@ static int adis16260_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16260_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - if (len < 1) - return -EINVAL; - switch (buf[0]) { - case '1': - case 'y': - case 'Y': - return adis16260_reset(indio_dev); - } - return -EINVAL; -} - int adis16260_set_irq(struct iio_dev *indio_dev, bool enable) { int ret; @@ -375,8 +359,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16260_read_frequency, adis16260_write_frequency); -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16260_write_reset, 0); - static IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, adis16260_read_frequency_available, NULL, 0); @@ -604,7 +586,6 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, static struct attribute *adis16260_attributes[] = { &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_reset.dev_attr.attr, NULL }; From 07c7f79ee1c7e6288c614ba88005a8de6dbaadff Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 5 May 2012 09:17:12 +0100 Subject: [PATCH 6/9] staging:iio:imu:adis16400 drop sysfs interface for manual device reset. There is no reason for userspace to do this, so lets drop this abi. Signed-off-by: Jonathan Cameron Acked-by: Michael Hennerich --- drivers/staging/iio/imu/adis16400_core.c | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 387301437cf5..1f4c17779b5a 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -268,25 +268,6 @@ static int adis16400_reset(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16400_write_reset(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - bool val; - int ret; - - ret = strtobool(buf, &val); - if (ret < 0) - return ret; - if (val) { - ret = adis16400_reset(dev_to_iio_dev(dev)); - if (ret < 0) - return ret; - } - - return len; -} - int adis16400_set_irq(struct iio_dev *indio_dev, bool enable) { int ret; @@ -454,8 +435,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, adis16400_read_frequency, adis16400_write_frequency); -static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16400_write_reset, 0); - static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("409 546 819 1638"); enum adis16400_chan { @@ -1066,7 +1045,6 @@ static const struct iio_chan_spec adis16334_channels[] = { static struct attribute *adis16400_attributes[] = { &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_reset.dev_attr.attr, NULL }; From 8f5879b20be7f918cdc4b3d831cfd8f3dc02c74c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 5 May 2012 10:39:22 +0100 Subject: [PATCH 7/9] IIO: Add a modifier for sqrt(x^2+y^2) There will probably be a number of such modifiers eventually but this one is used in the adis16204 accelerometer driver. Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 1 + include/linux/iio/types.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index a5a446beb2fa..e42749ec5c3c 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -70,6 +70,7 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_X] = "x", [IIO_MOD_Y] = "y", [IIO_MOD_Z] = "z", + [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", [IIO_MOD_LIGHT_BOTH] = "both", [IIO_MOD_LIGHT_IR] = "ir", }; diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index d086736a9033..210559ddf8a3 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -44,6 +44,7 @@ enum iio_modifier { IIO_MOD_X_OR_Y_OR_Z, IIO_MOD_LIGHT_BOTH, IIO_MOD_LIGHT_IR, + IIO_MOD_ROOT_SUM_SQUARED_X_Y, }; #define IIO_VAL_INT 1 From f699d10202d50a764614ff9191b5c4b9dd75e36c Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 5 May 2012 10:47:12 +0100 Subject: [PATCH 8/9] staging:iio:accel:adis16204 support the rss channel via chan spec. Reduces code and makes this channel available within the kernel. Note that it is not added to the buffer, thus maintaining the previous functionality of this driver. Signed-off-by: Jonathan Cameron Acked-by: Michael Hennerich --- drivers/staging/iio/accel/adis16204_core.c | 79 ++++++++-------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c index 685fa925d9df..5f2e5f11c543 100644 --- a/drivers/staging/iio/accel/adis16204_core.c +++ b/drivers/staging/iio/accel/adis16204_core.c @@ -169,32 +169,6 @@ static int adis16204_check_status(struct iio_dev *indio_dev) return ret; } -static ssize_t adis16204_read_14bit_signed(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); - s16 val = 0; - ssize_t ret; - - mutex_lock(&indio_dev->mlock); - - ret = adis16204_spi_read_reg_16(indio_dev, - this_attr->address, (u16 *)&val); - if (!ret) { - if (val & ADIS16204_ERROR_ACTIVE) - adis16204_check_status(indio_dev); - - val = ((s16)(val << 2) >> 2); - ret = sprintf(buf, "%d\n", val); - } - - mutex_unlock(&indio_dev->mlock); - - return ret; -} - static int adis16204_reset(struct iio_dev *indio_dev) { int ret; @@ -282,16 +256,6 @@ static int adis16204_initial_setup(struct iio_dev *indio_dev) } /* Unique to this driver currently */ -#define IIO_DEV_ATTR_ACCEL_XY(_show, _addr) \ - IIO_DEVICE_ATTR(in_accel_xy, S_IRUGO, _show, NULL, _addr) -#define IIO_DEV_ATTR_ACCEL_XYPEAK(_show, _addr) \ - IIO_DEVICE_ATTR(in_accel_xypeak, S_IRUGO, _show, NULL, _addr) - -static IIO_DEV_ATTR_ACCEL_XY(adis16204_read_14bit_signed, - ADIS16204_XY_RSS_OUT); -static IIO_DEV_ATTR_ACCEL_XYPEAK(adis16204_read_14bit_signed, - ADIS16204_XY_PEAK_OUT); -static IIO_CONST_ATTR(in_accel_xy_scale, "0.017125"); enum adis16204_channel { in_supply, @@ -299,9 +263,10 @@ enum adis16204_channel { temp, accel_x, accel_y, + accel_xy, }; -static u8 adis16204_addresses[5][3] = { +static u8 adis16204_addresses[6][3] = { [in_supply] = { ADIS16204_SUPPLY_OUT }, [in_aux] = { ADIS16204_AUX_ADC }, [temp] = { ADIS16204_TEMP_OUT }, @@ -309,6 +274,8 @@ static u8 adis16204_addresses[5][3] = { ADIS16204_X_PEAK_OUT }, [accel_y] = { ADIS16204_XACCL_OUT, ADIS16204_YACCL_NULL, ADIS16204_Y_PEAK_OUT }, + [accel_xy] = { ADIS16204_XY_RSS_OUT, 0, + ADIS16204_XY_PEAK_OUT }, }; static int adis16204_read_raw(struct iio_dev *indio_dev, @@ -362,10 +329,16 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_MICRO; case IIO_ACCEL: *val = 0; - if (chan->channel2 == IIO_MOD_X) + switch (chan->channel2) { + case IIO_MOD_X: + case IIO_MOD_ROOT_SUM_SQUARED_X_Y: *val2 = 17125; - else + break; + case IIO_MOD_Y: + case IIO_MOD_Z: *val2 = 8407; + break; + } return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; @@ -498,21 +471,23 @@ static struct iio_chan_spec adis16204_channels[] = { }, }, IIO_CHAN_SOFT_TIMESTAMP(5), -}; - -static struct attribute *adis16204_attributes[] = { - &iio_dev_attr_in_accel_xy.dev_attr.attr, - &iio_dev_attr_in_accel_xypeak.dev_attr.attr, - &iio_const_attr_in_accel_xy_scale.dev_attr.attr, - NULL -}; - -static const struct attribute_group adis16204_attribute_group = { - .attrs = adis16204_attributes, + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_ROOT_SUM_SQUARED_X_Y, + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | + IIO_CHAN_INFO_PEAK_SEPARATE_BIT, + .address = accel_xy, + .scan_type = { + .sign = 'u', + .realbits = 14, + .storagebits = 16, + }, + } }; static const struct iio_info adis16204_info = { - .attrs = &adis16204_attribute_group, .read_raw = &adis16204_read_raw, .write_raw = &adis16204_write_raw, .driver_module = THIS_MODULE, @@ -549,7 +524,7 @@ static int __devinit adis16204_probe(struct spi_device *spi) ret = iio_buffer_register(indio_dev, adis16204_channels, - ARRAY_SIZE(adis16204_channels)); + 6); if (ret) { printk(KERN_ERR "failed to initialize the ring\n"); goto error_unreg_ring_funcs; From cf82cb8128496955a38fa62e1819ceb1d596e2eb Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Sat, 5 May 2012 10:56:41 +0100 Subject: [PATCH 9/9] IIO: Add a modifier for x^2+y^2+z^2 There will probably be a number of such modifiers eventually but this one is used in the adis16240 accelerometer driver. Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 1 + include/linux/iio/types.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index e42749ec5c3c..bb3c692e49b8 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -71,6 +71,7 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_Y] = "y", [IIO_MOD_Z] = "z", [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", + [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", [IIO_MOD_LIGHT_BOTH] = "both", [IIO_MOD_LIGHT_IR] = "ir", }; diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 210559ddf8a3..e25040173346 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -45,6 +45,7 @@ enum iio_modifier { IIO_MOD_LIGHT_BOTH, IIO_MOD_LIGHT_IR, IIO_MOD_ROOT_SUM_SQUARED_X_Y, + IIO_MOD_SUM_SQUARED_X_Y_Z, }; #define IIO_VAL_INT 1