All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-09  9:05 ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:05 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

Hi all,

Here is another version of the patches to bring ADC driver to Atmel boards.
Since last version, here is what changed:
  * Rebased on top of staging-next to move out of staging. Had to change to IIO
    kfifo buffer along the way.
  * Reworked the DT bindings according to Jean-Christophe reviews
  * Made various fixes according to reviews
  * Support for X5 boards

Thanks,
Maxime


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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-09  9:05 ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hi all,

Here is another version of the patches to bring ADC driver to Atmel boards.
Since last version, here is what changed:
  * Rebased on top of staging-next to move out of staging. Had to change to IIO
    kfifo buffer along the way.
  * Reworked the DT bindings according to Jean-Christophe reviews
  * Made various fixes according to reviews
  * Support for X5 boards

Thanks,
Maxime

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

* [PATCH 1/9] ARM: AT91: Add platform data for the AT91 ADCs
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:05   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:05 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

The AT91 SoCs often embeds an ADC. This patch adds the needed
platform data to specify the informations required by the driver
to work properly.

For now, we only need the reference voltage and which channels
are available on the board.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 include/linux/platform_data/at91_adc.h |   61 ++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 include/linux/platform_data/at91_adc.h

diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
new file mode 100644
index 0000000..f9e2f00
--- /dev/null
+++ b/include/linux/platform_data/at91_adc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#ifndef _AT91_ADC_H_
+#define _AT91_ADC_H_
+
+/**
+ * struct at91_adc_reg_desc - Various informations relative to registers
+ * @channel_base:	Base address for the channel data registers
+ * @drdy_mask:		Mask of the DRDY field in the relevant registers
+			(Interruptions registers mostly)
+ * @status_register:	Address of the Interrupt Status Register
+ * @trigger_register:	Address of the Trigger setup register
+ */
+struct at91_adc_reg_desc {
+	u8	channel_base;
+	u32	drdy_mask;
+	u8	status_register;
+	u8	trigger_register;
+};
+
+/**
+ * struct at91_adc_trigger - description of triggers
+ * @name:		name of the trigger advertised to the user
+ * @value:		value to set in the ADC's mode register to enable
+			the trigger
+ * @is_external:	is the trigger relies on an external pin ?
+ */
+struct at91_adc_trigger {
+	const char	*name;
+	u8		value;
+	bool		is_external;
+};
+
+/**
+ * struct at91_adc_data - platform data for ADC driver
+ * @channels_used:		channels in use on the board as a bitmask
+ * @num_channels:		global number of channels available on the board
+ * @registers:			Registers definition on the board
+ * @startup_time:		startup time of the ADC in microseconds
+ * @trigger_list:		Triggers available in the ADC
+ * @trigger_number:		Number of triggers available in the ADC
+ * @use_external_triggers:	does the board has external triggers availables
+ * @vref:			Reference voltage for the ADC in millivolts
+ */
+struct at91_adc_data {
+	unsigned long			channels_used;
+	u8				num_channels;
+	struct at91_adc_reg_desc	*registers;
+	u8				startup_time;
+	struct at91_adc_trigger		*trigger_list;
+	u8				trigger_number;
+	bool				use_external_triggers;
+	u16				vref;
+};
+
+extern void __init at91_add_device_adc(struct at91_adc_data *data);
+#endif
-- 
1.7.9.5


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

* [PATCH 1/9] ARM: AT91: Add platform data for the AT91 ADCs
@ 2012-05-09  9:05   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

The AT91 SoCs often embeds an ADC. This patch adds the needed
platform data to specify the informations required by the driver
to work properly.

For now, we only need the reference voltage and which channels
are available on the board.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 include/linux/platform_data/at91_adc.h |   61 ++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 include/linux/platform_data/at91_adc.h

diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
new file mode 100644
index 0000000..f9e2f00
--- /dev/null
+++ b/include/linux/platform_data/at91_adc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#ifndef _AT91_ADC_H_
+#define _AT91_ADC_H_
+
+/**
+ * struct at91_adc_reg_desc - Various informations relative to registers
+ * @channel_base:	Base address for the channel data registers
+ * @drdy_mask:		Mask of the DRDY field in the relevant registers
+			(Interruptions registers mostly)
+ * @status_register:	Address of the Interrupt Status Register
+ * @trigger_register:	Address of the Trigger setup register
+ */
+struct at91_adc_reg_desc {
+	u8	channel_base;
+	u32	drdy_mask;
+	u8	status_register;
+	u8	trigger_register;
+};
+
+/**
+ * struct at91_adc_trigger - description of triggers
+ * @name:		name of the trigger advertised to the user
+ * @value:		value to set in the ADC's mode register to enable
+			the trigger
+ * @is_external:	is the trigger relies on an external pin ?
+ */
+struct at91_adc_trigger {
+	const char	*name;
+	u8		value;
+	bool		is_external;
+};
+
+/**
+ * struct at91_adc_data - platform data for ADC driver
+ * @channels_used:		channels in use on the board as a bitmask
+ * @num_channels:		global number of channels available on the board
+ * @registers:			Registers definition on the board
+ * @startup_time:		startup time of the ADC in microseconds
+ * @trigger_list:		Triggers available in the ADC
+ * @trigger_number:		Number of triggers available in the ADC
+ * @use_external_triggers:	does the board has external triggers availables
+ * @vref:			Reference voltage for the ADC in millivolts
+ */
+struct at91_adc_data {
+	unsigned long			channels_used;
+	u8				num_channels;
+	struct at91_adc_reg_desc	*registers;
+	u8				startup_time;
+	struct at91_adc_trigger		*trigger_list;
+	u8				trigger_number;
+	bool				use_external_triggers;
+	u16				vref;
+};
+
+extern void __init at91_add_device_adc(struct at91_adc_data *data);
+#endif
-- 
1.7.9.5

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

* [PATCH 2/9] ARM: AT91: IIO: Add AT91 ADC driver.
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:05   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:05 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

Add the ADC driver for Atmel's AT91SAM9G20-EK, AT91SAM9M10G45-EK
and AT91SAM9X5 family boards.

It has support for both software and hardware triggers.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/iio/Kconfig        |    2 +
 drivers/iio/Makefile       |    2 +
 drivers/iio/adc/Kconfig    |   16 ++
 drivers/iio/adc/Makefile   |    5 +
 drivers/iio/adc/at91_adc.c |  674 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 699 insertions(+)
 create mode 100644 drivers/iio/adc/Kconfig
 create mode 100644 drivers/iio/adc/Makefile
 create mode 100644 drivers/iio/adc/at91_adc.c

diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 3ab7d48..47e0920 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -48,4 +48,6 @@ config IIO_CONSUMERS_PER_TRIGGER
 	This value controls the maximum number of consumers that a
 	given trigger may handle. Default is 2.
 
+source "drivers/iio/adc/Kconfig"
+
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index d5fc57d..eb926a2 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -8,3 +8,5 @@ industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
 industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
 
 obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+
