All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] staging:iio: Make write_event_value callback optional
@ 2011-10-27  8:44 Lars-Peter Clausen
  2011-10-27  8:44 ` [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers Lars-Peter Clausen
  2011-10-27  8:44 ` [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen
  0 siblings, 2 replies; 8+ messages in thread
From: Lars-Peter Clausen @ 2011-10-27  8:44 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>
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;
-- 
1.7.7

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers
  2011-10-27  8:44 [PATCH 1/3] staging:iio: Make write_event_value callback optional Lars-Peter Clausen
@ 2011-10-27  8:44 ` Lars-Peter Clausen
  2011-10-27  9:02   ` Lars-Peter Clausen
  2011-10-27  8:44 ` [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen
  1 sibling, 1 reply; 8+ messages in thread
From: Lars-Peter Clausen @ 2011-10-27  8:44 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers,
	Lars-Peter Clausen

Make sure we only use the allotted space for channel numbers in the event mask
and do not let them override other fields.

Since negative values are valid channel number, cast the channel number to
signed when extracting it from an event mask.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
 drivers/staging/iio/events.h |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h
index 7cf9306..fc2b7e5 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) | (((u16)chan2) << 16) | ((u16)chan1) | \
+	 ((u16)chan))
 
 
 #define IIO_EV_DIR_MAX 4
@@ -95,7 +96,7 @@ enum iio_event_direction {
 
 /* Event code number extraction depends on which type of event we have.
  * Perhaps review this function in the future*/
-#define IIO_EVENT_CODE_EXTRACT_NUM(mask) (mask & 0xFFFF)
+#define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((s16)(mask & 0xFFFF))
 
 #define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
 
-- 
1.7.7

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver
  2011-10-27  8:44 [PATCH 1/3] staging:iio: Make write_event_value callback optional Lars-Peter Clausen
  2011-10-27  8:44 ` [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers Lars-Peter Clausen
@ 2011-10-27  8:44 ` Lars-Peter Clausen
  2011-10-31 11:28   ` Jonathan Cameron
  1 sibling, 1 reply; 8+ messages in thread
From: Lars-Peter Clausen @ 2011-10-27  8:44 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>

---
Changes since v1:
	* Added lock to protect fault_mask
	* Use channel index -1 for the temperature channel
	* Explicitly initialize current_range in case of absent platform data
	* Minor code style cleanups
---
 drivers/staging/iio/dac/Kconfig  |   10 +
 drivers/staging/iio/dac/Makefile |    1 +
 drivers/staging/iio/dac/ad5421.c |  555 ++++++++++++++++++++++++++++++++++++++
 drivers/staging/iio/dac/ad5421.h |   32 +++
 4 files changed, 598 insertions(+), 0 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..71ee868
--- /dev/null
+++ b/drivers/staging/iio/dac/ad5421.c
@@ -0,0 +1,555 @@
+/*
+ * 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)
+{
+	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 IIO_CHAN_INFO_CALIBBIAS:
+		val += 32768;
+		if (val >= max_val || val < 0)
+			return -EINVAL;
+
+		return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
+	case 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;
+	}
+
+	mutex_lock(&indio_dev->mlock);
+	if (state)
+		st->fault_mask |= mask;
+	else
+		st->fault_mask &= ~mask;
+	mutex_unlock(&indio_dev->mlock);
+
+	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 (bool)(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:
+		return -EINVAL;
+	}
+
+	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;
+	} else {
+		st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
+	}
+
+	/* 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
-- 
1.7.7

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers
  2011-10-27  8:44 ` [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers Lars-Peter Clausen
@ 2011-10-27  9:02   ` Lars-Peter Clausen
  2011-10-31 12:30     ` Jonathan Cameron
  0 siblings, 1 reply; 8+ messages in thread
From: Lars-Peter Clausen @ 2011-10-27  9:02 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Jonathan Cameron, Michael Hennerich, linux-iio,
	device-drivers-devel, drivers

On 10/27/2011 10:44 AM, Lars-Peter Clausen wrote:
> Make sure we only use the allotted space for channel numbers in the event mask
> and do not let them override other fields.
> 
> Since negative values are valid channel number, cast the channel number to
> signed when extracting it from an event mask.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
>  drivers/staging/iio/events.h |    5 +++--
>  1 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h
> index 7cf9306..fc2b7e5 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) | (((u16)chan2) << 16) | ((u16)chan1) | \
> +	 ((u16)chan))
>  
>  
>  #define IIO_EV_DIR_MAX 4
> @@ -95,7 +96,7 @@ enum iio_event_direction {
>  
>  /* Event code number extraction depends on which type of event we have.
>   * Perhaps review this function in the future*/
> -#define IIO_EVENT_CODE_EXTRACT_NUM(mask) (mask & 0xFFFF)
> +#define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((s16)(mask & 0xFFFF))
>  

Since we want to use it in userspace this should obviously be __s16, sorry.
Will fix this before sending the patch on.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver
  2011-10-27  8:44 ` [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen
@ 2011-10-31 11:28   ` Jonathan Cameron
  2011-10-31 12:14     ` Lars-Peter Clausen
  0 siblings, 1 reply; 8+ messages in thread
From: Jonathan Cameron @ 2011-10-31 11:28 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers

On 10/27/11 09:44, 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>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>

Feel free to send on to Greg as you've nailed everything I cared about.

I do wonder if we might be better with an explicit 'no_read' flag in the
chan_spec for channels like this. That way we could assign more meaningful
channel numbers?  Afterall, sooner of later we are going to have something
with two temperature sensors that only generate events.

What do you think?
> 
> ---
> Changes since v1:
> 	* Added lock to protect fault_mask
> 	* Use channel index -1 for the temperature channel
> 	* Explicitly initialize current_range in case of absent platform data
> 	* Minor code style cleanups
> ---
>  drivers/staging/iio/dac/Kconfig  |   10 +
>  drivers/staging/iio/dac/Makefile |    1 +
>  drivers/staging/iio/dac/ad5421.c |  555 ++++++++++++++++++++++++++++++++++++++
>  drivers/staging/iio/dac/ad5421.h |   32 +++
>  4 files changed, 598 insertions(+), 0 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..71ee868
> --- /dev/null
> +++ b/drivers/staging/iio/dac/ad5421.c
> @@ -0,0 +1,555 @@
> +/*
> + * 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)
> +{
> +	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 IIO_CHAN_INFO_CALIBBIAS:
> +		val += 32768;
> +		if (val >= max_val || val < 0)
> +			return -EINVAL;
> +
> +		return ad5421_write(indio_dev, AD5421_REG_OFFSET, val);
> +	case 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;
> +	}
> +
> +	mutex_lock(&indio_dev->mlock);
> +	if (state)
> +		st->fault_mask |= mask;
> +	else
> +		st->fault_mask &= ~mask;
> +	mutex_unlock(&indio_dev->mlock);
> +
> +	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 (bool)(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:
> +		return -EINVAL;
> +	}
> +
> +	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;
> +	} else {
> +		st->current_range = AD5421_CURRENT_RANGE_4mA_20mA;
> +	}
> +
> +	/* 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] 8+ messages in thread

* Re: [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver
  2011-10-31 11:28   ` Jonathan Cameron
@ 2011-10-31 12:14     ` Lars-Peter Clausen
  0 siblings, 0 replies; 8+ messages in thread
From: Lars-Peter Clausen @ 2011-10-31 12:14 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Lars-Peter Clausen, Hennerich, Michael, linux-iio@vger.kernel.org,
	device-drivers-devel@blackfin.uclinux.org, Drivers

On 10/31/2011 12:28 PM, Jonathan Cameron wrote:
> On 10/27/11 09:44, 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>
> Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
> 
> Feel free to send on to Greg as you've nailed everything I cared about.
> 
> I do wonder if we might be better with an explicit 'no_read' flag in the
> chan_spec for channels like this. That way we could assign more meaningful
> channel numbers?  Afterall, sooner of later we are going to have something
> with two temperature sensors that only generate events.
> 
> What do you think?

Makes sense, but I think we can add this when we have to add support for
such a device.

An alternative would be to make devices explicitly request raw attributes
through info_mask. But that would require touching all existing drivers again.

Could you also Ack "staging:iio: IIO_EVENT_CODE: Clamp channel numbers"?
I'll replace the s16 with __s16 before sending it on to Greg.


Thanks
- Lars

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers
  2011-10-27  9:02   ` Lars-Peter Clausen
@ 2011-10-31 12:30     ` Jonathan Cameron
  0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Cameron @ 2011-10-31 12:30 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Michael Hennerich, linux-iio, device-drivers-devel, drivers

On 10/27/11 10:02, Lars-Peter Clausen wrote:
> On 10/27/2011 10:44 AM, Lars-Peter Clausen wrote:
>> Make sure we only use the allotted space for channel numbers in the event mask
>> and do not let them override other fields.
>>
>> Since negative values are valid channel number, cast the channel number to
>> signed when extracting it from an event mask.
>>
>> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
>> ---
>>  drivers/staging/iio/events.h |    5 +++--
>>  1 files changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h
>> index 7cf9306..fc2b7e5 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) | (((u16)chan2) << 16) | ((u16)chan1) | \
>> +	 ((u16)chan))
>>  
>>  
>>  #define IIO_EV_DIR_MAX 4
>> @@ -95,7 +96,7 @@ enum iio_event_direction {
>>  
>>  /* Event code number extraction depends on which type of event we have.
>>   * Perhaps review this function in the future*/
>> -#define IIO_EVENT_CODE_EXTRACT_NUM(mask) (mask & 0xFFFF)
>> +#define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((s16)(mask & 0xFFFF))
>>  
> 
> Since we want to use it in userspace this should obviously be __s16, sorry.
> Will fix this before sending the patch on.
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers
  2011-11-02  8:40 [PATCH 1/3] staging:iio: Make write_event_value callback optional Lars-Peter Clausen
@ 2011-11-02  8:40 ` Lars-Peter Clausen
  0 siblings, 0 replies; 8+ messages in thread
From: Lars-Peter Clausen @ 2011-11-02  8:40 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Jonathan Cameron, Michael Hennerich, devel, linux-iio,
	device-drivers-devel, drivers, Lars-Peter Clausen

Make sure we only use the allotted space for channel numbers in the event mask
and do not let them override other fields.

Since negative values are valid channel number, cast the channel number to
signed when extracting it from an event mask.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
---
 drivers/staging/iio/events.h |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/iio/events.h b/drivers/staging/iio/events.h
index 7cf9306..91b3c45 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) | (((u16)chan2) << 16) | ((u16)chan1) | \
+	 ((u16)chan))
 
 
 #define IIO_EV_DIR_MAX 4
