This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 08b8234e9e arch/arm/src/stm32f7: port ADC driver from arch/stm32
08b8234e9e is described below

commit 08b8234e9e90ee20913e203050a96b98ce2a55fc
Author: raiden00pl <[email protected]>
AuthorDate: Sat Jul 30 18:20:20 2022 +0200

    arch/arm/src/stm32f7: port ADC driver from arch/stm32
    
    This change adds support for the following features:
      - injected channels (default: 0)
      - ADC resolution (default: 12bit)
      - ADC low-level operations
      - ADC external triggers
      - custom ADC interrupts
      - ADC sample time configuration
      - configurable ADC SCAN mode (default on if DMA)
      - configurable ADC DMA mode (default: one shot mode)
      - reset the ADC block only if all ADC instances are closed
---
 arch/arm/src/stm32f7/Kconfig                       |  192 ++
 arch/arm/src/stm32f7/hardware/stm32f72xx73xx_adc.h |    2 +
 arch/arm/src/stm32f7/hardware/stm32f74xx77xx_adc.h |    2 +
 arch/arm/src/stm32f7/stm32_adc.c                   | 1887 ++++++++++++++++----
 arch/arm/src/stm32f7/stm32_adc.h                   |  424 ++++-
 5 files changed, 2116 insertions(+), 391 deletions(-)

diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig
index 388ef1d975..2dbf77eaad 100644
--- a/arch/arm/src/stm32f7/Kconfig
+++ b/arch/arm/src/stm32f7/Kconfig
@@ -6089,12 +6089,66 @@ endmenu
 menu "ADC Configuration"
        depends on STM32F7_ADC
 
+config STM32F7_ADC1_RESOLUTION
+       int "ADC1 resolution"
+       depends on STM32F7_ADC1
+       default 0
+       range 0 3
+       ---help---
+               ADC1 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit
+
+config STM32F7_ADC2_RESOLUTION
+       int "ADC2 resolution"
+       depends on STM32F7_ADC2
+       default 0
+       range 0 3
+       ---help---
+               ADC2 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit
+
+config STM32F7_ADC3_RESOLUTION
+       int "ADC3 resolution"
+       depends on STM32F7_ADC3
+       default 0
+       range 0 3
+       ---help---
+               ADC3 resolution. 0 - 12 bit, 1 - 10 bit, 2 - 8 bit, 3 - 6 bit
+
+config STM32F7_ADC_MAX_SAMPLES
+       int "The maximum number of channels that can be sampled"
+       default 16
+       ---help---
+               The maximum number of samples which can be handled without
+               overrun depends on various factors. This is the user's
+               responsibility to correctly select this value.
+               Since the interface to update the sampling time is available
+               for all supported devices, the user can change the default
+               values in the board initialization logic and avoid ADC overrun.
+
 config STM32F7_ADC_NO_STARTUP_CONV
        bool "Do not start conversion when opening ADC device"
        default n
        ---help---
                Do not start conversion when opening ADC device.
 
+config STM32F7_ADC_NOIRQ
+       bool "Do not use default ADC interrupts"
+       default n
+       ---help---
+               Do not use default ADC interrupts handlers.
+
+config STM32F7_ADC_LL_OPS
+       bool "ADC low-level operations"
+       default n
+       ---help---
+               Enable low-level ADC ops.
+
+config STM32F7_ADC_CHANGE_SAMPLETIME
+       bool "ADC sample time configuration"
+       default n
+       depends on STM32F7_ADC_LL_OPS
+       ---help---
+               Enable ADC sample time configuration (SMPRx registers).
+
 config STM32F7_ADC1_DMA
        bool "ADC1 DMA"
        depends on STM32F7_ADC1 && STM32F7_HAVE_ADC1_DMA
@@ -6104,6 +6158,30 @@ config STM32F7_ADC1_DMA
                DMA transfer, which is necessary if multiple channels are read
                or if very high trigger frequencies are used.
 
+config STM32F7_ADC1_SCAN
+       bool "ADC1 scan mode"
+       depends on STM32F7_ADC1
+       default y if STM32F7_ADC1_DMA
+       default n
+
+config STM32F7_ADC1_DMA_CFG
+       int "ADC1 DMA configuration"
+       depends on STM32F7_ADC1_DMA
+       range 0 1
+       default 0
+       ---help---
+               0 - ADC1 DMA in One Shot Mode, 1 - ADC1 DMA in Circular Mode
+
+config STM32F7_ADC1_ANIOC_TRIGGER
+       int "ADC1 software trigger (ANIOC_TRIGGER) configuration"
+       depends on STM32F7_ADC1
+       range 1 3
+       default 3
+       ---help---
+               1 - ANIOC_TRIGGER only starts regular conversion
+               2 - ANIOC_TRIGGER only starts injected conversion
+               3 - ANIOC_TRIGGER starts both regular and injected conversions
+
 config STM32F7_ADC2_DMA
        bool "ADC2 DMA"
        depends on STM32F7_ADC2 && STM32F7_HAVE_ADC2_DMA
@@ -6113,6 +6191,30 @@ config STM32F7_ADC2_DMA
                DMA transfer, which is necessary if multiple channels are read
                or if very high trigger frequencies are used.
 
+config STM32F7_ADC2_SCAN
+       bool "ADC2 scan mode"
+       depends on STM32F7_ADC2
+       default y if STM32F7_ADC2_DMA
+       default n
+
+config STM32F7_ADC2_DMA_CFG
+       int "ADC2 DMA configuration"
+       depends on STM32F7_ADC2_DMA
+       range 0 1
+       default 0
+       ---help---
+               0 - ADC2 DMA in One Shot Mode, 1 - ADC2 DMA in Circular Mode
+
+config STM32F7_ADC2_ANIOC_TRIGGER
+       int "ADC2 software trigger (ANIOC_TRIGGER) configuration"
+       depends on STM32F7_ADC2
+       range 1 3
+       default 3
+       ---help---
+               1 - ANIOC_TRIGGER only starts regular conversion
+               2 - ANIOC_TRIGGER only starts injected conversion
+               3 - ANIOC_TRIGGER starts both regular and injected conversions
+
 config STM32F7_ADC3_DMA
        bool "ADC3 DMA"
        depends on STM32F7_ADC3 && STM32F7_HAVE_ADC3_DMA
@@ -6122,6 +6224,96 @@ config STM32F7_ADC3_DMA
                DMA transfer, which is necessary if multiple channels are read
                or if very high trigger frequencies are used.
 
+config STM32F7_ADC3_SCAN
+       bool "ADC3 scan mode"
+       depends on STM32F7_ADC3
+       default y if STM32F7_ADC3_DMA
+       default n
+
+config STM32F7_ADC3_DMA_CFG
+       int "ADC3 DMA configuration"
+       depends on STM32F7_ADC3_DMA
+       range 0 1
+       default 0
+       ---help---
+               0 - ADC3 DMA in One Shot Mode, 1 - ADC3 DMA in Circular Mode
+
+config STM32F7_ADC3_ANIOC_TRIGGER
+       int "ADC3 software trigger (ANIOC_TRIGGER) configuration"
+       depends on STM32F7_ADC3
+       range 1 3
+       default 3
+       ---help---
+               1 - ANIOC_TRIGGER only starts regular conversion
+               2 - ANIOC_TRIGGER only starts injected conversion
+               3 - ANIOC_TRIGGER starts both regular and injected conversions
+
+config STM32F7_ADC1_INJECTED_CHAN
+       int "ADC1 injected channels"
+       depends on STM32F7_ADC1
+       range 0 4
+       default 0
+       ---help---
+               Support for ADC1 injected channels.
+
+config STM32F7_ADC2_INJECTED_CHAN
+       int "ADC2 injected channels"
+       depends on STM32F7_ADC2
+       range 0 4
+       default 0
+       ---help---
+               Support for ADC2 injected channels.
+
+config STM32F7_ADC3_INJECTED_CHAN
+       int "ADC3 injected channels"
+       depends on STM32F7_ADC3
+       range 0 4
+       default 0
+       ---help---
+               Support for ADC3 injected channels.
+
+config STM32F7_ADC1_EXTSEL
+       bool "ADC1 external trigger for regular group"
+       depends on STM32F7_ADC1 && !STM32F7_HAVE_ADC1_TIMER
+       default n
+       ---help---
+               Enable EXTSEL for ADC1.
+
+config STM32F7_ADC2_EXTSEL
+       bool "ADC2 external trigger for regular group"
+       depends on STM32F7_ADC2 && !STM32F7_HAVE_ADC2_TIMER
+       default n
+       ---help---
+               Enable EXTSEL for ADC2.
+
+config STM32F7_ADC3_EXTSEL
+       bool "ADC3 external trigger for regular group"
+       depends on STM32F7_ADC3 && !STM32F7_HAVE_ADC3_TIMER
+       default n
+       ---help---
+               Enable EXTSEL for ADC3.
+
+config STM32F7_ADC1_JEXTSEL
+       bool "ADC1 external trigger for injected group"
+       depends on STM32F7_ADC1
+       default n
+       ---help---
+               Enable JEXTSEL for ADC1.
+
+config STM32F7_ADC2_JEXTSEL
+       bool "ADC2 external trigger for injected group"
+       depends on STM32F7_ADC2
+       default n
+       ---help---
+               Enable JEXTSEL for ADC2.
+
+config STM32F7_ADC3_JEXTSEL
+       bool "ADC3 external trigger for injected group"
+       depends on STM32F7_ADC3
+       default n
+       ---help---
+               Enable JEXTSEL for ADC3.
+
 endmenu # "ADC Configuration"
 
 menu "Ethernet MAC configuration"
diff --git a/arch/arm/src/stm32f7/hardware/stm32f72xx73xx_adc.h 
b/arch/arm/src/stm32f7/hardware/stm32f72xx73xx_adc.h
index 9fa38fb02f..083f66074b 100644
--- a/arch/arm/src/stm32f7/hardware/stm32f72xx73xx_adc.h
+++ b/arch/arm/src/stm32f7/hardware/stm32f72xx73xx_adc.h
@@ -372,8 +372,10 @@
 #define ADC_JSQR_JSQ3_MASK           (0x1f << ADC_JSQR_JSQ3_SHIFT)
 #define ADC_JSQR_JSQ4_SHIFT          (15)      /* Bits 19-15: 4th conversion 
in injected sequence */
 #define ADC_JSQR_JSQ4_MASK           (0x1f << ADC_JSQR_JSQ4_SHIFT)
+#define ADC_JSQR_JSQ_SHIFT           (5)       /* Shift between JSQx bits */
 #define ADC_JSQR_JL_SHIFT            (20)      /* Bits 21-20: Injected 
Sequence length */
 #define ADC_JSQR_JL_MASK             (3 << ADC_JSQR_JL_SHIFT)
+#  define ADC_JSQR_JL(n)             (((n) - 1) << ADC_JSQR_JL_SHIFT) /* 
n=1..4 */
 
 /* ADC injected data register 1-4 */
 
diff --git a/arch/arm/src/stm32f7/hardware/stm32f74xx77xx_adc.h 
b/arch/arm/src/stm32f7/hardware/stm32f74xx77xx_adc.h
index 2ec4d963b8..9b2a598833 100644
--- a/arch/arm/src/stm32f7/hardware/stm32f74xx77xx_adc.h
+++ b/arch/arm/src/stm32f7/hardware/stm32f74xx77xx_adc.h
@@ -372,8 +372,10 @@
 #define ADC_JSQR_JSQ3_MASK           (0x1f << ADC_JSQR_JSQ3_SHIFT)
 #define ADC_JSQR_JSQ4_SHIFT          (15)      /* Bits 19-15: 4th conversion 
in injected sequence */
 #define ADC_JSQR_JSQ4_MASK           (0x1f << ADC_JSQR_JSQ4_SHIFT)
+#define ADC_JSQR_JSQ_SHIFT           (5)       /* Shift between JSQx bits */
 #define ADC_JSQR_JL_SHIFT            (20)      /* Bits 21-20: Injected 
Sequence length */
 #define ADC_JSQR_JL_MASK             (3 << ADC_JSQR_JL_SHIFT)
+#  define ADC_JSQR_JL(n)             (((n) - 1) << ADC_JSQR_JL_SHIFT) /* 
n=1..4 */
 
 /* ADC injected data register 1-4 */
 
diff --git a/arch/arm/src/stm32f7/stm32_adc.c b/arch/arm/src/stm32f7/stm32_adc.c
index 5a23886e96..c452001a46 100644
--- a/arch/arm/src/stm32f7/stm32_adc.c
+++ b/arch/arm/src/stm32f7/stm32_adc.c
@@ -45,6 +45,7 @@
 #include <nuttx/power/pm.h>
 #include <nuttx/analog/adc.h>
 #include <nuttx/analog/ioctl.h>
+#include <nuttx/semaphore.h>
 
 #include "arm_internal.h"
 #include "chip.h"
@@ -53,20 +54,21 @@
 #include "stm32_dma.h"
 #include "stm32_adc.h"
 
-/* ADC "upper half" support must be enabled */
+/* Based on arch/src/stm32/stm32_adc.c */
 
-#ifdef CONFIG_ADC
-
-/* Some ADC peripheral must be enabled */
+/* STM32 ADC "lower-half" support must be enabled */
 
-#if defined(CONFIG_STM32F7_ADC1) || defined(CONFIG_STM32F7_ADC2) || \
-    defined(CONFIG_STM32F7_ADC3)
+#ifdef CONFIG_STM32F7_ADC
 
-/* This implementation is for the STM32 F7[4-7] only */
+/* This implementation is for the STM32 ADC IP version 1 */
 
-#if defined(CONFIG_STM32F7_STM32F72XX) || defined(CONFIG_STM32F7_STM32F73XX) 
|| \
-    defined(CONFIG_STM32F7_STM32F74XX) || defined(CONFIG_STM32F7_STM32F75XX) 
|| \
-    defined(CONFIG_STM32F7_STM32F76XX) || defined(CONFIG_STM32F7_STM32F77XX)
+/* Supported ADC modes:
+ *   - SW triggering with/without DMA transfer
+ *   - TIM triggering with/without DMA transfer
+ *   - external triggering with/without DMA transfer
+ *
+ * (tested with ADC example app from NuttX apps repo).
+ */
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -74,65 +76,18 @@
 
 /* RCC reset ****************************************************************/
 
