Skip to content

Commit 97c54cf

Browse files
ehristevjic23
authored andcommitted
iio: adc: at91-sama5d2_adc: handle unfinished conversions
It can happen that on IRQ trigger, not all conversions are done if we are enabling multiple channels. The IRQ is triggered on first EOC (end of channel), but it can happen that not all channels are done. This leads into erroneous reports to userspace (zero values or previous values). To solve this, in trigger handler, check if the mask of done channels is the same as the mask of active scan channels. If it's the same, proceed and push to buffers. Otherwise, use usleep to sleep until the conversion is done or we timeout. Normally, it should happen that in a short time fashion, all channels are ready, since the first IRQ triggered. If a hardware fault happens (for example the clock suddently dissappears), the handler will not be completed, in which case we do not report anything to userspace anymore. Also, change from using the EOC interrupts to DRDY interrupt. This helps with the fact that not 'n' interrupt statuses are enabled, each being able to trigger an interrupt, and instead only data ready interrupt can wake up the CPU. Like this, when data is ready, check in handler which and how many channels are done. While the DRDY is raised, other IRQs cannot occur. Once the channel data is being read, we ack the IRQ and finish the conversion. Signed-off-by: Eugen Hristev <[email protected]> Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 77baa8d commit 97c54cf

File tree

1 file changed

+48
-14
lines changed

1 file changed

+48
-14
lines changed

drivers/iio/adc/at91-sama5d2_adc.c

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/bitops.h>
1010
#include <linux/clk.h>
11+
#include <linux/delay.h>
1112
#include <linux/dma-mapping.h>
1213
#include <linux/dmaengine.h>
1314
#include <linux/interrupt.h>
@@ -100,6 +101,8 @@
100101
#define AT91_SAMA5D2_IER_YRDY BIT(21)
101102
/* Interrupt Enable Register - TS pressure measurement ready */
102103
#define AT91_SAMA5D2_IER_PRDY BIT(22)
104+
/* Interrupt Enable Register - Data ready */
105+
#define AT91_SAMA5D2_IER_DRDY BIT(24)
103106
/* Interrupt Enable Register - general overrun error */
104107
#define AT91_SAMA5D2_IER_GOVRE BIT(25)
105108
/* Interrupt Enable Register - Pen detect */
@@ -486,6 +489,21 @@ static inline int at91_adc_of_xlate(struct iio_dev *indio_dev,
486489
return at91_adc_chan_xlate(indio_dev, iiospec->args[0]);
487490
}
488491

492+
static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev)
493+
{
494+
u32 mask = 0;
495+
u8 bit;
496+
497+
for_each_set_bit(bit, indio_dev->active_scan_mask,
498+
indio_dev->num_channels) {
499+
struct iio_chan_spec const *chan =
500+
at91_adc_chan_get(indio_dev, bit);
501+
mask |= BIT(chan->channel);
502+
}
503+
504+
return mask & GENMASK(11, 0);
505+
}
506+
489507
static void at91_adc_config_emr(struct at91_adc_state *st)
490508
{
491509
/* configure the extended mode register */
@@ -746,25 +764,23 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
746764
at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
747765
}
748766

749-
if (state) {
767+
if (state)
750768
at91_adc_writel(st, AT91_SAMA5D2_CHER,
751769
BIT(chan->channel));
752-
/* enable irq only if not using DMA */
753-
if (!st->dma_st.dma_chan) {
754-
at91_adc_writel(st, AT91_SAMA5D2_IER,
755-
BIT(chan->channel));
756-
}
757-
} else {
758-
/* disable irq only if not using DMA */
759-
if (!st->dma_st.dma_chan) {
760-
at91_adc_writel(st, AT91_SAMA5D2_IDR,
761-
BIT(chan->channel));
762-
}
770+
else
763771
at91_adc_writel(st, AT91_SAMA5D2_CHDR,
764772
BIT(chan->channel));
765-
}
766773
}
767774

775+
/* Nothing to do if using DMA */
776+
if (st->dma_st.dma_chan)
777+
return 0;
778+
779+
if (state)
780+
at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_DRDY);
781+
else
782+
at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_DRDY);
783+
768784
return 0;
769785
}
770786

@@ -781,6 +797,7 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig)
781797

782798
/* Needed to ACK the DRDY interruption */
783799
at91_adc_readl(st, AT91_SAMA5D2_LCDR);
800+
784801
return 0;
785802
}
786803

@@ -1015,6 +1032,22 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
10151032
int i = 0;
10161033
int val;
10171034
u8 bit;
1035+
u32 mask = at91_adc_active_scan_mask_to_reg(indio_dev);
1036+
unsigned int timeout = 50;
1037+
1038+
/*
1039+
* Check if the conversion is ready. If not, wait a little bit, and
1040+
* in case of timeout exit with an error.
1041+
*/
1042+
while ((at91_adc_readl(st, AT91_SAMA5D2_ISR) & mask) != mask &&
1043+
timeout) {
1044+
usleep_range(50, 100);
1045+
timeout--;
1046+
}
1047+
1048+
/* Cannot read data, not ready. Continue without reporting data */
1049+
if (!timeout)
1050+
return;
10181051

10191052
for_each_set_bit(bit, indio_dev->active_scan_mask,
10201053
indio_dev->num_channels) {
@@ -1281,7 +1314,8 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
12811314
status = at91_adc_readl(st, AT91_SAMA5D2_XPOSR);
12821315
status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR);
12831316
status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR);
1284-
} else if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) {
1317+
} else if (iio_buffer_enabled(indio) &&
1318+
(status & AT91_SAMA5D2_IER_DRDY)) {
12851319
/* triggered buffer without DMA */
12861320
disable_irq_nosync(irq);
12871321
iio_trigger_poll(indio->trig);

0 commit comments

Comments
 (0)