@@ -95,7 +96,7 @@ enum iio_event_direction {
 
 /* Event code number extraction depends on which type of event we have.
  * Perhaps review this function in the future*/
-#define IIO_EVENT_CODE_EXTRACT_NUM(mask) (mask & 0xFFFF)
+#define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((__s16)(mask & 0xFFFF))
 
 #define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 40) & 0xFF)
 
-- 
1.7.7

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-11-02  8:40 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-27  8:44 [PATCH 1/3] staging:iio: Make write_event_value callback optional Lars-Peter Clausen
2011-10-27  8:44 ` [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers Lars-Peter Clausen
2011-10-27  9:02   ` Lars-Peter Clausen
2011-10-31 12:30     ` Jonathan Cameron
2011-10-27  8:44 ` [PATCH v2 3/3] staging:iio:dac: Add AD5421 driver Lars-Peter Clausen
2011-10-31 11:28   ` Jonathan Cameron
2011-10-31 12:14     ` Lars-Peter Clausen
  -- strict thread matches above, loose matches on Subject: below --
2011-11-02  8:40 [PATCH 1/3] staging:iio: Make write_event_value callback optional Lars-Peter Clausen
2011-11-02  8:40 ` [PATCH 2/3] staging:iio: IIO_EVENT_CODE: Clamp channel numbers Lars-Peter Clausen

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.