* [PATCH 1/2] staging:iio: Make write_event_value callback optional @ 2011-10-26 12:01 Lars-Peter Clausen 2011-10-26 12:01 ` [PATCH 2/2] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen 2011-10-26 12:02 ` [PATCH 1/2] staging:iio: Make write_event_value callback optional Jonathan Cameron 0 siblings, 2 replies; 6+ messages in thread From: Lars-Peter Clausen @ 2011-10-26 12:01 UTC (permalink / raw) To: Jonathan Cameron Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers, Lars-Peter Clausen Some devices have fixed thresholds which can not be modified so make the write_event_value callback optional, so the drivers for these devices do not have to implement a boilerplate no-op callback. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> --- drivers/staging/iio/industrialio-core.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index cfa4fcb..d2eea07 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -782,6 +782,9 @@ static ssize_t iio_ev_value_store(struct device *dev, unsigned long val; int ret; + if (!indio_dev->info->write_event_value) + return -EINVAL; + ret = strict_strtoul(buf, 10, &val); if (ret) return ret; -- 1.7.7 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/2] staging:iio:dac: Add AD5421 driver 2011-10-26 12:01 [PATCH 1/2] staging:iio: Make write_event_value callback optional Lars-Peter Clausen @ 2011-10-26 12:01 ` Lars-Peter Clausen 2011-10-26 13:21 ` Lars-Peter Clausen 2011-10-26 17:04 ` Jonathan Cameron 2011-10-26 12:02 ` [PATCH 1/2] staging:iio: Make write_event_value callback optional Jonathan Cameron 1 sibling, 2 replies; 6+ messages in thread From: Lars-Peter Clausen @ 2011-10-26 12:01 UTC (permalink / raw) To: Jonathan Cameron Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers, Lars-Peter Clausen This patch adds support for the Analog Devices AD5421 Loop-Powered, 4mA to 20mA DAC. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> --- drivers/staging/iio/dac/Kconfig | 10 + drivers/staging/iio/dac/Makefile | 1 + drivers/staging/iio/dac/ad5421.c | 551 ++++++++++++++++++++++++++++++++++++++ drivers/staging/iio/dac/ad5421.h | 32 +++ drivers/staging/iio/events.h | 3 +- 5 files changed, 596 insertions(+), 1 deletions(-) create mode 100644 drivers/staging/iio/dac/ad5421.c create mode 100644 drivers/staging/iio/dac/ad5421.h diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig index fac8549..0e8983a 100644 --- a/drivers/staging/iio/dac/Kconfig +++ b/drivers/staging/iio/dac/Kconfig @@ -24,6 +24,16 @@ config AD5360 To compile this driver as module choose M here: the module will be called ad5360. +config AD5421 + tristate "Analog Devices AD5421 DAC driver" + depends on SPI + help + Say yes here to build support for Analog Devices AD5421 loop-powered + digital-to-analog convertors (DAC). + + To compile this driver as module choose M here: the module will be called + ad5421. + config AD5624R_SPI tristate "Analog Devices AD5624/44/64R DAC spi driver" depends on SPI diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile index 07b6f5e..e75b0c8 100644 --- a/drivers/staging/iio/dac/Makefile +++ b/drivers/staging/iio/dac/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_AD5360) += ad5360.o +obj-$(CONFIG_AD5421) += ad5421.o obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o obj-$(CONFIG_AD5064) += ad5064.o obj-$(CONFIG_AD5504) += ad5504.o diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c new file mode 100644 index 0000000..1491277 --- /dev/null +++ b/drivers/staging/iio/dac/ad5421.c @@ -0,0 +1,551 @@ +/* + * AD5421 Digital to analog converters driver + * + * Copyright 2011 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/sysfs.h> + +#include "../iio.h" +#include "../sysfs.h" +#include "../events.h" +#include "dac.h" +#include "ad5421.h" + + +#define AD5421_REG_DAC_DATA 0x1 +#define AD5421_REG_CTRL 0x2 +#define AD5421_REG_OFFSET 0x3 +#define AD5421_REG_GAIN 0x4 +/* load dac and fault shared the same register number. Writing to it will cause + * a dac load command, reading from it will return the fault status register */ +#define AD5421_REG_LOAD_DAC 0x5 +#define AD5421_REG_FAULT 0x5 +#define AD5421_REG_FORCE_ALARM_CURRENT 0x6 +#define AD5421_REG_RESET 0x7 +#define AD5421_REG_START_CONVERSION 0x8 +#define AD5421_REG_NOOP 0x9 + +#define AD5421_CTRL_WATCHDOG_DISABLE BIT(12) +#define AD5421_CTRL_AUTO_FAULT_READBACK BIT(11) +#define AD5421_CTRL_MIN_CURRENT BIT(9) +#define AD5421_CTRL_ADC_SOURCE_TEMP BIT(8) +#define AD5421_CTRL_ADC_ENABLE BIT(7) +#define AD5421_CTRL_PWR_DOWN_INT_VREF BIT(6) + +#define AD5421_FAULT_SPI BIT(15) +#define AD5421_FAULT_PEC BIT(14) +#define AD5421_FAULT_OVER_CURRENT BIT(13) +#define AD5421_FAULT_UNDER_CURRENT BIT(12) +#define AD5421_FAULT_TEMP_OVER_140 BIT(11) +#define AD5421_FAULT_TEMP_OVER_100 BIT(10) +#define AD5421_FAULT_UNDER_VOLTAGE_6V BIT(9) +#define AD5421_FAULT_UNDER_VOLTAGE_12V BIT(8) + +/* These bits will cause the fault pin to go high */ +#define AD5421_FAULT_TRIGGER_IRQ \ + (AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \ + AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140) + +/** + * struct ad5421_state - driver instance specific data + * @spi: spi_device + * @ctrl: control register cache + * @current_range: current range which the device is configured for + * @data: spi transfer buffers + * @fault_mask: software masking of events + */ +struct ad5421_state { + struct spi_device *spi; + unsigned int ctrl; + enum ad5421_current_range current_range; + unsigned int fault_mask; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + union { + u32 d32; + u8 d8[4]; + } data[2] ____cacheline_aligned; +}; + +static const struct iio_chan_spec ad5421_channels[] = { + { + .type = IIO_CURRENT, + .indexed = 1, + .output = 1, + .channel = 0, + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, + .scan_type = IIO_ST('u', 16, 16, 0), + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), + }, + { + .type = IIO_TEMP, + .channel = 1, + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), + }, +}; + +static int ad5421_write_unlocked(struct iio_dev *indio_dev, + unsigned int reg, unsigned int val) +{ + struct ad5421_state *st = iio_priv(indio_dev); + + st->data[0].d32 = cpu_to_be32((reg << 16) | val); + + return spi_write(st->spi, &st->data[0].d8[1], 3); +} + +static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg, + unsigned int val) +{ + int ret; + + mutex_lock(&indio_dev->mlock); + ret = ad5421_write_unlocked(indio_dev, reg, val); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg) +{ + struct ad5421_state *st = iio_priv(indio_dev); + struct spi_message m; + int ret; + struct spi_transfer t[] = { + { + .tx_buf = &st->data[0].d8[1], + .len = 3, + .cs_change = 1, + }, { + .rx_buf = &st->data[1].d8[1], + .len = 3, + }, + }; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + + mutex_lock(&indio_dev->mlock); + + st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); + + ret = spi_sync(st->spi, &m); + if (ret >= 0) + ret = be32_to_cpu(st->data[1].d32) & 0xffff; + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set, + unsigned int clr) +{ + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int ret; + + mutex_lock(&indio_dev->mlock); + + st->ctrl &= ~clr; + st->ctrl |= set; + + ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl); + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static irqreturn_t ad5421_fault_handler(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int fault; + unsigned int old_fault = 0; + unsigned int events; + + fault = ad5421_read(indio_dev, AD5421_REG_FAULT); + if (!fault) + return IRQ_NONE; + + /* If we had a fault, this might mean that the DAC has lost its state + * and has been reset. Make sure that the control register actually + * contains what we expect it to contain. Otherwise the watchdog might + * be enabled and we get watchdog timeout faults, which will render the + * DAC unusable. */ + ad5421_update_ctrl(indio_dev, 0, 0); + + + /* The fault pin stays high as long as a fault condition is present and + * it is not possible to mask fault conditions. For certain fault + * conditions for example like over-temperature it takes some time + * until the fault condition disappears. If we would exit the interrupt + * handler immediately after handling the event it would be entered + * again instantly. Thus we fall back to polling in case we detect that + * a interrupt condition is still present. + */ + do { + /* 0xffff is a invalid value for the register and will only be + * read if there has been a communication error */ + if (fault == 0xffff) + fault = 0; + + /* we are only interested in new events */ + events = (old_fault ^ fault) & fault; + events &= st->fault_mask; + + if (events & AD5421_FAULT_OVER_CURRENT) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } + + if (events & AD5421_FAULT_UNDER_CURRENT) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } + + if (events & AD5421_FAULT_TEMP_OVER_140) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_TEMP, + 0, + IIO_EV_TYPE_MAG, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + } + + old_fault = fault; + fault = ad5421_read(indio_dev, AD5421_REG_FAULT); + + /* still active? go to sleep for some time */ + if (fault & AD5421_FAULT_TRIGGER_IRQ) + msleep(1000); + + } while (fault & AD5421_FAULT_TRIGGER_IRQ); + + + return IRQ_HANDLED; +} + +static void ad5421_get_current_min_max(struct ad5421_state *st, + unsigned int *min, unsigned int *max) +{ + /* The current range is configured using external pins, which are + * usually hard-wired and not run-time switchable. */ + switch (st->current_range) { + case AD5421_CURRENT_RANGE_4mA_20mA: + *min = 4000; + *max = 20000; + break; + case AD5421_CURRENT_RANGE_3mA8_21mA: + *min = 3800; + *max = 21000; + break; + case AD5421_CURRENT_RANGE_3mA2_24mA: + *min = 3200; + *max = 24000; + break; + default: + *min = 0; + *max = 1; + break; + } +} + +static inline unsigned int ad5421_get_offset(struct ad5421_state *st) +{ + unsigned int min, max; + + ad5421_get_current_min_max(st, &min, &max); + return (min * (1 << 16)) / (max - min); +} + +static inline unsigned int ad5421_get_scale(struct ad5421_state *st) +{ + unsigned int min, max; + + ad5421_get_current_min_max(st, &min, &max); + return ((max - min) * 1000) / (1 << 16); +} + +static int ad5421_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long m) +{ + struct ad5421_state *st = iio_priv(indio_dev); + int ret; + + if (chan->type != IIO_CURRENT) + return -EINVAL; + + switch (m) { + case 0: + ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = ad5421_get_scale(st); + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val = ad5421_get_offset(st); + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + ret = ad5421_read(indio_dev, AD5421_REG_OFFSET); + if (ret < 0) + return ret; + *val = ret - 32768; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBSCALE: + ret = ad5421_read(indio_dev, AD5421_REG_GAIN); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int ad5421_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + unsigned int max_val = 1 << 16; + + switch (mask) { + case 0: + if (val >= max_val || val < 0) + return -EINVAL; + + return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val); + case (1 << IIO_CHAN_INFO_CALIBBIAS): + val += 32768; + if (val >= max_val || val < 0) + return -EINVAL; + + return ad5421_write(indio_dev, AD5421_REG_OFFSET, val); + case (1 << IIO_CHAN_INFO_CALIBSCALE): + if (val >= max_val || val < 0) + return -EINVAL; + + return ad5421_write(indio_dev, AD5421_REG_GAIN, val); + default: + break; + } + + return -EINVAL; +} + +static int ad5421_write_event_config(struct iio_dev *indio_dev, + u64 event_code, int state) +{ + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int mask; + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_CURRENT: + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == + IIO_EV_DIR_RISING) + mask = AD5421_FAULT_OVER_CURRENT; + else + mask = AD5421_FAULT_UNDER_CURRENT; + break; + case IIO_TEMP: + mask = AD5421_FAULT_TEMP_OVER_140; + break; + default: + return -EINVAL; + } + + if (state) + st->fault_mask |= mask; + else + st->fault_mask &= ~mask; + + return 0; +} + +static int ad5421_read_event_config(struct iio_dev *indio_dev, + u64 event_code) +{ + struct ad5421_state *st = iio_priv(indio_dev); + unsigned int mask; + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_CURRENT: + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == + IIO_EV_DIR_RISING) + mask = AD5421_FAULT_OVER_CURRENT; + else + mask = AD5421_FAULT_UNDER_CURRENT; + break; + case IIO_TEMP: + mask = AD5421_FAULT_TEMP_OVER_140; + break; + default: + return -EINVAL; + } + + return !!(st->fault_mask & mask); +} + +static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code, + int *val) +{ + int ret; + + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { + case IIO_CURRENT: + ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); + if (ret < 0) + return ret; + *val = ret; + break; + case IIO_TEMP: + *val = 140000; + break; + default: + break; + } + + return 0; +} + +static const struct iio_info ad5421_info = { + .read_raw = ad5421_read_raw, + .write_raw = ad5421_write_raw, + .read_event_config = ad5421_read_event_config, + .write_event_config = ad5421_write_event_config, + .read_event_value = ad5421_read_event_value, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad5421_probe(struct spi_device *spi) +{ + struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev); + struct iio_dev *indio_dev; + struct ad5421_state *st; + int ret; + + indio_dev = iio_allocate_device(sizeof(*st)); + if (indio_dev == NULL) { + dev_err(&spi->dev, "Failed to allocate iio device\n"); + return -ENOMEM; + } + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + + st->spi = spi; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = "ad5421"; + indio_dev->info = &ad5421_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad5421_channels; + indio_dev->num_channels = ARRAY_SIZE(ad5421_channels); + + st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE | + AD5421_CTRL_AUTO_FAULT_READBACK; + + if (pdata) { + st->current_range = pdata->current_range; + if (pdata->external_vref) + st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF; + } + + /* write initial ctrl register value */ + ad5421_update_ctrl(indio_dev, 0, 0); + + if (spi->irq) { + ret = request_threaded_irq(spi->irq, + NULL, + ad5421_fault_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "ad5421 fault", + indio_dev); + if (ret) + goto error_free; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); + goto error_free_irq; + } + + return 0; + +error_free_irq: + if (spi->irq) + free_irq(spi->irq, indio_dev); +error_free: + iio_free_device(indio_dev); + + return ret; +} + +static int __devexit ad5421_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + iio_device_unregister(indio_dev); + if (spi->irq) + free_irq(spi->irq, indio_dev); + iio_free_device(indio_dev); + + return 0; +} + +static struct spi_driver ad5421_driver = { + .driver = { + .name = "ad5421", + .owner = THIS_MODULE, + }, + .probe = ad5421_probe, + .remove = __devexit_p(ad5421_remove), +}; + +static __init int ad5421_init(void) +{ + return spi_register_driver(&ad5421_driver); +} +module_init(ad5421_init); + +static __exit void ad5421_exit(void) +{ + spi_unregister_driver(&ad5421_driver); +} +module_exit(ad5421_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD5421 DAC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("spi:ad5421"); diff --git a/drivers/staging/iio/dac/ad5421.h b/drivers/staging/iio/dac/ad5421.h new file mode 100644 index 0000000..cd2bb84 --- /dev/null +++ b/drivers/staging/iio/dac/ad5421.h @@ -0,0 +1,32 @@ +#ifndef __IIO_DAC_AD5421_H__ +#define __IIO_DAC_AD5421_H__ + +/* + * TODO: This file needs to go into include/linux/iio + */ + +/** + * enum ad5421_current_range - Current range the AD5421 is configured for. + * @AD5421_CURRENT_RANGE_4mA_20mA: 4 mA to 20 mA (RANGE1,0 pins = 00) + * @AD5421_CURRENT_RANGE_3mA8_21mA: 3.8 mA to 21 mA (RANGE1,0 pins = x1) + * @AD5421_CURRENT_RANGE_3mA2_24mA: 3.2 mA to 24 mA (RANGE1,0 pins = 10) + */ + +enum ad5421_current_range { + AD5421_CURRENT_RANGE_4mA_20mA, + AD5421_CURRENT_RANGE_3mA8_21mA, + AD5421_CURRENT_RANGE_3mA2_24mA, +}; + +/** + * struct ad5421_platform_data - AD5421 DAC driver platform data + * @external_vref: whether an external reference voltage is used or not + * @current_range: Current range the AD5421 is configured for + */ + +struct ad5421_platform_data { + bool external_vref; + enum ad5421_current_range current_range; +}; + +#endif diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h index 7cf9306..2b4d2d9 100644 --- a/drivers/staging/iio/events.h +++ b/drivers/staging/iio/events.h @@ -56,7 +56,8 @@ enum iio_event_direction { type, chan, chan1, chan2) \ (((u64)type << 56) | ((u64)diff << 55) | \ ((u64)direction << 48) | ((u64)modifier << 40) | \ - ((u64)chan_type << 32) | (chan2 << 16) | chan1 | chan) + ((u64)chan_type << 32) | (((s16)chan2) << 16) | ((s16)chan1) | \ + ((s16)chan)) #define IIO_EV_DIR_MAX 4 -- 1.7.7 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] staging:iio:dac: Add AD5421 driver 2011-10-26 12:01 ` [PATCH 2/2] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen @ 2011-10-26 13:21 ` Lars-Peter Clausen 2011-10-26 17:04 ` Jonathan Cameron 1 sibling, 0 replies; 6+ messages in thread From: Lars-Peter Clausen @ 2011-10-26 13:21 UTC (permalink / raw) To: Lars-Peter Clausen Cc: Jonathan Cameron, Michael Hennerich, linux-iio, device-drivers-devel, drivers On 10/26/2011 02:01 PM, Lars-Peter Clausen wrote: > This patch adds support for the Analog Devices AD5421 Loop-Powered, 4mA to 20mA > DAC. > > Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> > --- > [...] > > drivers/staging/iio/events.h | 3 +- > > [...] > diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h > index 7cf9306..2b4d2d9 100644 > --- a/drivers/staging/iio/events.h > +++ b/drivers/staging/iio/events.h > @@ -56,7 +56,8 @@ enum iio_event_direction { > type, chan, chan1, chan2) \ > (((u64)type << 56) | ((u64)diff << 55) | \ > ((u64)direction << 48) | ((u64)modifier << 40) | \ > - ((u64)chan_type << 32) | (chan2 << 16) | chan1 | chan) > + ((u64)chan_type << 32) | (((s16)chan2) << 16) | ((s16)chan1) | \ > + ((s16)chan)) > Uhm, this was not supposed to be in this patch... > > #define IIO_EV_DIR_MAX 4 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] staging:iio:dac: Add AD5421 driver 2011-10-26 12:01 ` [PATCH 2/2] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen 2011-10-26 13:21 ` Lars-Peter Clausen @ 2011-10-26 17:04 ` Jonathan Cameron 2011-10-27 7:25 ` Lars-Peter Clausen 1 sibling, 1 reply; 6+ messages in thread From: Jonathan Cameron @ 2011-10-26 17:04 UTC (permalink / raw) To: Lars-Peter Clausen Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers On 10/26/11 13:01, Lars-Peter Clausen wrote: > This patch adds support for the Analog Devices AD5421 Loop-Powered, 4mA to 20mA > DAC. Couple of nitpicks, but basically fine. If you want to be hopeful and push on to Greg after answering those, feel free to add my Ack. No idea if he is planning another staging pull request or not. It's a new driver so he might be happy to slip it in. Obviously clear up the stray stuff at the end that you pointed out before I ever opened your email! Jonathan > > Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> > --- > drivers/staging/iio/dac/Kconfig | 10 + > drivers/staging/iio/dac/Makefile | 1 + > drivers/staging/iio/dac/ad5421.c | 551 ++++++++++++++++++++++++++++++++++++++ > drivers/staging/iio/dac/ad5421.h | 32 +++ > drivers/staging/iio/events.h | 3 +- > 5 files changed, 596 insertions(+), 1 deletions(-) > create mode 100644 drivers/staging/iio/dac/ad5421.c > create mode 100644 drivers/staging/iio/dac/ad5421.h > > diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig > index fac8549..0e8983a 100644 > --- a/drivers/staging/iio/dac/Kconfig > +++ b/drivers/staging/iio/dac/Kconfig > @@ -24,6 +24,16 @@ config AD5360 > To compile this driver as module choose M here: the module will be called > ad5360. > > +config AD5421 > + tristate "Analog Devices AD5421 DAC driver" > + depends on SPI > + help > + Say yes here to build support for Analog Devices AD5421 loop-powered > + digital-to-analog convertors (DAC). > + > + To compile this driver as module choose M here: the module will be called > + ad5421. > + > config AD5624R_SPI > tristate "Analog Devices AD5624/44/64R DAC spi driver" > depends on SPI > diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile > index 07b6f5e..e75b0c8 100644 > --- a/drivers/staging/iio/dac/Makefile > +++ b/drivers/staging/iio/dac/Makefile > @@ -3,6 +3,7 @@ > # > > obj-$(CONFIG_AD5360) += ad5360.o > +obj-$(CONFIG_AD5421) += ad5421.o > obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o > obj-$(CONFIG_AD5064) += ad5064.o > obj-$(CONFIG_AD5504) += ad5504.o > diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c > new file mode 100644 > index 0000000..1491277 > --- /dev/null > +++ b/drivers/staging/iio/dac/ad5421.c > @@ -0,0 +1,551 @@ > +/* > + * AD5421 Digital to analog converters driver > + * > + * Copyright 2011 Analog Devices Inc. > + * > + * Licensed under the GPL-2. > + */ > + > +#include <linux/device.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/module.h> > +#include <linux/interrupt.h> > +#include <linux/kernel.h> > +#include <linux/spi/spi.h> > +#include <linux/slab.h> > +#include <linux/sysfs.h> > + > +#include "../iio.h" > +#include "../sysfs.h" > +#include "../events.h" > +#include "dac.h" > +#include "ad5421.h" > + > + > +#define AD5421_REG_DAC_DATA 0x1 > +#define AD5421_REG_CTRL 0x2 > +#define AD5421_REG_OFFSET 0x3 > +#define AD5421_REG_GAIN 0x4 > +/* load dac and fault shared the same register number. Writing to it will cause > + * a dac load command, reading from it will return the fault status register */ > +#define AD5421_REG_LOAD_DAC 0x5 > +#define AD5421_REG_FAULT 0x5 > +#define AD5421_REG_FORCE_ALARM_CURRENT 0x6 > +#define AD5421_REG_RESET 0x7 > +#define AD5421_REG_START_CONVERSION 0x8 > +#define AD5421_REG_NOOP 0x9 > + > +#define AD5421_CTRL_WATCHDOG_DISABLE BIT(12) > +#define AD5421_CTRL_AUTO_FAULT_READBACK BIT(11) > +#define AD5421_CTRL_MIN_CURRENT BIT(9) > +#define AD5421_CTRL_ADC_SOURCE_TEMP BIT(8) > +#define AD5421_CTRL_ADC_ENABLE BIT(7) > +#define AD5421_CTRL_PWR_DOWN_INT_VREF BIT(6) > + > +#define AD5421_FAULT_SPI BIT(15) > +#define AD5421_FAULT_PEC BIT(14) > +#define AD5421_FAULT_OVER_CURRENT BIT(13) > +#define AD5421_FAULT_UNDER_CURRENT BIT(12) > +#define AD5421_FAULT_TEMP_OVER_140 BIT(11) > +#define AD5421_FAULT_TEMP_OVER_100 BIT(10) > +#define AD5421_FAULT_UNDER_VOLTAGE_6V BIT(9) > +#define AD5421_FAULT_UNDER_VOLTAGE_12V BIT(8) > + > +/* These bits will cause the fault pin to go high */ > +#define AD5421_FAULT_TRIGGER_IRQ \ > + (AD5421_FAULT_SPI | AD5421_FAULT_PEC | AD5421_FAULT_OVER_CURRENT | \ > + AD5421_FAULT_UNDER_CURRENT | AD5421_FAULT_TEMP_OVER_140) > + > +/** > + * struct ad5421_state - driver instance specific data > + * @spi: spi_device > + * @ctrl: control register cache > + * @current_range: current range which the device is configured for > + * @data: spi transfer buffers > + * @fault_mask: software masking of events > + */ > +struct ad5421_state { > + struct spi_device *spi; > + unsigned int ctrl; > + enum ad5421_current_range current_range; > + unsigned int fault_mask; > + > + /* > + * DMA (thus cache coherency maintenance) requires the > + * transfer buffers to live in their own cache lines. > + */ > + union { > + u32 d32; > + u8 d8[4]; > + } data[2] ____cacheline_aligned; > +}; > + > +static const struct iio_chan_spec ad5421_channels[] = { > + { > + .type = IIO_CURRENT, > + .indexed = 1, > + .output = 1, > + .channel = 0, > + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | > + IIO_CHAN_INFO_OFFSET_SHARED_BIT | > + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | > + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, > + .scan_type = IIO_ST('u', 16, 16, 0), > + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | > + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), > + }, > + { Wasn't the plan to have this set to channel -1 to avoid it appearing? If that doesn't work we should probably make it do so. At a quick glance I can't see why it wouldn't... > + .type = IIO_TEMP, > + .channel = 1, > + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), > + }, > +}; > + > +static int ad5421_write_unlocked(struct iio_dev *indio_dev, > + unsigned int reg, unsigned int val) > +{ > + struct ad5421_state *st = iio_priv(indio_dev); > + > + st->data[0].d32 = cpu_to_be32((reg << 16) | val); > + > + return spi_write(st->spi, &st->data[0].d8[1], 3); > +} > + > +static int ad5421_write(struct iio_dev *indio_dev, unsigned int reg, > + unsigned int val) > +{ > + int ret; > + > + mutex_lock(&indio_dev->mlock); > + ret = ad5421_write_unlocked(indio_dev, reg, val); > + mutex_unlock(&indio_dev->mlock); > + > + return ret; > +} > + > +static int ad5421_read(struct iio_dev *indio_dev, unsigned int reg) > +{ > + struct ad5421_state *st = iio_priv(indio_dev); > + struct spi_message m; > + int ret; > + struct spi_transfer t[] = { > + { > + .tx_buf = &st->data[0].d8[1], > + .len = 3, > + .cs_change = 1, > + }, { > + .rx_buf = &st->data[1].d8[1], > + .len = 3, > + }, > + }; > + > + spi_message_init(&m); > + spi_message_add_tail(&t[0], &m); > + spi_message_add_tail(&t[1], &m); > + > + mutex_lock(&indio_dev->mlock); > + > + st->data[0].d32 = cpu_to_be32((1 << 23) | (reg << 16)); > + > + ret = spi_sync(st->spi, &m); > + if (ret >= 0) > + ret = be32_to_cpu(st->data[1].d32) & 0xffff; > + > + mutex_unlock(&indio_dev->mlock); > + > + return ret; > +} > + > +static int ad5421_update_ctrl(struct iio_dev *indio_dev, unsigned int set, > + unsigned int clr) > +{ > + struct ad5421_state *st = iio_priv(indio_dev); > + unsigned int ret; > + > + mutex_lock(&indio_dev->mlock); > + > + st->ctrl &= ~clr; > + st->ctrl |= set; > + > + ret = ad5421_write_unlocked(indio_dev, AD5421_REG_CTRL, st->ctrl); > + > + mutex_unlock(&indio_dev->mlock); > + > + return ret; > +} > + > +static irqreturn_t ad5421_fault_handler(int irq, void *data) > +{ > + struct iio_dev *indio_dev = data; > + struct ad5421_state *st = iio_priv(indio_dev); > + unsigned int fault; > + unsigned int old_fault = 0; > + unsigned int events; > + > + fault = ad5421_read(indio_dev, AD5421_REG_FAULT); > + if (!fault) > + return IRQ_NONE; > + > + /* If we had a fault, this might mean that the DAC has lost its state > + * and has been reset. Make sure that the control register actually > + * contains what we expect it to contain. Otherwise the watchdog might > + * be enabled and we get watchdog timeout faults, which will render the > + * DAC unusable. */ > + ad5421_update_ctrl(indio_dev, 0, 0); > + > + > + /* The fault pin stays high as long as a fault condition is present and > + * it is not possible to mask fault conditions. For certain fault > + * conditions for example like over-temperature it takes some time > + * until the fault condition disappears. If we would exit the interrupt > + * handler immediately after handling the event it would be entered > + * again instantly. Thus we fall back to polling in case we detect that > + * a interrupt condition is still present. > + */ > + do { > + /* 0xffff is a invalid value for the register and will only be > + * read if there has been a communication error */ > + if (fault == 0xffff) > + fault = 0; > + > + /* we are only interested in new events */ > + events = (old_fault ^ fault) & fault; > + events &= st->fault_mask; > + > + if (events & AD5421_FAULT_OVER_CURRENT) { > + iio_push_event(indio_dev, > + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, > + 0, > + IIO_EV_TYPE_THRESH, > + IIO_EV_DIR_RISING), > + iio_get_time_ns()); > + } > + > + if (events & AD5421_FAULT_UNDER_CURRENT) { > + iio_push_event(indio_dev, > + IIO_UNMOD_EVENT_CODE(IIO_CURRENT, > + 0, > + IIO_EV_TYPE_THRESH, > + IIO_EV_DIR_FALLING), > + iio_get_time_ns()); > + } > + > + if (events & AD5421_FAULT_TEMP_OVER_140) { > + iio_push_event(indio_dev, > + IIO_UNMOD_EVENT_CODE(IIO_TEMP, > + 0, > + IIO_EV_TYPE_MAG, > + IIO_EV_DIR_RISING), > + iio_get_time_ns()); > + } > + > + old_fault = fault; > + fault = ad5421_read(indio_dev, AD5421_REG_FAULT); > + > + /* still active? go to sleep for some time */ > + if (fault & AD5421_FAULT_TRIGGER_IRQ) > + msleep(1000); > + > + } while (fault & AD5421_FAULT_TRIGGER_IRQ); > + > + > + return IRQ_HANDLED; > +} > + > +static void ad5421_get_current_min_max(struct ad5421_state *st, > + unsigned int *min, unsigned int *max) > +{ > + /* The current range is configured using external pins, which are > + * usually hard-wired and not run-time switchable. */ > + switch (st->current_range) { > + case AD5421_CURRENT_RANGE_4mA_20mA: > + *min = 4000; > + *max = 20000; > + break; > + case AD5421_CURRENT_RANGE_3mA8_21mA: > + *min = 3800; > + *max = 21000; > + break; > + case AD5421_CURRENT_RANGE_3mA2_24mA: > + *min = 3200; > + *max = 24000; > + break; > + default: > + *min = 0; > + *max = 1; > + break; > + } > +} > + > +static inline unsigned int ad5421_get_offset(struct ad5421_state *st) > +{ > + unsigned int min, max; > + > + ad5421_get_current_min_max(st, &min, &max); > + return (min * (1 << 16)) / (max - min); > +} > + > +static inline unsigned int ad5421_get_scale(struct ad5421_state *st) > +{ > + unsigned int min, max; > + > + ad5421_get_current_min_max(st, &min, &max); > + return ((max - min) * 1000) / (1 << 16); > +} > + > +static int ad5421_read_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *chan, int *val, int *val2, long m) > +{ > + struct ad5421_state *st = iio_priv(indio_dev); > + int ret; > + > + if (chan->type != IIO_CURRENT) > + return -EINVAL; > + > + switch (m) { > + case 0: > + ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); > + if (ret < 0) > + return ret; > + *val = ret; > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_SCALE: > + *val = 0; > + *val2 = ad5421_get_scale(st); > + return IIO_VAL_INT_PLUS_MICRO; > + case IIO_CHAN_INFO_OFFSET: > + *val = ad5421_get_offset(st); > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_CALIBBIAS: > + ret = ad5421_read(indio_dev, AD5421_REG_OFFSET); > + if (ret < 0) > + return ret; > + *val = ret - 32768; > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_CALIBSCALE: > + ret = ad5421_read(indio_dev, AD5421_REG_GAIN); > + if (ret < 0) > + return ret; > + *val = ret; > + return IIO_VAL_INT; > + } > + > + return -EINVAL; > +} > + > +static int ad5421_write_raw(struct iio_dev *indio_dev, > + struct iio_chan_spec const *chan, int val, int val2, long mask) > +{ const > + unsigned int max_val = 1 << 16; > + > + switch (mask) { > + case 0: > + if (val >= max_val || val < 0) > + return -EINVAL; > + > + return ad5421_write(indio_dev, AD5421_REG_DAC_DATA, val); > + case (1 << IIO_CHAN_INFO_CALIBBIAS): > + val += 32768; > + if (val >= max_val || val < 0) > + return -EINVAL; > + > + return ad5421_write(indio_dev, AD5421_REG_OFFSET, val); > + case (1 << IIO_CHAN_INFO_CALIBSCALE): > + if (val >= max_val || val < 0) > + return -EINVAL; > + > + return ad5421_write(indio_dev, AD5421_REG_GAIN, val); > + default: > + break; > + } > + > + return -EINVAL; > +} > + > +static int ad5421_write_event_config(struct iio_dev *indio_dev, > + u64 event_code, int state) > +{ > + struct ad5421_state *st = iio_priv(indio_dev); > + unsigned int mask; > + > + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { > + case IIO_CURRENT: > + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == > + IIO_EV_DIR_RISING) > + mask = AD5421_FAULT_OVER_CURRENT; > + else > + mask = AD5421_FAULT_UNDER_CURRENT; > + break; > + case IIO_TEMP: > + mask = AD5421_FAULT_TEMP_OVER_140; > + break; > + default: > + return -EINVAL; > + } > + > + if (state) > + st->fault_mask |= mask; > + else > + st->fault_mask &= ~mask; > + > + return 0; > +} > + > +static int ad5421_read_event_config(struct iio_dev *indio_dev, > + u64 event_code) > +{ > + struct ad5421_state *st = iio_priv(indio_dev); > + unsigned int mask; > + > + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { > + case IIO_CURRENT: > + if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == > + IIO_EV_DIR_RISING) > + mask = AD5421_FAULT_OVER_CURRENT; > + else > + mask = AD5421_FAULT_UNDER_CURRENT; > + break; > + case IIO_TEMP: > + mask = AD5421_FAULT_TEMP_OVER_140; > + break; > + default: > + return -EINVAL; > + } > + > + return !!(st->fault_mask & mask); > +} > + > +static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code, > + int *val) > +{ > + int ret; > + > + switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) { > + case IIO_CURRENT: > + ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA); > + if (ret < 0) > + return ret; > + *val = ret; > + break; > + case IIO_TEMP: > + *val = 140000; > + break; > + default: > + break; > + } > + > + return 0; > +} > + > +static const struct iio_info ad5421_info = { > + .read_raw = ad5421_read_raw, > + .write_raw = ad5421_write_raw, > + .read_event_config = ad5421_read_event_config, > + .write_event_config = ad5421_write_event_config, > + .read_event_value = ad5421_read_event_value, > + .driver_module = THIS_MODULE, > +}; > + > +static int __devinit ad5421_probe(struct spi_device *spi) > +{ > + struct ad5421_platform_data *pdata = dev_get_platdata(&spi->dev); > + struct iio_dev *indio_dev; > + struct ad5421_state *st; > + int ret; > + > + indio_dev = iio_allocate_device(sizeof(*st)); > + if (indio_dev == NULL) { > + dev_err(&spi->dev, "Failed to allocate iio device\n"); > + return -ENOMEM; > + } > + > + st = iio_priv(indio_dev); > + spi_set_drvdata(spi, indio_dev); > + > + st->spi = spi; > + > + indio_dev->dev.parent = &spi->dev; > + indio_dev->name = "ad5421"; > + indio_dev->info = &ad5421_info; > + indio_dev->modes = INDIO_DIRECT_MODE; > + indio_dev->channels = ad5421_channels; > + indio_dev->num_channels = ARRAY_SIZE(ad5421_channels); > + > + st->ctrl = AD5421_CTRL_WATCHDOG_DISABLE | > + AD5421_CTRL_AUTO_FAULT_READBACK; > + > + if (pdata) { Nitpick, but I think I'd prefer to see an explicit default for st->current_range in the absense of pdata. Obviously it is the enum value of 0, but either commenting it, or separately would make that clear. > + st->current_range = pdata->current_range; > + if (pdata->external_vref) > + st->ctrl |= AD5421_CTRL_PWR_DOWN_INT_VREF; > + } > + > + /* write initial ctrl register value */ > + ad5421_update_ctrl(indio_dev, 0, 0); > + > + if (spi->irq) { > + ret = request_threaded_irq(spi->irq, > + NULL, > + ad5421_fault_handler, > + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, > + "ad5421 fault", > + indio_dev); > + if (ret) > + goto error_free; > + } > + > + ret = iio_device_register(indio_dev); > + if (ret) { > + dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); > + goto error_free_irq; > + } > + > + return 0; > + > +error_free_irq: > + if (spi->irq) > + free_irq(spi->irq, indio_dev); > +error_free: > + iio_free_device(indio_dev); > + > + return ret; > +} > + > +static int __devexit ad5421_remove(struct spi_device *spi) > +{ > + struct iio_dev *indio_dev = spi_get_drvdata(spi); > + > + iio_device_unregister(indio_dev); > + if (spi->irq) > + free_irq(spi->irq, indio_dev); > + iio_free_device(indio_dev); > + > + return 0; > +} > + > +static struct spi_driver ad5421_driver = { > + .driver = { > + .name = "ad5421", > + .owner = THIS_MODULE, > + }, > + .probe = ad5421_probe, > + .remove = __devexit_p(ad5421_remove), > +}; > + > +static __init int ad5421_init(void) > +{ > + return spi_register_driver(&ad5421_driver); > +} > +module_init(ad5421_init); > + > +static __exit void ad5421_exit(void) > +{ > + spi_unregister_driver(&ad5421_driver); > +} > +module_exit(ad5421_exit); > + > +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); > +MODULE_DESCRIPTION("Analog Devices AD5421 DAC"); > +MODULE_LICENSE("GPL v2"); > +MODULE_ALIAS("spi:ad5421"); > diff --git a/drivers/staging/iio/dac/ad5421.h b/drivers/staging/iio/dac/ad5421.h > new file mode 100644 > index 0000000..cd2bb84 > --- /dev/null > +++ b/drivers/staging/iio/dac/ad5421.h > @@ -0,0 +1,32 @@ > +#ifndef __IIO_DAC_AD5421_H__ > +#define __IIO_DAC_AD5421_H__ > + > +/* > + * TODO: This file needs to go into include/linux/iio > + */ > + > +/** > + * enum ad5421_current_range - Current range the AD5421 is configured for. > + * @AD5421_CURRENT_RANGE_4mA_20mA: 4 mA to 20 mA (RANGE1,0 pins = 00) > + * @AD5421_CURRENT_RANGE_3mA8_21mA: 3.8 mA to 21 mA (RANGE1,0 pins = x1) > + * @AD5421_CURRENT_RANGE_3mA2_24mA: 3.2 mA to 24 mA (RANGE1,0 pins = 10) > + */ > + > +enum ad5421_current_range { > + AD5421_CURRENT_RANGE_4mA_20mA, > + AD5421_CURRENT_RANGE_3mA8_21mA, > + AD5421_CURRENT_RANGE_3mA2_24mA, > +}; > + > +/** > + * struct ad5421_platform_data - AD5421 DAC driver platform data > + * @external_vref: whether an external reference voltage is used or not > + * @current_range: Current range the AD5421 is configured for > + */ > + > +struct ad5421_platform_data { > + bool external_vref; > + enum ad5421_current_range current_range; > +}; > + > +#endif ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] staging:iio:dac: Add AD5421 driver 2011-10-26 17:04 ` Jonathan Cameron @ 2011-10-27 7:25 ` Lars-Peter Clausen 0 siblings, 0 replies; 6+ messages in thread From: Lars-Peter Clausen @ 2011-10-27 7:25 UTC (permalink / raw) To: Jonathan Cameron Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers On 10/26/2011 07:04 PM, Jonathan Cameron wrote: > On 10/26/11 13:01, Lars-Peter Clausen wrote: >> [...] >> + >> +static const struct iio_chan_spec ad5421_channels[] = { >> + { >> + .type = IIO_CURRENT, >> + .indexed = 1, >> + .output = 1, >> + .channel = 0, >> + .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | >> + IIO_CHAN_INFO_OFFSET_SHARED_BIT | >> + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | >> + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, >> + .scan_type = IIO_ST('u', 16, 16, 0), >> + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | >> + IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING), >> + }, >> + { > Wasn't the plan to have this set to channel -1 to avoid it appearing? > If that doesn't work we should probably make it do so. At a quick glance > I can't see why it wouldn't... hehe, that was what the hunk at bottom was about. If the binary representation of channel is greater than 0xffff it will overwrite other fields. I'll resend with a proper fix included in the series. >> + .type = IIO_TEMP, >> + .channel = 1, >> + .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), >> + }, >> +}; >> + ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] staging:iio: Make write_event_value callback optional 2011-10-26 12:01 [PATCH 1/2] staging:iio: Make write_event_value callback optional Lars-Peter Clausen 2011-10-26 12:01 ` [PATCH 2/2] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen @ 2011-10-26 12:02 ` Jonathan Cameron 1 sibling, 0 replies; 6+ messages in thread From: Jonathan Cameron @ 2011-10-26 12:02 UTC (permalink / raw) To: Lars-Peter Clausen Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers On 10/26/11 13:01, Lars-Peter Clausen wrote: > Some devices have fixed thresholds which can not be modified so make the > write_event_value callback optional, so the drivers for these devices do not > have to implement a boilerplate no-op callback. > > Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Jonathan Cameron <jic23@cam.ac.uk> > --- > drivers/staging/iio/industrialio-core.c | 3 +++ > 1 files changed, 3 insertions(+), 0 deletions(-) > > diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c > index cfa4fcb..d2eea07 100644 > --- a/drivers/staging/iio/industrialio-core.c > +++ b/drivers/staging/iio/industrialio-core.c > @@ -782,6 +782,9 @@ static ssize_t iio_ev_value_store(struct device *dev, > unsigned long val; > int ret; > > + if (!indio_dev->info->write_event_value) > + return -EINVAL; > + > ret = strict_strtoul(buf, 10, &val); > if (ret) > return ret; ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-10-27 7:24 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2011-10-26 12:01 [PATCH 1/2] staging:iio: Make write_event_value callback optional Lars-Peter Clausen 2011-10-26 12:01 ` [PATCH 2/2] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen 2011-10-26 13:21 ` Lars-Peter Clausen 2011-10-26 17:04 ` Jonathan Cameron 2011-10-27 7:25 ` Lars-Peter Clausen 2011-10-26 12:02 ` [PATCH 1/2] staging:iio: Make write_event_value callback optional Jonathan Cameron
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.