Re: [PATCH 4/4] iio: adc: at91-sama5d2: add support for sama7g5 device

From: Eugen.Hristev
Date: Mon Mar 08 2021 - 08:28:32 EST


On 06.03.2021 19:30, Jonathan Cameron wrote:
> On Mon, 1 Mar 2021 16:32:56 +0200
> Eugen Hristev <eugen.hristev@xxxxxxxxxxxxx> wrote:
>
>> Add support to sama7g5 ADC which is similar with sama5d2/sam9x60 device.
>> Differences are highlighted by compatible.
>> Main differences include 16 channels instead of 12 and missing
>> resistive touchscreen.
>>
>> Signed-off-by: Eugen Hristev <eugen.hristev@xxxxxxxxxxxxx>
>
> Hi Eugen,
>
> What tends to end up cleaner than the many scattered places you have
> had to bolt in part support here, is to use a per device type constant
> structure. That structure can contain register addresses where that
> is all the differs between parts, and callbacks for more complex cases.
>
> Along the lines of
>
> static const struct sam5d2_chip_info sam5d2_inf {
> .eoc_register = 0x33,
> .max_chan_idx = bob,
> .ccr = bob_function,
> ...
> };
>
> Then you can just put a pointer to this in the match_data and look that
> up in probe

Hi Jonathan,


Could you have a look a little at this driver though:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/watchdog/sama5d4_wdt.c

The specific support for 'sam9x60' was added by me, and the driver does
not look so bad after all, having if/else clauses nearly everywhere, and
getting that 'sam9x60_supported' bit from the compatible string comparison.

That's the reason why I tried to have this ADC driver in a similar fashion.

I like your approach as well, I guess it's just a matter of preference.
I will start to change things to implement it as you suggested if you
don't say otherwise.

Thanks for reviewing,
Eugen

