diff options
Diffstat (limited to 'drivers/iio/adc/at91-sama5d2_adc.c')
-rw-r--r-- | drivers/iio/adc/at91-sama5d2_adc.c | 233 |
1 files changed, 140 insertions, 93 deletions
diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 9d96f7d08b95..9abbbdcc7420 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -8,6 +8,7 @@ #include <linux/bitops.h> #include <linux/clk.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/interrupt.h> @@ -100,6 +101,8 @@ #define AT91_SAMA5D2_IER_YRDY BIT(21) /* Interrupt Enable Register - TS pressure measurement ready */ #define AT91_SAMA5D2_IER_PRDY BIT(22) +/* Interrupt Enable Register - Data ready */ +#define AT91_SAMA5D2_IER_DRDY BIT(24) /* Interrupt Enable Register - general overrun error */ #define AT91_SAMA5D2_IER_GOVRE BIT(25) /* Interrupt Enable Register - Pen detect */ @@ -486,6 +489,21 @@ static inline int at91_adc_of_xlate(struct iio_dev *indio_dev, return at91_adc_chan_xlate(indio_dev, iiospec->args[0]); } +static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev) +{ + u32 mask = 0; + u8 bit; + + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->num_channels) { + struct iio_chan_spec const *chan = + at91_adc_chan_get(indio_dev, bit); + mask |= BIT(chan->channel); + } + + return mask & GENMASK(11, 0); +} + static void at91_adc_config_emr(struct at91_adc_state *st) { /* configure the extended mode register */ @@ -710,7 +728,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) struct iio_dev *indio = iio_trigger_get_drvdata(trig); struct at91_adc_state *st = iio_priv(indio); u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR); - u8 bit; /* clear TRGMOD */ status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK; @@ -721,50 +738,6 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) /* set/unset hw trigger */ at91_adc_writel(st, AT91_SAMA5D2_TRGR, status); - for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) { - struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit); - u32 cor; - - if (!chan) - continue; - /* these channel types cannot be handled by this trigger */ - if (chan->type == IIO_POSITIONRELATIVE || - chan->type == IIO_PRESSURE) - continue; - - if (state) { - cor = at91_adc_readl(st, AT91_SAMA5D2_COR); - - if (chan->differential) - cor |= (BIT(chan->channel) | - BIT(chan->channel2)) << - AT91_SAMA5D2_COR_DIFF_OFFSET; - else - cor &= ~(BIT(chan->channel) << - AT91_SAMA5D2_COR_DIFF_OFFSET); - - at91_adc_writel(st, AT91_SAMA5D2_COR, cor); - } - - if (state) { - at91_adc_writel(st, AT91_SAMA5D2_CHER, - BIT(chan->channel)); - /* enable irq only if not using DMA */ - if (!st->dma_st.dma_chan) { - at91_adc_writel(st, AT91_SAMA5D2_IER, - BIT(chan->channel)); - } - } else { - /* disable irq only if not using DMA */ - if (!st->dma_st.dma_chan) { - at91_adc_writel(st, AT91_SAMA5D2_IDR, - BIT(chan->channel)); - } - at91_adc_writel(st, AT91_SAMA5D2_CHDR, - BIT(chan->channel)); - } - } - return 0; } @@ -781,6 +754,7 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig) /* Needed to ACK the DRDY interruption */ at91_adc_readl(st, AT91_SAMA5D2_LCDR); + return 0; } @@ -888,18 +862,37 @@ static int at91_adc_dma_start(struct iio_dev *indio_dev) return 0; } -static int at91_adc_buffer_postenable(struct iio_dev *indio_dev) +static bool at91_adc_buffer_check_use_irq(struct iio_dev *indio, + struct at91_adc_state *st) +{ + /* if using DMA, we do not use our own IRQ (we use DMA-controller) */ + if (st->dma_st.dma_chan) + return false; + /* if the trigger is not ours, then it has its own IRQ */ + if (iio_trigger_validate_own_device(indio->trig, indio)) + return false; + return true; +} + +static bool at91_adc_current_chan_is_touch(struct iio_dev *indio_dev) +{ + struct at91_adc_state *st = iio_priv(indio_dev); + + return !!bitmap_subset(indio_dev->active_scan_mask, + &st->touch_st.channels_bitmask, + AT91_SAMA5D2_MAX_CHAN_IDX + 1); +} + +static int at91_adc_buffer_preenable(struct iio_dev *indio_dev) { int ret; + u8 bit; struct at91_adc_state *st = iio_priv(indio_dev); /* check if we are enabling triggered buffer or the touchscreen */ - if (bitmap_subset(indio_dev->active_scan_mask, - &st->touch_st.channels_bitmask, - AT91_SAMA5D2_MAX_CHAN_IDX + 1)) { - /* touchscreen enabling */ + if (at91_adc_current_chan_is_touch(indio_dev)) return at91_adc_configure_touch(st, true); - } + /* if we are not in triggered mode, we cannot enable the buffer. */ if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES)) return -EINVAL; @@ -911,41 +904,65 @@ static int at91_adc_buffer_postenable(struct iio_dev *indio_dev) return ret; } + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->num_channels) { + struct iio_chan_spec const *chan = + at91_adc_chan_get(indio_dev, bit); + u32 cor; + + if (!chan) + continue; + /* these channel types cannot be handled by this trigger */ + if (chan->type == IIO_POSITIONRELATIVE || + chan->type == IIO_PRESSURE) + continue; + + cor = at91_adc_readl(st, AT91_SAMA5D2_COR); + + if (chan->differential) + cor |= (BIT(chan->channel) | BIT(chan->channel2)) << + AT91_SAMA5D2_COR_DIFF_OFFSET; + else + cor &= ~(BIT(chan->channel) << + AT91_SAMA5D2_COR_DIFF_OFFSET); + + at91_adc_writel(st, AT91_SAMA5D2_COR, cor); + + at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel)); + } + + if (at91_adc_buffer_check_use_irq(indio_dev, st)) + at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_DRDY); + + return 0; +} + +static int at91_adc_buffer_postenable(struct iio_dev *indio_dev) +{ + if (at91_adc_current_chan_is_touch(indio_dev)) + return 0; + return iio_triggered_buffer_postenable(indio_dev); } -static int at91_adc_buffer_predisable(struct iio_dev *indio_dev) +static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev) { struct at91_adc_state *st = iio_priv(indio_dev); - int ret; u8 bit; /* check if we are disabling triggered buffer or the touchscreen */ - if (bitmap_subset(indio_dev->active_scan_mask, - &st->touch_st.channels_bitmask, - AT91_SAMA5D2_MAX_CHAN_IDX + 1)) { - /* touchscreen disable */ + if (at91_adc_current_chan_is_touch(indio_dev)) return at91_adc_configure_touch(st, false); - } + /* if we are not in triggered mode, nothing to do here */ if (!(indio_dev->currentmode & INDIO_ALL_TRIGGERED_MODES)) return -EINVAL; - /* continue with the triggered buffer */ - ret = iio_triggered_buffer_predisable(indio_dev); - if (ret < 0) - dev_err(&indio_dev->dev, "buffer predisable failed\n"); - - if (!st->dma_st.dma_chan) - return ret; - - /* if we are using DMA we must clear registers and end DMA */ - dmaengine_terminate_sync(st->dma_st.dma_chan); - /* - * For each enabled channel we must read the last converted value + * For each enable channel we must disable it in hardware. + * In the case of DMA, we must read the last converted value * to clear EOC status and not get a possible interrupt later. - * This value is being read by DMA from LCDR anyway + * This value is being read by DMA from LCDR anyway, so it's not lost. */ for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->num_channels) { @@ -958,16 +975,37 @@ static int at91_adc_buffer_predisable(struct iio_dev *indio_dev) if (chan->type == IIO_POSITIONRELATIVE || chan->type == IIO_PRESSURE) continue; + + at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel)); + if (st->dma_st.dma_chan) at91_adc_readl(st, chan->address); } + if (at91_adc_buffer_check_use_irq(indio_dev, st)) + at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_DRDY); + /* read overflow register to clear possible overflow status */ at91_adc_readl(st, AT91_SAMA5D2_OVER); - return ret; + + /* if we are using DMA we must clear registers and end DMA */ + if (st->dma_st.dma_chan) + dmaengine_terminate_sync(st->dma_st.dma_chan); + + return 0; +} + +static int at91_adc_buffer_predisable(struct iio_dev *indio_dev) +{ + if (at91_adc_current_chan_is_touch(indio_dev)) + return 0; + + return iio_triggered_buffer_predisable(indio_dev); } static const struct iio_buffer_setup_ops at91_buffer_setup_ops = { + .preenable = &at91_adc_buffer_preenable, + .postdisable = &at91_adc_buffer_postdisable, .postenable = &at91_adc_buffer_postenable, .predisable = &at91_adc_buffer_predisable, }; @@ -1015,6 +1053,22 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev, int i = 0; int val; u8 bit; + u32 mask = at91_adc_active_scan_mask_to_reg(indio_dev); + unsigned int timeout = 50; + + /* + * Check if the conversion is ready. If not, wait a little bit, and + * in case of timeout exit with an error. + */ + while ((at91_adc_readl(st, AT91_SAMA5D2_ISR) & mask) != mask && + timeout) { + usleep_range(50, 100); + timeout--; + } + + /* Cannot read data, not ready. Continue without reporting data */ + if (!timeout) + return; for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->num_channels) { @@ -1102,6 +1156,13 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct at91_adc_state *st = iio_priv(indio_dev); + /* + * If it's not our trigger, start a conversion now, as we are + * actually polling the trigger now. + */ + if (iio_trigger_validate_own_device(indio_dev->trig, indio_dev)) + at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START); + if (st->dma_st.dma_chan) at91_adc_trigger_handler_dma(indio_dev); else @@ -1114,20 +1175,9 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) static int at91_adc_buffer_init(struct iio_dev *indio) { - struct at91_adc_state *st = iio_priv(indio); - - if (st->selected_trig->hw_trig) { - return devm_iio_triggered_buffer_setup(&indio->dev, indio, - &iio_pollfunc_store_time, - &at91_adc_trigger_handler, &at91_buffer_setup_ops); - } - /* - * we need to prepare the buffer ops in case we will get - * another buffer attached (like a callback buffer for the touchscreen) - */ - indio->setup_ops = &at91_buffer_setup_ops; - - return 0; + return devm_iio_triggered_buffer_setup(&indio->dev, indio, + &iio_pollfunc_store_time, + &at91_adc_trigger_handler, &at91_buffer_setup_ops); } static unsigned at91_adc_startup_time(unsigned startup_time_min, @@ -1281,7 +1331,8 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private) status = at91_adc_readl(st, AT91_SAMA5D2_XPOSR); status = at91_adc_readl(st, AT91_SAMA5D2_YPOSR); status = at91_adc_readl(st, AT91_SAMA5D2_PRESSR); - } else if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) { + } else if (iio_buffer_enabled(indio) && + (status & AT91_SAMA5D2_IER_DRDY)) { /* triggered buffer without DMA */ disable_irq_nosync(irq); iio_trigger_poll(indio->trig); @@ -1901,14 +1952,10 @@ static __maybe_unused int at91_adc_resume(struct device *dev) return 0; /* check if we are enabling triggered buffer or the touchscreen */ - if (bitmap_subset(indio_dev->active_scan_mask, - &st->touch_st.channels_bitmask, - AT91_SAMA5D2_MAX_CHAN_IDX + 1)) { - /* touchscreen enabling */ + if (at91_adc_current_chan_is_touch(indio_dev)) return at91_adc_configure_touch(st, true); - } else { + else return at91_adc_configure_trigger(st->trig, true); - } /* not needed but more explicit */ return 0; |