From f5e91affbe2687f0fce78be4525f9d9c1fef93d7 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sat, 13 Jun 2020 23:23:45 +0200 Subject: [PATCH] iio/adc: ingenic: Add support for sampling X-/Y- and X/Y differential There are now 6 stream-capable channels: - channel #0 samples X+/GND (like before) - channel #1 samples Y+/GND (like before) - channel #2 samples X-/GND - channel #3 samples Y-/GND - channel #4 samples X+/X- - channel #5 samples Y+/Y- Being able to sample X-/GND and Y-/GND is useful on some devices, where one joystick is connected to the X+/Y+ pins, and a second joystick is connected to the X-/Y- pins. Signed-off-by: Paul Cercueil --- drivers/iio/adc/ingenic-adc.c | 110 +++++++++++++++++++--- include/dt-bindings/iio/adc/ingenic,adc.h | 4 + 2 files changed, 99 insertions(+), 15 deletions(-) diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 1cbf611f9f627a..9222fc8a59f72c 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -107,7 +107,7 @@ struct ingenic_adc { bool low_vref_mode; }; -static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev) +static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask) { struct ingenic_adc *adc = iio_priv(iio_dev); @@ -116,17 +116,45 @@ static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev) /* Init ADCMD */ readl(adc->base + JZ_ADC_REG_ADCMD); - /* Second channel (INGENIC_ADC_TOUCH_YP): sample YP vs. GND */ - writel(JZ_ADC_REG_ADCMD_XNGRU - | JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33 - | JZ_ADC_REG_ADCMD_YPADC, - adc->base + JZ_ADC_REG_ADCMD); + if (mask & 0x3) { + /* Second channel (INGENIC_ADC_TOUCH_YP): sample YP vs. GND */ + writel(JZ_ADC_REG_ADCMD_XNGRU + | JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33 + | JZ_ADC_REG_ADCMD_YPADC, + adc->base + JZ_ADC_REG_ADCMD); + + /* First channel (INGENIC_ADC_TOUCH_XP): sample XP vs. GND */ + writel(JZ_ADC_REG_ADCMD_YNGRU + | JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33 + | JZ_ADC_REG_ADCMD_XPADC, + adc->base + JZ_ADC_REG_ADCMD); + } + + if (mask & 0xc) { + /* Fourth channel (INGENIC_ADC_TOUCH_YN): sample YN vs. GND */ + writel(JZ_ADC_REG_ADCMD_XNGRU + | JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33 + | JZ_ADC_REG_ADCMD_YNADC, + adc->base + JZ_ADC_REG_ADCMD); + + /* Third channel (INGENIC_ADC_TOUCH_XN): sample XN vs. GND */ + writel(JZ_ADC_REG_ADCMD_YNGRU + | JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33 + | JZ_ADC_REG_ADCMD_XNADC, + adc->base + JZ_ADC_REG_ADCMD); + } - /* First channel (INGENIC_ADC_TOUCH_XP): sample XP vs. GND */ - writel(JZ_ADC_REG_ADCMD_YNGRU - | JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33 - | JZ_ADC_REG_ADCMD_XPADC, - adc->base + JZ_ADC_REG_ADCMD); + if (mask & 0x30) { + /* Sixth channel (INGENIC_ADC_TOUCH_YD): sample YP vs. YN */ + writel(JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33 + | JZ_ADC_REG_ADCMD_YPADC, + adc->base + JZ_ADC_REG_ADCMD); + + /* Fifth channel (INGENIC_ADC_TOUCH_XD): sample XP vs. XN */ + writel(JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33 + | JZ_ADC_REG_ADCMD_XPADC, + adc->base + JZ_ADC_REG_ADCMD); + } /* We're done */ writel(0, adc->base + JZ_ADC_REG_ADCMD); @@ -397,6 +425,50 @@ static const struct iio_chan_spec jz4770_channels[] = { .storagebits = 16, }, }, + { + .type = IIO_POSITIONRELATIVE, + .indexed = 1, + .channel = INGENIC_ADC_TOUCH_XN, + .scan_index = 2, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, + { + .type = IIO_POSITIONRELATIVE, + .indexed = 1, + .channel = INGENIC_ADC_TOUCH_YN, + .scan_index = 3, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, + { + .type = IIO_POSITIONRELATIVE, + .indexed = 1, + .channel = INGENIC_ADC_TOUCH_XD, + .scan_index = 4, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, + { + .type = IIO_POSITIONRELATIVE, + .indexed = 1, + .channel = INGENIC_ADC_TOUCH_YD, + .scan_index = 5, + .scan_type = { + .sign = 'u', + .realbits = 12, + .storagebits = 16, + }, + }, { .extend_name = "aux", .type = IIO_VOLTAGE, @@ -628,7 +700,7 @@ static int ingenic_adc_buffer_enable(struct iio_dev *iio_dev) if (adc->soc_data->has_adcmd) { ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_CMD_SEL, JZ_ADC_REG_CFG_CMD_SEL); - ingenic_adc_set_adcmd(iio_dev); + ingenic_adc_set_adcmd(iio_dev, iio_dev->active_scan_mask[0]); } ingenic_adc_enable(adc, 2, true); @@ -664,10 +736,18 @@ static irqreturn_t ingenic_adc_irq(int irq, void *data) { struct iio_dev *iio_dev = data; struct ingenic_adc *adc = iio_priv(iio_dev); - u32 tdat; + unsigned long mask = iio_dev->active_scan_mask[0]; + unsigned int i; + u32 tdat[3]; + + for (i = 0; i < ARRAY_SIZE(tdat); mask >>= 2, i++) { + if (mask & 0x3) + tdat[i] = readl(adc->base + JZ_ADC_REG_ADTCH); + else + tdat[i] = 0; + } - tdat = readl(adc->base + JZ_ADC_REG_ADTCH); - iio_push_to_buffers(iio_dev, &tdat); + iio_push_to_buffers(iio_dev, tdat); writeb(JZ_ADC_IRQ_TOUCH, adc->base + JZ_ADC_REG_STATUS); return IRQ_HANDLED; diff --git a/include/dt-bindings/iio/adc/ingenic,adc.h b/include/dt-bindings/iio/adc/ingenic,adc.h index 95e20a8d6dc8f2..4627a00e369ea8 100644 --- a/include/dt-bindings/iio/adc/ingenic,adc.h +++ b/include/dt-bindings/iio/adc/ingenic,adc.h @@ -9,5 +9,9 @@ #define INGENIC_ADC_AUX2 2 #define INGENIC_ADC_TOUCH_XP 3 #define INGENIC_ADC_TOUCH_YP 4 +#define INGENIC_ADC_TOUCH_XN 5 +#define INGENIC_ADC_TOUCH_YN 6 +#define INGENIC_ADC_TOUCH_XD 7 +#define INGENIC_ADC_TOUCH_YD 8 #endif