-#define STM32_RCC_RSTR   STM32_RCC_APB2RSTR
-#define RCC_RSTR_ADC1RST RCC_APB2RSTR_ADCRST
-#define RCC_RSTR_ADC2RST RCC_APB2RSTR_ADCRST
-#define RCC_RSTR_ADC3RST RCC_APB2RSTR_ADCRST
-
-/* ADC interrupts ***********************************************************/
-
-#define STM32_ADC_DMAREG_OFFSET    STM32_ADC_CR2_OFFSET
-#define ADC_DMAREG_DMA             ADC_CR2_DMA
-#define STM32_ADC_EXTREG_OFFSET    STM32_ADC_CR2_OFFSET
-#define ADC_EXTREG_EXTSEL_MASK     ADC_CR2_EXTSEL_MASK
-#define STM32_ADC_ISR_OFFSET       STM32_ADC_SR_OFFSET
-#define STM32_ADC_IER_OFFSET       STM32_ADC_CR1_OFFSET
-#define ADC_ISR_EOC                ADC_SR_EOC
-#define ADC_IER_EOC                ADC_CR1_EOCIE
-#define ADC_ISR_AWD                ADC_SR_AWD
-#define ADC_IER_AWD                ADC_CR1_AWDIE
-#define ADC_ISR_JEOC               ADC_SR_JEOC
-#define ADC_IER_JEOC               ADC_CR1_JEOCIE
-#define ADC_EXTREG_EXTEN_MASK      ADC_CR2_EXTEN_MASK
-#define ADC_EXTREG_EXTEN_NONE      ADC_CR2_EXTEN_NONE
-#define ADC_EXTREG_EXTEN_DEFAULT   ADC_CR2_EXTEN_RISING
-#define ADC_ISR_OVR                ADC_SR_OVR
-#define ADC_IER_OVR                ADC_CR1_OVRIE
-
-#define ADC_ISR_ALLINTS (ADC_ISR_EOC | ADC_ISR_AWD | ADC_ISR_JEOC | \
-                         ADC_ISR_OVR)
-#define ADC_IER_ALLINTS (ADC_IER_EOC | ADC_IER_AWD | ADC_IER_JEOC | \
-                         ADC_IER_OVR)
+#define STM32_RCC_RSTR     STM32_RCC_APB2RSTR
+#define RCC_RSTR_ADC123RST RCC_APB2RSTR_ADCRST
 
 /* ADC Channels/DMA *********************************************************/
 
-/* The maximum number of channels that can be sampled.  If DMA support is
- * not enabled, then only a single channel can be sampled.  Otherwise,
- * data overruns would occur.
- */
-
-#define ADC_MAX_CHANNELS_DMA   16
-#define ADC_MAX_CHANNELS_NODMA 1
-
-#ifdef ADC_HAVE_DMA
-#  ifndef CONFIG_STM32F7_DMA2
-#    error "STM32F7 ADC DMA support requires CONFIG_STM32F7_DMA2"
-#  endif
-#endif
-
-#ifdef ADC_HAVE_DMA
-#  define ADC_MAX_SAMPLES ADC_MAX_CHANNELS_DMA
-#else
-#  define ADC_MAX_SAMPLES ADC_MAX_CHANNELS_NODMA
-#endif
-
-#define ADC_DMA_CONTROL_WORD (DMA_SCR_MSIZE_16BITS | \
-                                DMA_SCR_PSIZE_16BITS | \
-                                DMA_SCR_MINC | \
-                                DMA_SCR_CIRC | \
-                                DMA_SCR_DIR_P2M)
+#define ADC_DMA_CONTROL_WORD (DMA_SCR_MSIZE_16BITS |  \
+                              DMA_SCR_PSIZE_16BITS |  \
+                              DMA_SCR_MINC |          \
+                              DMA_SCR_CIRC |          \
+                              DMA_SCR_DIR_P2M)
 
-/* DMA channels and interface values */
+/* Sample time default configuration */
 
 #define ADC_SMPR_DEFAULT    ADC_SMPR_112
 #define ADC_SMPR1_DEFAULT   ((ADC_SMPR_DEFAULT << ADC_SMPR1_SMP10_SHIFT) | \
@@ -155,6 +110,41 @@
                                (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP8_SHIFT) | \
                                (ADC_SMPR_DEFAULT << ADC_SMPR2_SMP9_SHIFT))
 
+/* Number of channels per ADC */
+
+#define ADC_CHANNELS_NUMBER 19
+
+/* Max 4 injected channels */
+
+#define ADC_INJ_MAX_SAMPLES   4
+
+/* ADC scan mode support */
+
+#ifndef CONFIG_STM32F7_ADC1_SCAN
+#  define CONFIG_STM32F7_ADC1_SCAN 0
+#endif
+#ifndef CONFIG_STM32F7_ADC2_SCAN
+#  define CONFIG_STM32F7_ADC2_SCAN 0
+#endif
+#ifndef CONFIG_STM32F7_ADC3_SCAN
+#  define CONFIG_STM32F7_ADC3_SCAN 0
+#endif
+
+/* We have to support ADC callbacks if default ADC interrupts or
+ * DMA transfer are enabled
+ */
+
+#if !defined(CONFIG_STM32F7_ADC_NOIRQ) || defined(ADC_HAVE_DMA)
+#  define ADC_HAVE_CB
+#else
+#  undef ADC_HAVE_CB
+#endif
+
+/* ADC software trigger configuration */
+
+#define ANIOC_TRIGGER_REGULAR  (1 << 0)
+#define ANIOC_TRIGGER_INJECTED (1 << 1)
+
 /* The last external channel on ADC 1 to enable Reading Vref or
  * Vbat / Vsence
  */
@@ -181,32 +171,68 @@
  * Private Types
  ****************************************************************************/
 
+/* Data common to all ADC instances */
+
+struct adccmn_data_s
+{
+  uint8_t refcount; /* How many ADC instances are currently in use */
+  sem_t   lock;     /* Exclusive access to common ADC data */
+};
+
 /* This structure describes the state of one ADC block */
 
 struct stm32_dev_s
 {
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+  const struct stm32_adc_ops_s *llops; /* Low-level ADC ops */
+  struct adc_dev_s             *dev;   /* Upper-half ADC reference */
+#endif
+#ifdef ADC_HAVE_CB
   const struct adc_callback_s *cb;
-  uint8_t irq;          /* Interrupt generated by this ADC block */
-  uint8_t nchannels;    /* Number of channels */
-  uint8_t cchannels;    /* Number of configured channels */
-  uint8_t intf;         /* ADC interface number */
-  uint8_t current;      /* Current ADC channel being converted */
+  uint8_t irq;               /* Interrupt generated by this ADC block */
+#endif
+  struct adccmn_data_s *cmn; /* Common ADC data */
+  uint8_t rnchannels;        /* Number of regular channels */
+  uint8_t cr_channels;       /* Number of configured regular channels */
+#ifdef ADC_HAVE_INJECTED
+  uint8_t cj_channels;       /* Number of configured injected channels */
+#endif
+  uint8_t intf;              /* ADC interface number */
+  uint8_t initialized;       /* ADC interface initialization counter */
+  uint8_t current;           /* Current ADC channel being converted */
+  uint8_t anioc_trg;         /* ANIOC_TRIGGER configuration */
+  uint8_t resolution;        /* ADC resolution (0-3) */
 #ifdef ADC_HAVE_DMA
-  uint8_t dmachan;      /* DMA channel needed by this ADC */
-  bool    hasdma;       /* True: This channel supports DMA */
+  uint8_t dmachan;           /* DMA channel needed by this ADC */
+  uint8_t dmacfg;            /* DMA channel configuration, only for ADC IPv2 */
+  bool    hasdma;            /* True: This channel supports DMA */
+#endif
+  bool    scan;              /* True: Scan mode */
+#ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+  /* Sample time selection. These bits must be written only when ADON=0.
+   * REVISIT: this takes too much space. We need only 3 bits per channel.
+   */
+
+  uint8_t sample_rate[ADC_CHANNELS_NUMBER];
+  uint8_t adc_channels;      /* ADC channels number */
 #endif
 #ifdef ADC_HAVE_TIMER
-  uint8_t trigger;      /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3,
-                         * 3=CC4, 4=TRGO */
+  uint8_t trigger;           /* Timer trigger channel: 0=CC1, 1=CC2, 2=CC3,
+                              * 3=CC4, 4=TRGO */
+#endif
+  xcpt_t   isr;              /* Interrupt handler for this ADC block */
+  uint32_t base;             /* Base address of registers unique to this ADC
+                              * block */
+#ifdef ADC_HAVE_EXTCFG
+  uint32_t extcfg;           /* External event configuration for regular group 
*/
+#endif
+#ifdef ADC_HAVE_JEXTCFG
+  uint32_t jextcfg;          /* External event configuration for injected 
group */
 #endif
-  xcpt_t   isr;         /* Interrupt handler for this ADC block */
-  uint32_t base;        /* Base address of registers unique to this ADC
-                         * block */
 #ifdef ADC_HAVE_TIMER
-  uint32_t tbase;       /* Base address of timer used by this ADC block */
-  uint32_t extsel;      /* EXTSEL value used by this ADC block */
-  uint32_t pclck;       /* The PCLK frequency that drives this timer */
-  uint32_t freq;        /* The desired frequency of conversions */
+  uint32_t tbase;            /* Base address of timer used by this ADC block */
+  uint32_t pclck;            /* The PCLK frequency that drives this timer */
+  uint32_t freq;             /* The desired frequency of conversions */
 #endif
 
 #ifdef CONFIG_PM
@@ -214,16 +240,22 @@ struct stm32_dev_s
 #endif
 
 #ifdef ADC_HAVE_DMA
-  DMA_HANDLE dma;       /* Allocated DMA channel */
+  DMA_HANDLE dma;            /* Allocated DMA channel */
 
   /* DMA transfer buffer */
 
-  uint16_t dmabuffer[ADC_MAX_SAMPLES];
+  uint16_t r_dmabuffer[CONFIG_STM32F7_ADC_MAX_SAMPLES];
 #endif
 
   /* List of selected ADC channels to sample */
 
-  uint8_t  chanlist[ADC_MAX_SAMPLES];
+  uint8_t  r_chanlist[CONFIG_STM32F7_ADC_MAX_SAMPLES];
+
+#ifdef ADC_HAVE_INJECTED
+  /* List of selected ADC injected channels to sample */
+
+  uint8_t  j_chanlist[ADC_INJ_MAX_SAMPLES];
+#endif
 };
 
 /****************************************************************************
@@ -235,26 +267,33 @@ struct stm32_dev_s
 static void stm32_modifyreg32(unsigned int addr, uint32_t clrbits,
                               uint32_t setbits);
 static uint32_t adc_getreg(struct stm32_dev_s *priv, int offset);
-static void     adc_putreg(struct stm32_dev_s *priv, int offset,
-                           uint32_t value);
-static void     adc_modifyreg(struct stm32_dev_s *priv, int offset,
-                              uint32_t clrbits, uint32_t setbits);
+static void adc_putreg(struct stm32_dev_s *priv, int offset,
+                       uint32_t value);
+static void adc_modifyreg(struct stm32_dev_s *priv, int offset,
+                          uint32_t clrbits, uint32_t setbits);
+static void adccmn_modifyreg(struct stm32_dev_s *priv, uint32_t offset,
+                             uint32_t clrbits, uint32_t setbits);
+static uint32_t adccmn_getreg(struct stm32_dev_s *priv, uint32_t offset);
+
 #ifdef ADC_HAVE_TIMER
 static uint16_t tim_getreg(struct stm32_dev_s *priv, int offset);
-static void     tim_putreg(struct stm32_dev_s *priv, int offset,
-                           uint16_t value);
-static void     tim_modifyreg(struct stm32_dev_s *priv, int offset,
-                              uint16_t clrbits, uint16_t setbits);
-static void     tim_dumpregs(struct stm32_dev_s *priv,
-                             const char *msg);
+static void tim_putreg(struct stm32_dev_s *priv, int offset,
+                       uint16_t value);
+static void tim_modifyreg(struct stm32_dev_s *priv, int offset,
+                          uint16_t clrbits, uint16_t setbits);
+static void tim_dumpregs(struct stm32_dev_s *priv, const char *msg);
 #endif
 
+static int  adccmn_lock(struct stm32_dev_s *priv, bool lock);
+
 static void adc_rccreset(struct stm32_dev_s *priv, bool reset);
 
 /* ADC Interrupt Handler */
 
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
 static int adc_interrupt(struct adc_dev_s *dev);
 static int adc123_interrupt(int irq, void *context, void *arg);
+#endif /* CONFIG_STM32F7_ADC_NOIRQ */
 
 /* ADC Driver Methods */
 
@@ -268,28 +307,79 @@ static int  adc_ioctl(struct adc_dev_s *dev, int cmd, 
unsigned long arg);
 static void adc_enable(struct stm32_dev_s *priv, bool enable);
 
 static uint32_t adc_sqrbits(struct stm32_dev_s *priv, int first,
-                            int last,
-                            int offset);
-static int      adc_set_ch(struct adc_dev_s *dev, uint8_t ch);
-static bool     adc_internal(struct stm32_dev_s * priv);
+                            int last, int offset);
+static int  adc_set_ch(struct adc_dev_s *dev, uint8_t ch);
+static bool adc_internal(struct stm32_dev_s * priv);
+
+static int  adc_resolution_set(struct adc_dev_s *dev, uint8_t res);
 
 #ifdef ADC_HAVE_TIMER
 static void adc_timstart(struct stm32_dev_s *priv, bool enable);
 static int  adc_timinit(struct stm32_dev_s *priv);
 #endif
 
-#ifdef ADC_HAVE_DMA
+#if defined(ADC_HAVE_DMA) && !defined(CONFIG_STM32F7_ADC_NOIRQ)
 static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr,
                                 void *arg);
 #endif
 
-static void adc_startconv(struct stm32_dev_s *priv, bool enable);
-
 #ifdef CONFIG_PM
 static int adc_pm_prepare(struct pm_callback_s *cb, int domain,
                           enum pm_state_e state);
 #endif
 
+static void adc_reg_startconv(struct stm32_dev_s *priv, bool enable);
+#ifdef ADC_HAVE_INJECTED
+static void adc_inj_startconv(struct stm32_dev_s *priv, bool enable);
+static int adc_inj_set_ch(struct adc_dev_s *dev, uint8_t ch);
+#endif
+
+#ifdef ADC_HAVE_EXTCFG
+static int adc_extcfg_set(struct stm32_dev_s *priv, uint32_t extcfg);
+#endif
+#ifdef ADC_HAVE_JEXTCFG
+static int adc_jextcfg_set(struct stm32_dev_s *priv, uint32_t jextcfg);
+#endif
+
+static void adc_dumpregs(struct stm32_dev_s *priv);
+
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+static int adc_llops_setup(struct stm32_adc_dev_s *dev);
+static void adc_llops_shutdown(struct stm32_adc_dev_s *dev);
+static void adc_intack(struct stm32_adc_dev_s *dev, uint32_t source);
+static void adc_inten(struct stm32_adc_dev_s *dev, uint32_t source);
+static void adc_intdis(struct stm32_adc_dev_s *dev, uint32_t source);
+static uint32_t adc_intget(struct stm32_adc_dev_s *dev);
+static uint32_t adc_regget(struct stm32_adc_dev_s *dev);
+static void adc_llops_reg_startconv(struct stm32_adc_dev_s *dev,
+                                    bool enable);
+static int adc_offset_set(struct stm32_adc_dev_s *dev, uint8_t ch,
+                          uint8_t i, uint16_t offset);
+#  ifdef ADC_HAVE_EXTCFG
+static void adc_llops_extcfg_set(struct stm32_adc_dev_s *dev,
+                                 uint32_t extcfg);
+#  endif
+#  ifdef ADC_HAVE_JEXTCFG
+static void adc_llops_jextcfg_set(struct stm32_adc_dev_s *dev,
+                                  uint32_t jextcfg);
+#  endif
+#  ifdef ADC_HAVE_DMA
+static int adc_regbufregister(struct stm32_adc_dev_s *dev,
+                              uint16_t *buffer, uint8_t len);
+#  endif
+#  ifdef ADC_HAVE_INJECTED
+static uint32_t adc_injget(struct stm32_adc_dev_s *dev, uint8_t chan);
+static void adc_llops_inj_startconv(struct stm32_adc_dev_s *dev,
+                                    bool enable);
+#  endif
+#  ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+static void adc_sampletime_set(struct stm32_adc_dev_s *dev,
+                               struct adc_sample_time_s *time_samples);
+static void adc_sampletime_write(struct stm32_adc_dev_s *dev);
+#  endif
+static void adc_llops_dumpregs(struct stm32_adc_dev_s *dev);
+#endif
+
 /****************************************************************************
  * Private Data
  ****************************************************************************/