>
>> ---
>> drivers/iio/adc/at91-sama5d2_adc.c | 287 +++++++++++++++++++++++------
>> 1 file changed, 234 insertions(+), 53 deletions(-)
>>
>> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
>> index 066d0ad644ca..d61fa32ef294 100644
>> --- a/drivers/iio/adc/at91-sama5d2_adc.c
>> +++ b/drivers/iio/adc/at91-sama5d2_adc.c
>> @@ -1,9 +1,11 @@
>> // SPDX-License-Identifier: GPL-2.0-only
>> /*
>> - * Atmel ADC driver for SAMA5D2 devices and compatible.
>> + * Microchip ADC driver for SAMA5D2/SAMA7G5 devices and compatible.
>> *
>> * Copyright (C) 2015 Atmel,
>> - * 2015 Ludovic Desroches <ludovic.desroches@xxxxxxxxx>
>> + * 2015 Ludovic Desroches <ludovic.desroches@xxxxxxxxxxxxx>,
>> + * 2021 Microchip Technology, Inc.,
>> + * 2021 Eugen Hristev <eugen.hristev@xxxxxxxxxxxxx>
>> */
>>
>> #include <linux/bitops.h>
>> @@ -117,14 +119,26 @@
>> #define AT91_SAMA5D2_ISR 0x30
>> /* Interrupt Status Register - Pen touching sense status */
>> #define AT91_SAMA5D2_ISR_PENS BIT(31)
>> +
>> +/* End of Conversion Interrupt Enable Register */
>> +#define AT91_SAMA7G5_EOC_IER 0x34
>> +/* End of Conversion Interrupt Disable Register */
>> +#define AT91_SAMA7G5_EOC_IDR 0x38
>> +/* End of Conversion Interrupt Mask Register */
>> +#define AT91_SAMA7G5_EOC_IMR 0x3c
>> +/* End of Conversion Interrupt Status Register */
>> +#define AT91_SAMA7G5_EOC_ISR 0x40
>> +
>> /* Last Channel Trigger Mode Register */
>> #define AT91_SAMA5D2_LCTMR 0x34
>> /* Last Channel Compare Window Register */
>> #define AT91_SAMA5D2_LCCWR 0x38
>> /* Overrun Status Register */
>> #define AT91_SAMA5D2_OVER 0x3c
>> +#define AT91_SAMA7G5_OVER 0x4c
>> /* Extended Mode Register */
>> #define AT91_SAMA5D2_EMR 0x40
>> +#define AT91_SAMA7G5_EMR 0x50
>> /* Extended Mode Register - Oversampling rate */
>> #define AT91_SAMA5D2_EMR_OSR(V) ((V) << 16)
>> #define AT91_SAMA5D2_EMR_OSR_MASK GENMASK(17, 16)
>> @@ -142,6 +156,9 @@
>> /* Channel Offset Register */
>> #define AT91_SAMA5D2_COR 0x4c
>> #define AT91_SAMA5D2_COR_DIFF_OFFSET 16
>> +/* Channel Configuration Register */
>> +#define AT91_SAMA7G5_CCR 0x5c
>> +#define AT91_SAMA7G5_COR_DIFF_OFFSET 0
>>
>> /* Analog Control Register */
>> #define AT91_SAMA5D2_ACR 0x94
>> @@ -185,6 +202,7 @@
>> #define AT91_SAMA5D2_PRESSR 0xbc
>> /* Trigger Register */
>> #define AT91_SAMA5D2_TRGR 0xc0
>> +#define AT91_SAMA7G5_TRGR 0x100
>> /* Mask for TRGMOD field of TRGR register */
>> #define AT91_SAMA5D2_TRGR_TRGMOD_MASK GENMASK(2, 0)
>> /* No trigger, only software trigger can start conversions */
>> @@ -214,19 +232,26 @@
>> #define AT91_SAMA5D2_WPSR 0xe8
>> /* Version Register */
>> #define AT91_SAMA5D2_VERSION 0xfc
>> +#define AT91_SAMA7G5_VERSION 0x130
>>
>> #define AT91_SAMA5D2_HW_TRIG_CNT 3
>> #define AT91_SAMA5D2_SINGLE_CHAN_CNT 12
>> +#define AT91_SAMA7G5_SINGLE_CHAN_CNT 16
>> #define AT91_SAMA5D2_DIFF_CHAN_CNT 6
>> +#define AT91_SAMA7G5_DIFF_CHAN_CNT 8
>>
>> #define AT91_SAMA5D2_TIMESTAMP_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
>> AT91_SAMA5D2_DIFF_CHAN_CNT + 1)
>>
>> +#define AT91_SAMA7G5_TIMESTAMP_CHAN_IDX (AT91_SAMA7G5_SINGLE_CHAN_CNT + \
>> + AT91_SAMA7G5_DIFF_CHAN_CNT + 1)
>> +
>> #define AT91_SAMA5D2_TOUCH_X_CHAN_IDX (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
>> AT91_SAMA5D2_DIFF_CHAN_CNT * 2)
>> #define AT91_SAMA5D2_TOUCH_Y_CHAN_IDX (AT91_SAMA5D2_TOUCH_X_CHAN_IDX + 1)
>> #define AT91_SAMA5D2_TOUCH_P_CHAN_IDX (AT91_SAMA5D2_TOUCH_Y_CHAN_IDX + 1)
>> #define AT91_SAMA5D2_MAX_CHAN_IDX AT91_SAMA5D2_TOUCH_P_CHAN_IDX
>> +#define AT91_SAMA7G5_MAX_CHAN_IDX AT91_SAMA7G5_TIMESTAMP_CHAN_IDX
>>
>> #define AT91_SAMA5D2_TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */
>> #define AT91_SAMA5D2_TOUCH_PEN_DETECT_DEBOUNCE_US 200
>> @@ -239,8 +264,19 @@
>> * Maximum number of bytes to hold conversion from all channels
>> * without the timestamp.
>> */
>> -#define AT91_BUFFER_MAX_CONVERSION_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT + \
>> - AT91_SAMA5D2_DIFF_CHAN_CNT) * 2)
>> +#define AT91_SAMA5D2_BUFFER_MAX_CONVERSION_BYTES ( \
>> + (AT91_SAMA5D2_SINGLE_CHAN_CNT + \
>> + AT91_SAMA5D2_DIFF_CHAN_CNT) * 2)
>> +
>> +#define AT91_SAMA7G5_BUFFER_MAX_CONVERSION_BYTES ( \
>> + (AT91_SAMA7G5_SINGLE_CHAN_CNT + \
>> + AT91_SAMA7G5_DIFF_CHAN_CNT) * 2)
>> +
>> +#define AT91_BUFFER_MAX_CONVERSION_BYTES ( \
>> + (AT91_SAMA7G5_BUFFER_MAX_CONVERSION_BYTES > \
>> + AT91_SAMA5D2_BUFFER_MAX_CONVERSION_BYTES) ? \
>> + AT91_SAMA7G5_BUFFER_MAX_CONVERSION_BYTES : \
>> + AT91_SAMA5D2_BUFFER_MAX_CONVERSION_BYTES)
>>
>> /* This total must also include the timestamp */
>> #define AT91_BUFFER_MAX_BYTES (AT91_BUFFER_MAX_CONVERSION_BYTES + 8)
>> @@ -295,6 +331,27 @@
>> .indexed = 1, \
>> }
>>
>> +#define AT91_SAMA7G5_CHAN_DIFF(num, num2, addr) \
>> + { \
>> + .type = IIO_VOLTAGE, \
>> + .differential = 1, \
>> + .channel = num, \
>> + .channel2 = num2, \
>> + .address = addr, \
>> + .scan_index = num + AT91_SAMA7G5_SINGLE_CHAN_CNT, \
>> + .scan_type = { \
>> + .sign = 's', \
>> + .realbits = 14, \
>> + .storagebits = 16, \
>> + }, \
>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
>> + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
>> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ)|\
>> + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
>> + .datasheet_name = "CH"#num"-CH"#num2, \
>> + .indexed = 1, \
>> + }
>> +
>> #define AT91_SAMA5D2_CHAN_TOUCH(num, name, mod) \
>> { \
>> .type = IIO_POSITIONRELATIVE, \
>> @@ -335,6 +392,8 @@ struct at91_adc_soc_info {
>> unsigned startup_time;
>> unsigned min_sample_rate;
>> unsigned max_sample_rate;
>> +#define AT91_ADC_SAMA7G5(st) ((st)->soc_info.sama7g5)
>> + bool sama7g5;
>> };
>>
>> struct at91_adc_trigger {
>> @@ -436,7 +495,7 @@ static const struct at91_adc_trigger at91_adc_trigger_list[] = {
>> },
>> };
>>
>> -static const struct iio_chan_spec at91_adc_channels[] = {
>> +static const struct iio_chan_spec at91_sama5d2_adc_channels[] = {
>> AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
>> AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
>> AT91_SAMA5D2_CHAN_SINGLE(2, 0x58),
>> @@ -461,6 +520,42 @@ static const struct iio_chan_spec at91_adc_channels[] = {
>> AT91_SAMA5D2_CHAN_PRESSURE(AT91_SAMA5D2_TOUCH_P_CHAN_IDX, "pressure"),
>> };
>>
>> +static const struct iio_chan_spec at91_sama7g5_adc_channels[] = {
>> + AT91_SAMA5D2_CHAN_SINGLE(0, 0x60),
>> + AT91_SAMA5D2_CHAN_SINGLE(1, 0x64),
>> + AT91_SAMA5D2_CHAN_SINGLE(2, 0x68),
>> + AT91_SAMA5D2_CHAN_SINGLE(3, 0x6c),
>> + AT91_SAMA5D2_CHAN_SINGLE(4, 0x70),
>> + AT91_SAMA5D2_CHAN_SINGLE(5, 0x74),
>> + AT91_SAMA5D2_CHAN_SINGLE(6, 0x78),
>> + AT91_SAMA5D2_CHAN_SINGLE(7, 0x7c),
>> + AT91_SAMA5D2_CHAN_SINGLE(8, 0x80),
>> + AT91_SAMA5D2_CHAN_SINGLE(9, 0x84),
>> + AT91_SAMA5D2_CHAN_SINGLE(10, 0x88),
>> + AT91_SAMA5D2_CHAN_SINGLE(11, 0x8c),
>> + AT91_SAMA5D2_CHAN_SINGLE(12, 0x90),
>> + AT91_SAMA5D2_CHAN_SINGLE(13, 0x94),
>> + AT91_SAMA5D2_CHAN_SINGLE(14, 0x98),
>> + AT91_SAMA5D2_CHAN_SINGLE(15, 0x9c),
>> + AT91_SAMA7G5_CHAN_DIFF(0, 1, 0x60),
>> + AT91_SAMA7G5_CHAN_DIFF(2, 3, 0x68),
>> + AT91_SAMA7G5_CHAN_DIFF(4, 5, 0x70),
>> + AT91_SAMA7G5_CHAN_DIFF(6, 7, 0x78),
>> + AT91_SAMA7G5_CHAN_DIFF(8, 9, 0x80),
>> + AT91_SAMA7G5_CHAN_DIFF(10, 11, 0x88),
>> + AT91_SAMA7G5_CHAN_DIFF(12, 13, 0x90),
>> + AT91_SAMA7G5_CHAN_DIFF(14, 15, 0x98),
>> + IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA7G5_TIMESTAMP_CHAN_IDX),
>> +};
>> +
>> +static unsigned int at91_adc_max_chan_idx(struct at91_adc_state *st)
>> +{
>> + if (AT91_ADC_SAMA7G5(st))
>> + return AT91_SAMA7G5_MAX_CHAN_IDX;
>> + else
>> + return AT91_SAMA5D2_MAX_CHAN_IDX;
>> +}
>> +
>> static int at91_adc_chan_xlate(struct iio_dev *indio_dev, int chan)
>> {
>> int i;
>> @@ -492,6 +587,7 @@ static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev)
>> {
>> u32 mask = 0;
>> u8 bit;
>> + struct at91_adc_state *st = iio_priv(indio_dev);
>>
>> for_each_set_bit(bit, indio_dev->active_scan_mask,
>> indio_dev->num_channels) {
>> @@ -500,13 +596,78 @@ static unsigned int at91_adc_active_scan_mask_to_reg(struct iio_dev *indio_dev)
>> mask |= BIT(chan->channel);
>> }
>>
>> - return mask & GENMASK(11, 0);
>> + return mask & GENMASK(at91_adc_max_chan_idx(st), 0);
>> +}
>> +
>> +static void at91_adc_ccr(struct at91_adc_state *st,
>> + struct iio_chan_spec const *chan)
>> +{
>> + u32 ccr, cur_ccr;
>> +
>> + ccr = (BIT(chan->channel) | BIT(chan->channel2));
>> +
>> + if (AT91_ADC_SAMA7G5(st)) {
>> + cur_ccr = at91_adc_readl(st, AT91_SAMA7G5_CCR);
>> + ccr <<= AT91_SAMA7G5_COR_DIFF_OFFSET;
>> + if (chan->differential)
>> + at91_adc_writel(st, AT91_SAMA7G5_CCR, cur_ccr | ccr);
>> + else
>> + at91_adc_writel(st, AT91_SAMA7G5_CCR, cur_ccr & ~ccr);
>> + } else {
>> + cur_ccr = at91_adc_readl(st, AT91_SAMA5D2_COR);
>> + ccr <<= AT91_SAMA5D2_COR_DIFF_OFFSET;
>> + if (chan->differential)
>> + at91_adc_writel(st, AT91_SAMA5D2_COR, cur_ccr | ccr);
>> + else
>> + at91_adc_writel(st, AT91_SAMA5D2_COR, cur_ccr & ~ccr);
>> + }
>> +}
>> +
>> +static void at91_adc_irq_status(struct at91_adc_state *st, u32 *status,
>> + u32 *eoc)
>> +{
>> + if (AT91_ADC_SAMA7G5(st)) {
>> + *status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
>> + *eoc = at91_adc_readl(st, AT91_SAMA7G5_EOC_ISR);
>> + } else {
>> + *status = *eoc = at91_adc_readl(st, AT91_SAMA5D2_ISR);
>> + }
>> +}
>> +
>> +static void at91_adc_irq_mask(struct at91_adc_state *st, u32 *status, u32 *eoc)
>> +{
>> + if (AT91_ADC_SAMA7G5(st)) {
>> + *status = at91_adc_readl(st, AT91_SAMA5D2_IMR);
>> + *eoc = at91_adc_readl(st, AT91_SAMA7G5_EOC_IMR);
>> + } else {
>> + *status = *eoc = at91_adc_readl(st, AT91_SAMA5D2_IMR);
>> + }
>> +}
>> +
>> +static void at91_adc_eoc_dis(struct at91_adc_state *st, unsigned int channel)
>> +{
>> + if (!AT91_ADC_SAMA7G5(st))
>> + at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(channel));
>> + /* for SAMA7G5, Errata recommends not writing to EOC_IDR register */
>> +}
>> +
>> +static void at91_adc_eoc_ena(struct at91_adc_state *st, unsigned int channel)
>> +{
>> + if (AT91_ADC_SAMA7G5(st))
>> + at91_adc_writel(st, AT91_SAMA7G5_EOC_IER, BIT(channel));
>> + else
>> + at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(channel));
>> }
>>
>> static void at91_adc_config_emr(struct at91_adc_state *st)
>> {
>> /* configure the extended mode register */
>> - unsigned int emr = at91_adc_readl(st, AT91_SAMA5D2_EMR);
>> + unsigned int emr;
>> +
>> + if (AT91_ADC_SAMA7G5(st))
>> + emr = at91_adc_readl(st, AT91_SAMA7G5_EMR);
>> + else
>> + emr = at91_adc_readl(st, AT91_SAMA5D2_EMR);
>>
>> /* select oversampling per single trigger event */
>> emr |= AT91_SAMA5D2_EMR_ASTE(1);
>> @@ -530,7 +691,10 @@ static void at91_adc_config_emr(struct at91_adc_state *st)
>> break;
>> }
>>
>> - at91_adc_writel(st, AT91_SAMA5D2_EMR, emr);
>> + if (AT91_ADC_SAMA7G5(st))
>> + at91_adc_writel(st, AT91_SAMA7G5_EMR, emr);
>> + else
>> + at91_adc_writel(st, AT91_SAMA5D2_EMR, emr);
>> }
>>
>> static int at91_adc_adjust_val_osr(struct at91_adc_state *st, int *val)
>> @@ -726,7 +890,12 @@ 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);
>> + u32 status;
>> +
>> + if (AT91_ADC_SAMA7G5(st))
>> + status = at91_adc_readl(st, AT91_SAMA7G5_TRGR);
>> + else
>> + status = at91_adc_readl(st, AT91_SAMA5D2_TRGR);
>>
>> /* clear TRGMOD */
>> status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK;
>> @@ -735,7 +904,10 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
>> status |= st->selected_trig->trgmod_value;
>>
>> /* set/unset hw trigger */
>> - at91_adc_writel(st, AT91_SAMA5D2_TRGR, status);
>> + if (AT91_ADC_SAMA7G5(st))
>> + at91_adc_writel(st, AT91_SAMA7G5_TRGR, status);
>> + else
>> + at91_adc_writel(st, AT91_SAMA5D2_TRGR, status);
>>
>> return 0;
>> }
>> @@ -877,7 +1049,7 @@ static bool at91_adc_current_chan_is_touch(struct iio_dev *indio_dev)
>>
>> return !!bitmap_subset(indio_dev->active_scan_mask,
>> &st->touch_st.channels_bitmask,
>> - AT91_SAMA5D2_MAX_CHAN_IDX + 1);
>> + at91_adc_max_chan_idx(st) + 1);
>> }
>>
>> static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
>> @@ -905,7 +1077,6 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
>> indio_dev->num_channels) {
>> struct iio_chan_spec const *chan =
>> at91_adc_chan_get(indio_dev, bit);
>> - u32 cor;
>>
>> if (!chan)
>> continue;
>> @@ -914,16 +1085,7 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
>> 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_ccr(st, chan);
>>
>> at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
>> }
>> @@ -975,7 +1137,10 @@ static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev)
>> 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);
>> + if (AT91_ADC_SAMA7G5(st))
>> + at91_adc_readl(st, AT91_SAMA7G5_OVER);
>> + else
>> + at91_adc_readl(st, AT91_SAMA5D2_OVER);
>>
>> /* if we are using DMA we must clear registers and end DMA */
>> if (st->dma_st.dma_chan)
>> @@ -1018,13 +1183,15 @@ static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
>> u8 bit;
>> u32 mask = at91_adc_active_scan_mask_to_reg(indio_dev);
>> unsigned int timeout = 50;
>> + u32 status, imr, eoc = 0, eoc_imr;
>>
>> /*
>> * 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) {
>> + while (((eoc & mask) != mask) && timeout) {
>> + at91_adc_irq_status(st, &status, &eoc);
>> + at91_adc_irq_mask(st, &imr, &eoc_imr);
>> usleep_range(50, 100);
>> timeout--;
>> }
>> @@ -1195,7 +1362,7 @@ static void at91_adc_touch_data_handler(struct iio_dev *indio_dev)
>> int i = 0;
>>
>> for_each_set_bit(bit, indio_dev->active_scan_mask,
>> - AT91_SAMA5D2_MAX_CHAN_IDX + 1) {
>> + at91_adc_max_chan_idx(st) + 1) {
>> struct iio_chan_spec const *chan =
>> at91_adc_chan_get(indio_dev, bit);
>>
>> @@ -1262,12 +1429,14 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
>> {
>> struct iio_dev *indio = private;
>> struct at91_adc_state *st = iio_priv(indio);
>> - u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
>> - u32 imr = at91_adc_readl(st, AT91_SAMA5D2_IMR);
>> + u32 status, eoc, imr, eoc_imr;
>> u32 rdy_mask = AT91_SAMA5D2_IER_XRDY | AT91_SAMA5D2_IER_YRDY |
>> AT91_SAMA5D2_IER_PRDY;
>>
>> - if (!(status & imr))
>> + at91_adc_irq_status(st, &status, &eoc);
>> + at91_adc_irq_mask(st, &imr, &eoc_imr);
>> +
>> + if (!(status & imr) && !(eoc & eoc_imr))
>> return IRQ_NONE;
>> if (status & AT91_SAMA5D2_IER_PEN) {
>> /* pen detected IRQ */
>> @@ -1309,7 +1478,6 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
>> struct iio_chan_spec const *chan, int *val)
>> {
>> struct at91_adc_state *st = iio_priv(indio_dev);
>> - u32 cor = 0;
>> u16 tmp_val;
>> int ret;
>>
>> @@ -1355,13 +1523,9 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
>>
>> st->chan = chan;
>>
>> - if (chan->differential)
>> - cor = (BIT(chan->channel) | BIT(chan->channel2)) <<
>> - AT91_SAMA5D2_COR_DIFF_OFFSET;
>> -
>> - at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
>> + at91_adc_ccr(st, chan);
>> at91_adc_writel(st, AT91_SAMA5D2_CHER, BIT(chan->channel));
>> - at91_adc_writel(st, AT91_SAMA5D2_IER, BIT(chan->channel));
>> + at91_adc_eoc_ena(st, chan->channel);
>> at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_START);
>>
>> ret = wait_event_interruptible_timeout(st->wq_data_available,
>> @@ -1378,7 +1542,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
>> st->conversion_done = false;
>> }
>>
>> - at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
>> + at91_adc_eoc_dis(st, st->chan->channel);
>> at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
>>
>> /* Needed to ACK the DRDY interruption */
>> @@ -1577,14 +1741,14 @@ static int at91_adc_update_scan_mode(struct iio_dev *indio_dev,
>> struct at91_adc_state *st = iio_priv(indio_dev);
>>
>> if (bitmap_subset(scan_mask, &st->touch_st.channels_bitmask,
>> - AT91_SAMA5D2_MAX_CHAN_IDX + 1))
>> + at91_adc_max_chan_idx(st) + 1))
>> return 0;
>> /*
>> * if the new bitmap is a combination of touchscreen and regular
>> * channels, then we are not fine
>> */
>> if (bitmap_intersects(&st->touch_st.channels_bitmask, scan_mask,
>> - AT91_SAMA5D2_MAX_CHAN_IDX + 1))
>> + at91_adc_max_chan_idx(st) + 1))
>> return -EINVAL;
>> return 0;
>> }
>> @@ -1594,6 +1758,8 @@ static void at91_adc_hw_init(struct iio_dev *indio_dev)
>> struct at91_adc_state *st = iio_priv(indio_dev);
>>
>> at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
>> + if (AT91_ADC_SAMA7G5(st))
>> + at91_adc_writel(st, AT91_SAMA7G5_EOC_IDR, 0xffffffff);
>> at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
>> /*
>> * Transfer field must be set to 2 according to the datasheet and
>> @@ -1718,18 +1884,27 @@ static int at91_adc_probe(struct platform_device *pdev)
>> indio_dev->name = dev_name(&pdev->dev);
>> indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
>> indio_dev->info = &at91_adc_info;
>> - indio_dev->channels = at91_adc_channels;
>> - indio_dev->num_channels = ARRAY_SIZE(at91_adc_channels);
>>
>> st = iio_priv(indio_dev);
>> st->indio_dev = indio_dev;
>>
>> - bitmap_set(&st->touch_st.channels_bitmask,
>> - AT91_SAMA5D2_TOUCH_X_CHAN_IDX, 1);
>> - bitmap_set(&st->touch_st.channels_bitmask,
>> - AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, 1);
>> - bitmap_set(&st->touch_st.channels_bitmask,
>> - AT91_SAMA5D2_TOUCH_P_CHAN_IDX, 1);
>> + st->soc_info.sama7g5 = of_device_is_compatible(pdev->dev.of_node,
>> + "microchip,sama7g5-adc");
>
> Better to use match_data to get an enum value which is used to index
> into a table of support part description structures. Each of those
> structures has all the registers etc + channel specs and callbacks
> where needed for more complex handling.
>
> Other advantage is you can introduce the structures in a precursor patch with
> just one entry for existing behaviour. The new device support is then added
> in a second patch. All we need to do then is check first patch is a noop
> and that second much shorter patch makes sense.
>
>> +
>> + if (AT91_ADC_SAMA7G5(st)) {
>> + indio_dev->channels = at91_sama7g5_adc_channels;
>> + indio_dev->num_channels = ARRAY_SIZE(at91_sama7g5_adc_channels);
>> + } else {
>> + indio_dev->channels = at91_sama5d2_adc_channels;
>> + indio_dev->num_channels = ARRAY_SIZE(at91_sama5d2_adc_channels);
>> +
>> + bitmap_set(&st->touch_st.channels_bitmask,
>> + AT91_SAMA5D2_TOUCH_X_CHAN_IDX, 1);
>> + bitmap_set(&st->touch_st.channels_bitmask,
>> + AT91_SAMA5D2_TOUCH_Y_CHAN_IDX, 1);
>> + bitmap_set(&st->touch_st.channels_bitmask,
>> + AT91_SAMA5D2_TOUCH_P_CHAN_IDX, 1);
>> + }
>>
>> st->oversampling_ratio = AT91_OSR_1SAMPLES;
>>
>> @@ -1853,9 +2028,12 @@ static int at91_adc_probe(struct platform_device *pdev)
>> dev_info(&pdev->dev, "setting up trigger as %s\n",
>> st->selected_trig->name);
>>
>> - dev_info(&pdev->dev, "version: %x\n",
>> - readl_relaxed(st->base + AT91_SAMA5D2_VERSION));
>> -
>> + if (AT91_ADC_SAMA7G5(st))
>
> We may be better off with a look up table of all the registers
> (+ if needed some callback functions) rather than a whole bunch of
> if statements.
>
> You then just assign the right 'part number specific' structure
> once in probe.
>
>> + dev_info(&pdev->dev, "version: %x\n",
>> + at91_adc_readl(st, AT91_SAMA7G5_VERSION));
>> + else
>> + dev_info(&pdev->dev, "version: %x\n",
>> + at91_adc_readl(st, AT91_SAMA5D2_VERSION));
>> return 0;
>>
>> dma_disable:
>> @@ -1957,6 +2135,8 @@ static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
>> static const struct of_device_id at91_adc_dt_match[] = {
>> {
>> .compatible = "atmel,sama5d2-adc",
>> + }, {
>> + .compatible = "microchip,sama7g5-adc",
>> }, {
>> /* sentinel */
>> }
>> @@ -1967,13 +2147,14 @@ static struct platform_driver at91_adc_driver = {
>> .probe = at91_adc_probe,
>> .remove = at91_adc_remove,
>> .driver = {
>> - .name = "at91-sama5d2_adc",
>> + .name = "at91-sama5d2-sama7g5_adc",
>
> Please keep the driver name the same. It's common to have a name of one
> random part a driver supports used even if there are lots of others.
> This (or wild cards) never scales as more parts are added to a driver.
>
>> .of_match_table = at91_adc_dt_match,
>> .pm = &at91_adc_pm_ops,
>> },
>> };
>> module_platform_driver(at91_adc_driver)
>>
>> -MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@xxxxxxxxx>");
>> -MODULE_DESCRIPTION("Atmel AT91 SAMA5D2 ADC");
>> +MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches@xxxxxxxxxxxxx>");
>> +MODULE_AUTHOR("Eugen Hristev <eugen.hristev@xxxxxxxxxxxxx>");
>> +MODULE_DESCRIPTION("Microchip AT91 SAMA5D2/SAMA7G5 ADC");
>> MODULE_LICENSE("GPL v2");
>