+obj-y += adc/
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
new file mode 100644
index 0000000..9a0df81
--- /dev/null
+++ b/drivers/iio/adc/Kconfig
@@ -0,0 +1,16 @@
+#
+# ADC drivers
+#
+menu "Analog to digital converters"
+
+config AT91_ADC
+	tristate "Atmel AT91 ADC"
+	depends on ARCH_AT91
+	select IIO_BUFFER
+	select IIO_KFIFO_BUF
+	select IIO_TRIGGER
+	select SYSFS
+	help
+	  Say yes here to build support for Atmel AT91 ADC.
+
+endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
new file mode 100644
index 0000000..b62d488
--- /dev/null
+++ b/drivers/iio/adc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for IIO ADC drivers
+#
+
+obj-$(CONFIG_AT91_ADC) += at91_adc.o
\ No newline at end of file
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
new file mode 100644
index 0000000..febad23
--- /dev/null
+++ b/drivers/iio/adc/at91_adc.c
@@ -0,0 +1,674 @@
+/*
+ * Driver for the ADC present in the Atmel AT91 evaluation boards.
+ *
+ * Copyright 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <linux/platform_data/at91_adc.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include <mach/at91_adc.h>
+#include <mach/cpu.h>
+
+#define AT91_ADC_CHAN(st, ch) \
+	(st->registers->channel_base + (ch * 4))
+#define at91_adc_readl(st, reg) \
+	(readl_relaxed(st->reg_base + reg))
+#define at91_adc_writel(st, reg, val) \
+	(writel_relaxed(val, st->reg_base + reg))
+
+struct at91_adc_state {
+	struct clk		*adc_clk;
+	u16			*buffer;
+	unsigned long		channels_mask;
+	struct clk		*clk;
+	bool			done;
+	int			irq;
+	bool			irq_enabled;
+	u16			last_value;
+	struct mutex		lock;
+	u8			num_channels;
+	void __iomem		*reg_base;
+	struct at91_adc_reg_desc *registers;
+	u8			startup_time;
+	struct iio_trigger	**trig;
+	struct at91_adc_trigger	*trigger_list;
+	u32			trigger_number;
+	bool			use_external;
+	u32			vref_mv;
+	wait_queue_head_t	wq_data_avail;
+};
+
+static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *idev = pf->indio_dev;
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_buffer *buffer = idev->buffer;
+	int i, j = 0;
+
+	for (i = 0; i < idev->masklength; i++) {
+		if (!test_bit(i, idev->active_scan_mask))
+			continue;
+		st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
+		j++;
+	}
+
+	if (idev->scan_timestamp) {
+		s64 *timestamp = (s64 *)((u8 *)st->buffer +
+					ALIGN(j, sizeof(s64)));
+		*timestamp = pf->timestamp;
+	}
+
+	buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp);
+
+	iio_trigger_notify_done(idev->trig);
+	st->irq_enabled = true;
+
+	/* Needed to ACK the DRDY interruption */
+	at91_adc_readl(st, AT91_ADC_LCDR);
+
+	enable_irq(st->irq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+
+	if (!(status & st->registers->drdy_mask))
+		return IRQ_HANDLED;
+
+	if (iio_buffer_enabled(idev)) {
+		disable_irq_nosync(irq);
+		st->irq_enabled = false;
+		iio_trigger_poll(idev->trig, iio_get_time_ns());
+	} else {
+		st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
+		st->done = true;
+		wake_up_interruptible(&st->wq_data_avail);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int at91_adc_channel_init(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_chan_spec *chan_array, *timestamp;
+	int bit, idx = 0;
+
+	idev->num_channels = bitmap_weight(&st->channels_mask,
+					   st->num_channels) + 1;
+
+	chan_array = devm_kzalloc(&idev->dev,
+				  ((idev->num_channels + 1) *
+					sizeof(struct iio_chan_spec)),
+				  GFP_KERNEL);
+
+	if (!chan_array)
+		return -ENOMEM;
+
+	for_each_set_bit(bit, &st->channels_mask, st->num_channels) {
+		struct iio_chan_spec *chan = chan_array + idx;
+
+		chan->type = IIO_VOLTAGE;
+		chan->indexed = 1;
+		chan->channel = bit;
+		chan->scan_index = idx;
+		chan->scan_type.sign = 'u';
+		chan->scan_type.realbits = 10;
+		chan->scan_type.storagebits = 16;
+		chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+			IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+		idx++;
+	}
+	timestamp = chan_array + idx;
+
+	timestamp->type = IIO_TIMESTAMP;
+	timestamp->channel = -1;
+	timestamp->scan_index = idx;
+	timestamp->scan_type.sign = 's';
+	timestamp->scan_type.realbits = 64;
+	timestamp->scan_type.storagebits = 64;
+
+	idev->channels = chan_array;
+	return idev->num_channels;
+}
+
+static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
+					     struct at91_adc_trigger *triggers,
+					     const char *trigger_name)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	u8 value = 0;
+	int i;
+
+	for (i = 0; i < st->trigger_number; i++) {
+		char *name = kasprintf(GFP_KERNEL,
+				"%s-dev%d-%s",
+				idev->name,
+				idev->id,
+				triggers[i].name);
+		if (!name)
+			return -ENOMEM;
+
+		if (strcmp(trigger_name, name) == 0) {
+			value = triggers[i].value;
+			kfree(name);
+			break;
+		}
+
+		kfree(name);
+	}
+
+	return value;
+}
+
+static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *idev = trig->private_data;
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_buffer *buffer = idev->buffer;
+	struct at91_adc_reg_desc *reg = st->registers;
+	u32 status = at91_adc_readl(st, reg->trigger_register);
+	u8 value;
+	u8 bit;
+
+	value = at91_adc_get_trigger_value_by_name(idev,
+						   st->trigger_list,
+						   idev->trig->name);
+	if (value == 0)
+		return -EINVAL;
+
+	if (state) {
+		st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL);
+		if (st->buffer == NULL)
+			return -ENOMEM;
+
+		at91_adc_writel(st, reg->trigger_register,
+				status | value);
+
+		for_each_set_bit(bit, buffer->scan_mask,
+				 st->num_channels) {
+			struct iio_chan_spec const *chan = idev->channels + bit;
+			at91_adc_writel(st, AT91_ADC_CHER,
+					AT91_ADC_CH(chan->channel));
+		}
+
+		at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask);
+
+	} else {
+		at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask);
+
+		at91_adc_writel(st, reg->trigger_register,
+				status & ~value);
+
+		for_each_set_bit(bit, buffer->scan_mask,
+				 st->num_channels) {
+			struct iio_chan_spec const *chan = idev->channels + bit;
+			at91_adc_writel(st, AT91_ADC_CHDR,
+					AT91_ADC_CH(chan->channel));
+		}
+		kfree(st->buffer);
+	}
+
+	return 0;
+}
+
+static const struct iio_trigger_ops at91_adc_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &at91_adc_configure_trigger,
+};
+
+static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
+						     struct at91_adc_trigger *trigger)
+{
+	struct iio_trigger *trig;
+	int ret;
+
+	trig = iio_trigger_alloc("%s-dev%d-%s", idev->name,
+				 idev->id, trigger->name);
+	if (trig == NULL)
+		return NULL;
+
+	trig->dev.parent = idev->dev.parent;
+	trig->private_data = idev;
+	trig->ops = &at91_adc_trigger_ops;
+
+	ret = iio_trigger_register(trig);
+	if (ret)
+		return NULL;
+
+	return trig;
+}
+
+static int at91_adc_trigger_init(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int i, ret;
+
+	st->trig = devm_kzalloc(&idev->dev,
+				st->trigger_number * sizeof(st->trig),
+				GFP_KERNEL);
+
+	if (st->trig == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	for (i = 0; i < st->trigger_number; i++) {
+		if (st->trigger_list[i].is_external && !(st->use_external))
+			continue;
+
+		st->trig[i] = at91_adc_allocate_trigger(idev,
+							st->trigger_list + i);
+		if (st->trig[i] == NULL) {
+			dev_err(&idev->dev,
+				"Could not allocate trigger %d\n", i);
+			ret = -ENOMEM;
+			goto error_trigger;
+		}
+	}
+
+	return 0;
+
+error_trigger:
+	for (i--; i >= 0; i--) {
+		iio_trigger_unregister(st->trig[i]);
+		iio_trigger_free(st->trig[i]);
+	}
+error_ret:
+	return ret;
+}
+
+static void at91_adc_trigger_remove(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int i;
+
+	for (i = 0; i < st->trigger_number; i++) {
+		iio_trigger_unregister(st->trig[i]);
+		iio_trigger_free(st->trig[i]);
+	}
+}
+
+static const struct iio_buffer_setup_ops at91_adc_buffer_ops = {
+	.preenable = &iio_sw_buffer_preenable,
+	.postenable = &iio_triggered_buffer_postenable,
+	.predisable = &iio_triggered_buffer_predisable,
+};
+
+static int at91_adc_buffer_init(struct iio_dev *idev)
+{
+	int ret;
+
+	idev->buffer = iio_kfifo_allocate(idev);
+	if (!idev->buffer) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	idev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
+					    &at91_adc_trigger_handler,
+					    IRQF_ONESHOT,
+					    idev,
+					    "%s-consumer%d",
+					    idev->name,
+					    idev->id);
+	if (idev->pollfunc == NULL) {
+		ret = -ENOMEM;
+		goto error_pollfunc;
+	}
+
+	idev->setup_ops = &at91_adc_buffer_ops;
+	idev->modes |= INDIO_BUFFER_TRIGGERED;
+
+	ret = iio_buffer_register(idev,
+				  idev->channels,
+				  idev->num_channels);
+	if (ret)
+		goto error_register;
+
+	return 0;
+
+error_register:
+	iio_dealloc_pollfunc(idev->pollfunc);
+error_pollfunc:
+	iio_kfifo_free(idev->buffer);
+error_ret:
+	return ret;
+}
+
+static void at91_adc_buffer_remove(struct iio_dev *idev)
+{
+	iio_buffer_unregister(idev);
+	iio_dealloc_pollfunc(idev->pollfunc);
+	iio_kfifo_free(idev->buffer);
+}
+
+static int at91_adc_read_raw(struct iio_dev *idev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&st->lock);
+
+		at91_adc_writel(st, AT91_ADC_CHER,
+				AT91_ADC_CH(chan->channel));
+		at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask);
+		at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START);
+
+		ret = wait_event_interruptible_timeout(st->wq_data_avail,
+						       st->done,
+						       msecs_to_jiffies(1000));
+		if (ret == 0)
+			return -ETIMEDOUT;
+		else if (ret < 0)
+			return ret;
+
+		*val = st->last_value;
+
+		at91_adc_writel(st, AT91_ADC_CHDR,
+				AT91_ADC_CH(chan->channel));
+		at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask);
+
+		st->last_value = 0;
+		st->done = false;
+		mutex_unlock(&st->lock);
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val2 = 0;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int at91_adc_probe_pdata(struct at91_adc_state *st,
+				struct platform_device *pdev)
+{
+	struct at91_adc_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return -EINVAL;
+
+	st->use_external = pdata->use_external_triggers;
+	st->vref_mv = pdata->vref;
+	st->channels_mask = pdata->channels_used;
+	st->num_channels = pdata->num_channels;
+	st->startup_time = pdata->startup_time;
+	st->trigger_number = pdata->trigger_number;
+	st->trigger_list = pdata->trigger_list;
+	st->registers = pdata->registers;
+
+	return 0;
+}
+
+static const struct iio_info at91_adc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &at91_adc_read_raw,
+};
+
+static int __devinit at91_adc_probe(struct platform_device *pdev)
+{
+	unsigned int prsc, mstrclk, ticks, adc_clk;
+	int ret;
+	struct iio_dev *idev;
+	struct at91_adc_state *st;
+	struct resource *res;
+
+	idev = iio_device_alloc(sizeof(struct at91_adc_state));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	st = iio_priv(idev);
+
+	ret = at91_adc_probe_pdata(st, pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "No platform data available.\n");
+		ret = -EINVAL;
+		goto error_free_device;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "No resource defined\n");
+		ret = -ENXIO;
+		goto error_ret;
+	}
+
+	platform_set_drvdata(pdev, idev);
+
+	idev->dev.parent = &pdev->dev;
+	idev->name = dev_name(&pdev->dev);
+	idev->modes = INDIO_DIRECT_MODE;
+	idev->info = &at91_adc_info;
+
+	st->irq = platform_get_irq(pdev, 0);
+	if (st->irq < 0) {
+		dev_err(&pdev->dev, "No IRQ ID is designated\n");
+		ret = -ENODEV;
+		goto error_free_device;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res),
+				"AT91 adc registers")) {
+		dev_err(&pdev->dev, "Resources are unavailable.\n");
+		ret = -EBUSY;
+		goto error_free_device;
+	}
+
+	st->reg_base = ioremap(res->start, resource_size(res));
+	if (!st->reg_base) {
+		dev_err(&pdev->dev, "Failed to map registers.\n");
+		ret = -ENOMEM;
+		goto error_release_mem;
+	}
+
+	/*
+	 * Disable all IRQs before setting up the handler
+	 */
+	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
+	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
+	ret = request_irq(st->irq,
+			  at91_adc_eoc_trigger,
+			  0,
+			  pdev->dev.driver->name,
+			  idev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
+		goto error_unmap_reg;
+	}
+
+	st->clk = clk_get(&pdev->dev, "adc_clk");
+	if (IS_ERR(st->clk)) {
+		dev_err(&pdev->dev, "Failed to get the clock.\n");
+		ret = PTR_ERR(st->clk);
+		goto error_free_irq;
+	}
+
+	ret = clk_prepare(st->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not prepare the clock.\n");
+		goto error_free_clk;
+	}
+
+	ret = clk_enable(st->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not enable the clock.\n");
+		goto error_unprepare_clk;
+	}
+
+	st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+	if (IS_ERR(st->adc_clk)) {
+		dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
+		ret = PTR_ERR(st->clk);
+		goto error_disable_clk;
+	}
+
+	ret = clk_prepare(st->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
+		goto error_free_adc_clk;
+	}
+
+	ret = clk_enable(st->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not enable the ADC clock.\n");
+		goto error_unprepare_adc_clk;
+	}
+
+	/*
+	 * Prescaler rate computation using the formula from the Atmel's
+	 * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being
+	 * specified by the electrical characteristics of the board.
+	 */
+	mstrclk = clk_get_rate(st->clk);
+	adc_clk = clk_get_rate(st->adc_clk);
+	prsc = (mstrclk / (2 * adc_clk)) - 1;
+
+	if (!st->startup_time) {
+		dev_err(&pdev->dev, "No startup time available.\n");
+		ret = -EINVAL;
+		goto error_disable_adc_clk;
+	}
+
+	/*
+	 * Number of ticks needed to cover the startup time of the ADC as
+	 * defined in the electrical characteristics of the board, divided by 8.
+	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
+	 */
+	ticks = round_up((st->startup_time * adc_clk /
+			  1000000) - 1, 8) / 8;
+	at91_adc_writel(st, AT91_ADC_MR,
+			(AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) |
+			(AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP));
+
+	/* Setup the ADC channels available on the board */
+	ret = at91_adc_channel_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
+		goto error_disable_adc_clk;
+	}
+
+	init_waitqueue_head(&st->wq_data_avail);
+	mutex_init(&st->lock);
+
+	ret = at91_adc_buffer_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+		goto error_disable_adc_clk;
+	}
+
+	ret = at91_adc_trigger_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+		goto error_unregister_buffer;
+	}
+
+	ret = iio_device_register(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't register the device.\n");
+		goto error_remove_triggers;
+	}
+
+	return 0;
+
+error_remove_triggers:
+	at91_adc_trigger_remove(idev);
+error_unregister_buffer:
+	at91_adc_buffer_remove(idev);
+error_disable_adc_clk:
+	clk_disable(st->adc_clk);
+error_unprepare_adc_clk:
+	clk_unprepare(st->adc_clk);
+error_free_adc_clk:
+	clk_put(st->adc_clk);
+error_disable_clk:
+	clk_disable(st->clk);
+error_unprepare_clk:
+	clk_unprepare(st->clk);
+error_free_clk:
+	clk_put(st->clk);
+error_free_irq:
+	free_irq(st->irq, idev);
+error_unmap_reg:
+	iounmap(st->reg_base);
+error_release_mem:
+	release_mem_region(res->start, resource_size(res));
+error_free_device:
+	iio_device_free(idev);
+error_ret:
+	return ret;
+}
+
+static int __devexit at91_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *idev = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct at91_adc_state *st = iio_priv(idev);
+
+	iio_device_unregister(idev);
+	at91_adc_trigger_remove(idev);
+	at91_adc_buffer_remove(idev);
+	clk_disable(st->adc_clk);
+	clk_unprepare(st->adc_clk);
+	clk_put(st->adc_clk);
+	clk_disable(st->clk);
+	clk_unprepare(st->clk);
+	clk_put(st->clk);
+	free_irq(st->irq, idev);
+	iounmap(st->reg_base);
+	release_mem_region(res->start, resource_size(res));
+	iio_device_free(idev);
+
+	return 0;
+}
+
+static struct platform_driver at91_adc_driver = {
+	.probe = at91_adc_probe,
+	.remove = __devexit_p(at91_adc_remove),
+	.driver = {
+		   .name = "at91_adc",
+	},
+};
+
+module_platform_driver(at91_adc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atmel AT91 ADC Driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
-- 
1.7.9.5


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

* [PATCH 2/9] ARM: AT91: IIO: Add AT91 ADC driver.
@ 2012-05-09  9:05   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:05 UTC (permalink / raw)
  To: linux-arm-kernel

Add the ADC driver for Atmel's AT91SAM9G20-EK, AT91SAM9M10G45-EK
and AT91SAM9X5 family boards.

It has support for both software and hardware triggers.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/iio/Kconfig        |    2 +
 drivers/iio/Makefile       |    2 +
 drivers/iio/adc/Kconfig    |   16 ++
 drivers/iio/adc/Makefile   |    5 +
 drivers/iio/adc/at91_adc.c |  674 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 699 insertions(+)
 create mode 100644 drivers/iio/adc/Kconfig
 create mode 100644 drivers/iio/adc/Makefile
 create mode 100644 drivers/iio/adc/at91_adc.c

diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 3ab7d48..47e0920 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -48,4 +48,6 @@ config IIO_CONSUMERS_PER_TRIGGER
 	This value controls the maximum number of consumers that a
 	given trigger may handle. Default is 2.
 
+source "drivers/iio/adc/Kconfig"
+
 endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index d5fc57d..eb926a2 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -8,3 +8,5 @@ industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
 industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
 
 obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+
+obj-y += adc/
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
new file mode 100644
index 0000000..9a0df81
--- /dev/null
+++ b/drivers/iio/adc/Kconfig
@@ -0,0 +1,16 @@
+#
+# ADC drivers
+#
+menu "Analog to digital converters"
+
+config AT91_ADC
+	tristate "Atmel AT91 ADC"
+	depends on ARCH_AT91
+	select IIO_BUFFER
+	select IIO_KFIFO_BUF
+	select IIO_TRIGGER
+	select SYSFS
+	help
+	  Say yes here to build support for Atmel AT91 ADC.
+
+endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
new file mode 100644
index 0000000..b62d488
--- /dev/null
+++ b/drivers/iio/adc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for IIO ADC drivers
+#
+
+obj-$(CONFIG_AT91_ADC) += at91_adc.o
\ No newline at end of file
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
new file mode 100644
index 0000000..febad23
--- /dev/null
+++ b/drivers/iio/adc/at91_adc.c
@@ -0,0 +1,674 @@
+/*
+ * Driver for the ADC present in the Atmel AT91 evaluation boards.
+ *
+ * Copyright 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <linux/platform_data/at91_adc.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include <mach/at91_adc.h>
+#include <mach/cpu.h>
+
+#define AT91_ADC_CHAN(st, ch) \
+	(st->registers->channel_base + (ch * 4))
+#define at91_adc_readl(st, reg) \
+	(readl_relaxed(st->reg_base + reg))
+#define at91_adc_writel(st, reg, val) \
+	(writel_relaxed(val, st->reg_base + reg))
+
+struct at91_adc_state {
+	struct clk		*adc_clk;
+	u16			*buffer;
+	unsigned long		channels_mask;
+	struct clk		*clk;
+	bool			done;
+	int			irq;
+	bool			irq_enabled;
+	u16			last_value;
+	struct mutex		lock;
+	u8			num_channels;
+	void __iomem		*reg_base;
+	struct at91_adc_reg_desc *registers;
+	u8			startup_time;
+	struct iio_trigger	**trig;
+	struct at91_adc_trigger	*trigger_list;
+	u32			trigger_number;
+	bool			use_external;
+	u32			vref_mv;
+	wait_queue_head_t	wq_data_avail;
+};
+
+static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *idev = pf->indio_dev;
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_buffer *buffer = idev->buffer;
+	int i, j = 0;
+
+	for (i = 0; i < idev->masklength; i++) {
+		if (!test_bit(i, idev->active_scan_mask))
+			continue;
+		st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
+		j++;
+	}
+
+	if (idev->scan_timestamp) {
+		s64 *timestamp = (s64 *)((u8 *)st->buffer +
+					ALIGN(j, sizeof(s64)));
+		*timestamp = pf->timestamp;
+	}
+
+	buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp);
+
+	iio_trigger_notify_done(idev->trig);
+	st->irq_enabled = true;
+
+	/* Needed to ACK the DRDY interruption */
+	at91_adc_readl(st, AT91_ADC_LCDR);
+
+	enable_irq(st->irq);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+{
+	struct iio_dev *idev = private;
+	struct at91_adc_state *st = iio_priv(idev);
+	u32 status = at91_adc_readl(st, st->registers->status_register);
+
+	if (!(status & st->registers->drdy_mask))
+		return IRQ_HANDLED;
+
+	if (iio_buffer_enabled(idev)) {
+		disable_irq_nosync(irq);
+		st->irq_enabled = false;
+		iio_trigger_poll(idev->trig, iio_get_time_ns());
+	} else {
+		st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
+		st->done = true;
+		wake_up_interruptible(&st->wq_data_avail);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int at91_adc_channel_init(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_chan_spec *chan_array, *timestamp;
+	int bit, idx = 0;
+
+	idev->num_channels = bitmap_weight(&st->channels_mask,
+					   st->num_channels) + 1;
+
+	chan_array = devm_kzalloc(&idev->dev,
+				  ((idev->num_channels + 1) *
+					sizeof(struct iio_chan_spec)),
+				  GFP_KERNEL);
+
+	if (!chan_array)
+		return -ENOMEM;
+
+	for_each_set_bit(bit, &st->channels_mask, st->num_channels) {
+		struct iio_chan_spec *chan = chan_array + idx;
+
+		chan->type = IIO_VOLTAGE;
+		chan->indexed = 1;
+		chan->channel = bit;
+		chan->scan_index = idx;
+		chan->scan_type.sign = 'u';
+		chan->scan_type.realbits = 10;
+		chan->scan_type.storagebits = 16;
+		chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+			IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+		idx++;
+	}
+	timestamp = chan_array + idx;
+
+	timestamp->type = IIO_TIMESTAMP;
+	timestamp->channel = -1;
+	timestamp->scan_index = idx;
+	timestamp->scan_type.sign = 's';
+	timestamp->scan_type.realbits = 64;
+	timestamp->scan_type.storagebits = 64;
+
+	idev->channels = chan_array;
+	return idev->num_channels;
+}
+
+static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
+					     struct at91_adc_trigger *triggers,
+					     const char *trigger_name)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	u8 value = 0;
+	int i;
+
+	for (i = 0; i < st->trigger_number; i++) {
+		char *name = kasprintf(GFP_KERNEL,
+				"%s-dev%d-%s",
+				idev->name,
+				idev->id,
+				triggers[i].name);
+		if (!name)
+			return -ENOMEM;
+
+		if (strcmp(trigger_name, name) == 0) {
+			value = triggers[i].value;
+			kfree(name);
+			break;
+		}
+
+		kfree(name);
+	}
+
+	return value;
+}
+
+static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+	struct iio_dev *idev = trig->private_data;
+	struct at91_adc_state *st = iio_priv(idev);
+	struct iio_buffer *buffer = idev->buffer;
+	struct at91_adc_reg_desc *reg = st->registers;
+	u32 status = at91_adc_readl(st, reg->trigger_register);
+	u8 value;
+	u8 bit;
+
+	value = at91_adc_get_trigger_value_by_name(idev,
+						   st->trigger_list,
+						   idev->trig->name);
+	if (value == 0)
+		return -EINVAL;
+
+	if (state) {
+		st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL);
+		if (st->buffer == NULL)
+			return -ENOMEM;
+
+		at91_adc_writel(st, reg->trigger_register,
+				status | value);
+
+		for_each_set_bit(bit, buffer->scan_mask,
+				 st->num_channels) {
+			struct iio_chan_spec const *chan = idev->channels + bit;
+			at91_adc_writel(st, AT91_ADC_CHER,
+					AT91_ADC_CH(chan->channel));
+		}
+
+		at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask);
+
+	} else {
+		at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask);
+
+		at91_adc_writel(st, reg->trigger_register,
+				status & ~value);
+
+		for_each_set_bit(bit, buffer->scan_mask,
+				 st->num_channels) {
+			struct iio_chan_spec const *chan = idev->channels + bit;
+			at91_adc_writel(st, AT91_ADC_CHDR,
+					AT91_ADC_CH(chan->channel));
+		}
+		kfree(st->buffer);
+	}
+
+	return 0;
+}
+
+static const struct iio_trigger_ops at91_adc_trigger_ops = {
+	.owner = THIS_MODULE,
+	.set_trigger_state = &at91_adc_configure_trigger,
+};
+
+static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
+						     struct at91_adc_trigger *trigger)
+{
+	struct iio_trigger *trig;
+	int ret;
+
+	trig = iio_trigger_alloc("%s-dev%d-%s", idev->name,
+				 idev->id, trigger->name);
+	if (trig == NULL)
+		return NULL;
+
+	trig->dev.parent = idev->dev.parent;
+	trig->private_data = idev;
+	trig->ops = &at91_adc_trigger_ops;
+
+	ret = iio_trigger_register(trig);
+	if (ret)
+		return NULL;
+
+	return trig;
+}
+
+static int at91_adc_trigger_init(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int i, ret;
+
+	st->trig = devm_kzalloc(&idev->dev,
+				st->trigger_number * sizeof(st->trig),
+				GFP_KERNEL);
+
+	if (st->trig == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	for (i = 0; i < st->trigger_number; i++) {
+		if (st->trigger_list[i].is_external && !(st->use_external))
+			continue;
+
+		st->trig[i] = at91_adc_allocate_trigger(idev,
+							st->trigger_list + i);
+		if (st->trig[i] == NULL) {
+			dev_err(&idev->dev,
+				"Could not allocate trigger %d\n", i);
+			ret = -ENOMEM;
+			goto error_trigger;
+		}
+	}
+
+	return 0;
+
+error_trigger:
+	for (i--; i >= 0; i--) {
+		iio_trigger_unregister(st->trig[i]);
+		iio_trigger_free(st->trig[i]);
+	}
+error_ret:
+	return ret;
+}
+
+static void at91_adc_trigger_remove(struct iio_dev *idev)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int i;
+
+	for (i = 0; i < st->trigger_number; i++) {
+		iio_trigger_unregister(st->trig[i]);
+		iio_trigger_free(st->trig[i]);
+	}
+}
+
+static const struct iio_buffer_setup_ops at91_adc_buffer_ops = {
+	.preenable = &iio_sw_buffer_preenable,
+	.postenable = &iio_triggered_buffer_postenable,
+	.predisable = &iio_triggered_buffer_predisable,
+};
+
+static int at91_adc_buffer_init(struct iio_dev *idev)
+{
+	int ret;
+
+	idev->buffer = iio_kfifo_allocate(idev);
+	if (!idev->buffer) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	idev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
+					    &at91_adc_trigger_handler,
+					    IRQF_ONESHOT,
+					    idev,
+					    "%s-consumer%d",
+					    idev->name,
+					    idev->id);
+	if (idev->pollfunc == NULL) {
+		ret = -ENOMEM;
+		goto error_pollfunc;
+	}
+
+	idev->setup_ops = &at91_adc_buffer_ops;
+	idev->modes |= INDIO_BUFFER_TRIGGERED;
+
+	ret = iio_buffer_register(idev,
+				  idev->channels,
+				  idev->num_channels);
+	if (ret)
+		goto error_register;
+
+	return 0;
+
+error_register:
+	iio_dealloc_pollfunc(idev->pollfunc);
+error_pollfunc:
+	iio_kfifo_free(idev->buffer);
+error_ret:
+	return ret;
+}
+
+static void at91_adc_buffer_remove(struct iio_dev *idev)
+{
+	iio_buffer_unregister(idev);
+	iio_dealloc_pollfunc(idev->pollfunc);
+	iio_kfifo_free(idev->buffer);
+}
+
+static int at91_adc_read_raw(struct iio_dev *idev,
+			     struct iio_chan_spec const *chan,
+			     int *val, int *val2, long mask)
+{
+	struct at91_adc_state *st = iio_priv(idev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&st->lock);
+
+		at91_adc_writel(st, AT91_ADC_CHER,
+				AT91_ADC_CH(chan->channel));
+		at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask);
+		at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START);
+
+		ret = wait_event_interruptible_timeout(st->wq_data_avail,
+						       st->done,
+						       msecs_to_jiffies(1000));
+		if (ret == 0)
+			return -ETIMEDOUT;
+		else if (ret < 0)
+			return ret;
+
+		*val = st->last_value;
+
+		at91_adc_writel(st, AT91_ADC_CHDR,
+				AT91_ADC_CH(chan->channel));
+		at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask);
+
+		st->last_value = 0;
+		st->done = false;
+		mutex_unlock(&st->lock);
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		*val = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+		*val2 = 0;
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		break;
+	}
+	return -EINVAL;
+}
+
+static int at91_adc_probe_pdata(struct at91_adc_state *st,
+				struct platform_device *pdev)
+{
+	struct at91_adc_data *pdata = pdev->dev.platform_data;
+
+	if (!pdata)
+		return -EINVAL;
+
+	st->use_external = pdata->use_external_triggers;
+	st->vref_mv = pdata->vref;
+	st->channels_mask = pdata->channels_used;
+	st->num_channels = pdata->num_channels;
+	st->startup_time = pdata->startup_time;
+	st->trigger_number = pdata->trigger_number;
+	st->trigger_list = pdata->trigger_list;
+	st->registers = pdata->registers;
+
+	return 0;
+}
+
+static const struct iio_info at91_adc_info = {
+	.driver_module = THIS_MODULE,
+	.read_raw = &at91_adc_read_raw,
+};
+
+static int __devinit at91_adc_probe(struct platform_device *pdev)
+{
+	unsigned int prsc, mstrclk, ticks, adc_clk;
+	int ret;
+	struct iio_dev *idev;
+	struct at91_adc_state *st;
+	struct resource *res;
+
+	idev = iio_device_alloc(sizeof(struct at91_adc_state));
+	if (idev == NULL) {
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	st = iio_priv(idev);
+
+	ret = at91_adc_probe_pdata(st, pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "No platform data available.\n");
+		ret = -EINVAL;
+		goto error_free_device;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "No resource defined\n");
+		ret = -ENXIO;
+		goto error_ret;
+	}
+
+	platform_set_drvdata(pdev, idev);
+
+	idev->dev.parent = &pdev->dev;
+	idev->name = dev_name(&pdev->dev);
+	idev->modes = INDIO_DIRECT_MODE;
+	idev->info = &at91_adc_info;
+
+	st->irq = platform_get_irq(pdev, 0);
+	if (st->irq < 0) {
+		dev_err(&pdev->dev, "No IRQ ID is designated\n");
+		ret = -ENODEV;
+		goto error_free_device;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res),
+				"AT91 adc registers")) {
+		dev_err(&pdev->dev, "Resources are unavailable.\n");
+		ret = -EBUSY;
+		goto error_free_device;
+	}
+
+	st->reg_base = ioremap(res->start, resource_size(res));
+	if (!st->reg_base) {
+		dev_err(&pdev->dev, "Failed to map registers.\n");
+		ret = -ENOMEM;
+		goto error_release_mem;
+	}
+
+	/*
+	 * Disable all IRQs before setting up the handler
+	 */
+	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
+	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
+	ret = request_irq(st->irq,
+			  at91_adc_eoc_trigger,
+			  0,
+			  pdev->dev.driver->name,
+			  idev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
+		goto error_unmap_reg;
+	}
+
+	st->clk = clk_get(&pdev->dev, "adc_clk");
+	if (IS_ERR(st->clk)) {
+		dev_err(&pdev->dev, "Failed to get the clock.\n");
+		ret = PTR_ERR(st->clk);
+		goto error_free_irq;
+	}
+
+	ret = clk_prepare(st->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not prepare the clock.\n");
+		goto error_free_clk;
+	}
+
+	ret = clk_enable(st->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not enable the clock.\n");
+		goto error_unprepare_clk;
+	}
+
+	st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+	if (IS_ERR(st->adc_clk)) {
+		dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
+		ret = PTR_ERR(st->clk);
+		goto error_disable_clk;
+	}
+
+	ret = clk_prepare(st->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
+		goto error_free_adc_clk;
+	}
+
+	ret = clk_enable(st->adc_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not enable the ADC clock.\n");
+		goto error_unprepare_adc_clk;
+	}
+
+	/*
+	 * Prescaler rate computation using the formula from the Atmel's
+	 * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being
+	 * specified by the electrical characteristics of the board.
+	 */
+	mstrclk = clk_get_rate(st->clk);
+	adc_clk = clk_get_rate(st->adc_clk);
+	prsc = (mstrclk / (2 * adc_clk)) - 1;
+
+	if (!st->startup_time) {
+		dev_err(&pdev->dev, "No startup time available.\n");
+		ret = -EINVAL;
+		goto error_disable_adc_clk;
+	}
+
+	/*
+	 * Number of ticks needed to cover the startup time of the ADC as
+	 * defined in the electrical characteristics of the board, divided by 8.
+	 * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
+	 */
+	ticks = round_up((st->startup_time * adc_clk /
+			  1000000) - 1, 8) / 8;
+	at91_adc_writel(st, AT91_ADC_MR,
+			(AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) |
+			(AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP));
+
+	/* Setup the ADC channels available on the board */
+	ret = at91_adc_channel_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
+		goto error_disable_adc_clk;
+	}
+
+	init_waitqueue_head(&st->wq_data_avail);
+	mutex_init(&st->lock);
+
+	ret = at91_adc_buffer_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+		goto error_disable_adc_clk;
+	}
+
+	ret = at91_adc_trigger_init(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+		goto error_unregister_buffer;
+	}
+
+	ret = iio_device_register(idev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Couldn't register the device.\n");
+		goto error_remove_triggers;
+	}
+
+	return 0;
+
+error_remove_triggers:
+	at91_adc_trigger_remove(idev);
+error_unregister_buffer:
+	at91_adc_buffer_remove(idev);
+error_disable_adc_clk:
+	clk_disable(st->adc_clk);
+error_unprepare_adc_clk:
+	clk_unprepare(st->adc_clk);
+error_free_adc_clk:
+	clk_put(st->adc_clk);
+error_disable_clk:
+	clk_disable(st->clk);
+error_unprepare_clk:
+	clk_unprepare(st->clk);
+error_free_clk:
+	clk_put(st->clk);
+error_free_irq:
+	free_irq(st->irq, idev);
+error_unmap_reg:
+	iounmap(st->reg_base);
+error_release_mem:
+	release_mem_region(res->start, resource_size(res));
+error_free_device:
+	iio_device_free(idev);
+error_ret:
+	return ret;
+}
+
+static int __devexit at91_adc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *idev = platform_get_drvdata(pdev);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct at91_adc_state *st = iio_priv(idev);
+
+	iio_device_unregister(idev);
+	at91_adc_trigger_remove(idev);
+	at91_adc_buffer_remove(idev);
+	clk_disable(st->adc_clk);
+	clk_unprepare(st->adc_clk);
+	clk_put(st->adc_clk);
+	clk_disable(st->clk);
+	clk_unprepare(st->clk);
+	clk_put(st->clk);
+	free_irq(st->irq, idev);
+	iounmap(st->reg_base);
+	release_mem_region(res->start, resource_size(res));
+	iio_device_free(idev);
+
+	return 0;
+}
+
+static struct platform_driver at91_adc_driver = {
+	.probe = at91_adc_probe,
+	.remove = __devexit_p(at91_adc_remove),
+	.driver = {
+		   .name = "at91_adc",
+	},
+};
+
+module_platform_driver(at91_adc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atmel AT91 ADC Driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
-- 
1.7.9.5

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

* [PATCH 3/9] ARM: AT91: Add the ADC to the sam9g20ek board
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:06   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

This patch adds platform data for the AT91 ADC driver support for
the AT91SAM9G20-EK board.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/mach-at91/at91sam9260.c         |    8 +++
 arch/arm/mach-at91/at91sam9260_devices.c |   89 ++++++++++++++++++++++++++++++
 arch/arm/mach-at91/board-sam9g20ek.c     |   14 +++++
 3 files changed, 111 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 46f7742..63d4432 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -55,6 +55,13 @@ static struct clk adc_clk = {
 	.pmc_mask	= 1 << AT91SAM9260_ID_ADC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 5000000,
+};
+
 static struct clk usart0_clk = {
 	.name		= "usart0_clk",
 	.pmc_mask	= 1 << AT91SAM9260_ID_US0,
@@ -166,6 +173,7 @@ static struct clk *periph_clocks[] __initdata = {
 	&pioB_clk,
 	&pioC_clk,
 	&adc_clk,
+	&adc_op_clk,
 	&usart0_clk,
 	&usart1_clk,
 	&usart2_clk,
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 5652dde..2125851 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -17,6 +17,8 @@
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/board.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9260.h>
@@ -1369,6 +1371,93 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
 void __init at91_add_device_cf(struct at91_cf_data * data) {}
 #endif
 
+/* --------------------------------------------------------------------
+ *  ADCs
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9260_BASE_ADC,
+		.end	= AT91SAM9260_BASE_ADC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9260_ID_ADC,
+		.end	= AT91SAM9260_ID_ADC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_adc_device = {
+	.name		= "at91_adc",
+	.id		= -1,
+	.dev		= {
+				.platform_data		= &adc_data,
+	},
+	.resource	= adc_resources,
+	.num_resources	= ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+	[0] = {
+		.name = "timer-counter-0",
+		.value = AT91_ADC_TRGSEL_TC0 | AT91_ADC_TRGEN,
+	},
+	[1] = {
+		.name = "timer-counter-1",
+		.value = AT91_ADC_TRGSEL_TC1 | AT91_ADC_TRGEN,
+	},
+	[2] = {
+		.name = "timer-counter-2",
+		.value = AT91_ADC_TRGSEL_TC2 | AT91_ADC_TRGEN,
+	},
+	[3] = {
+		.name = "external",
+		.value = AT91_ADC_TRGSEL_EXTERNAL | AT91_ADC_TRGEN,
+		.is_external = true,
+	},
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g20 = {
+	.channel_base = AT91_ADC_CHR(0),
+	.drdy_mask = AT91_ADC_DRDY,
+	.status_register = AT91_ADC_SR,
+	.trigger_register = AT91_ADC_MR,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+	if (!data)
+		return;
+
+	if (test_bit(0, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC0, 0);
+	if (test_bit(1, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC1, 0);
+	if (test_bit(2, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC2, 0);
+	if (test_bit(3, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC3, 0);
+
+	if (data->use_external_triggers)
+		at91_set_A_periph(AT91_PIN_PA22, 0);
+
+	data->num_channels = 4;
+	data->startup_time = 10;
+	data->registers = &at91_adc_register_g20;
+	data->trigger_number = 4;
+	data->trigger_list = at91_adc_triggers;
+
+	adc_data = *data;
+	platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
 /* -------------------------------------------------------------------- */
 /*
  * These devices are always present and don't need any board-specific
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 8923ec9..291b0fe 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -32,6 +32,8 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/consumer.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -318,6 +320,16 @@ static void __init ek_add_device_buttons(void)
 static void __init ek_add_device_buttons(void) {}
 #endif
 
+/*
+ * ADCs
+ */
+
+static struct at91_adc_data ek_adc_data = {
+	.channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+	.use_external_triggers = true,
+	.vref = 3300,
+};
+
 #if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
 static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
 	REGULATOR_SUPPLY("AVDD", "0-001b"),
@@ -393,6 +405,8 @@ static void __init ek_board_init(void)
 	ek_add_device_gpio_leds();
 	/* Push Buttons */
 	ek_add_device_buttons();
+	/* ADCs */
+	at91_add_device_adc(&ek_adc_data);
 	/* PCK0 provides MCLK to the WM8731 */
 	at91_set_B_periph(AT91_PIN_PC1, 0);
 	/* SSC (for WM8731) */
-- 
1.7.9.5


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

* [PATCH 3/9] ARM: AT91: Add the ADC to the sam9g20ek board
@ 2012-05-09  9:06   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds platform data for the AT91 ADC driver support for
the AT91SAM9G20-EK board.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/mach-at91/at91sam9260.c         |    8 +++
 arch/arm/mach-at91/at91sam9260_devices.c |   89 ++++++++++++++++++++++++++++++
 arch/arm/mach-at91/board-sam9g20ek.c     |   14 +++++
 3 files changed, 111 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 46f7742..63d4432 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -55,6 +55,13 @@ static struct clk adc_clk = {
 	.pmc_mask	= 1 << AT91SAM9260_ID_ADC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 5000000,
+};
+
 static struct clk usart0_clk = {
 	.name		= "usart0_clk",
 	.pmc_mask	= 1 << AT91SAM9260_ID_US0,
@@ -166,6 +173,7 @@ static struct clk *periph_clocks[] __initdata = {
 	&pioB_clk,
 	&pioC_clk,
 	&adc_clk,
+	&adc_op_clk,
 	&usart0_clk,
 	&usart1_clk,
 	&usart2_clk,
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 5652dde..2125851 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -17,6 +17,8 @@
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/board.h>
 #include <mach/cpu.h>
 #include <mach/at91sam9260.h>
@@ -1369,6 +1371,93 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
 void __init at91_add_device_cf(struct at91_cf_data * data) {}
 #endif
 
+/* --------------------------------------------------------------------
+ *  ADCs
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9260_BASE_ADC,
+		.end	= AT91SAM9260_BASE_ADC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9260_ID_ADC,
+		.end	= AT91SAM9260_ID_ADC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_adc_device = {
+	.name		= "at91_adc",
+	.id		= -1,
+	.dev		= {
+				.platform_data		= &adc_data,
+	},
+	.resource	= adc_resources,
+	.num_resources	= ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+	[0] = {
+		.name = "timer-counter-0",
+		.value = AT91_ADC_TRGSEL_TC0 | AT91_ADC_TRGEN,
+	},
+	[1] = {
+		.name = "timer-counter-1",
+		.value = AT91_ADC_TRGSEL_TC1 | AT91_ADC_TRGEN,
+	},
+	[2] = {
+		.name = "timer-counter-2",
+		.value = AT91_ADC_TRGSEL_TC2 | AT91_ADC_TRGEN,
+	},
+	[3] = {
+		.name = "external",
+		.value = AT91_ADC_TRGSEL_EXTERNAL | AT91_ADC_TRGEN,
+		.is_external = true,
+	},
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g20 = {
+	.channel_base = AT91_ADC_CHR(0),
+	.drdy_mask = AT91_ADC_DRDY,
+	.status_register = AT91_ADC_SR,
+	.trigger_register = AT91_ADC_MR,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+	if (!data)
+		return;
+
+	if (test_bit(0, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC0, 0);
+	if (test_bit(1, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC1, 0);
+	if (test_bit(2, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC2, 0);
+	if (test_bit(3, &data->channels_used))
+		at91_set_A_periph(AT91_PIN_PC3, 0);
+
+	if (data->use_external_triggers)
+		at91_set_A_periph(AT91_PIN_PA22, 0);
+
+	data->num_channels = 4;
+	data->startup_time = 10;
+	data->registers = &at91_adc_register_g20;
+	data->trigger_number = 4;
+	data->trigger_list = at91_adc_triggers;
+
+	adc_data = *data;
+	platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
 /* -------------------------------------------------------------------- */
 /*
  * These devices are always present and don't need any board-specific
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 8923ec9..291b0fe 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -32,6 +32,8 @@
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/consumer.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/hardware.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -318,6 +320,16 @@ static void __init ek_add_device_buttons(void)
 static void __init ek_add_device_buttons(void) {}
 #endif
 
+/*
+ * ADCs
+ */
+
+static struct at91_adc_data ek_adc_data = {
+	.channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+	.use_external_triggers = true,
+	.vref = 3300,
+};
+
 #if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
 static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
 	REGULATOR_SUPPLY("AVDD", "0-001b"),
@@ -393,6 +405,8 @@ static void __init ek_board_init(void)
 	ek_add_device_gpio_leds();
 	/* Push Buttons */
 	ek_add_device_buttons();
+	/* ADCs */
+	at91_add_device_adc(&ek_adc_data);
 	/* PCK0 provides MCLK to the WM8731 */
 	at91_set_B_periph(AT91_PIN_PC1, 0);
 	/* SSC (for WM8731) */
-- 
1.7.9.5

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

* [PATCH 4/9] IIO: AT91: ADC: Add support for the AT91SAM9M10G45-EK board
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:06   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

This patch adds platform data for the AT91 ADC driver support for
the AT91SAM9M10G45-EK board.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/mach-at91/at91sam9g45.c         |    9 +++
 arch/arm/mach-at91/at91sam9g45_devices.c |  101 ++++++++++++++++++++++++++++++
 arch/arm/mach-at91/board-sam9m10g45ek.c  |   12 ++++
 3 files changed, 122 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index d222f83..30865c6 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -176,6 +176,12 @@ static struct clk vdec_clk = {
 	.type		= CLK_TYPE_PERIPHERAL,
 };
 
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 13200000,
+};
+
 static struct clk *periph_clocks[] __initdata = {
 	&pioA_clk,
 	&pioB_clk,
@@ -204,6 +210,7 @@ static struct clk *periph_clocks[] __initdata = {
 	&isi_clk,
 	&udphs_clk,
 	&mmc1_clk,
+	&adc_op_clk,
 	// irq0
 };
 
@@ -242,6 +249,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_ID("pioC", &pioC_clk),
 	CLKDEV_CON_ID("pioD", &pioDE_clk),
 	CLKDEV_CON_ID("pioE", &pioDE_clk),
+	/* Fake adc clock */
+	CLKDEV_CON_ID("adc_clk", &tsc_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 6b008ae..0c6d9fe 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -19,9 +19,12 @@
 #include <linux/i2c-gpio.h>
 #include <linux/atmel-mci.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <linux/fb.h>
 #include <video/atmel_lcdc.h>
 
+#include <mach/at91_adc.h>
 #include <mach/board.h>
 #include <mach/at91sam9g45.h>
 #include <mach/at91sam9g45_matrix.h>
@@ -1207,6 +1210,104 @@ void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {}
 
 
 /* --------------------------------------------------------------------
+ *  ADC
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9G45_BASE_TSC,
+		.end	= AT91SAM9G45_BASE_TSC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9G45_ID_TSC,
+		.end	= AT91SAM9G45_ID_TSC,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device at91_adc_device = {
+	.name		= "at91_adc",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= &adc_data,
+	},
+	.resource	= adc_resources,
+	.num_resources	= ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+	[0] = {
+		.name = "external-rising",
+		.value = 1,
+		.is_external = true,
+	},
+	[1] = {
+		.name = "external-falling",
+		.value = 2,
+		.is_external = true,
+	},
+	[2] = {
+		.name = "external-any",
+		.value = 3,
+		.is_external = true,
+	},
+	[3] = {
+		.name = "continuous",
+		.value = 6,
+		.is_external = false,
+	},
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g45 = {
+	.channel_base = AT91_ADC_CHR(0),
+	.drdy_mask = AT91_ADC_DRDY,
+	.status_register = AT91_ADC_SR,
+	.trigger_register = 0x08,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+	if (!data)
+		return;
+
+	if (test_bit(0, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD20, 0);
+	if (test_bit(1, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD21, 0);
+	if (test_bit(2, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD22, 0);
+	if (test_bit(3, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD23, 0);
+	if (test_bit(4, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD24, 0);
+	if (test_bit(5, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD25, 0);
+	if (test_bit(6, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD26, 0);
+	if (test_bit(7, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD27, 0);
+
+	if (data->use_external_triggers)
+		at91_set_A_periph(AT91_PIN_PD28, 0);
+
+	data->num_channels = 8;
+	data->startup_time = 40;
+	data->registers = &at91_adc_register_g45;
+	data->trigger_number = 4;
+	data->trigger_list = at91_adc_triggers;
+
+	adc_data = *data;
+	platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
+/* --------------------------------------------------------------------
  *  RTT
  * -------------------------------------------------------------------- */
 
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index c88e908..337abd2 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -27,6 +27,8 @@
 #include <linux/atmel-mci.h>
 #include <linux/delay.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
 #include <media/soc_camera.h>
@@ -315,6 +317,14 @@ static struct at91_tsadcc_data ek_tsadcc_data = {
 	.ts_sample_hold_time	= 0x0a,
 };
 
+/*
+ * ADCs
+ */
+static struct at91_adc_data ek_adc_data = {
+	.channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7),
+	.use_external_triggers = true,
+	.vref = 3300,
+};
 
 /*
  * GPIO Buttons
@@ -480,6 +490,8 @@ static void __init ek_board_init(void)
 	at91_add_device_lcdc(&ek_lcdc_data);
 	/* Touch Screen */
 	at91_add_device_tsadcc(&ek_tsadcc_data);
+	/* ADC */
+	at91_add_device_adc(&ek_adc_data);
 	/* Push Buttons */
 	ek_add_device_buttons();
 	/* AC97 */
-- 
1.7.9.5


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

* [PATCH 4/9] IIO: AT91: ADC: Add support for the AT91SAM9M10G45-EK board
@ 2012-05-09  9:06   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds platform data for the AT91 ADC driver support for
the AT91SAM9M10G45-EK board.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/mach-at91/at91sam9g45.c         |    9 +++
 arch/arm/mach-at91/at91sam9g45_devices.c |  101 ++++++++++++++++++++++++++++++
 arch/arm/mach-at91/board-sam9m10g45ek.c  |   12 ++++
 3 files changed, 122 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index d222f83..30865c6 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -176,6 +176,12 @@ static struct clk vdec_clk = {
 	.type		= CLK_TYPE_PERIPHERAL,
 };
 
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 13200000,
+};
+
 static struct clk *periph_clocks[] __initdata = {
 	&pioA_clk,
 	&pioB_clk,
@@ -204,6 +210,7 @@ static struct clk *periph_clocks[] __initdata = {
 	&isi_clk,
 	&udphs_clk,
 	&mmc1_clk,
+	&adc_op_clk,
 	// irq0
 };
 
@@ -242,6 +249,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
 	CLKDEV_CON_ID("pioC", &pioC_clk),
 	CLKDEV_CON_ID("pioD", &pioDE_clk),
 	CLKDEV_CON_ID("pioE", &pioDE_clk),
+	/* Fake adc clock */
+	CLKDEV_CON_ID("adc_clk", &tsc_clk),
 };
 
 static struct clk_lookup usart_clocks_lookups[] = {
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 6b008ae..0c6d9fe 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -19,9 +19,12 @@
 #include <linux/i2c-gpio.h>
 #include <linux/atmel-mci.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <linux/fb.h>
 #include <video/atmel_lcdc.h>
 
+#include <mach/at91_adc.h>
 #include <mach/board.h>
 #include <mach/at91sam9g45.h>
 #include <mach/at91sam9g45_matrix.h>
@@ -1207,6 +1210,104 @@ void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {}
 
 
 /* --------------------------------------------------------------------
+ *  ADC
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9G45_BASE_TSC,
+		.end	= AT91SAM9G45_BASE_TSC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9G45_ID_TSC,
+		.end	= AT91SAM9G45_ID_TSC,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device at91_adc_device = {
+	.name		= "at91_adc",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= &adc_data,
+	},
+	.resource	= adc_resources,
+	.num_resources	= ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+	[0] = {
+		.name = "external-rising",
+		.value = 1,
+		.is_external = true,
+	},
+	[1] = {
+		.name = "external-falling",
+		.value = 2,
+		.is_external = true,
+	},
+	[2] = {
+		.name = "external-any",
+		.value = 3,
+		.is_external = true,
+	},
+	[3] = {
+		.name = "continuous",
+		.value = 6,
+		.is_external = false,
+	},
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g45 = {
+	.channel_base = AT91_ADC_CHR(0),
+	.drdy_mask = AT91_ADC_DRDY,
+	.status_register = AT91_ADC_SR,
+	.trigger_register = 0x08,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+	if (!data)
+		return;
+
+	if (test_bit(0, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD20, 0);
+	if (test_bit(1, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD21, 0);
+	if (test_bit(2, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD22, 0);
+	if (test_bit(3, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD23, 0);
+	if (test_bit(4, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD24, 0);
+	if (test_bit(5, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD25, 0);
+	if (test_bit(6, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD26, 0);
+	if (test_bit(7, &data->channels_used))
+		at91_set_gpio_input(AT91_PIN_PD27, 0);
+
+	if (data->use_external_triggers)
+		at91_set_A_periph(AT91_PIN_PD28, 0);
+
+	data->num_channels = 8;
+	data->startup_time = 40;
+	data->registers = &at91_adc_register_g45;
+	data->trigger_number = 4;
+	data->trigger_list = at91_adc_triggers;
+
+	adc_data = *data;
+	platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
+/* --------------------------------------------------------------------
  *  RTT
  * -------------------------------------------------------------------- */
 
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index c88e908..337abd2 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -27,6 +27,8 @@
 #include <linux/atmel-mci.h>
 #include <linux/delay.h>
 
+#include <linux/platform_data/at91_adc.h>
+
 #include <mach/hardware.h>
 #include <video/atmel_lcdc.h>
 #include <media/soc_camera.h>
@@ -315,6 +317,14 @@ static struct at91_tsadcc_data ek_tsadcc_data = {
 	.ts_sample_hold_time	= 0x0a,
 };
 
+/*
+ * ADCs
+ */
+static struct at91_adc_data ek_adc_data = {
+	.channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7),
+	.use_external_triggers = true,
+	.vref = 3300,
+};
 
 /*
  * GPIO Buttons
@@ -480,6 +490,8 @@ static void __init ek_board_init(void)
 	at91_add_device_lcdc(&ek_lcdc_data);
 	/* Touch Screen */
 	at91_add_device_tsadcc(&ek_tsadcc_data);
+	/* ADC */
+	at91_add_device_adc(&ek_adc_data);
 	/* Push Buttons */
 	ek_add_device_buttons();
 	/* AC97 */
-- 
1.7.9.5

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

* [PATCH 5/9] Add clocks for X5 boards
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:06   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

---
 arch/arm/mach-at91/at91sam9x5.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 13c8cae..1b144b4 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -120,6 +120,11 @@ static struct clk adc_clk = {
 	.pmc_mask	= 1 << AT91SAM9X5_ID_ADC,
 	.type	= CLK_TYPE_PERIPHERAL,
 };
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 5000000,
+};
 static struct clk dma0_clk = {
 	.name		= "dma0_clk",
 	.pmc_mask	= 1 << AT91SAM9X5_ID_DMA0,
@@ -205,6 +210,7 @@ static struct clk *periph_clocks[] __initdata = {
 	&tcb0_clk,
 	&pwm_clk,
 	&adc_clk,
+	&adc_op_clk,
 	&dma0_clk,
 	&dma1_clk,
 	&uhphs_clk,
-- 
1.7.9.5


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

* [PATCH 5/9] Add clocks for X5 boards
@ 2012-05-09  9:06   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

---
 arch/arm/mach-at91/at91sam9x5.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 13c8cae..1b144b4 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -120,6 +120,11 @@ static struct clk adc_clk = {
 	.pmc_mask	= 1 << AT91SAM9X5_ID_ADC,
 	.type	= CLK_TYPE_PERIPHERAL,
 };
+static struct clk adc_op_clk = {
+	.name		= "adc_op_clk",
+	.type		= CLK_TYPE_PERIPHERAL,
+	.rate_hz	= 5000000,
+};
 static struct clk dma0_clk = {
 	.name		= "dma0_clk",
 	.pmc_mask	= 1 << AT91SAM9X5_ID_DMA0,
@@ -205,6 +210,7 @@ static struct clk *periph_clocks[] __initdata = {
 	&tcb0_clk,
 	&pwm_clk,
 	&adc_clk,
+	&adc_op_clk,
 	&dma0_clk,
 	&dma1_clk,
 	&uhphs_clk,
-- 
1.7.9.5

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

* [PATCH 6/9] IIO: AT91: Add DT support to at91_adc driver
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:06   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 .../devicetree/bindings/arm/atmel-adc.txt          |   65 ++++++++++
 drivers/iio/adc/at91_adc.c                         |  133 +++++++++++++++++++-
 2 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/arm/atmel-adc.txt

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
new file mode 100644
index 0000000..da2b67d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -0,0 +1,65 @@
+* AT91's Analog to Digital Converter (ADC)
+
+Required properties:
+  - compatible: Should be "atmel,at91-adc"
+  - reg: Should contain ADC registers location and length
+  - interrupts: Should contain the IRQ line for the ADC
+  - atmel,adc-channel-base: Address of the first channel data register
+  - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
+    device
+  - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
+  - atmel,adc-num-channels: Number of channels available in the ADC
+  - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
+    defined in the datasheet
+  - atmel,adc-status-register: Address of the Interrupt Status Register
+  - atmel,adc-trigger-register: Address of the Trigger Register
+  - atmel,adc-vref: Reference voltage in millivolts for the conversions
+
+Optional properties:
+  - atmel,adc-use-external: Boolean to enable of external triggers
+ 
+Optional trigger Nodes:
+  - Required properties:
+    * trigger-name: Name of the trigger exposed to the user
+    * trigger-value: Value to put in the Trigger register
+      to activate this trigger
+  - Optional properties:
+    * trigger-external: Is the trigger an external trigger?
+
+Examples:
+adc0: adc@fffb0000 {
+	compatible = "atmel,at91-adc";
+	reg = <0xfffb0000 0x100>;
+	interrupts = <20 4>;
+	atmel,adc-channel-base = <0x30>;
+	atmel,adc-channels-used = <0xff>;
+	atmel,adc-drdy-mask = <0x10000>;
+	atmel,adc-num-channels = <8>;
+	atmel,adc-startup-time = <40>;
+	atmel,adc-status-register = <0x1c>;
+	atmel,adc-trigger-register = <0x08>;
+	atmel,adc-use-external;
+	atmel,adc-vref = <3300>;
+
+	trigger@0 {
+		trigger-name = "external-rising";
+		trigger-value = <0x1>;
+		trigger-external;
+	};
+	trigger@1 {
+		trigger-name = "external-falling";
+		trigger-value = <0x2>;
+		trigger-external;
+	};
+
+	trigger@2 {
+		trigger-name = "external-any";
+		trigger-value = <0x3>;
+		trigger-external;
+	};
+
+	trigger@3 {
+		trigger-name = "continuous";
+		trigger-value = <0x6>;
+	};
+};
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index febad23..35892fa 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -15,6 +15,8 @@
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -416,6 +418,124 @@ static int at91_adc_read_raw(struct iio_dev *idev,
 	return -EINVAL;
 }
 
+static int at91_adc_probe_dt(struct at91_adc_state *st,
+			     struct platform_device *pdev)
+{
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *trig_node;
+	int i = 0, ret;
+	u32 prop;
+
+	if (!node)
+		return -EINVAL;
+
+	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
+		st->use_external = true;
+
+	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
+		dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->channels_mask = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
+		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->num_channels = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
+		dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->startup_time = prop;
+
+
+	if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
+		dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->vref_mv = prop;
+
+	st->registers = devm_kzalloc(&idev->dev,
+				     sizeof(struct at91_adc_reg_desc),
+				     GFP_KERNEL);
+	if (!st->registers) {
+		dev_err(&idev->dev, "Could not allocate register memory.\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
+		dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->channel_base = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
+		dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->drdy_mask = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
+		dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->status_register = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
+		dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->trigger_register = prop;
+
+	st->trigger_number = of_get_child_count(node);
+	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
+					sizeof(struct at91_adc_trigger),
+					GFP_KERNEL);
+	if (!st->trigger_list) {
+		dev_err(&idev->dev, "Could not allocate trigger list memory.\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	for_each_child_of_node(node, trig_node) {
+		struct at91_adc_trigger *trig = st->trigger_list + i;
+		const char* name;
+
+		if (of_property_read_string(node, "trigger-name", &name)) {
+			dev_err(&idev->dev, "Missing trigger-name property in the DT.\n");
+			ret = -EINVAL;
+			goto error_ret;
+		}
+	        trig->name = name;
+
+		if (of_property_read_u32(node, "trigger-value", &prop)) {
+			dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
+			ret = -EINVAL;
+			goto error_ret;
+		}
+	        trig->value = prop;
+		trig->is_external = of_property_read_bool(node, "trigger-external");
+		i++;
+	}
+
+	return 0;
+
+error_ret:
+	return ret;
+}
+
 static int at91_adc_probe_pdata(struct at91_adc_state *st,
 				struct platform_device *pdev)
 {
@@ -457,7 +577,11 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 
 	st = iio_priv(idev);
 
-	ret = at91_adc_probe_pdata(st, pdev);
+	if (pdev->dev.of_node)
+		ret = at91_adc_probe_dt(st, pdev);
+	else
+		ret = at91_adc_probe_pdata(st, pdev);
+
 	if (ret) {
 		dev_err(&pdev->dev, "No platform data available.\n");
 		ret = -EINVAL;
@@ -659,11 +783,18 @@ static int __devexit at91_adc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id at91_adc_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9g20-adc" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
+
 static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = __devexit_p(at91_adc_remove),
 	.driver = {
 		   .name = "at91_adc",
+		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
 
-- 
1.7.9.5


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

* [PATCH 6/9] IIO: AT91: Add DT support to at91_adc driver
@ 2012-05-09  9:06   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 .../devicetree/bindings/arm/atmel-adc.txt          |   65 ++++++++++
 drivers/iio/adc/at91_adc.c                         |  133 +++++++++++++++++++-
 2 files changed, 197 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/arm/atmel-adc.txt

diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
new file mode 100644
index 0000000..da2b67d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -0,0 +1,65 @@
+* AT91's Analog to Digital Converter (ADC)
+
+Required properties:
+  - compatible: Should be "atmel,at91-adc"
+  - reg: Should contain ADC registers location and length
+  - interrupts: Should contain the IRQ line for the ADC
+  - atmel,adc-channel-base: Address of the first channel data register
+  - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
+    device
+  - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
+  - atmel,adc-num-channels: Number of channels available in the ADC
+  - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
+    defined in the datasheet
+  - atmel,adc-status-register: Address of the Interrupt Status Register
+  - atmel,adc-trigger-register: Address of the Trigger Register
+  - atmel,adc-vref: Reference voltage in millivolts for the conversions
+
+Optional properties:
+  - atmel,adc-use-external: Boolean to enable of external triggers
+ 
+Optional trigger Nodes:
+  - Required properties:
+    * trigger-name: Name of the trigger exposed to the user
+    * trigger-value: Value to put in the Trigger register
+      to activate this trigger
+  - Optional properties:
+    * trigger-external: Is the trigger an external trigger?
+
+Examples:
+adc0: adc at fffb0000 {
+	compatible = "atmel,at91-adc";
+	reg = <0xfffb0000 0x100>;
+	interrupts = <20 4>;
+	atmel,adc-channel-base = <0x30>;
+	atmel,adc-channels-used = <0xff>;
+	atmel,adc-drdy-mask = <0x10000>;
+	atmel,adc-num-channels = <8>;
+	atmel,adc-startup-time = <40>;
+	atmel,adc-status-register = <0x1c>;
+	atmel,adc-trigger-register = <0x08>;
+	atmel,adc-use-external;
+	atmel,adc-vref = <3300>;
+
+	trigger at 0 {
+		trigger-name = "external-rising";
+		trigger-value = <0x1>;
+		trigger-external;
+	};
+	trigger at 1 {
+		trigger-name = "external-falling";
+		trigger-value = <0x2>;
+		trigger-external;
+	};
+
+	trigger at 2 {
+		trigger-name = "external-any";
+		trigger-value = <0x3>;
+		trigger-external;
+	};
+
+	trigger at 3 {
+		trigger-name = "continuous";
+		trigger-value = <0x6>;
+	};
+};
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index febad23..35892fa 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -15,6 +15,8 @@
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -416,6 +418,124 @@ static int at91_adc_read_raw(struct iio_dev *idev,
 	return -EINVAL;
 }
 
+static int at91_adc_probe_dt(struct at91_adc_state *st,
+			     struct platform_device *pdev)
+{
+	struct iio_dev *idev = iio_priv_to_dev(st);
+	struct device_node *node = pdev->dev.of_node;
+	struct device_node *trig_node;
+	int i = 0, ret;
+	u32 prop;
+
+	if (!node)
+		return -EINVAL;
+
+	st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
+		st->use_external = true;
+
+	if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
+		dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->channels_mask = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
+		dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->num_channels = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
+		dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->startup_time = prop;
+
+
+	if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
+		dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->vref_mv = prop;
+
+	st->registers = devm_kzalloc(&idev->dev,
+				     sizeof(struct at91_adc_reg_desc),
+				     GFP_KERNEL);
+	if (!st->registers) {
+		dev_err(&idev->dev, "Could not allocate register memory.\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
+		dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->channel_base = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
+		dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->drdy_mask = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
+		dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->status_register = prop;
+
+	if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
+		dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
+		ret = -EINVAL;
+		goto error_ret;
+	}
+	st->registers->trigger_register = prop;
+
+	st->trigger_number = of_get_child_count(node);
+	st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
+					sizeof(struct at91_adc_trigger),
+					GFP_KERNEL);
+	if (!st->trigger_list) {
+		dev_err(&idev->dev, "Could not allocate trigger list memory.\n");
+		ret = -ENOMEM;
+		goto error_ret;
+	}
+
+	for_each_child_of_node(node, trig_node) {
+		struct at91_adc_trigger *trig = st->trigger_list + i;
+		const char* name;
+
+		if (of_property_read_string(node, "trigger-name", &name)) {
+			dev_err(&idev->dev, "Missing trigger-name property in the DT.\n");
+			ret = -EINVAL;
+			goto error_ret;
+		}
+	        trig->name = name;
+
+		if (of_property_read_u32(node, "trigger-value", &prop)) {
+			dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
+			ret = -EINVAL;
+			goto error_ret;
+		}
+	        trig->value = prop;
+		trig->is_external = of_property_read_bool(node, "trigger-external");
+		i++;
+	}
+
+	return 0;
+
+error_ret:
+	return ret;
+}
+
 static int at91_adc_probe_pdata(struct at91_adc_state *st,
 				struct platform_device *pdev)
 {
@@ -457,7 +577,11 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
 
 	st = iio_priv(idev);
 
-	ret = at91_adc_probe_pdata(st, pdev);
+	if (pdev->dev.of_node)
+		ret = at91_adc_probe_dt(st, pdev);
+	else
+		ret = at91_adc_probe_pdata(st, pdev);
+
 	if (ret) {
 		dev_err(&pdev->dev, "No platform data available.\n");
 		ret = -EINVAL;
@@ -659,11 +783,18 @@ static int __devexit at91_adc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id at91_adc_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9g20-adc" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
+
 static struct platform_driver at91_adc_driver = {
 	.probe = at91_adc_probe,
 	.remove = __devexit_p(at91_adc_remove),
 	.driver = {
 		   .name = "at91_adc",
+		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
 	},
 };
 
-- 
1.7.9.5

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

* [PATCH 7/9] Add ADC driver to the at91sam9g45 dtsi
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:06   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/at91sam9g45.dtsi |   37 ++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index c804214..6f0d21e 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -199,6 +199,43 @@
 				interrupts = <25 4>;
 				status = "disabled";
 			};
+
+			adc0: adc@fffb0000 {
+				compatible = "atmel,at91sam9g20-adc";
+				reg = <0xfffb0000 0x100>;
+				interrupts = <20 4>;
+				atmel,adc-use-external-triggers;
+				atmel,adc-channels-used = <0xff>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <8>;
+				atmel,adc-startup-time = <40>;
+				atmel,adc-channel-base = <0x30>;
+				atmel,adc-drdy-mask = <0x10000>;
+				atmel,adc-status-register = <0x1c>;
+				atmel,adc-trigger-register = <0x08>;
+
+				trigger@0 {
+					trigger-name = "external-rising";
+					trigger-value = <0x1>;
+					trigger-external;
+				};
+				trigger@1 {
+					trigger-name = "external-falling";
+					trigger-value = <0x2>;
+					trigger-external;
+				};
+
+				trigger@2 {
+					trigger-name = "external-any";
+					trigger-value = <0x3>;
+					trigger-external;
+				};
+
+				trigger@3 {
+					trigger-name = "continuous";
+					trigger-value = <0x6>;
+				};
+			};
 		};
 
 		nand0: nand@40000000 {
-- 
1.7.9.5


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

* [PATCH 7/9] Add ADC driver to the at91sam9g45 dtsi
@ 2012-05-09  9:06   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/at91sam9g45.dtsi |   37 ++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index c804214..6f0d21e 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -199,6 +199,43 @@
 				interrupts = <25 4>;
 				status = "disabled";
 			};
+
+			adc0: adc at fffb0000 {
+				compatible = "atmel,at91sam9g20-adc";
+				reg = <0xfffb0000 0x100>;
+				interrupts = <20 4>;
+				atmel,adc-use-external-triggers;
+				atmel,adc-channels-used = <0xff>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <8>;
+				atmel,adc-startup-time = <40>;
+				atmel,adc-channel-base = <0x30>;
+				atmel,adc-drdy-mask = <0x10000>;
+				atmel,adc-status-register = <0x1c>;
+				atmel,adc-trigger-register = <0x08>;
+
+				trigger at 0 {
+					trigger-name = "external-rising";
+					trigger-value = <0x1>;
+					trigger-external;
+				};
+				trigger at 1 {
+					trigger-name = "external-falling";
+					trigger-value = <0x2>;
+					trigger-external;
+				};
+
+				trigger at 2 {
+					trigger-name = "external-any";
+					trigger-value = <0x3>;
+					trigger-external;
+				};
+
+				trigger at 3 {
+					trigger-name = "continuous";
+					trigger-value = <0x6>;
+				};
+			};
 		};
 
 		nand0: nand at 40000000 {
-- 
1.7.9.5

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

* [PATCH 8/9] Add ADC driver to the at91sam9x5 dtsi
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:06   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/at91sam9x5.dtsi |   38 +++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index dd4ed74..03b9eff 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -190,6 +190,44 @@
 				interrupts = <27 4>;
 				status = "disabled";
 			};
+
+			adc0: adc@f804c000 {
+				compatible = "atmel,at91-adc";
+				reg = <0xf804c000 0x100>;
+				interrupts = <19 4>;
+				atmel,adc-use-external;
+				atmel,adc-channels-used = <0xffff>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <12>;
+				atmel,adc-startup-time = <40>;
+				atmel,adc-channel-base = <0x50>;
+				atmel,adc-drdy-mask = <0x1000000>;
+				atmel,adc-status-register = <0x30>;
+				atmel,adc-trigger-register = <0xc0>;
+
+				trigger@0 {
+					trigger-name = "external-rising";
+					trigger-value = <0x1>;
+					trigger-external;
+				};
+
+				trigger@1 {
+					trigger-name = "external-falling";
+					trigger-value = <0x2>;
+					trigger-external;
+				};
+
+				trigger@2 {
+					trigger-name = "external-any";
+					trigger-value = <0x3>;
+					trigger-external;
+				};
+
+				trigger@3 {
+					trigger-name = "continuous";
+					trigger-value = <0x6>;
+				};
+			};
 		};
 
 		nand0: nand@40000000 {
-- 
1.7.9.5


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

* [PATCH 8/9] Add ADC driver to the at91sam9x5 dtsi
@ 2012-05-09  9:06   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/at91sam9x5.dtsi |   38 +++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index dd4ed74..03b9eff 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -190,6 +190,44 @@
 				interrupts = <27 4>;
 				status = "disabled";
 			};
+
+			adc0: adc at f804c000 {
+				compatible = "atmel,at91-adc";
+				reg = <0xf804c000 0x100>;
+				interrupts = <19 4>;
+				atmel,adc-use-external;
+				atmel,adc-channels-used = <0xffff>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <12>;
+				atmel,adc-startup-time = <40>;
+				atmel,adc-channel-base = <0x50>;
+				atmel,adc-drdy-mask = <0x1000000>;
+				atmel,adc-status-register = <0x30>;
+				atmel,adc-trigger-register = <0xc0>;
+
+				trigger at 0 {
+					trigger-name = "external-rising";
+					trigger-value = <0x1>;
+					trigger-external;
+				};
+
+				trigger at 1 {
+					trigger-name = "external-falling";
+					trigger-value = <0x2>;
+					trigger-external;
+				};
+
+				trigger at 2 {
+					trigger-name = "external-any";
+					trigger-value = <0x3>;
+					trigger-external;
+				};
+
+				trigger at 3 {
+					trigger-name = "continuous";
+					trigger-value = <0x6>;
+				};
+			};
 		};
 
 		nand0: nand at 40000000 {
-- 
1.7.9.5

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

* [PATCH 9/9] Add DTSI for the G20 SoC
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09  9:06   ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-iio, linux-arm-kernel
  Cc: thomas, patrice.vilchez, nicolas.ferre, plagnioj

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/at91sam9g20.dtsi |   35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
index 773ef48..2b1ad83 100644
--- a/arch/arm/boot/dts/at91sam9g20.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
@@ -197,6 +197,41 @@
 				interrupts = <10 4>;
 				status = "disabled";
 			};
+
+			adc0: adc@fffe0000 {
+				compatible = "atmel,at91sam9g20-adc";
+				reg = <0xfffe0000 0x100>;
+				interrupts = <5 4>;
+				atmel,adc-use-external-triggers;
+				atmel,adc-channels-used = <0xf>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <4>;
+				atmel,adc-startup-time = <10>;
+				atmel,adc-channel-base = <0x30>;
+				atmel,adc-drdy-mask = <0x10000>;
+				atmel,adc-status-register = <0x1c>;
+				atmel,adc-trigger-register = <0x04>;
+
+				trigger@0 {
+					trigger-name = "timer-counter-0";
+					trigger-value = <0x1>;
+				};
+				trigger@1 {
+					trigger-name = "timer-counter-1";
+					trigger-value = <0x3>;
+				};
+
+				trigger@2 {
+					trigger-name = "timer-counter-2";
+					trigger-value = <0x5>;
+				};
+
+				trigger@3 {
+					trigger-name = "external";
+					trigger-value = <0x13>;
+					trigger-external;
+				};
+			};
 		};
 
 		nand0: nand@40000000 {
-- 
1.7.9.5


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

* [PATCH 9/9] Add DTSI for the G20 SoC
@ 2012-05-09  9:06   ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-09  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/at91sam9g20.dtsi |   35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
index 773ef48..2b1ad83 100644
--- a/arch/arm/boot/dts/at91sam9g20.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
@@ -197,6 +197,41 @@
 				interrupts = <10 4>;
 				status = "disabled";
 			};
+
+			adc0: adc at fffe0000 {
+				compatible = "atmel,at91sam9g20-adc";
+				reg = <0xfffe0000 0x100>;
+				interrupts = <5 4>;
+				atmel,adc-use-external-triggers;
+				atmel,adc-channels-used = <0xf>;
+				atmel,adc-vref = <3300>;
+				atmel,adc-num-channels = <4>;
+				atmel,adc-startup-time = <10>;
+				atmel,adc-channel-base = <0x30>;
+				atmel,adc-drdy-mask = <0x10000>;
+				atmel,adc-status-register = <0x1c>;
+				atmel,adc-trigger-register = <0x04>;
+
+				trigger at 0 {
+					trigger-name = "timer-counter-0";
+					trigger-value = <0x1>;
+				};
+				trigger at 1 {
+					trigger-name = "timer-counter-1";
+					trigger-value = <0x3>;
+				};
+
+				trigger at 2 {
+					trigger-name = "timer-counter-2";
+					trigger-value = <0x5>;
+				};
+
+				trigger at 3 {
+					trigger-name = "external";
+					trigger-value = <0x13>;
+					trigger-external;
+				};
+			};
 		};
 
 		nand0: nand at 40000000 {
-- 
1.7.9.5

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

* Re: [PATCH 1/9] ARM: AT91: Add platform data for the AT91 ADCs
  2012-05-09  9:05   ` Maxime Ripard
@ 2012-05-09 13:04     ` Jonathan Cameron
  -1 siblings, 0 replies; 38+ messages in thread
From: Jonathan Cameron @ 2012-05-09 13:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: linux-iio, linux-arm-kernel, thomas, patrice.vilchez,
	nicolas.ferre, plagnioj

On 5/9/2012 10:05 AM, Maxime Ripard wrote:
> The AT91 SoCs often embeds an ADC. This patch adds the needed
> platform data to specify the informations required by the driver
> to work properly.
>
> For now, we only need the reference voltage and which channels
> are available on the board.
One utterly trivial element inline.
> Signed-off-by: Maxime Ripard<maxime.ripard@free-electrons.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
> ---
>   include/linux/platform_data/at91_adc.h |   61 ++++++++++++++++++++++++++++++++
>   1 file changed, 61 insertions(+)
>   create mode 100644 include/linux/platform_data/at91_adc.h
>
> diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
> new file mode 100644
> index 0000000..f9e2f00
> --- /dev/null
> +++ b/include/linux/platform_data/at91_adc.h
> @@ -0,0 +1,61 @@
> +/*
> + * Copyright (C) 2011 Free Electrons
> + *
> + * Licensed under the GPLv2 or later.
> + */
> +
> +#ifndef _AT91_ADC_H_
> +#define _AT91_ADC_H_
> +
> +/**
> + * struct at91_adc_reg_desc - Various informations relative to registers
> + * @channel_base:	Base address for the channel data registers
> + * @drdy_mask:		Mask of the DRDY field in the relevant registers
> +			(Interruptions registers mostly)
> + * @status_register:	Address of the Interrupt Status Register
> + * @trigger_register:	Address of the Trigger setup register
> + */
> +struct at91_adc_reg_desc {
> +	u8	channel_base;
> +	u32	drdy_mask;
> +	u8	status_register;
> +	u8	trigger_register;
> +};
> +
> +/**
> + * struct at91_adc_trigger - description of triggers
> + * @name:		name of the trigger advertised to the user
> + * @value:		value to set in the ADC's mode register to enable
> +			the trigger
> + * @is_external:	is the trigger relies on an external pin ?
no space before the ? (nitpick of the day ;)
> + */
> +struct at91_adc_trigger {
> +	const char	*name;
> +	u8		value;
> +	bool		is_external;
> +};
> +
> +/**
> + * struct at91_adc_data - platform data for ADC driver
> + * @channels_used:		channels in use on the board as a bitmask
> + * @num_channels:		global number of channels available on the board
> + * @registers:			Registers definition on the board
> + * @startup_time:		startup time of the ADC in microseconds
> + * @trigger_list:		Triggers available in the ADC
> + * @trigger_number:		Number of triggers available in the ADC
> + * @use_external_triggers:	does the board has external triggers availables
> + * @vref:			Reference voltage for the ADC in millivolts
> + */
> +struct at91_adc_data {
> +	unsigned long			channels_used;
> +	u8				num_channels;
> +	struct at91_adc_reg_desc	*registers;
> +	u8				startup_time;
> +	struct at91_adc_trigger		*trigger_list;
> +	u8				trigger_number;
> +	bool				use_external_triggers;
> +	u16				vref;
> +};
> +
> +extern void __init at91_add_device_adc(struct at91_adc_data *data);
> +#endif


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

* [PATCH 1/9] ARM: AT91: Add platform data for the AT91 ADCs
@ 2012-05-09 13:04     ` Jonathan Cameron
  0 siblings, 0 replies; 38+ messages in thread
From: Jonathan Cameron @ 2012-05-09 13:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/9/2012 10:05 AM, Maxime Ripard wrote:
> The AT91 SoCs often embeds an ADC. This patch adds the needed
> platform data to specify the informations required by the driver
> to work properly.
>
> For now, we only need the reference voltage and which channels
> are available on the board.
One utterly trivial element inline.
> Signed-off-by: Maxime Ripard<maxime.ripard@free-electrons.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
> ---
>   include/linux/platform_data/at91_adc.h |   61 ++++++++++++++++++++++++++++++++
>   1 file changed, 61 insertions(+)
>   create mode 100644 include/linux/platform_data/at91_adc.h
>
> diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
> new file mode 100644
> index 0000000..f9e2f00
> --- /dev/null
> +++ b/include/linux/platform_data/at91_adc.h
> @@ -0,0 +1,61 @@
> +/*
> + * Copyright (C) 2011 Free Electrons
> + *
> + * Licensed under the GPLv2 or later.
> + */
> +
> +#ifndef _AT91_ADC_H_
> +#define _AT91_ADC_H_
> +
> +/**
> + * struct at91_adc_reg_desc - Various informations relative to registers
> + * @channel_base:	Base address for the channel data registers
> + * @drdy_mask:		Mask of the DRDY field in the relevant registers
> +			(Interruptions registers mostly)
> + * @status_register:	Address of the Interrupt Status Register
> + * @trigger_register:	Address of the Trigger setup register
> + */
> +struct at91_adc_reg_desc {
> +	u8	channel_base;
> +	u32	drdy_mask;
> +	u8	status_register;
> +	u8	trigger_register;
> +};
> +
> +/**
> + * struct at91_adc_trigger - description of triggers
> + * @name:		name of the trigger advertised to the user
> + * @value:		value to set in the ADC's mode register to enable
> +			the trigger
> + * @is_external:	is the trigger relies on an external pin ?
no space before the ? (nitpick of the day ;)
> + */
> +struct at91_adc_trigger {
> +	const char	*name;
> +	u8		value;
> +	bool		is_external;
> +};
> +
> +/**
> + * struct at91_adc_data - platform data for ADC driver
> + * @channels_used:		channels in use on the board as a bitmask
> + * @num_channels:		global number of channels available on the board
> + * @registers:			Registers definition on the board
> + * @startup_time:		startup time of the ADC in microseconds
> + * @trigger_list:		Triggers available in the ADC
> + * @trigger_number:		Number of triggers available in the ADC
> + * @use_external_triggers:	does the board has external triggers availables
> + * @vref:			Reference voltage for the ADC in millivolts
> + */
> +struct at91_adc_data {
> +	unsigned long			channels_used;
> +	u8				num_channels;
> +	struct at91_adc_reg_desc	*registers;
> +	u8				startup_time;
> +	struct at91_adc_trigger		*trigger_list;
> +	u8				trigger_number;
> +	bool				use_external_triggers;
> +	u16				vref;
> +};
> +
> +extern void __init at91_add_device_adc(struct at91_adc_data *data);
> +#endif

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09 14:18   ` Nicolas Ferre
  -1 siblings, 0 replies; 38+ messages in thread
From: Nicolas Ferre @ 2012-05-09 14:18 UTC (permalink / raw)
  To: Maxime Ripard, Jonathan Cameron, Arnd Bergmann, Olof Johansson
  Cc: linux-iio, linux-arm-kernel, thomas, patrice.vilchez, plagnioj

On 05/09/2012 11:05 AM, Maxime Ripard :
> Hi all,
> 
> Here is another version of the patches to bring ADC driver to Atmel boards.
> Since last version, here is what changed:
>   * Rebased on top of staging-next to move out of staging. Had to change to IIO
>     kfifo buffer along the way.
>   * Reworked the DT bindings according to Jean-Christophe reviews
>   * Made various fixes according to reviews
>   * Support for X5 boards
> 
> Thanks,
> Maxime

Hi Maxime,

Thanks for posting this new series. My overall feeling is that it is
very close to an achievement! Apart from some trivial fixes, you can add
my :

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

on the whole series.

Jonathan, Arnd, Olof,

As explained by Maxime, this patch series is adding the Atmel ADC driver
to the out-of-staging iio subsystem. It relies on patches that are in
staging-next.
On the other hand, I really wouldn't like to split the series between
iio and arm-soc...
My question is: would it be possible to take this series in Jonathan
iio/staging-next git tree for inclusion in 3.5? Arnd & Olof, is it ok
for you? Do you want to add your Acked-by on some patches?

Thanks, best regards,
-- 
Nicolas Ferre

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-09 14:18   ` Nicolas Ferre
  0 siblings, 0 replies; 38+ messages in thread
From: Nicolas Ferre @ 2012-05-09 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/09/2012 11:05 AM, Maxime Ripard :
> Hi all,
> 
> Here is another version of the patches to bring ADC driver to Atmel boards.
> Since last version, here is what changed:
>   * Rebased on top of staging-next to move out of staging. Had to change to IIO
>     kfifo buffer along the way.
>   * Reworked the DT bindings according to Jean-Christophe reviews
>   * Made various fixes according to reviews
>   * Support for X5 boards
> 
> Thanks,
> Maxime

Hi Maxime,

Thanks for posting this new series. My overall feeling is that it is
very close to an achievement! Apart from some trivial fixes, you can add
my :

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

on the whole series.

Jonathan, Arnd, Olof,

As explained by Maxime, this patch series is adding the Atmel ADC driver
to the out-of-staging iio subsystem. It relies on patches that are in
staging-next.
On the other hand, I really wouldn't like to split the series between
iio and arm-soc...
My question is: would it be possible to take this series in Jonathan
iio/staging-next git tree for inclusion in 3.5? Arnd & Olof, is it ok
for you? Do you want to add your Acked-by on some patches?

Thanks, best regards,
-- 
Nicolas Ferre

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-09  9:05 ` Maxime Ripard
@ 2012-05-09 14:40   ` Arnd Bergmann
  -1 siblings, 0 replies; 38+ messages in thread
From: Arnd Bergmann @ 2012-05-09 14:40 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Maxime Ripard, linux-iio, thomas, nicolas.ferre, plagnioj,
	patrice.vilchez

On Wednesday 09 May 2012, Maxime Ripard wrote:
> Here is another version of the patches to bring ADC driver to Atmel boards.
> Since last version, here is what changed:
>   * Rebased on top of staging-next to move out of staging. Had to change to IIO
>     kfifo buffer along the way.
>   * Reworked the DT bindings according to Jean-Christophe reviews
>   * Made various fixes according to reviews
>   * Support for X5 boards

What's the reason for providing both DT and non-DT probing in that driver?
Doesn't it make more sense to just require that everyone who uses this
device boots using the device tree?

	Arnd

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-09 14:40   ` Arnd Bergmann
  0 siblings, 0 replies; 38+ messages in thread
From: Arnd Bergmann @ 2012-05-09 14:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 09 May 2012, Maxime Ripard wrote:
> Here is another version of the patches to bring ADC driver to Atmel boards.
> Since last version, here is what changed:
>   * Rebased on top of staging-next to move out of staging. Had to change to IIO
>     kfifo buffer along the way.
>   * Reworked the DT bindings according to Jean-Christophe reviews
>   * Made various fixes according to reviews
>   * Support for X5 boards

What's the reason for providing both DT and non-DT probing in that driver?
Doesn't it make more sense to just require that everyone who uses this
device boots using the device tree?

	Arnd

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-09 14:18   ` Nicolas Ferre
@ 2012-05-09 14:46     ` Arnd Bergmann
  -1 siblings, 0 replies; 38+ messages in thread
From: Arnd Bergmann @ 2012-05-09 14:46 UTC (permalink / raw)
  To: Nicolas Ferre
  Cc: Maxime Ripard, Jonathan Cameron, Olof Johansson, linux-iio,
	linux-arm-kernel, thomas, patrice.vilchez, plagnioj

On Wednesday 09 May 2012, Nicolas Ferre wrote:
> Jonathan, Arnd, Olof,
> 
> As explained by Maxime, this patch series is adding the Atmel ADC driver
> to the out-of-staging iio subsystem. It relies on patches that are in
> staging-next.
> On the other hand, I really wouldn't like to split the series between
> iio and arm-soc...
> My question is: would it be possible to take this series in Jonathan
> iio/staging-next git tree for inclusion in 3.5? Arnd & Olof, is it ok
> for you? Do you want to add your Acked-by on some patches?

Hmm, if we would do only the DT-based probing for this, it would be
very simple to split the patches between the two branches, but with
the dependency on the platform_data definition, we can't do that.

If you think we still need the platform_data, I guess it can go in
the iio tree, but I'd be happier if we didn't need it any more.

	Arnd

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-09 14:46     ` Arnd Bergmann
  0 siblings, 0 replies; 38+ messages in thread
From: Arnd Bergmann @ 2012-05-09 14:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 09 May 2012, Nicolas Ferre wrote:
> Jonathan, Arnd, Olof,
> 
> As explained by Maxime, this patch series is adding the Atmel ADC driver
> to the out-of-staging iio subsystem. It relies on patches that are in
> staging-next.
> On the other hand, I really wouldn't like to split the series between
> iio and arm-soc...
> My question is: would it be possible to take this series in Jonathan
> iio/staging-next git tree for inclusion in 3.5? Arnd & Olof, is it ok
> for you? Do you want to add your Acked-by on some patches?

Hmm, if we would do only the DT-based probing for this, it would be
very simple to split the patches between the two branches, but with
the dependency on the platform_data definition, we can't do that.

If you think we still need the platform_data, I guess it can go in
the iio tree, but I'd be happier if we didn't need it any more.

	Arnd

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-09 14:40   ` Arnd Bergmann
@ 2012-05-10  8:32     ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-10  8:32 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-arm-kernel, linux-iio, thomas, nicolas.ferre, plagnioj,
	patrice.vilchez

Le 09/05/2012 16:40, Arnd Bergmann a =E9crit :
> On Wednesday 09 May 2012, Maxime Ripard wrote:
>> Here is another version of the patches to bring ADC driver to Atmel =
boards.
>> Since last version, here is what changed:
>>   * Rebased on top of staging-next to move out of staging. Had to ch=
ange to IIO
>>     kfifo buffer along the way.
>>   * Reworked the DT bindings according to Jean-Christophe reviews
>>   * Made various fixes according to reviews
>>   * Support for X5 boards
>=20
> What's the reason for providing both DT and non-DT probing in that dr=
iver?
> Doesn't it make more sense to just require that everyone who uses thi=
s
> device boots using the device tree?

Mostly historical actually.
The first versions were made using only non-DT probing, and then DT was
added, so I didn't remove it.
I've no strong feeling about this however, I believe we can definitely
drop it, moreover if it makes life easier for you to merge it.

I'll send an updated version.

Maxime

--=20
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-10  8:32     ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-10  8:32 UTC (permalink / raw)
  To: linux-arm-kernel

Le 09/05/2012 16:40, Arnd Bergmann a ?crit :
> On Wednesday 09 May 2012, Maxime Ripard wrote:
>> Here is another version of the patches to bring ADC driver to Atmel boards.
>> Since last version, here is what changed:
>>   * Rebased on top of staging-next to move out of staging. Had to change to IIO
>>     kfifo buffer along the way.
>>   * Reworked the DT bindings according to Jean-Christophe reviews
>>   * Made various fixes according to reviews
>>   * Support for X5 boards
> 
> What's the reason for providing both DT and non-DT probing in that driver?
> Doesn't it make more sense to just require that everyone who uses this
> device boots using the device tree?

Mostly historical actually.
The first versions were made using only non-DT probing, and then DT was
added, so I didn't remove it.
I've no strong feeling about this however, I believe we can definitely
drop it, moreover if it makes life easier for you to merge it.

I'll send an updated version.

Maxime

-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-10  8:32     ` Maxime Ripard
@ 2012-05-10  8:50       ` Nicolas Ferre
  -1 siblings, 0 replies; 38+ messages in thread
From: Nicolas Ferre @ 2012-05-10  8:50 UTC (permalink / raw)
  To: Maxime Ripard, Arnd Bergmann
  Cc: linux-arm-kernel, linux-iio, thomas, plagnioj, patrice.vilchez

On 05/10/2012 10:32 AM, Maxime Ripard :
> Le 09/05/2012 16:40, Arnd Bergmann a =E9crit :
>> On Wednesday 09 May 2012, Maxime Ripard wrote:
>>> Here is another version of the patches to bring ADC driver to Atmel=
 boards.
>>> Since last version, here is what changed:
>>>   * Rebased on top of staging-next to move out of staging. Had to c=
hange to IIO
>>>     kfifo buffer along the way.
>>>   * Reworked the DT bindings according to Jean-Christophe reviews
>>>   * Made various fixes according to reviews
>>>   * Support for X5 boards
>>
>> What's the reason for providing both DT and non-DT probing in that d=
river?
>> Doesn't it make more sense to just require that everyone who uses th=
is
>> device boots using the device tree?
>=20
> Mostly historical actually.
> The first versions were made using only non-DT probing, and then DT w=
as
> added, so I didn't remove it.
> I've no strong feeling about this however, I believe we can definitel=
y
> drop it, moreover if it makes life easier for you to merge it.
>=20
> I'll send an updated version.

Hold on Maxime,

Non-DT is important for us as several boards are not converted to DT an=
d
I guess that some never will. Moreover, some AT91 SoC will certainly
never be converted to DT but all are equipped with ADC...

So I would really like to keep the non-DT probing. This will give the
ability for users to experiment IIO/ADC with whichever kernel revision,
whichever AT91 SoC they like.

Arnd, we will have to agree on a way to push this work into mainline,
but please consider keeping the non-DT part for this driver.

Best regards,
--=20
Nicolas Ferre

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-10  8:50       ` Nicolas Ferre
  0 siblings, 0 replies; 38+ messages in thread
From: Nicolas Ferre @ 2012-05-10  8:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/10/2012 10:32 AM, Maxime Ripard :
> Le 09/05/2012 16:40, Arnd Bergmann a ?crit :
>> On Wednesday 09 May 2012, Maxime Ripard wrote:
>>> Here is another version of the patches to bring ADC driver to Atmel boards.
>>> Since last version, here is what changed:
>>>   * Rebased on top of staging-next to move out of staging. Had to change to IIO
>>>     kfifo buffer along the way.
>>>   * Reworked the DT bindings according to Jean-Christophe reviews
>>>   * Made various fixes according to reviews
>>>   * Support for X5 boards
>>
>> What's the reason for providing both DT and non-DT probing in that driver?
>> Doesn't it make more sense to just require that everyone who uses this
>> device boots using the device tree?
> 
> Mostly historical actually.
> The first versions were made using only non-DT probing, and then DT was
> added, so I didn't remove it.
> I've no strong feeling about this however, I believe we can definitely
> drop it, moreover if it makes life easier for you to merge it.
> 
> I'll send an updated version.

Hold on Maxime,

Non-DT is important for us as several boards are not converted to DT and
I guess that some never will. Moreover, some AT91 SoC will certainly
never be converted to DT but all are equipped with ADC...

So I would really like to keep the non-DT probing. This will give the
ability for users to experiment IIO/ADC with whichever kernel revision,
whichever AT91 SoC they like.

Arnd, we will have to agree on a way to push this work into mainline,
but please consider keeping the non-DT part for this driver.

Best regards,
-- 
Nicolas Ferre

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-10  8:50       ` Nicolas Ferre
@ 2012-05-10 13:28         ` Arnd Bergmann
  -1 siblings, 0 replies; 38+ messages in thread
From: Arnd Bergmann @ 2012-05-10 13:28 UTC (permalink / raw)
  To: Nicolas Ferre
  Cc: Maxime Ripard, linux-arm-kernel, linux-iio, thomas, plagnioj,
	patrice.vilchez

On Thursday 10 May 2012, Nicolas Ferre wrote:
> So I would really like to keep the non-DT probing. This will give the
> ability for users to experiment IIO/ADC with whichever kernel revision,
> whichever AT91 SoC they like.
> 
> Arnd, we will have to agree on a way to push this work into mainline,
> but please consider keeping the non-DT part for this driver.

Ok. If the non-DT part is important to you, I suggest you merge it
all through the IIO tree, to avoid dependency problems with the
platform data header file.

Please add my Acked-by for the arch/arm patches.

	Arnd

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-10 13:28         ` Arnd Bergmann
  0 siblings, 0 replies; 38+ messages in thread
From: Arnd Bergmann @ 2012-05-10 13:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 10 May 2012, Nicolas Ferre wrote:
> So I would really like to keep the non-DT probing. This will give the
> ability for users to experiment IIO/ADC with whichever kernel revision,
> whichever AT91 SoC they like.
> 
> Arnd, we will have to agree on a way to push this work into mainline,
> but please consider keeping the non-DT part for this driver.

Ok. If the non-DT part is important to you, I suggest you merge it
all through the IIO tree, to avoid dependency problems with the
platform data header file.

Please add my Acked-by for the arch/arm patches.

	Arnd

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-10 13:28         ` Arnd Bergmann
@ 2012-05-11  7:54           ` Maxime Ripard
  -1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-11  7:54 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Arnd Bergmann, Nicolas Ferre, linux-arm-kernel, linux-iio,
	thomas, plagnioj, patrice.vilchez

Hi Jonathan,

Since everyone seems to have put his Acked-By (Nicolas, Arnd and you),
are you ok to merge it in your tree ?

You still had some minor comments, do you you want me to post a new
patchset to the mailing list, or a public git branch would be enough ?

Thanks,
Maxime

Le 10/05/2012 15:28, Arnd Bergmann a =E9crit :
> On Thursday 10 May 2012, Nicolas Ferre wrote:
>> So I would really like to keep the non-DT probing. This will give th=
e
>> ability for users to experiment IIO/ADC with whichever kernel revisi=
on,
>> whichever AT91 SoC they like.
>>
>> Arnd, we will have to agree on a way to push this work into mainline=
,
>> but please consider keeping the non-DT part for this driver.
>=20
> Ok. If the non-DT part is important to you, I suggest you merge it
> all through the IIO tree, to avoid dependency problems with the
> platform data header file.
>=20
> Please add my Acked-by for the arch/arm patches.
>=20
> 	Arnd


--=20
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-11  7:54           ` Maxime Ripard
  0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2012-05-11  7:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jonathan,

Since everyone seems to have put his Acked-By (Nicolas, Arnd and you),
are you ok to merge it in your tree ?

You still had some minor comments, do you you want me to post a new
patchset to the mailing list, or a public git branch would be enough ?

Thanks,
Maxime

Le 10/05/2012 15:28, Arnd Bergmann a ?crit :
> On Thursday 10 May 2012, Nicolas Ferre wrote:
>> So I would really like to keep the non-DT probing. This will give the
>> ability for users to experiment IIO/ADC with whichever kernel revision,
>> whichever AT91 SoC they like.
>>
>> Arnd, we will have to agree on a way to push this work into mainline,
>> but please consider keeping the non-DT part for this driver.
> 
> Ok. If the non-DT part is important to you, I suggest you merge it
> all through the IIO tree, to avoid dependency problems with the
> platform data header file.
> 
> Please add my Acked-by for the arch/arm patches.
> 
> 	Arnd


-- 
Maxime Ripard, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

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

* Re: [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
  2012-05-11  7:54           ` Maxime Ripard
@ 2012-05-11 12:26             ` Jonathan Cameron
  -1 siblings, 0 replies; 38+ messages in thread
From: Jonathan Cameron @ 2012-05-11 12:26 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Jonathan Cameron, Arnd Bergmann, Nicolas Ferre, linux-arm-kernel,
	linux-iio, thomas, plagnioj, patrice.vilchez, Greg Kroah-Hartman

On 5/11/2012 8:54 AM, Maxime Ripard wrote:
> Hi Jonathan,
>
> Since everyone seems to have put his Acked-By (Nicolas, Arnd and you),
> are you ok to merge it in your tree ?
>
> You still had some minor comments, do you you want me to post a new
> patchset to the mailing list, or a public git branch would be enough ?
IIO is still in staging from the point of view of git trees.  Hence Greg
will actually merge the patches.  Could you send him a clean set
with all the acks etc. (cc'd on this).
>
> Thanks,
> Maxime
>
> Le 10/05/2012 15:28, Arnd Bergmann a =E9crit :
>> On Thursday 10 May 2012, Nicolas Ferre wrote:
>>> So I would really like to keep the non-DT probing. This will give the
>>> ability for users to experiment IIO/ADC with whichever kernel revisio=
n,
>>> whichever AT91 SoC they like.
>>>
>>> Arnd, we will have to agree on a way to push this work into mainline,
>>> but please consider keeping the non-DT part for this driver.
>>
>> Ok. If the non-DT part is important to you, I suggest you merge it
>> all through the IIO tree, to avoid dependency problems with the
>> platform data header file.
>>
>> Please add my Acked-by for the arch/arm patches.
>>
>> 	Arnd
>
>

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

* [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards
@ 2012-05-11 12:26             ` Jonathan Cameron
  0 siblings, 0 replies; 38+ messages in thread
From: Jonathan Cameron @ 2012-05-11 12:26 UTC (permalink / raw)
  To: linux-arm-kernel

On 5/11/2012 8:54 AM, Maxime Ripard wrote:
> Hi Jonathan,
>
> Since everyone seems to have put his Acked-By (Nicolas, Arnd and you),
> are you ok to merge it in your tree ?
>
> You still had some minor comments, do you you want me to post a new
> patchset to the mailing list, or a public git branch would be enough ?
IIO is still in staging from the point of view of git trees.  Hence Greg
will actually merge the patches.  Could you send him a clean set
with all the acks etc. (cc'd on this).
>
> Thanks,
> Maxime
>
> Le 10/05/2012 15:28, Arnd Bergmann a ?crit :
>> On Thursday 10 May 2012, Nicolas Ferre wrote:
>>> So I would really like to keep the non-DT probing. This will give the
>>> ability for users to experiment IIO/ADC with whichever kernel revision,
>>> whichever AT91 SoC they like.
>>>
>>> Arnd, we will have to agree on a way to push this work into mainline,
>>> but please consider keeping the non-DT part for this driver.
>>
>> Ok. If the non-DT part is important to you, I suggest you merge it
>> all through the IIO tree, to avoid dependency problems with the
>> platform data header file.
>>
>> Please add my Acked-by for the arch/arm patches.
>>
>> 	Arnd
>
>

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

end of thread, other threads:[~2012-05-11 12:26 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-09  9:05 [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards Maxime Ripard
2012-05-09  9:05 ` Maxime Ripard
2012-05-09  9:05 ` [PATCH 1/9] ARM: AT91: Add platform data for the AT91 ADCs Maxime Ripard
2012-05-09  9:05   ` Maxime Ripard
2012-05-09 13:04   ` Jonathan Cameron
2012-05-09 13:04     ` Jonathan Cameron
2012-05-09  9:05 ` [PATCH 2/9] ARM: AT91: IIO: Add AT91 ADC driver Maxime Ripard
2012-05-09  9:05   ` Maxime Ripard
2012-05-09  9:06 ` [PATCH 3/9] ARM: AT91: Add the ADC to the sam9g20ek board Maxime Ripard
2012-05-09  9:06   ` Maxime Ripard
2012-05-09  9:06 ` [PATCH 4/9] IIO: AT91: ADC: Add support for the AT91SAM9M10G45-EK board Maxime Ripard
2012-05-09  9:06   ` Maxime Ripard
2012-05-09  9:06 ` [PATCH 5/9] Add clocks for X5 boards Maxime Ripard
2012-05-09  9:06   ` Maxime Ripard
2012-05-09  9:06 ` [PATCH 6/9] IIO: AT91: Add DT support to at91_adc driver Maxime Ripard
2012-05-09  9:06   ` Maxime Ripard
2012-05-09  9:06 ` [PATCH 7/9] Add ADC driver to the at91sam9g45 dtsi Maxime Ripard
2012-05-09  9:06   ` Maxime Ripard
2012-05-09  9:06 ` [PATCH 8/9] Add ADC driver to the at91sam9x5 dtsi Maxime Ripard
2012-05-09  9:06   ` Maxime Ripard
2012-05-09  9:06 ` [PATCH 9/9] Add DTSI for the G20 SoC Maxime Ripard
2012-05-09  9:06   ` Maxime Ripard
2012-05-09 14:18 ` [PATCHv3] Add ADC driver for Atmel G20, G45 and X5 boards Nicolas Ferre
2012-05-09 14:18   ` Nicolas Ferre
2012-05-09 14:46   ` Arnd Bergmann
2012-05-09 14:46     ` Arnd Bergmann
2012-05-09 14:40 ` Arnd Bergmann
2012-05-09 14:40   ` Arnd Bergmann
2012-05-10  8:32   ` Maxime Ripard
2012-05-10  8:32     ` Maxime Ripard
2012-05-10  8:50     ` Nicolas Ferre
2012-05-10  8:50       ` Nicolas Ferre
2012-05-10 13:28       ` Arnd Bergmann
2012-05-10 13:28         ` Arnd Bergmann
2012-05-11  7:54         ` Maxime Ripard
2012-05-11  7:54           ` Maxime Ripard
2012-05-11 12:26           ` Jonathan Cameron
2012-05-11 12:26             ` 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.