@@ -306,26 +396,90 @@ static const struct adc_ops_s g_adcops =
   .ao_ioctl       = adc_ioctl,
 };
 
+/* Publicly visible ADC lower-half operations */
+
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+static const struct stm32_adc_ops_s g_adc_llops =
+{
+  .setup         = adc_llops_setup,
+  .shutdown      = adc_llops_shutdown,
+  .int_ack       = adc_intack,
+  .int_get       = adc_intget,
+  .int_en        = adc_inten,
+  .int_dis       = adc_intdis,
+  .val_get       = adc_regget,
+  .reg_startconv = adc_llops_reg_startconv,
+  .offset_set    = adc_offset_set,
+#  ifdef ADC_HAVE_DMA
+  .regbuf_reg    = adc_regbufregister,
+#  endif
+#  ifdef ADC_HAVE_EXTCFG
+  .extcfg_set    = adc_llops_extcfg_set,
+#  endif
+#  ifdef ADC_HAVE_JEXTCFG
+  .jextcfg_set   = adc_llops_jextcfg_set,
+#  endif
+#  ifdef ADC_HAVE_INJECTED
+  .inj_get       = adc_injget,
+  .inj_startconv = adc_llops_inj_startconv,
+#  endif
+#  ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+  .stime_set     = adc_sampletime_set,
+  .stime_write   = adc_sampletime_write,
+#  endif
+  .dump_regs     = adc_llops_dumpregs
+};
+#endif
+
+/* ADC instances are coupled in blocks */
+
+#define ADC1CMN_DATA g_adc123_cmn
+#define ADC2CMN_DATA g_adc123_cmn
+#define ADC3CMN_DATA g_adc123_cmn
+
+/* ADC123 common data */
+
+struct adccmn_data_s g_adc123_cmn =
+{
+  .refcount = 0
+};
+
 /* ADC1 state */
 
 #ifdef CONFIG_STM32F7_ADC1
 static struct stm32_dev_s g_adcpriv1 =
 {
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+  .llops       = &g_adc_llops,
+#endif
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
   .irq         = STM32_IRQ_ADC,
   .isr         = adc123_interrupt,
+#endif /* CONFIG_STM32F7_ADC_NOIRQ */
+  .cmn         = &ADC1CMN_DATA,
   .intf        = 1,
+  .initialized = 0,
+  .anioc_trg   = CONFIG_STM32F7_ADC1_ANIOC_TRIGGER,
+  .resolution  = CONFIG_STM32F7_ADC1_RESOLUTION,
   .base        = STM32_ADC1_BASE,
+#ifdef ADC1_HAVE_EXTCFG
+  .extcfg      = ADC1_EXTCFG_VALUE,
+#endif
+#ifdef ADC1_HAVE_JEXTCFG
+  .jextcfg     = ADC1_JEXTCFG_VALUE,
+#endif
 #ifdef ADC1_HAVE_TIMER
   .trigger     = CONFIG_STM32F7_ADC1_TIMTRIG,
   .tbase       = ADC1_TIMER_BASE,
-  .extsel      = ADC1_EXTSEL_VALUE,
   .pclck       = ADC1_TIMER_PCLK_FREQUENCY,
   .freq        = CONFIG_STM32F7_ADC1_SAMPLE_FREQUENCY,
 #endif
 #ifdef ADC1_HAVE_DMA
   .dmachan     = ADC1_DMA_CHAN,
+  .dmacfg      = CONFIG_STM32F7_ADC1_DMA_CFG,
   .hasdma      = true,
 #endif
+  .scan        = CONFIG_STM32F7_ADC1_SCAN,
 #ifdef CONFIG_PM
   .pm_callback =
     {
@@ -346,21 +500,37 @@ static struct adc_dev_s g_adcdev1 =
 #ifdef CONFIG_STM32F7_ADC2
 static struct stm32_dev_s g_adcpriv2 =
 {
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+  .llops       = &g_adc_llops,
+#endif
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
   .irq         = STM32_IRQ_ADC,
   .isr         = adc123_interrupt,
+#endif /* CONFIG_STM32F7_ADC_NOIRQ */
+  .cmn         = &ADC2CMN_DATA,
   .intf        = 2,
+  .initialized = 0,
+  .anioc_trg   = CONFIG_STM32F7_ADC2_ANIOC_TRIGGER,
+  .resolution  = CONFIG_STM32F7_ADC2_RESOLUTION,
   .base        = STM32_ADC2_BASE,
+#ifdef ADC2_HAVE_EXTCFG
+  .extcfg      = ADC2_EXTCFG_VALUE,
+#endif
+#ifdef ADC2_HAVE_JEXTCFG
+  .jextcfg     = ADC2_JEXTCFG_VALUE,
+#endif
 #ifdef ADC2_HAVE_TIMER
   .trigger     = CONFIG_STM32F7_ADC2_TIMTRIG,
   .tbase       = ADC2_TIMER_BASE,
-  .extsel      = ADC2_EXTSEL_VALUE,
   .pclck       = ADC2_TIMER_PCLK_FREQUENCY,
   .freq        = CONFIG_STM32F7_ADC2_SAMPLE_FREQUENCY,
 #endif
 #ifdef ADC2_HAVE_DMA
   .dmachan     = ADC2_DMA_CHAN,
+  .dmacfg      = CONFIG_STM32F7_ADC2_DMA_CFG,
   .hasdma      = true,
 #endif
+  .scan        = CONFIG_STM32F7_ADC2_SCAN,
 #ifdef CONFIG_PM
   .pm_callback =
     {
@@ -381,21 +551,37 @@ static struct adc_dev_s g_adcdev2 =
 #ifdef CONFIG_STM32F7_ADC3
 static struct stm32_dev_s g_adcpriv3 =
 {
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+  .llops       = &g_adc_llops,
+#endif
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
   .irq         = STM32_IRQ_ADC,
   .isr         = adc123_interrupt,
+#endif /* CONFIG_STM32F7_ADC_NOIRQ */
+  .cmn         = &ADC3CMN_DATA,
   .intf        = 3,
+  .initialized = 0,
+  .anioc_trg   = CONFIG_STM32F7_ADC3_ANIOC_TRIGGER,
+  .resolution  = CONFIG_STM32F7_ADC3_RESOLUTION,
   .base        = STM32_ADC3_BASE,
+#ifdef ADC3_HAVE_EXTCFG
+  .extcfg      = ADC3_EXTCFG_VALUE,
+#endif
+#ifdef ADC3_HAVE_JEXTCFG
+  .jextcfg     = ADC3_JEXTCFG_VALUE,
+#endif
 #ifdef ADC3_HAVE_TIMER
   .trigger     = CONFIG_STM32F7_ADC3_TIMTRIG,
   .tbase       = ADC3_TIMER_BASE,
-  .extsel      = ADC3_EXTSEL_VALUE,
   .pclck       = ADC3_TIMER_PCLK_FREQUENCY,
   .freq        = CONFIG_STM32F7_ADC3_SAMPLE_FREQUENCY,
 #endif
 #ifdef ADC3_HAVE_DMA
   .dmachan     = ADC3_DMA_CHAN,
+  .dmacfg      = CONFIG_STM32F7_ADC3_DMA_CFG,
   .hasdma      = true,
 #endif
+  .scan        = CONFIG_STM32F7_ADC3_SCAN,
 #ifdef CONFIG_PM
   .pm_callback =
     {
@@ -502,6 +688,29 @@ static void adc_modifyreg(struct stm32_dev_s *priv, int 
offset,
   adc_putreg(priv, offset, (adc_getreg(priv, offset) & ~clrbits) | setbits);
 }
 
+/****************************************************************************
+ * Name: adccmn_modifyreg
+ ****************************************************************************/
+
+static void adccmn_modifyreg(struct stm32_dev_s *priv, uint32_t offset,
+                             uint32_t clrbits, uint32_t setbits)
+{
+  /* Modify register */
+
+  stm32_modifyreg32(offset + STM32_ADCCMN_BASE, clrbits, setbits);
+}
+
+/****************************************************************************
+ * Name: adccmn_getreg
+ ****************************************************************************/
+
+static uint32_t adccmn_getreg(struct stm32_dev_s *priv, uint32_t offset)
+{
+  /* Return register value */
+
+  return getreg32(offset + STM32_ADCCMN_BASE);
+}
+
 /****************************************************************************
  * Name: tim_getreg
  *
@@ -610,6 +819,7 @@ static void tim_dumpregs(struct stm32_dev_s *priv, const 
char *msg)
         tim_getreg(priv, STM32_GTIM_CCR2_OFFSET),
         tim_getreg(priv, STM32_GTIM_CCR3_OFFSET),
         tim_getreg(priv, STM32_GTIM_CCR4_OFFSET));
+
   if (priv->tbase == STM32_TIM1_BASE || priv->tbase == STM32_TIM8_BASE)
     {
       ainfo("  RCR: %04x BDTR: %04x DCR:   %04x DMAR:  %04x\n",
@@ -703,20 +913,7 @@ static int adc_timinit(struct stm32_dev_s *priv)
       return ERROR;
     }
 
-  /* EXTSEL selection: These bits select the external event used to trigger
-   * the start of conversion of a regular group.  NOTE:
-   *
-   * - The position with of the EXTSEL field varies from one STM32 MCU
-   *   to another.
-   * - The width of the EXTSEL field varies from one STM32 MCU to another.
-   * - The value in priv->extsel is already shifted into the correct bit
-   *   position.
-   */
-
-  ainfo("Initializing timers extsel = 0x%08" PRIx32 "\n", priv->extsel);
-  adc_modifyreg(priv, STM32_ADC_EXTREG_OFFSET,
-                ADC_EXTREG_EXTEN_MASK | ADC_EXTREG_EXTSEL_MASK,
-                ADC_EXTREG_EXTEN_DEFAULT | priv->extsel);
+  /* NOTE: EXTSEL configuration is done in adc_reset function */
 
   /* Configure the timer channel to drive the ADC */
 
@@ -971,6 +1168,20 @@ static int adc_timinit(struct stm32_dev_s *priv)
       ccer &= ~(GTIM_CCER_CC1NP | GTIM_CCER_CC2NP | GTIM_CCER_CC3NP);
     }
 
+  /* Reset the output compare and output compare N IDLE State */
+
+  if (priv->tbase >= STM32_TIM2_BASE && priv->tbase <= STM32_TIM4_BASE)
+    {
+      /* Reset output N polarity level, output N state, output compare state,
+       * output compare N idle state.
+       */
+
+      ccer &= ~(GTIM_CCER_CC1NE | GTIM_CCER_CC1NP |
+                GTIM_CCER_CC2NE | GTIM_CCER_CC2NP |
+                GTIM_CCER_CC3NE | GTIM_CCER_CC3NP |
+                GTIM_CCER_CC4NP);
+    }
+
   /* Save the modified register values */
 
   tim_putreg(priv, STM32_GTIM_CR2_OFFSET, cr2);
@@ -1023,10 +1234,10 @@ static int adc_pm_prepare(struct pm_callback_s *cb, int 
domain,
 #endif
 
 /****************************************************************************
- * Name: adc_startconv
+ * Name: adc_reg_startconv
  *
  * Description:
- *   Start (or stop) the ADC conversion process
+ *   Start (or stop) the ADC regular conversion process
  *
  * Input Parameters:
  *   priv - A reference to the ADC block status
@@ -1036,9 +1247,9 @@ static int adc_pm_prepare(struct pm_callback_s *cb, int 
domain,
  *
  ****************************************************************************/
 
-static void adc_startconv(struct stm32_dev_s *priv, bool enable)
+static void adc_reg_startconv(struct stm32_dev_s *priv, bool enable)
 {
-  ainfo("enable: %d\n", enable ? 1 : 0);
+  ainfo("reg enable: %d\n", enable ? 1 : 0);
 
   if (enable)
     {
@@ -1054,6 +1265,62 @@ static void adc_startconv(struct stm32_dev_s *priv, bool 
enable)
     }
 }
 
+#ifdef ADC_HAVE_INJECTED
+
+/****************************************************************************
+ * Name: adc_inj_startconv
+ *
+ * Description:
+ *   Start (or stop) the ADC injected conversion process
+ *
+ * Input Parameters:
+ *   priv - A reference to the ADC block status
+ *   enable - True: Start conversion
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_inj_startconv(struct stm32_dev_s *priv, bool enable)
+{
+  ainfo("inj enable: %d\n", enable ? 1 : 0);
+
+  if (enable)
+    {
+      /* Start the conversion of injected channels */
+
+      adc_modifyreg(priv, STM32_ADC_CR2_OFFSET, 0, ADC_CR2_JSWSTART);
+    }
+  else
+    {
+      /* Stop the conversion */
+
+      adc_modifyreg(priv, STM32_ADC_CR2_OFFSET, ADC_CR2_JSWSTART, 0);
+    }
+}
+
+#endif /* ADC_HAVE_INJECTED */
+
+/****************************************************************************
+ * Name: adccmn_lock
+ ****************************************************************************/
+
+static int adccmn_lock(struct stm32_dev_s *priv, bool lock)
+{
+  int ret;
+
+  if (lock)
+    {
+      ret = nxsem_wait_uninterruptible(&priv->cmn->lock);
+    }
+  else
+    {
+      ret = nxsem_post(&priv->cmn->lock);
+    }
+
+  return ret;
+}
+
 /****************************************************************************
  * Name: adc_rccreset
  *
@@ -1073,37 +1340,27 @@ static void adc_rccreset(struct stm32_dev_s *priv, bool 
reset)
 {
   uint32_t adcbit;
 
-  /* Pick the appropriate bit in the APB2 reset register.
-   * For the STM32 F1, there is an individual bit to reset each ADC,
-   * but for the STM32 F2/F4, there is one common reset for all ADCs.
-   * THIS will probably cause some problems!
+  /* Pick the appropriate bit in the RCC reset register.
+   * For the STM32 ADC IPv1, there is one common reset for all ADCs.
    */
 
   switch (priv->intf)
     {
-#ifdef CONFIG_STM32F7_ADC1
       case 1:
-        adcbit = RCC_RSTR_ADC1RST;
-        break;
-#endif
-#ifdef CONFIG_STM32F7_ADC2
       case 2:
-        adcbit = RCC_RSTR_ADC2RST;
-        break;
-#endif
-#ifdef CONFIG_STM32F7_ADC3
       case 3:
-        adcbit = RCC_RSTR_ADC3RST;
-        break;
-#endif
+        {
+          adcbit = RCC_RSTR_ADC123RST;
+          break;
+        }
+
       default:
-        return;
+        {
+          return;
+        }
     }
 
-  /* Set or clear the selected bit in the APB2 reset register.
-   * modifyreg32() disables interrupts.  Disabling interrupts is necessary
-   * because the APB2RTSR register is used by several different drivers.
-   */
+  /* Set or clear the selected bit in the RCC reset register */
 
   if (reset)
     {
@@ -1150,7 +1407,7 @@ static void adc_enable(struct stm32_dev_s *priv, bool 
enable)
 }
 
 /****************************************************************************
- * Name: adc_dmacovcallback
+ * Name: adc_dmaconvcallback
  *
  * Description:
  *   Callback for DMA.  Called from the DMA transfer complete interrupt after
@@ -1166,7 +1423,7 @@ static void adc_enable(struct stm32_dev_s *priv, bool 
enable)
  *
  ****************************************************************************/
 
-#ifdef ADC_HAVE_DMA
+#if defined(ADC_HAVE_DMA) && !defined(CONFIG_STM32F7_ADC_NOIRQ)
 static void adc_dmaconvcallback(DMA_HANDLE handle, uint8_t isr,
                                 void *arg)
 {
@@ -1174,8 +1431,9 @@ static void adc_dmaconvcallback(DMA_HANDLE handle, 
uint8_t isr,
   struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
   int i;
 
-  up_invalidate_dcache((uintptr_t)priv->dmabuffer,
-                       (uintptr_t)priv->dmabuffer + sizeof(priv->dmabuffer));
+  up_invalidate_dcache((uintptr_t)priv->r_dmabuffer,
+                       (uintptr_t)priv->r_dmabuffer +
+                       sizeof(priv->r_dmabuffer));
 
   /* Verify that the upper-half driver has bound its callback functions */
 
@@ -1183,12 +1441,12 @@ static void adc_dmaconvcallback(DMA_HANDLE handle, 
uint8_t isr,
     {
       DEBUGASSERT(priv->cb->au_receive != NULL);
 
-      for (i = 0; i < priv->nchannels; i++)
+      for (i = 0; i < priv->rnchannels; i++)
         {
-          priv->cb->au_receive(dev, priv->chanlist[priv->current],
-                               priv->dmabuffer[priv->current]);
+          priv->cb->au_receive(dev, priv->r_chanlist[priv->current],
+                               priv->r_dmabuffer[priv->current]);
           priv->current++;
-          if (priv->current >= priv->nchannels)
+          if (priv->current >= priv->rnchannels)
             {
               /* Restart the conversion sequence from the beginning */
 
@@ -1216,46 +1474,27 @@ static void adc_dmaconvcallback(DMA_HANDLE handle, 
uint8_t isr,
 static int adc_bind(struct adc_dev_s *dev,
                     const struct adc_callback_s *callback)
 {
+#ifdef ADC_HAVE_CB
   struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
 
   DEBUGASSERT(priv != NULL);
   priv->cb = callback;
+#else
+  UNUSED(dev);
+  UNUSED(callback);
+#endif
+
   return OK;
 }
 
 /****************************************************************************
- * Name: adc_reset
- *
- * Description:
- *   Reset the ADC device.  Called early to initialize the hardware. This
- *   is called, before adc_setup() and on error conditions.
- *
- * Input Parameters:
- *
- * Returned Value:
- *
+ * Name: adc_watchdog_cfg
  ****************************************************************************/
 
-static void adc_reset(struct adc_dev_s *dev)
+static void adc_watchdog_cfg(struct stm32_dev_s *priv)
 {
-  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
-  irqstate_t flags;
-  uint32_t clrbits;
-  uint32_t setbits;
-#ifdef ADC_HAVE_TIMER
-  int ret;
-#endif
-
-  ainfo("intf: %d\n", priv->intf);
-  flags = enter_critical_section();
-
-  /* Enable ADC reset state */
-
-  adc_rccreset(priv, true);
-
-  /* Release ADC from reset state */
-
-  adc_rccreset(priv, false);
+  uint32_t clrbits = 0;
+  uint32_t setbits = 0;
 
   /* Initialize the watchdog high threshold register */
 
@@ -1265,34 +1504,27 @@ static void adc_reset(struct adc_dev_s *dev)
 
   adc_putreg(priv, STM32_ADC_LTR_OFFSET, 0x00000000);
 
-  /* Initialize the same sample time for each ADC.
-   * During sample cycles channel selection bits must remain unchanged.
-   */
-
-  adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, ADC_SMPR1_DEFAULT);
-  adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, ADC_SMPR2_DEFAULT);
+  clrbits = ADC_CR1_AWDCH_MASK;
+  setbits = ADC_CR1_AWDEN | (priv->r_chanlist[0] << ADC_CR1_AWDCH_SHIFT);
 
-  /* Enable the analog watchdog */
+  /* Modify CR1 configuration */
 
-  clrbits = ADC_CR1_AWDCH_MASK;
-  setbits = ADC_CR1_AWDEN | (priv->chanlist[0] << ADC_CR1_AWDCH_SHIFT);
+  adc_modifyreg(priv, STM32_ADC_CR1_OFFSET, clrbits, setbits);
+}
 
-  /* Set the resolution of the conversion */
+/****************************************************************************
+ * Name: adc_mode_cfg
+ ****************************************************************************/
 
-  clrbits |= ADC_CR1_RES_MASK;
-  setbits |= ADC_CR1_RES_12BIT;
+static void adc_mode_cfg(struct stm32_dev_s *priv)
+{
+  uint32_t clrbits = 0;
+  uint32_t setbits = 0;
 
-#ifdef ADC_HAVE_DMA
-  if (priv->hasdma)
+  if (priv->scan)
     {
       setbits |= ADC_CR1_SCAN;
     }
-#endif
-
-  /* Enable interrupt flags, but disable overrun interrupt */
-
-  clrbits |= ADC_IER_OVR;
-  setbits |= ADC_IER_ALLINTS & ~ADC_IER_OVR;
 
   /* Set CR1 configuration */
 
@@ -1308,25 +1540,42 @@ static void adc_reset(struct adc_dev_s *dev)
   clrbits |= ADC_EXTREG_EXTEN_MASK;
   setbits |= ADC_EXTREG_EXTEN_NONE;
 
-#ifdef ADC_HAVE_DMA
-  if (priv->hasdma)
-    {
-      setbits |= ADC_CR2_DMA;
-    }
-#endif
-
   /* Set CR2 configuration */
 
   adc_modifyreg(priv, STM32_ADC_CR2_OFFSET, clrbits, setbits);
+}
 
-  /* Configuration of the channel conversions */
+/****************************************************************************
+ * Name: adc_sampletime_cfg
+ ****************************************************************************/
+
+static void adc_sampletime_cfg(struct adc_dev_s *dev)
+{
+  /* Initialize the same sample time for each ADC.
+   * During sample cycles channel selection bits must remain unchanged.
+   */
+
+#ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+  adc_sampletime_write((struct stm32_adc_dev_s *)dev->ad_priv);
+#else
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+
+  adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, ADC_SMPR1_DEFAULT);
+  adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, ADC_SMPR2_DEFAULT);
+#endif
+}
 
-  adc_set_ch(dev, 0);
+/****************************************************************************
+ * Name: adc_common_cfg
+ ****************************************************************************/
 
-  /* ADC CCR configuration */
+static void adc_common_cfg(struct stm32_dev_s *priv)
+{
+  uint32_t clrbits = 0;
+  uint32_t setbits = 0;
 
-  clrbits = ADC_CCR_ADCPRE_MASK | ADC_CCR_TSVREFE;
-  setbits = ADC_CCR_ADCPRE_DIV;
+  clrbits  = ADC_CCR_ADCPRE_MASK;
+  setbits  = ADC_CCR_ADCPRE_DIV;
 
   if (adc_internal(priv))
     {
@@ -1337,73 +1586,209 @@ static void adc_reset(struct adc_dev_s *dev)
              ADC_CCR_DMA_MASK | ADC_CCR_VBATE;
   setbits |= ADC_CCR_MULTI_NONE | ADC_CCR_DMA_DISABLED;
 
-  stm32_modifyreg32(STM32_ADC_CCR, clrbits, setbits);
+  adccmn_modifyreg(priv, STM32_ADC_CCR_OFFSET, clrbits, setbits);
+}
 
 #ifdef ADC_HAVE_DMA
+/****************************************************************************
+ * Name: adc_dma_cfg
+ ****************************************************************************/
 
-  /* Enable DMA */
+static void adc_dma_cfg(struct stm32_dev_s *priv)
+{
+  uint32_t clrbits = 0;
+  uint32_t setbits = 0;
 
-  if (priv->hasdma)
+  /* Set DMA mode */
+
+  if (priv->dmacfg == 0)
     {
-      /* Stop and free DMA if it was started before */
+      /* One Shot Mode */
 
-      if (priv->dma != NULL)
-        {
-          stm32_dmastop(priv->dma);
-          stm32_dmafree(priv->dma);
-        }
+      clrbits |= ADC_CR2_DDS;
+    }
+  else
+    {
+      /* Circular Mode */
 
-      priv->dma = stm32_dmachannel(priv->dmachan);
+      setbits |= ADC_CR2_DDS;
+    }
+
+  /* Enable DMA */
 
-      stm32_dmasetup(priv->dma,
-                     priv->base + STM32_ADC_DR_OFFSET,
-                     (uint32_t)priv->dmabuffer,
-                     priv->nchannels,
-                     ADC_DMA_CONTROL_WORD);
+  setbits |= ADC_CR2_DMA;
 
-      stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false);
+  /* Modify CR2 configuration */
+
+  adc_modifyreg(priv, STM32_ADC_CR2_OFFSET, clrbits, setbits);
+}
+
+/****************************************************************************
+ * Name: adc_dma_start
+ ****************************************************************************/
+
+static void adc_dma_start(struct adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+
+  /* Stop and free DMA if it was started before */
+
+  if (priv->dma != NULL)
+    {
+      stm32_dmastop(priv->dma);
+      stm32_dmafree(priv->dma);
     }
 
+  priv->dma = stm32_dmachannel(priv->dmachan);
+
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
+  /* Start DMA only if standard ADC interrupts used */
+
+  stm32_dmasetup(priv->dma,
+                 priv->base + STM32_ADC_DR_OFFSET,
+                 (uint32_t)priv->r_dmabuffer,
+                 priv->rnchannels,
+                 ADC_DMA_CONTROL_WORD);
+
+  stm32_dmastart(priv->dma, adc_dmaconvcallback, dev, false);
 #endif
+}
+#endif /* ADC_HAVE_DMA */
 
-  /* Set ADON to wake up the ADC from the power down state */
+/****************************************************************************
+ * Name: adc_configure
+ ****************************************************************************/
 
-  adc_enable(priv, true);
+static void adc_configure(struct adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
 
-#ifdef ADC_HAVE_TIMER
-  if (priv->tbase != 0)
+  /* Turn off the ADC before configuration */
+
+  adc_enable(priv, false);
+
+  /* Initialize the ADC watchdog */
+
+  adc_watchdog_cfg(priv);
+
+  /* Initialize the ADC sample time */
+
+  adc_sampletime_cfg(dev);
+
+  /* Set ADC working mode */
+
+  adc_mode_cfg(priv);
+
+  /* Configuration of the channel conversions */
+
+  if (priv->cr_channels > 0)
     {
-      ret = adc_timinit(priv);
-      if (ret < 0)
-        {
-          aerr("ERROR: adc_timinit failed: %d\n", ret);
-        }
+      adc_set_ch(dev, 0);
+    }
+
+#ifdef ADC_HAVE_INJECTED
+  /* Configuration of the injected channel conversions after adc enabled */
+
+  if (priv->cj_channels > 0)
+    {
+      adc_inj_set_ch(dev, 0);
     }
-#ifndef CONFIG_STM32F7_ADC_NO_STARTUP_CONV
-  else
-#endif
 #endif
-#ifndef CONFIG_STM32F7_ADC_NO_STARTUP_CONV
+
+  /* ADC common register configuration */
+
+  adc_common_cfg(priv);
+
+#ifdef ADC_HAVE_DMA
+  /* Configure ADC DMA if enabled */
+
+  if (priv->hasdma)
     {
-      adc_startconv(priv, true);
+      /* Configure ADC DMA */
+
+      adc_dma_cfg(priv);
+
+      /* Start ADC DMA */
+
+      adc_dma_start(dev);
     }
 #endif
 
-  leave_critical_section(flags);
+  /* Configure ADC resolution */
 
-  ainfo("SR:   0x%08" PRIx32 " CR1:  0x%08" PRIx32
-        " CR2:  0x%08" PRIx32 "\n",
-        adc_getreg(priv, STM32_ADC_SR_OFFSET),
-        adc_getreg(priv, STM32_ADC_CR1_OFFSET),
-        adc_getreg(priv, STM32_ADC_CR2_OFFSET));
+  adc_resolution_set(dev, priv->resolution);
 
-  ainfo("SQR1: 0x%08" PRIx32 " SQR2: 0x%08" PRIx32
-        " SQR3: 0x%08" PRIx32 "\n",
-        adc_getreg(priv, STM32_ADC_SQR1_OFFSET),
-        adc_getreg(priv, STM32_ADC_SQR2_OFFSET),
-        adc_getreg(priv, STM32_ADC_SQR3_OFFSET));
+#ifdef ADC_HAVE_EXTCFG
+  /* Configure external event for regular group */
+
+  adc_extcfg_set(priv, priv->extcfg);
+#endif
+
+  /* Enable ADC */
 
-  ainfo("CCR:  0x%08" PRIx32 "\n", getreg32(STM32_ADC_CCR));
+  adc_enable(priv, true);
+
+#ifdef ADC_HAVE_JEXTCFG
+  /* Configure external event for injected group when ADC enabled */
+
+  adc_jextcfg_set(priv, priv->jextcfg);
+#endif
+
+  /* Dump regs */
+
+  adc_dumpregs(priv);
+}
+
+/****************************************************************************
+ * Name: adc_reset
+ *
+ * Description:
+ *   Reset the ADC device.  Called early to initialize the hardware.
+ *   This is called, before adc_setup() and on error conditions.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void adc_reset(struct adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  irqstate_t flags;
+
+  ainfo("intf: %d\n", priv->intf);
+  flags = enter_critical_section();
+
+  /* Do nothing if ADC instance is currently in use */
+
+  if (priv->initialized > 0)
+    {
+      goto out;
+    }
+
+  /* Only if this is the first initialzied ADC instance in the ADC block */
+
+  if (adccmn_lock(priv, true) < 0)
+    {
+      goto out;
+    }
+
+  if (priv->cmn->refcount == 0)
+    {
+      /* Enable ADC reset state */
+
+      adc_rccreset(priv, true);
+
+      /* Release ADC from reset state */
+
+      adc_rccreset(priv, false);
+    }
+
+  adccmn_lock(priv, false);
+
+out:
+  leave_critical_section(flags);
 }
 
 /****************************************************************************
@@ -1424,25 +1809,85 @@ static void adc_reset(struct adc_dev_s *dev)
 static int adc_setup(struct adc_dev_s *dev)
 {
   struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
-  int ret;
+  int ret = OK;
+
+  /* Do nothing when the ADC device is already set up */
+
+  if (priv->initialized > 0)
+    {
+      return OK;
+    }
 
   /* Attach the ADC interrupt */
 
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
   ret = irq_attach(priv->irq, priv->isr, NULL);
   if (ret < 0)
     {
       ainfo("irq_attach failed: %d\n", ret);
       return ret;
     }
+#endif
 
   /* Make sure that the ADC device is in the powered up, reset state */
 
   adc_reset(dev);
 
-  /* Enable the ADC interrupt */
+  /* Configure ADC device */
 
-  ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq);
-  up_enable_irq(priv->irq);
+  adc_configure(dev);
+
+#ifdef ADC_HAVE_TIMER
+  /* Configure timer */
+
+  if (priv->tbase != 0)
+    {
+      ret = adc_timinit(priv);
+      if (ret < 0)
+        {
+          aerr("ERROR: adc_timinit failed: %d\n", ret);
+        }
+    }
+#endif
+
+  /* As default conversion is started here */
+
+#ifndef CONFIG_STM32F7_ADC_NO_STARTUP_CONV
+  /* Start regular conversion */
+
+  adc_reg_startconv(priv, true);
+
+#  ifdef ADC_HAVE_INJECTED
+  /* Start injected conversion */
+
+  adc_inj_startconv(priv, true);
+#  endif
+#endif
+
+  /* Increase instances counter */
+
+  ret = adccmn_lock(priv, true);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (priv->cmn->refcount == 0)
+    {
+      /* Enable the ADC interrupt */
+
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
+      ainfo("Enable the ADC interrupt: irq=%d\n", priv->irq);
+      up_enable_irq(priv->irq);
+#endif
+    }
+
+  priv->cmn->refcount += 1;
+  adccmn_lock(priv, false);
+
+  /* The ADC device is ready */
+
+  priv->initialized += 1;
 
   return ret;
 }
@@ -1464,16 +1909,67 @@ static void adc_shutdown(struct adc_dev_s *dev)
 {
   struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
 
+  /* Decrement count only when ADC device is in use */
+
+  if (priv->initialized > 0)
+    {
+      priv->initialized -= 1;
+    }
+
+  /* Shutdown the ADC device only when not in use */
+
+  if (priv->initialized > 0)
+    {
+      return;
+    }
+
+  /* Disable ADC */
+
   adc_enable(priv, false);
 
-  /* Disable ADC interrupts and detach the ADC interrupt handler */
+  if (adccmn_lock(priv, true) < 0)
+    {
+      return;
+    }
 
-  up_disable_irq(priv->irq);
-  irq_detach(priv->irq);
+  if (priv->cmn->refcount <= 1)
+    {
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
+      /* Disable ADC interrupts and detach the ADC interrupt handler */
 
-  /* Disable and reset the ADC module */
+      up_disable_irq(priv->irq);
+      irq_detach(priv->irq);
+#endif
 
-  adc_rccreset(priv, true);
+      /* Disable and reset the ADC module.
+       *
+       * NOTE: The ADC block will be reset to its reset state only if all
+       *       ADC block instances are closed. This means that the closed
+       *       ADC may not be reset which in turn may affect low-power
+       *       applications. (But ADC is turned off here, is not that
+       *       enough?)
+       */
+
+      adc_rccreset(priv, true);
+    }
+
+#ifdef ADC_HAVE_TIMER
+  /* Disable timer */
+
+  if (priv->tbase != 0)
+    {
+      adc_timstart(priv, false);
+    }
+#endif
+
+  /* Decrease instances counter */
+
+  if (priv->cmn->refcount > 0)
+    {
+      priv->cmn->refcount -= 1;
+    }
+
+  adccmn_lock(priv, false);
 }
 
 /****************************************************************************
@@ -1491,14 +1987,25 @@ static void adc_shutdown(struct adc_dev_s *dev)
 static void adc_rxint(struct adc_dev_s *dev, bool enable)
 {
   struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  uint32_t regval;
 
   ainfo("intf: %d enable: %d\n", priv->intf, enable ? 1 : 0);
 
   if (enable)
     {
-      /* Enable the end-of-conversion ADC and analog watchdog interrupts */
+      /* Enable the analog watchdog / overrun interrupts, and if no DMA,
+       * end-of-conversion ADC.
+       */
 
-      adc_modifyreg(priv, STM32_ADC_IER_OFFSET, 0, ADC_IER_ALLINTS);
+      regval = ADC_IER_ALLINTS;
+#ifdef ADC_HAVE_DMA
+      if (priv->hasdma)
+        {
+          regval &= ~(ADC_IER_EOC | ADC_IER_JEOC);
+        }
+#endif
+
+      adc_modifyreg(priv, STM32_ADC_IER_OFFSET, 0, regval);
     }
   else
     {
@@ -1508,22 +2015,161 @@ static void adc_rxint(struct adc_dev_s *dev, bool 
enable)
     }
 }
 
+/****************************************************************************
+ * Name: adc_resolution_set
+ ****************************************************************************/
+
+static int adc_resolution_set(struct adc_dev_s *dev, uint8_t res)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  int ret = OK;
+
+  /* Check input */
+
+  if (res > 3)
+    {
+      ret = -EINVAL;
+      goto errout;
+    }
+
+  /* Modify appropriate register */
+
+  adc_modifyreg(priv, STM32_ADC_CR1_OFFSET, ADC_CR1_RES_MASK,
+                res << ADC_CR1_RES_SHIFT);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: adc_extcfg_set
+ ****************************************************************************/
+
+#ifdef ADC_HAVE_EXTCFG
+static int adc_extcfg_set(struct stm32_dev_s *priv, uint32_t extcfg)
+{
+  uint32_t exten  = 0;
+  uint32_t extsel = 0;
+  uint32_t setbits = 0;
+  uint32_t clrbits = 0;
+
+  /* Get EXTEN and EXTSEL from input */
+
+  exten = extcfg & ADC_EXTREG_EXTEN_MASK;
+  extsel = extcfg & ADC_EXTREG_EXTSEL_MASK;
+
+  /* EXTSEL selection: These bits select the external event used
+   * to trigger the start of conversion of a regular group.  NOTE:
+   *
+   * - The position with of the EXTSEL field varies from one STM32 MCU
+   *   to another.
+   * - The width of the EXTSEL field varies from one STM32 MCU to another.
+   */
+
+  if (exten > 0)
+    {
+      setbits = extsel | exten;
+      clrbits = ADC_EXTREG_EXTEN_MASK | ADC_EXTREG_EXTSEL_MASK;
+
+      ainfo("Initializing extsel = 0x%08" PRIx32 "\n", extsel);
+
+      /* Write register */
+
+      adc_modifyreg(priv, STM32_ADC_EXTREG_OFFSET, clrbits, setbits);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: adc_jextcfg_set
+ ****************************************************************************/
+
+#ifdef ADC_HAVE_JEXTCFG
+static int adc_jextcfg_set(struct stm32_dev_s *priv, uint32_t jextcfg)
+{
+  uint32_t jexten =  0;
+  uint32_t jextsel = 0;
+  uint32_t setbits = 0;
+  uint32_t clrbits = 0;
+
+  /* Get JEXTEN and JEXTSEL from input */
+
+  jexten = jextcfg & ADC_JEXTREG_JEXTEN_MASK;
+  jextsel = jextcfg & ADC_JEXTREG_JEXTSEL_MASK;
+
+  /* JEXTSEL selection: These bits select the external event used
+   * to trigger the start of conversion of a injected group.  NOTE:
+   *
+   * - The position with of the JEXTSEL field varies from one STM32 MCU
+   *   to another.
+   * - The width of the JEXTSEL field varies from one STM32 MCU to another.
+   */
+
+  if (jexten > 0)
+    {
+      setbits = jexten | jextsel;
+      clrbits = ADC_JEXTREG_JEXTEN_MASK | ADC_JEXTREG_JEXTSEL_MASK;
+
+      ainfo("Initializing jextsel = 0x%08" PRIx32 "\n", jextsel);
+
+      /* Write register */
+
+      adc_modifyreg(priv, STM32_ADC_JEXTREG_OFFSET, clrbits, setbits);
+    }
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: adc_dumpregs
+ ****************************************************************************/
+
+static void adc_dumpregs(struct stm32_dev_s *priv)
+{
+  UNUSED(priv);
+
+  ainfo("SR:   0x%08" PRIx32 " CR1:  0x%08" PRIx32
+        " CR2:  0x%08" PRIx32 "\n",
+        adc_getreg(priv, STM32_ADC_SR_OFFSET),
+        adc_getreg(priv, STM32_ADC_CR1_OFFSET),
+        adc_getreg(priv, STM32_ADC_CR2_OFFSET));
+
+  ainfo("SQR1: 0x%08" PRIx32 " SQR2: 0x%08" PRIx32
+        " SQR3: 0x%08" PRIx32 "\n",
+        adc_getreg(priv, STM32_ADC_SQR1_OFFSET),
+        adc_getreg(priv, STM32_ADC_SQR2_OFFSET),
+        adc_getreg(priv, STM32_ADC_SQR3_OFFSET));
+
+  ainfo("SMPR1: 0x%08" PRIx32 " SMPR2: 0x%08" PRIx32 "\n",
+        adc_getreg(priv, STM32_ADC_SMPR1_OFFSET),
+        adc_getreg(priv, STM32_ADC_SMPR2_OFFSET));
+
+#ifdef ADC_HAVE_INJECTED
+  ainfo("JSQR: 0x%08" PRIx32 "\n", adc_getreg(priv, STM32_ADC_JSQR_OFFSET));
+#endif
+
+  ainfo("CCR:  0x%08" PRIx32 "\n",
+        adccmn_getreg(priv, STM32_ADC_CCR_OFFSET));
+}
+
 /****************************************************************************
  * Name: adc_sqrbits
  ****************************************************************************/
 
 static uint32_t adc_sqrbits(struct stm32_dev_s *priv, int first,
-                            int last,
-                            int offset)
+                            int last, int offset)
 {
   uint32_t bits = 0;
   int i;
 
   for (i = first - 1;
-       i < priv->nchannels && i < last;
+       i < priv->rnchannels && i < last;
        i++, offset += ADC_SQ_OFFSET)
     {
-      bits |= (uint32_t)priv->chanlist[i] << offset;
+      bits |= (uint32_t)priv->r_chanlist[i] << offset;
     }
 
   return bits;
@@ -1539,13 +2185,23 @@ static bool adc_internal(struct stm32_dev_s * priv)
 
   if (priv->intf == 1)
     {
-      for (i  = 0; i < priv->nchannels; i++)
+      for (i = 0; i < priv->cr_channels; i++)
         {
-          if (priv->chanlist[i] > ADC_LAST_EXTERNAL_CHAN)
+          if (priv->r_chanlist[i] > ADC_LAST_EXTERNAL_CHAN)
             {
               return true;
             }
         }
+
+#ifdef ADC_HAVE_INJECTED
+      for (i = 0; i < priv->cj_channels; i++)
+        {
+          if (priv->j_chanlist[i] > ADC_LAST_EXTERNAL_CHAN)
+            {
+              return true;
+            }
+        }
+#endif
     }
 
   return false;
@@ -1575,19 +2231,20 @@ static int adc_set_ch(struct adc_dev_s *dev, uint8_t ch)
   if (ch == 0)
     {
       priv->current   = 0;
-      priv->nchannels = priv->cchannels;
+      priv->rnchannels = priv->cr_channels;
     }
   else
     {
-      for (i = 0; i < priv->cchannels && priv->chanlist[i] != ch - 1; i++);
+      for (i = 0; i < priv->cr_channels && priv->r_chanlist[i] != ch - 1;
+           i++);
 
-      if (i >= priv->cchannels)
+      if (i >= priv->cr_channels)
         {
           return -ENODEV;
         }
 
-      priv->current   = i;
-      priv->nchannels = 1;
+      priv->current    = i;
+      priv->rnchannels = 1;
     }
 
   bits = adc_sqrbits(priv, ADC_SQR3_FIRST, ADC_SQR3_LAST,
@@ -1598,14 +2255,57 @@ static int adc_set_ch(struct adc_dev_s *dev, uint8_t ch)
                      ADC_SQR2_SQ_OFFSET);
   adc_modifyreg(priv, STM32_ADC_SQR2_OFFSET, ~ADC_SQR2_RESERVED, bits);
 
-  bits = ((uint32_t)priv->nchannels - 1) << ADC_SQR1_L_SHIFT |
-         adc_sqrbits(priv, ADC_SQR1_FIRST, ADC_SQR1_LAST,
-                     ADC_SQR1_SQ_OFFSET);
+  bits = ((uint32_t)priv->rnchannels - 1) << ADC_SQR1_L_SHIFT;
+  bits |= adc_sqrbits(priv, ADC_SQR1_FIRST,
+                      ADC_SQR1_LAST, ADC_SQR1_SQ_OFFSET);
   adc_modifyreg(priv, STM32_ADC_SQR1_OFFSET, ~ADC_SQR1_RESERVED, bits);
 
   return OK;
 }
 
+#ifdef ADC_HAVE_INJECTED
+
+/****************************************************************************
+ * Name: adc_inj_set_ch
+ ****************************************************************************/
+
+static int adc_inj_set_ch(struct adc_dev_s *dev, uint8_t ch)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev->ad_priv;
+  uint32_t clrbits;
+  uint32_t setbits;
+  int i;
+
+  /* Configure injected sequence length */
+
+  setbits = ADC_JSQR_JL(priv->cj_channels);
+  clrbits = ADC_JEXTREG_JEXTSEL_MASK | ADC_JSQR_JL_MASK;
+
+  /* Configure injected channels */
+
+  for (i = 0 ; i < priv->cj_channels; i += 1)
+    {
+      /* Injected channels sequence for for ADC IPv1:
+       *
+       *           1      2     3      4
+       *   IL=1: JSQR4,
+       *   IL=2: JSQR3, JSQR4
+       *   IL=3: JSQR2, JSQR3, JSQR4
+       *   IL=4: JSQR1, JSQR2, JSQR3, JSQR4
+       */
+
+      setbits |= (priv->j_chanlist[priv->cj_channels - 1 - i] <<
+                  (ADC_JSQR_JSQ4_SHIFT - ADC_JSQR_JSQ_SHIFT * i));
+    }
+
+  /* Write register */
+
+  adc_modifyreg(priv, STM32_ADC_JSQR_OFFSET, clrbits, setbits);
+
+  return OK;
+}
+#endif
+
 /****************************************************************************
  * Name: adc_ioctl
  *
@@ -1630,29 +2330,114 @@ static int adc_ioctl(struct adc_dev_s *dev, int cmd, 
unsigned long arg)
     {
       case ANIOC_TRIGGER:
         {
-          adc_startconv(priv, true);
+          /* Start regular conversion if regular channels configured */
+
+          if (priv->anioc_trg & ANIOC_TRIGGER_REGULAR)
+            {
+              if (priv->cr_channels > 0)
+                {
+                  adc_reg_startconv(priv, true);
+                }
+            }
+
+#ifdef ADC_HAVE_INJECTED
+          /* Start injected conversion if injected channels configured */
+
+          if (priv->anioc_trg & ANIOC_TRIGGER_INJECTED)
+            {
+              if (priv->cj_channels > 0)
+                {
+                  adc_inj_startconv(priv, true);
+                }
+            }
+#endif
+
+          break;
         }
-        break;
 
       case ANIOC_GET_NCHANNELS:
         {
           /* Return the number of configured channels */
 
-          ret = priv->cchannels;
+          ret = priv->rnchannels;
+        }
+        break;
+
+      case IO_TRIGGER_REG:
+        {
+          /* Start regular conversion if regular channels configured */
+
+          if (priv->cr_channels > 0)
+            {
+              adc_reg_startconv(priv, true);
+            }
+
+          break;
+        }
+
+#ifdef ADC_HAVE_INJECTED
+      case IO_TRIGGER_INJ:
+        {
+          /* Start injected conversion if injected channels configured */
+
+          if (priv->cj_channels > 0)
+            {
+              adc_inj_startconv(priv, true);
+            }
+
+          break;
+        }
+#endif
+
+      case IO_STOP_ADC:
+        {
+          adc_enable(priv, false);
+          break;
+        }
+
+      case IO_START_ADC:
+        {
+          adc_enable(priv, true);
+          break;
+        }
+
+      case IO_START_CONV:
+        {
+          uint8_t ch = ((uint8_t)arg);
+
+          ret = adc_set_ch(dev, ch);
+          if (ret < 0)
+            {
+              return ret;
+            }
+
+#ifdef CONFIG_ADC
+          if (ch)
+            {
+              /* Clear fifo if upper-half driver enabled */
+
+              dev->ad_recv.af_head = 0;
+              dev->ad_recv.af_tail = 0;
+            }
+#endif
+
+          adc_reg_startconv(priv, true);
+          break;
         }
-        break;
 
       default:
         {
           aerr("ERROR: Unknown cmd: %d\n", cmd);
           ret = -ENOTTY;
+          break;
         }
-        break;
     }
 
   return ret;
 }
 
