[3.13.y.z extended stable] Patch "iio: adc: at91: don't use the last converted data register" has been added to staging queue

Kamal Mostafa kamal at canonical.com
Thu Oct 9 20:51:33 UTC 2014

This is a note to let you know that I have just added a patch titled

    iio: adc: at91: don't use the last converted data register

to the linux-3.13.y-queue branch of the 3.13.y.z extended stable tree 
which can be found at:


This patch is scheduled to be released in version

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.13.y.z tree, see



>From 72fa1e448b39420839156e64a774362630355c0e Mon Sep 17 00:00:00 2001
From: Ludovic Desroches <ludovic.desroches at atmel.com>
Date: Thu, 9 Oct 2014 15:02:00 +0100
Subject: iio: adc: at91: don't use the last converted data register

commit d4f51956ac8ad302db9b0c4e4232775b1baa7b44 upstream.

If touchscreen mode is enabled and a conversion is requested on another
channel, the result in the last converted data register can be a
touchscreen relative value. Starting a conversion involves to do a
conversion for all active channel. It starts with ADC channels and ends
with touchscreen channels. Then if ADC_LCD register is not read quickly,
its content may be a touchscreen conversion.
To remove this temporal constraint, the conversion value is taken from
the channel data register.

Signed-off-by: Ludovic Desroches <ludovic.desroches at atmel.com>
Acked-by: Alexandre Belloni <alexandre.belloni at free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre at atmel.com>
Signed-off-by: Jonathan Cameron <jic23 at kernel.org>
[ kamal: backport to 3.13-stable: no _9x5_interrupt handler ]
Signed-off-by: Kamal Mostafa <kamal at canonical.com>
 drivers/iio/adc/at91_adc.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index e6bf77d..059946e 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -78,6 +78,7 @@ struct at91_adc_state {
 	bool			done;
 	int			irq;
 	u16			last_value;
+	int			chnb;
 	struct mutex		lock;
 	u8			num_channels;
 	void __iomem		*reg_base;
@@ -151,7 +152,7 @@ void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
 		iio_trigger_poll(idev->trig, iio_get_time_ns());
 	} else {
-		st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
+		st->last_value = at91_adc_readl(st, AT91_ADC_CHAN(st, st->chnb));
 		st->done = true;
@@ -230,7 +231,7 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)

-	if (status & st->registers->drdy_mask)
+	if (status & GENMASK(st->num_channels - 1, 0))
 		handle_adc_eoc_trigger(irq, idev);

 	if (status & AT91_ADC_IER_PEN) {
@@ -501,9 +502,10 @@ static int at91_adc_read_raw(struct iio_dev *idev,

+		st->chnb = chan->channel;
 		at91_adc_writel(st, AT91_ADC_CHER,
-		at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask);
+		at91_adc_writel(st, AT91_ADC_IER, BIT(chan->channel));
 		at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START);

 		ret = wait_event_interruptible_timeout(st->wq_data_avail,
@@ -520,7 +522,7 @@ static int at91_adc_read_raw(struct iio_dev *idev,

 		at91_adc_writel(st, AT91_ADC_CHDR,
-		at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask);
+		at91_adc_writel(st, AT91_ADC_IDR, BIT(chan->channel));

 		st->last_value = 0;
 		st->done = false;

More information about the kernel-team mailing list