+#ifndef CONFIG_STM32F7_ADC_NOIRQ
+
 /****************************************************************************
  * Name: adc_interrupt
  *
@@ -1714,7 +2499,7 @@ static int adc_interrupt(struct adc_dev_s *dev)
            */
 
           DEBUGASSERT(priv->cb->au_receive != NULL);
-          priv->cb->au_receive(dev, priv->chanlist[priv->current], data);
+          priv->cb->au_receive(dev, priv->r_chanlist[priv->current], data);
         }
 
       /* Set the channel number of the next channel that will complete
@@ -1723,7 +2508,7 @@ static int adc_interrupt(struct adc_dev_s *dev)
 
       priv->current++;
 
-      if (priv->current >= priv->nchannels)
+      if (priv->current >= priv->rnchannels)
         {
           /* Restart the conversion sequence from the beginning */
 
@@ -1731,8 +2516,10 @@ static int adc_interrupt(struct adc_dev_s *dev)
         }
     }
 
-  regval &= ~pending;
-  adc_putreg(priv, STM32_ADC_ISR_OFFSET, regval);
+  /* Clear pending interrupts */
+
+  adc_putreg(priv, STM32_ADC_ISR_OFFSET, pending);
+
   return OK;
 }
 
@@ -1764,6 +2551,347 @@ static int adc123_interrupt(int irq, void *context, 
void *arg)
 
   return OK;
 }
+#endif /* CONFIG_STM32F7_ADC_NOIRQ */
+
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+
+/****************************************************************************
+ * Name: adc_llops_setup
+ ****************************************************************************/
+
+static int adc_llops_setup(struct stm32_adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  return adc_setup(priv->dev);
+}
+
+/****************************************************************************
+ * Name: adc_llops_shutdown
+ ****************************************************************************/
+
+static void adc_llops_shutdown(struct stm32_adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  adc_shutdown(priv->dev);
+}
+
+/****************************************************************************
+ * Name: adc_intack
+ ****************************************************************************/
+
+static void adc_intack(struct stm32_adc_dev_s *dev, uint32_t source)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  /* Cleared by writing 0 to it */
+
+  adc_modifyreg(priv, STM32_ADC_ISR_OFFSET, (source & ADC_ISR_ALLINTS), 0);
+}
+
+/****************************************************************************
+ * Name: adc_inten
+ ****************************************************************************/
+
+static void adc_inten(struct stm32_adc_dev_s *dev, uint32_t source)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  /* Enable interrupts */
+
+  adc_modifyreg(priv, STM32_ADC_IER_OFFSET, 0, (source & ADC_IER_ALLINTS));
+}
+
+/****************************************************************************
+ * Name: adc_intdis
+ ****************************************************************************/
+
+static void adc_intdis(struct stm32_adc_dev_s *dev, uint32_t source)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  /* Disable interrupts */
+
+  adc_modifyreg(priv, STM32_ADC_IER_OFFSET, (source & ADC_IER_ALLINTS), 0);
+}
+
+/****************************************************************************
+ * Name: adc_ackget
+ ****************************************************************************/
+
+static uint32_t adc_intget(struct stm32_adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+  uint32_t regval;
+  uint32_t pending;
+
+  regval  = adc_getreg(priv, STM32_ADC_ISR_OFFSET);
+  pending = regval & ADC_ISR_ALLINTS;
+
+  return pending;
+}
+
+/****************************************************************************
+ * Name: adc_regget
+ ****************************************************************************/
+
+static uint32_t adc_regget(struct stm32_adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  return adc_getreg(priv, STM32_ADC_DR_OFFSET) & ADC_DR_RDATA_MASK;
+}
+
+/****************************************************************************
+ * Name: adc_llops_reg_startconv
+ ****************************************************************************/
+
+static void adc_llops_reg_startconv(struct stm32_adc_dev_s *dev,
+                                    bool enable)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  adc_reg_startconv(priv, enable);
+}
+
+/****************************************************************************
+ * Name: adc_offset_set
+ ****************************************************************************/
+
+static int adc_offset_set(struct stm32_adc_dev_s *dev, uint8_t ch,
+                          uint8_t i, uint16_t offset)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+  uint32_t reg = 0;
+  int      ret = OK;
+
+  /* WARNING: Offset only for injected channels! */
+
+  UNUSED(ch);
+
+  if (i >= 4)
+    {
+      /* There are only four offset registers. */
+
+      ret = -E2BIG;
+      goto errout;
+    }
+
+  reg = STM32_ADC_JOFR1_OFFSET + i * 4;
+
+  adc_putreg(priv, reg, offset);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: adc_llops_extcfg_set
+ ****************************************************************************/
+
+#ifdef ADC_HAVE_EXTCFG
+static void adc_llops_extcfg_set(struct stm32_adc_dev_s *dev,
+                                 uint32_t extcfg)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  adc_extcfg_set(priv, extcfg);
+}
+#endif
+
+/****************************************************************************
+ * Name: adc_llops_jextcfg_set
+ ****************************************************************************/
+
+#ifdef ADC_HAVE_JEXTCFG
+static void  adc_llops_jextcfg_set(struct stm32_adc_dev_s *dev,
+                                   uint32_t jextcfg)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  adc_jextcfg_set(priv, jextcfg);
+}
+#endif
+
+/****************************************************************************
+ * Name: adc_regbufregister
+ ****************************************************************************/
+
+#ifdef ADC_HAVE_DMA
+static int adc_regbufregister(struct stm32_adc_dev_s *dev,
+                              uint16_t *buffer, uint8_t len)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  stm32_dmasetup(priv->dma,
+                 priv->base + STM32_ADC_DR_OFFSET,
+                 (uint32_t)buffer,
+                 len,
+                 ADC_DMA_CONTROL_WORD);
+
+  /* No DMA callback */
+
+  stm32_dmastart(priv->dma, NULL, dev, false);
+
+  return OK;
+}
+#endif /* ADC_HAVE_DMA */
+
+/****************************************************************************
+ * Name: adc_injget
+ ****************************************************************************/
+
+#ifdef ADC_HAVE_INJECTED
+static uint32_t adc_injget(struct stm32_adc_dev_s *dev, uint8_t chan)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+  uint32_t regval = 0;
+
+  if (chan > (priv->cj_channels - 1))
+    {
+      /* REVISIT: return valute with MSB set to indicate error ? */
+
+      goto errout;
+    }
+
+  regval = adc_getreg(priv, STM32_ADC_JDR1_OFFSET + 4 * (chan)) &
+           ADC_JDR_JDATA_MASK;
+
+errout:
+  return regval;
+}
+
+/****************************************************************************
+ * Name: adc_llops_inj_startconv
+ ****************************************************************************/
+
+static void adc_llops_inj_startconv(struct stm32_adc_dev_s *dev,
+                                    bool enable)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  adc_inj_startconv(priv, enable);
+}
+
+#endif /* ADC_HAVE_INJECTED */
+
+/****************************************************************************
+ * Name: adc_sampletime_write
+ *
+ * Description:
+ *   Writes previously defined values into ADC_SMPRx registers.
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+static void adc_sampletime_write(struct stm32_adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+  uint32_t value = 0;
+  uint8_t i;
+  uint8_t shift;
+
+  /* Sampling time individually for each channel */
+
+  for (i = 0, shift = 0; i < priv->adc_channels; i++)
+    {
+      value |= priv->sample_rate[i] << (shift * 3);
+      switch (i)
+        {
+          case (ADC_CHANNELS_NUMBER - 1):
+            {
+              adc_putreg(priv, STM32_ADC_SMPR2_OFFSET, value);
+              shift = 0;
+              value = 0;
+              break;
+            }
+
+          case 9:
+            {
+              adc_putreg(priv, STM32_ADC_SMPR1_OFFSET, value);
+              shift = 0;
+              value = 0;
+              break;
+            }
+
+          default:
+            {
+              shift++;
+              break;
+            }
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: adc_sampletime_set
+ *
+ * Description:
+ *   Changes sample times for specified channels. This method
+ *   doesn't make any register writing. So, it's only stores the information.
+ *   Values provided by user will be written in registers only on the next
+ *   ADC peripheral start, as it was told to do in manual. However, before
+ *   very first start, user can call this method and override default values
+ *   either for every channels or for only some predefined by user channel(s)
+ *
+ * Input Parameters:
+ *   dev          - pointer to the adc device structure
+ *   time_samples - pointe to the adc sample time configuration data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void adc_sampletime_set(struct stm32_adc_dev_s *dev,
+                        struct adc_sample_time_s *time_samples)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+  uint8_t ch_index;
+  uint8_t i;
+
+  /* Check if user wants to assign the same value for all channels
+   * or just wants to change sample time values for certain channels
+   */
+
+  if (time_samples->all_same)
+    {
+      memset(priv->sample_rate, time_samples->all_ch_sample_time,
+             ADC_CHANNELS_NUMBER);
+    }
+  else
+    {
+      for (i = 0; i < time_samples->channels_nbr; i++)
+        {
+          ch_index = time_samples->channel[i].channel;
+          if (ch_index >= ADC_CHANNELS_NUMBER)
+            {
+              break;
+            }
+
+          priv->sample_rate[ch_index] = time_samples->channel[i].sample_time;
+        }
+    }
+}
+#endif /* CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME */
+
+/****************************************************************************
+ * Name: adc_llops_dumpregs
+ ****************************************************************************/
+
+static void adc_llops_dumpregs(struct stm32_adc_dev_s *dev)
+{
+  struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
+
+  adc_dumpregs(priv);
+}
+
+#endif /* CONFIG_STM32F7_ADC_LL_OPS */
 
 /****************************************************************************
  * Public Functions
@@ -1775,79 +2903,182 @@ static int adc123_interrupt(int irq, void *context, 
void *arg)
  * Description:
  *   Initialize the ADC.
  *
- *   The logic is, save nchannels : # of channels (conversions) in ADC_SQR1_L
- *   Then, take the chanlist array and store it in the SQR Regs,
- *     chanlist[0] -> ADC_SQR3_SQ1
- *     chanlist[1] -> ADC_SQR3_SQ2
+ *   The logic allow initialize ADC regular and injected channels.
+ *
+ *   The number of injected channels for given ADC is selected from Kconfig
+ *   with CONFIG_STM32F7_ADCx_INJECTED_CHAN definitions
+ *
+ *   The number of regular channels is obtained from the equation:
+ *
+ *     cr_channels = channels - cj_channels
+ *
+ *   where:
+ *     cr_channels - regular channels
+ *     cj_channels - injected channels
+ *     channels    - this function parameter
+ *
+ *   The chanlist array store both regular channels and injected channels
+ *   configuration so that regular channels are the first in order:
+ *
+ *     # regular channels start from here
+ *     chanlist[0]                  -> ADC_SQRx_SQ1
+ *     chanlist[1]                  -> ADC_SQRx_SQ2
  *     ...
- *     chanlist[15]-> ADC_SQR1_SQ16
+ *     # injected channels start from here
+ *     chanlist[channels - (y - 1)] -> ADC_JSQR_JSQ1
+ *     ...
+ *     chanlist[channels]           -> ADC_JSQR_ISQy
+ *
+ *   where:
+ *      y = CONFIG_STM32F7_ADCx_INJECTED_CHAN, and y > 0
  *
- *   up to
- *     chanlist[nchannels]
+ *   If CONFIG_STM32F7_ADCx_INJECTED_CHAN = 0, then all channels from
+ *   chanlist are regular channels.
  *
  * Input Parameters:
- *   intf      - Could be {1,2,3} for ADC1, ADC2, or ADC3
- *   chanlist  - The list of channels
- *   cchannels - Number of channels
+ *   intf      - Could be {1,2,3,4} for ADC1, ADC2, ADC3
+ *   chanlist  - The list of channels (regular + injected)
+ *   channels  - Number of channels (regular + injected)
  *
  * Returned Value:
  *   Valid ADC device structure reference on success; a NULL on failure
  *
  ****************************************************************************/
 
-struct adc_dev_s *stm32_adc_initialize(int intf, const uint8_t *chanlist,
-                                       int cchannels)
+struct adc_dev_s *stm32_adc_initialize(int intf,
+                                       const uint8_t *chanlist,
+                                       int channels)
 {
   struct adc_dev_s   *dev;
   struct stm32_dev_s *priv;
-
-  ainfo("intf: %d cchannels: %d\n", intf, cchannels);
+  uint8_t     cr_channels = 0;
+  uint8_t     cj_channels = 0;
+#ifdef ADC_HAVE_INJECTED
+  uint8_t *j_chanlist = NULL;
+#endif
 
   switch (intf)
     {
 #ifdef CONFIG_STM32F7_ADC1
       case 1:
-        ainfo("ADC1 selected\n");
-        dev = &g_adcdev1;
-        break;
-#endif
+        {
+          ainfo("ADC1 selected\n");
+          dev = &g_adcdev1;
+          cj_channels = CONFIG_STM32F7_ADC1_INJECTED_CHAN;
+          cr_channels = channels - cj_channels;
+#  ifdef ADC_HAVE_INJECTED
+          if (cj_channels > 0)
+            {
+              j_chanlist  = (uint8_t *)chanlist + cr_channels;
+            }
+#  endif
+          break;
+        }
+#endif /* CONFIG_STM32F7_ADC1 */
+
 #ifdef CONFIG_STM32F7_ADC2
       case 2:
-        ainfo("ADC2 selected\n");
-        dev = &g_adcdev2;
-        break;
-#endif
+        {
+          ainfo("ADC2 selected\n");
+          dev = &g_adcdev2;
+          cj_channels = CONFIG_STM32F7_ADC2_INJECTED_CHAN;
+          cr_channels = channels - cj_channels;
+#  ifdef ADC_HAVE_INJECTED
+          if (cj_channels > 0)
+            {
+              j_chanlist  = (uint8_t *)chanlist + cr_channels;
+            }
+#  endif
+          break;
+        }
+#endif /* CONFIG_STM32F7_ADC2 */
+
 #ifdef CONFIG_STM32F7_ADC3
       case 3:
-        ainfo("ADC3 selected\n");
-        dev = &g_adcdev3;
-        break;
-#endif
+        {
+          ainfo("ADC3 selected\n");
+          dev = &g_adcdev3;
+          cj_channels = CONFIG_STM32F7_ADC3_INJECTED_CHAN;
+          cr_channels = channels - cj_channels;
+#  ifdef ADC_HAVE_INJECTED
+          if (cj_channels > 0)
+            {
+              j_chanlist  = (uint8_t *)chanlist + cr_channels;
+            }
+#  endif
+          break;
+        }
+
+#endif /* CONFIG_STM32F7_ADC3 */
+
       default:
-        aerr("ERROR: No ADC interface defined\n");
-        return NULL;
+        {
+          aerr("ERROR: No ADC interface defined\n");
+          return NULL;
+        }
     }
 
   /* Configure the selected ADC */
 
-  priv     = (struct stm32_dev_s *)dev->ad_priv;
-  priv->cb = NULL;
+  priv = (struct stm32_dev_s *)dev->ad_priv;
+
+  /* Configure regular channels */
+
+  DEBUGASSERT(cr_channels <= CONFIG_STM32F7_ADC_MAX_SAMPLES);
+  if (cr_channels > CONFIG_STM32F7_ADC_MAX_SAMPLES)
+    {
+      cr_channels = CONFIG_STM32F7_ADC_MAX_SAMPLES;
+    }
+
+  priv->cr_channels = cr_channels;
+  memcpy(priv->r_chanlist, chanlist, cr_channels);
 
-  DEBUGASSERT(cchannels <= ADC_MAX_SAMPLES);
-  if (cchannels > ADC_MAX_SAMPLES)
+#ifdef ADC_HAVE_INJECTED
+  /* Configure injected channels */
+
+  DEBUGASSERT(cj_channels <= ADC_INJ_MAX_SAMPLES);
+  if (cj_channels > ADC_INJ_MAX_SAMPLES)
     {
-      cchannels = ADC_MAX_SAMPLES;
+      cj_channels = ADC_INJ_MAX_SAMPLES;
     }
 
-  priv->cchannels = cchannels;
+  priv->cj_channels = cj_channels;
+  memcpy(priv->j_chanlist, j_chanlist, cj_channels);
+#endif
+
+#ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+  /* Assign default values for the sample time table */
+
+  memset(priv->sample_rate, ADC_SMPR_DEFAULT, ADC_CHANNELS_NUMBER);
+  priv->adc_channels = ADC_CHANNELS_NUMBER;
+#endif
+
+#ifdef ADC_HAVE_CB
+  priv->cb        = NULL;
+#endif
+
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+  /* Store reference to the upper-half ADC device */
+
+  priv->dev = dev;
+#endif
+
+#ifdef ADC_HAVE_INJECTED
+  ainfo("intf: %d cr_channels: %d, cj_channels: %d\n",
+        intf, priv->cr_channels, priv->cj_channels);
+#else
+  ainfo("intf: %d cr_channels: %d\n", intf, priv->cr_channels);
+#endif
+
+  /* Initialize the ADC common data semaphore.
+   *
+   * REVISIT: This will be done several times for each initialzied ADC in
+   *          the ADC block.
+   */
 
-  memcpy(priv->chanlist, chanlist, cchannels);
+  nxsem_init(&priv->cmn->lock, 0, 1);
 
   return dev;
 }
 
-#endif /* CONFIG_STM32F7_STM32F74XX */
-#endif /* CONFIG_STM32F7_ADC1 || CONFIG_STM32F7_ADC2 ||
-        * CONFIG_STM32F7_ADC3
-        */
-#endif /* CONFIG_ADC */
+#endif /* CONFIG_STM32F7_ADC */
diff --git a/arch/arm/src/stm32f7/stm32_adc.h b/arch/arm/src/stm32f7/stm32_adc.h
index cdeb74511f..6ebde261ca 100644
--- a/arch/arm/src/stm32f7/stm32_adc.h
+++ b/arch/arm/src/stm32f7/stm32_adc.h
@@ -34,6 +34,25 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+/* Generalized definitions for ADC  *****************************************/
+
+#define STM32_ADC_DMAREG_OFFSET    STM32_ADC_CR2_OFFSET
+#define ADC_DMAREG_DMA             ADC_CR2_DMA
+#define STM32_ADC_EXTREG_OFFSET    STM32_ADC_CR2_OFFSET
+#define ADC_EXTREG_EXTSEL_MASK     ADC_CR2_EXTSEL_MASK
+#define ADC_EXTREG_EXTSEL_SHIFT    ADC_CR2_EXTSEL_SHIFT
+#define STM32_ADC_JEXTREG_OFFSET   STM32_ADC_CR2_OFFSET
+#define ADC_JEXTREG_JEXTSEL_MASK   ADC_CR2_JEXTSEL_MASK
+#define ADC_EXTREG_JEXTSEL_SHIFT   ADC_CR2_JEXTSEL_SHIFT
+#define STM32_ADC_ISR_OFFSET       STM32_ADC_SR_OFFSET
+#define STM32_ADC_IER_OFFSET       STM32_ADC_CR1_OFFSET
+#define ADC_EXTREG_EXTEN_MASK      ADC_CR2_EXTEN_MASK
+#define ADC_EXTREG_EXTEN_NONE      ADC_CR2_EXTEN_NONE
+#define ADC_EXTREG_EXTEN_DEFAULT   ADC_CR2_EXTEN_RISING
+#define ADC_JEXTREG_JEXTEN_MASK    ADC_CR2_JEXTEN_MASK
+#define ADC_JEXTREG_JEXTEN_NONE    ADC_CR2_JEXTEN_NONE
+#define ADC_JEXTREG_JEXTEN_DEFAULT ADC_CR2_JEXTEN_RISING
+
 /* Configuration ************************************************************/
 
 /* Timer devices may be used for different purposes.  One special purpose is
@@ -87,18 +106,6 @@
 
 /* Up to 3 ADC interfaces are supported */
 
-#if STM32F7_NADC < 3
-#  undef CONFIG_STM32F7_ADC3
-#endif
-
-#if STM32F7_NADC < 2
-#  undef CONFIG_STM32F7_ADC2
-#endif
-
-#if STM32F7_NADC < 1
-#  undef CONFIG_STM32F7_ADC1
-#endif
-
 #if defined(CONFIG_STM32F7_ADC1) || defined(CONFIG_STM32F7_ADC2) || \
     defined(CONFIG_STM32F7_ADC3)
 
@@ -128,6 +135,14 @@
 #  undef  ADC3_HAVE_DMA
 #endif
 
+/* Injected channels support */
+
+#if (defined(CONFIG_STM32F7_ADC1) && (CONFIG_STM32F7_ADC1_INJECTED_CHAN > 0)) 
|| \
+    (defined(CONFIG_STM32F7_ADC2) && (CONFIG_STM32F7_ADC2_INJECTED_CHAN > 0)) 
|| \
+    (defined(CONFIG_STM32F7_ADC3) && (CONFIG_STM32F7_ADC3_INJECTED_CHAN > 0))
+#  define ADC_HAVE_INJECTED
+#endif
+
 /* Timer configuration:  If a timer trigger is specified, then get
  * information about the timer.
  */
@@ -175,35 +190,35 @@
 #endif
 
 #if defined(CONFIG_STM32F7_TIM1_ADC2)
-#    define ADC2_HAVE_TIMER           1
-#    define ADC2_TIMER_BASE           STM32_TIM1_BASE
-#    define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM1_CLKIN
+#  define ADC2_HAVE_TIMER           1
+#  define ADC2_TIMER_BASE           STM32_TIM1_BASE
+#  define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM1_CLKIN
 #elif defined(CONFIG_STM32F7_TIM2_ADC2)
-#    define ADC2_HAVE_TIMER           1
-#    define ADC2_TIMER_BASE           STM32_TIM2_BASE
-#    define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM2_CLKIN
+#  define ADC2_HAVE_TIMER           1
+#  define ADC2_TIMER_BASE           STM32_TIM2_BASE
+#  define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM2_CLKIN
 #elif defined(CONFIG_STM32F7_TIM3_ADC2)
-#    define ADC2_HAVE_TIMER           1
-#    define ADC2_TIMER_BASE           STM32_TIM3_BASE
-#    define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM3_CLKIN
+#  define ADC2_HAVE_TIMER           1
+#  define ADC2_TIMER_BASE           STM32_TIM3_BASE
+#  define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM3_CLKIN
 #elif defined(CONFIG_STM32F7_TIM4_ADC2)
-#    define ADC2_HAVE_TIMER           1
-#    define ADC2_TIMER_BASE           STM32_TIM4_BASE
-#    define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM4_CLKIN
+#  define ADC2_HAVE_TIMER           1
+#  define ADC2_TIMER_BASE           STM32_TIM4_BASE
+#  define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM4_CLKIN
 #elif defined(CONFIG_STM32F7_TIM5_ADC2)
-#    define ADC2_HAVE_TIMER           1
-#    define ADC2_TIMER_BASE           STM32_TIM5_BASE
-#    define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM5_CLKIN
+#  define ADC2_HAVE_TIMER           1
+#  define ADC2_TIMER_BASE           STM32_TIM5_BASE
+#  define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM5_CLKIN
 #elif defined(CONFIG_STM32F7_TIM6_ADC2)
-#    define ADC2_HAVE_TIMER           1
-#    define ADC2_TIMER_BASE           STM32_TIM6_BASE
-#    define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM6_CLKIN
+#  define ADC2_HAVE_TIMER           1
+#  define ADC2_TIMER_BASE           STM32_TIM6_BASE
+#  define ADC2_TIMER_PCLK_FREQUENCY STM32_APB1_TIM6_CLKIN
 #elif defined(CONFIG_STM32F7_TIM8_ADC2)
-#    define ADC2_HAVE_TIMER           1
-#    define ADC2_TIMER_BASE           STM32_TIM8_BASE
-#    define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN
+#  define ADC2_HAVE_TIMER           1
+#  define ADC2_TIMER_BASE           STM32_TIM8_BASE
+#  define ADC2_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN
 #else
-#    undef  ADC2_HAVE_TIMER
+#  undef  ADC2_HAVE_TIMER
 #endif
 
 #ifdef ADC2_HAVE_TIMER
@@ -217,35 +232,31 @@
 #endif
 
 #if defined(CONFIG_STM32F7_TIM1_ADC3)
-#    define ADC3_HAVE_TIMER           1
-#    define ADC3_TIMER_BASE           STM32_TIM1_BASE
-#    define ADC3_TIMER_PCLK_FREQUENCY STM32_APB2_TIM1_CLKIN
+#  define ADC3_HAVE_TIMER           1
+#  define ADC3_TIMER_BASE           STM32_TIM1_BASE
+#  define ADC3_TIMER_PCLK_FREQUENCY STM32_APB2_TIM1_CLKIN
 #elif defined(CONFIG_STM32F7_TIM2_ADC3)
-#    define ADC3_HAVE_TIMER           1
-#    define ADC3_TIMER_BASE           STM32_TIM2_BASE
-#    define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM2_CLKIN
+#  define ADC3_HAVE_TIMER           1
+#  define ADC3_TIMER_BASE           STM32_TIM2_BASE
+#  define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM2_CLKIN
 #elif defined(CONFIG_STM32F7_TIM3_ADC3)
-#    define ADC3_HAVE_TIMER           1
-#    define ADC3_TIMER_BASE           STM32_TIM3_BASE
-#    define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM3_CLKIN
+#  define ADC3_HAVE_TIMER           1
+#  define ADC3_TIMER_BASE           STM32_TIM3_BASE
+#  define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM3_CLKIN
 #elif defined(CONFIG_STM32F7_TIM4_ADC3)
-#    define ADC3_HAVE_TIMER           1
-#    define ADC3_TIMER_BASE           STM32_TIM4_BASE
-#    define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM4_CLKIN
+#  define ADC3_HAVE_TIMER           1
+#  define ADC3_TIMER_BASE           STM32_TIM4_BASE
+#  define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM4_CLKIN
 #elif defined(CONFIG_STM32F7_TIM5_ADC3)
-#    define ADC3_HAVE_TIMER           1
-#    define ADC3_TIMER_BASE           STM32_TIM5_BASE
-#    define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM5_CLKIN
-#elif defined(CONFIG_STM32F7_TIM6_ADC3)
-#    define ADC3_HAVE_TIMER           1
-#    define ADC3_TIMER_BASE           STM32_TIM6_BASE
-#    define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM6_CLKIN
+#  define ADC3_HAVE_TIMER           1
+#  define ADC3_TIMER_BASE           STM32_TIM5_BASE
+#  define ADC3_TIMER_PCLK_FREQUENCY STM32_APB1_TIM5_CLKIN
 #elif defined(CONFIG_STM32F7_TIM8_ADC3)
-#    define ADC3_HAVE_TIMER           1
-#    define ADC3_TIMER_BASE           STM32_TIM8_BASE
-#    define ADC3_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN
+#  define ADC3_HAVE_TIMER           1
+#  define ADC3_TIMER_BASE           STM32_TIM8_BASE
+#  define ADC3_TIMER_PCLK_FREQUENCY STM32_APB2_TIM8_CLKIN
 #else
-#    undef  ADC3_HAVE_TIMER
+#  undef  ADC3_HAVE_TIMER
 #endif
 
 #ifdef ADC3_HAVE_TIMER
@@ -390,7 +401,15 @@
 #define ADC3_EXTSEL_T8CC3      ADC_CR2_EXTSEL_T8CC3
 #define ADC3_EXTSEL_T8CC4      ADC_CR2_EXTSEL_T8CC4
 #define ADC3_EXTSEL_T8TRGO     ADC_CR2_EXTSEL_T8TRGO
-#define ADC3_EXTSEL_T8TRGO2     ADC_CR2_EXTSEL_T8TRGO2
+#define ADC3_EXTSEL_T8TRGO2    ADC_CR2_EXTSEL_T8TRGO2
+
+/* EXTSEL configuration *****************************************************/
+
+/* NOTE:
+ * this configuration if used only if CONFIG_STM32F7_TIMx_ADCy is selected.
+ * You can still connect the ADC with a timer trigger using the
+ * CONFIG_STM32F7_ADCx_EXTSEL option.
+ */
 
 #if defined(CONFIG_STM32F7_TIM1_ADC1)
 #  if CONFIG_STM32F7_ADC1_TIMTRIG == 0
@@ -704,10 +723,288 @@
 #  endif
 #endif
 
+/* Regular channels external trigger support */
+
+#ifdef ADC1_EXTSEL_VALUE
+#  define ADC1_HAVE_EXTCFG  1
+#  define ADC1_EXTCFG_VALUE (ADC1_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT)
+#elif defined(CONFIG_STM32F7_ADC1_EXTSEL)
+#  define ADC1_HAVE_EXTCFG  1
+#  define ADC1_EXTCFG_VALUE 0
+#else
+#  undef ADC1_HAVE_EXTCFG
+#endif
+#ifdef ADC2_EXTSEL_VALUE
+#  define ADC2_HAVE_EXTCFG  1
+#  define ADC2_EXTCFG_VALUE (ADC2_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT)
+#elif defined(CONFIG_STM32F7_ADC2_EXTSEL)
+#  define ADC2_HAVE_EXTCFG  1
+#  define ADC2_EXTCFG_VALUE 0
+#else
+#  undef ADC2_HAVE_EXTCFG
+#endif
+#ifdef ADC3_EXTSEL_VALUE
+#  define ADC3_HAVE_EXTCFG  1
+#  define ADC3_EXTCFG_VALUE (ADC3_EXTSEL_VALUE | ADC_EXTREG_EXTEN_DEFAULT)
+#elif defined(CONFIG_STM32F7_ADC3_EXTSEL)
+#  define ADC3_HAVE_EXTCFG  1
+#  define ADC3_EXTCFG_VALUE 0
+#else
+#  undef ADC3_HAVE_EXTCFG
+#endif
+
+#if defined(ADC1_HAVE_EXTCFG) || defined(ADC2_HAVE_EXTCFG) || \
+    defined(ADC3_HAVE_EXTCFG) || defined(ADC3_HAVE_EXTCFG)
+#  define ADC_HAVE_EXTCFG
+#endif
+
+/* JEXTSEL configuration ****************************************************/
+
+/* There is no automatic timer tirgger configuration from Kconfig for
+ * injected channels conversion.
+ */
+
+/* Injected channels external trigger support */
+
+#ifdef ADC1_JEXTSEL_VALUE
+#  define ADC1_HAVE_JEXTCFG  1
+#  define ADC1_JEXTCFG_VALUE (ADC1_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT)
+#elif defined(CONFIG_STM32F7_ADC1_JEXTSEL)
+#  define ADC1_HAVE_JEXTCFG  1
+#  define ADC1_JEXTCFG_VALUE 0
+#else
+#  undef ADC1_HAVE_JEXTCFG
+#endif
+#ifdef ADC2_JEXTSEL_VALUE
+#  define ADC2_HAVE_JEXTCFG  1
+#  define ADC2_JEXTCFG_VALUE (ADC2_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT)
+#elif defined(CONFIG_STM32F7_ADC2_JEXTSEL)
+#  define ADC2_HAVE_JEXTCFG  1
+#  define ADC2_JEXTCFG_VALUE 0
+#else
+#  undef ADC2_HAVE_JEXTCFG
+#endif
+#ifdef ADC3_JEXTSEL_VALUE
+#  define ADC3_HAVE_JEXTCFG  1
+#  define ADC3_JEXTCFG_VALUE (ADC3_JEXTSEL_VALUE | ADC_JEXTREG_JEXTEN_DEFAULT)
+#elif defined(CONFIG_STM32F7_ADC3_JEXTSEL)
+#  define ADC3_HAVE_JEXTCFG  1
+#  define ADC3_JEXTCFG_VALUE 0
+#else
+#  undef ADC3_HAVE_JEXTCFG
+#endif
+
+#if defined(ADC1_HAVE_JEXTCFG) || defined(ADC2_HAVE_JEXTCFG) || \
+    defined(ADC3_HAVE_JEXTCFG)
+#  define ADC_HAVE_JEXTCFG
+#endif
+
+/* ADC interrupts ***********************************************************/
+
+#define ADC_ISR_EOC                ADC_SR_EOC
+#define ADC_IER_EOC                ADC_CR1_EOCIE
+#define ADC_ISR_AWD                ADC_SR_AWD
+#define ADC_IER_AWD                ADC_CR1_AWDIE
+#define ADC_ISR_JEOC               ADC_SR_JEOC
+#define ADC_IER_JEOC               ADC_CR1_JEOCIE
+#define ADC_ISR_JEOS               0 /* No JEOS */
+#define ADC_IER_JEOS               0 /* No JEOS */
+#define ADC_ISR_OVR                ADC_SR_OVR
+#define ADC_IER_OVR                ADC_CR1_OVRIE
+
+#define ADC_ISR_ALLINTS (ADC_ISR_EOC | ADC_ISR_AWD | ADC_ISR_JEOC | \
+                         ADC_ISR_JEOS | ADC_ISR_OVR)
+#define ADC_IER_ALLINTS (ADC_IER_EOC | ADC_IER_AWD | ADC_IER_JEOC | \
+                         ADC_IER_JEOS | ADC_IER_OVR)
+
+/* Low-level ops helpers ****************************************************/
+
+#define STM32_ADC_INT_ACK(adc, source)              \
+        (adc)->llops->int_ack(adc, source)
+#define STM32_ADC_INT_GET(adc)                      \
+        (adc)->llops->int_get(adc)
+#define STM32_ADC_INT_ENABLE(adc, source)           \
+        (adc)->llops->int_en(adc, source)
+#define STM32_ADC_INT_DISABLE(adc, source)          \
+        (adc)->llops->int_dis(adc, source)
+#define STM32_ADC_REGDATA_GET(adc)                  \
+        (adc)->llops->val_get(adc)
+#define STM32_ADC_REGBUF_REGISTER(adc, buffer, len) \
+        (adc)->llops->regbuf_reg(adc, buffer, len)
+#define STM32_ADC_REG_STARTCONV(adc, state)         \
+        (adc)->llops->reg_startconv(adc, state)
+#define STM32_ADC_OFFSET_SET(adc, ch, i, o)         \
+        (adc)->llops->offset_set(adc, ch, i, o)
+#define STM32_ADC_EXTCFG_SET(adc, c)                \
+        (adc)->llops->extcfg_set(adc, c)
+#define STM32_ADC_INJ_STARTCONV(adc, state)         \
+        (adc)->llops->inj_startconv(adc, state)
+#define STM32_ADC_INJDATA_GET(adc, chan)            \
+        (adc)->llops->inj_get(adc, chan)
+#define STM32_ADC_JEXTCFG_SET(adc, c)               \
+        (adc)->llops->jextcfg_set(adc, c)
+#define STM32_ADC_SAMPLETIME_SET(adc, time_samples) \
+        (adc)->llops->stime_set(adc, time_samples)
+#define STM32_ADC_SAMPLETIME_WRITE(adc)             \
+        (adc)->llops->stime_write(adc)
+#define STM32_ADC_DUMP_REGS(adc)                    \
+        (adc)->llops->dump_regs(adc)
+#define STM32_ADC_SETUP(adc)                        \
+        (adc)->llops->setup(adc)
+#define STM32_ADC_SHUTDOWN(adc)                     \
+        (adc)->llops->shutdown(adc)
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
 
+enum adc_io_cmds_e
+{
+  IO_STOP_ADC,
+  IO_START_ADC,
+  IO_START_CONV,
+  IO_TRIGGER_REG,
+#ifdef ADC_HAVE_INJECTED
+  IO_TRIGGER_INJ,
+#endif
+};
+
+/* ADC resolution can be reduced in order to perform faster conversion */
+
+enum stm32_adc_resoluton_e
+{
+  ADC_RESOLUTION_12BIT = 0,     /* 12 bit */
+  ADC_RESOLUTION_10BIT = 1,     /* 10 bit */
+  ADC_RESOLUTION_8BIT  = 2,     /* 8 bit */
+  ADC_RESOLUTION_6BIT  = 3      /* 6 bit */
+};
+
+#ifdef CONFIG_STM32F7_ADC_LL_OPS
+
+#ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+
+/* Channel and sample time pair */
+
+typedef struct adc_channel_s
+{
+  uint8_t channel:5;
+
+  /* Sampling time individually for each channel */
+
+  uint8_t sample_time:3;
+} adc_channel_t;
+
+/* This structure will be used while setting channels to specified by the
+ * "channel-sample time" pairs' values
+ */
+
+struct adc_sample_time_s
+{
+  adc_channel_t *channel;                /* Array of channels */
+  uint8_t        channels_nbr:5;         /* Number of channels in array */
+  bool           all_same:1;             /* All channels will get the
+                                          * same value of the sample time */
+  uint8_t        all_ch_sample_time:3;   /* Sample time for all channels */
+};
+#endif /* CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME */
+
+/* This structure provides the publicly visible representation of the
+ * "lower-half" ADC driver structure.
+ */
+
+struct stm32_adc_dev_s
+{
+  /* Publicly visible portion of the "lower-half" ADC driver structure */
+
+  const struct stm32_adc_ops_s *llops;
+
+  /* Require cast-compatibility with private "lower-half" ADC structure */
+};
+
+/* Low-level operations for ADC */
+
+struct stm32_adc_ops_s
+{
+  /* Low-level ADC setup */
+
+  int (*setup)(struct stm32_adc_dev_s *dev);
+
+  /* Low-level ADC shutdown */
+
+  void (*shutdown)(struct stm32_adc_dev_s *dev);
+
+  /* Acknowledge interrupts */
+
+  void (*int_ack)(struct stm32_adc_dev_s *dev, uint32_t source);
+
+  /* Get pending interrupts */
+
+  uint32_t (*int_get)(struct stm32_adc_dev_s *dev);
+
+  /* Enable interrupts */
+
+  void (*int_en)(struct stm32_adc_dev_s *dev, uint32_t source);
+
+  /* Disable interrupts */
+
+  void (*int_dis)(struct stm32_adc_dev_s *dev, uint32_t source);
+
+  /* Get current ADC data register */
+
+  uint32_t (*val_get)(struct stm32_adc_dev_s *dev);
+
+  /* Register buffer for ADC DMA transfer */
+
+  int (*regbuf_reg)(struct stm32_adc_dev_s *dev,
+                    uint16_t *buffer, uint8_t len);
+
+  /* Start/stop regular conversion */
+
+  void (*reg_startconv)(struct stm32_adc_dev_s *dev, bool state);
+
+  /* Set offset for channel */
+
+  int (*offset_set)(struct stm32_adc_dev_s *dev, uint8_t ch, uint8_t i,
+                    uint16_t offset);
+
+#ifdef ADC_HAVE_EXTCFG
+  /* Configure the ADC external trigger for regular conversion */
+
+  void (*extcfg_set)(struct stm32_adc_dev_s *dev, uint32_t extcfg);
+#endif
+
+#ifdef ADC_HAVE_JEXTCFG
+  /* Configure the ADC external trigger for injected conversion */
+
+  void (*jextcfg_set)(struct stm32_adc_dev_s *dev, uint32_t jextcfg);
+#endif
+
+#ifdef ADC_HAVE_INJECTED
+  /* Get current ADC injected data register */
+
+  uint32_t (*inj_get)(struct stm32_adc_dev_s *dev, uint8_t chan);
+
+  /* Start/stop injected conversion */
+
+  void (*inj_startconv)(struct stm32_adc_dev_s *dev, bool state);
+#endif
+
+#ifdef CONFIG_STM32F7_ADC_CHANGE_SAMPLETIME
+  /* Set ADC sample time */
+
+  void (*stime_set)(struct stm32_adc_dev_s *dev,
+                    struct adc_sample_time_s *time_samples);
+
+  /* Write ADC sample time */
+
+  void (*stime_write)(struct stm32_adc_dev_s *dev);
+#endif
+
+  void (*dump_regs)(struct stm32_adc_dev_s *dev);
+};
+
+#endif /* CONFIG_STM32F7_ADC_LL_OPS */
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
@@ -722,15 +1019,15 @@ extern "C"
 #endif
 
 /****************************************************************************
- * Name: stm32_adc_initialiize
+ * Name: stm32_adc_initialize
  *
  * Description:
- *   Initialize the ADC.
+ *   Initialize the ADC. See stm32_adc.c for more details.
  *
  * Input Parameters:
- *   intf      - Could be {1,2,3} for ADC1, ADC2, or ADC3
- *   chanlist  - The list of channels
- *   nchannels - Number of channels
+ *   intf      - Could be {1,2,3} for ADC1, ADC2, ADC3
+ *   chanlist  - The list of channels (regular + injected)
+ *   nchannels - Number of channels (regular + injected)
  *
  * Returned Value:
  *   Valid ADC device structure reference on success; a NULL on failure
@@ -741,6 +1038,7 @@ struct adc_dev_s;
 struct adc_dev_s *stm32_adc_initialize(int intf,
                                        const uint8_t *chanlist,
                                        int nchannels);
+
 #undef EXTERN
 #ifdef __cplusplus
 }

Reply via email to