You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/09/23 16:17:29 UTC
[incubator-nuttx] 01/02: imxrt: ADC driver
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit d67bc0c3c82dd5fb4f7b2feaae1601207c1c84ab
Author: Thomas Axelsson <th...@actia.se>
AuthorDate: Tue Sep 15 14:50:19 2020 +0200
imxrt: ADC driver
Based on LPC17xx_40xx and STM32 drivers.
---
arch/arm/src/imxrt/Kconfig | 18 +
arch/arm/src/imxrt/Make.defs | 4 +
arch/arm/src/imxrt/hardware/imxrt_adc.h | 8 +-
arch/arm/src/imxrt/hardware/imxrt_iomuxc.h | 2 +
.../src/imxrt/hardware/rt106x/imxrt106x_pinmux.h | 34 ++
arch/arm/src/imxrt/imxrt_adc.c | 619 +++++++++++++++++++++
arch/arm/src/imxrt/imxrt_adc.h | 100 ++++
boards/arm/imxrt/imxrt1060-evk/src/Makefile | 4 +
boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h | 12 +
boards/arm/imxrt/imxrt1060-evk/src/imxrt_adc.c | 167 ++++++
boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c | 10 +
11 files changed, 974 insertions(+), 4 deletions(-)
diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig
index 8290ff5..0364e47 100644
--- a/arch/arm/src/imxrt/Kconfig
+++ b/arch/arm/src/imxrt/Kconfig
@@ -163,6 +163,10 @@ config IMXRT_LPSPI
bool
default n
+config IMXRT_ADC
+ bool
+ default n
+
config IMXRT_ENC
bool
default n
@@ -518,6 +522,20 @@ menuconfig IMXRT_LPSPI4
endmenu # LPSPI Peripherals
+menu "ADC Peripherals"
+
+menuconfig IMXRT_ADC1
+ bool "ADC1"
+ default n
+ select IMXRT_ADC
+
+menuconfig IMXRT_ADC2
+ bool "ADC2"
+ default n
+ select IMXRT_ADC
+
+endmenu
+
config IMXRT_SEMC
bool "Smart External Memory Controller (SEMC)"
default n
diff --git a/arch/arm/src/imxrt/Make.defs b/arch/arm/src/imxrt/Make.defs
index 3d3b8cf..bfcefe5 100644
--- a/arch/arm/src/imxrt/Make.defs
+++ b/arch/arm/src/imxrt/Make.defs
@@ -167,3 +167,7 @@ endif
ifeq ($(CONFIG_IMXRT_USBDEV),y)
CHIP_CSRCS += imxrt_usbdev.c
endif
+
+ifeq ($(CONFIG_IMXRT_ADC),y)
+CHIP_CSRCS += imxrt_adc.c
+endif
diff --git a/arch/arm/src/imxrt/hardware/imxrt_adc.h b/arch/arm/src/imxrt/hardware/imxrt_adc.h
index de19fc8..78f04ae 100644
--- a/arch/arm/src/imxrt/hardware/imxrt_adc.h
+++ b/arch/arm/src/imxrt/hardware/imxrt_adc.h
@@ -194,10 +194,10 @@
#define ADC_CFG_ADSTS_SHIFT (8) /* Bits: 8-9 Defines the sample time duration. */
#define ADC_CFG_ADSTS_MASK (3 << ADC_CFG_ADSTS_SHIFT)
# define ADC_CFG_ADSTS(n) ((uint32_t)(n) << ADC_CFG_ADSTS_SHIFT)
-# define ADC_CFG_ADSTS_2_12 (0 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 2 if ADLSMP=0b, 12 if ADLSMP=1b */
-# define ADC_CFG_ADSTS_4_16 (1 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 4 if ADLSMP=0b, 16 if ADLSMP=1b */
-# define ADC_CFG_ADSTS_6_20 (2 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 6 if ADLSMP=0b, 20 if ADLSMP=1b */
-# define ADC_CFG_ADSTS_8_24 (3 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 8 if ADLSMP=0b, 24 if ADLSMP=1b */
+# define ADC_CFG_ADSTS_3_13 (0 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 3 if ADLSMP=0b, 13 if ADLSMP=1b */
+# define ADC_CFG_ADSTS_5_17 (1 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 5 if ADLSMP=0b, 17 if ADLSMP=1b */
+# define ADC_CFG_ADSTS_7_21 (2 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 7 if ADLSMP=0b, 21 if ADLSMP=1b */
+# define ADC_CFG_ADSTS_9_25 (3 << ADC_CFG_ADSTS_SHIFT) /* Sample period (ADC clocks) = 9 if ADLSMP=0b, 25 if ADLSMP=1b */
#define ADC_CFG_ADHSC (1 << 10) /* Bit: 10 High Speed Configuration*/
#define ADC_CFG_REFSEL_SHIFT (11) /* Bits: 11-12 Voltage Reference Selection */
#define ADC_CFG_REFSEL_MASK (3 << ADC_CFG_REFSEL_SHIFT)
diff --git a/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h b/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h
index 43041f4..493bf3b 100644
--- a/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h
+++ b/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h
@@ -181,4 +181,6 @@
IOMUX_SPEED_LOW )
#define IOMUX_USBOTG_OC_DEFAULT (IOMUX_PULL_UP_100K)
+#define IOMUX_ADC_DEFAULT (0)
+
#endif /* __ARCH_ARM_SRC_IMXRT_HARDWARE_IMXRT_IOMUXC_H */
diff --git a/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h b/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h
index 94608d0..8b71af2 100644
--- a/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h
+++ b/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h
@@ -1081,4 +1081,38 @@
#define GPIO_XBAR1_INOUT19_4 (GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_07_INDEX))
#define GPIO_XBAR1_XBAR_IN02_1 (GPIO_PERIPH | GPIO_ALT3 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_00_INDEX))
+/* ADC */
+#define GPIO_ADC1_CH0 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_11_INDEX))
+#define GPIO_ADC1_CH1 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_12_INDEX))
+#define GPIO_ADC1_CH2 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_13_INDEX))
+#define GPIO_ADC1_CH3 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_14_INDEX))
+#define GPIO_ADC1_CH4 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_15_INDEX))
+#define GPIO_ADC1_CH5 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_00_INDEX))
+#define GPIO_ADC1_CH6 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_01_INDEX))
+#define GPIO_ADC1_CH7 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_02_INDEX))
+#define GPIO_ADC1_CH8 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_03_INDEX))
+#define GPIO_ADC1_CH9 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_04_INDEX))
+#define GPIO_ADC1_CH10 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_05_INDEX))
+#define GPIO_ADC1_CH11 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_06_INDEX))
+#define GPIO_ADC1_CH12 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_07_INDEX))
+#define GPIO_ADC1_CH13 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_08_INDEX))
+#define GPIO_ADC1_CH14 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_09_INDEX))
+#define GPIO_ADC1_CH15 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_10_INDEX))
+#define GPIO_ADC2_CH0 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_11_INDEX))
+#define GPIO_ADC2_CH1 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_12_INDEX))
+#define GPIO_ADC2_CH2 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_13_INDEX))
+#define GPIO_ADC2_CH3 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_14_INDEX))
+#define GPIO_ADC2_CH4 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_15_INDEX))
+#define GPIO_ADC2_CH5 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_00_INDEX))
+#define GPIO_ADC2_CH6 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_01_INDEX))
+#define GPIO_ADC2_CH7 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_02_INDEX))
+#define GPIO_ADC2_CH8 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_03_INDEX))
+#define GPIO_ADC2_CH9 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_04_INDEX))
+#define GPIO_ADC2_CH10 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_05_INDEX))
+#define GPIO_ADC2_CH11 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_06_INDEX))
+#define GPIO_ADC2_CH12 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_07_INDEX))
+#define GPIO_ADC2_CH13 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_08_INDEX))
+#define GPIO_ADC2_CH14 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_09_INDEX))
+#define GPIO_ADC2_CH15 (GPIO_PERIPH | GPIO_ALT5 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_10_INDEX))
+
#endif /* __ARCH_ARM_SRC_IMXRT_HARDWARE_IMXRT106X_PINMUX_H */
diff --git a/arch/arm/src/imxrt/imxrt_adc.c b/arch/arm/src/imxrt/imxrt_adc.c
new file mode 100644
index 0000000..585eb60
--- /dev/null
+++ b/arch/arm/src/imxrt/imxrt_adc.c
@@ -0,0 +1,619 @@
+/****************************************************************************
+ * arch/arm/src/imxrt/imxrt_adc.c
+ *
+ * Copyright (C) 2020 Actia Nordic AB. All rights reserved.
+ * Author: Thomas Axelsson <th...@actia.se>
+ *
+ * Based on arch/arm/src/lpc_17xx_40xx/imxrt_adc.c
+ *
+ * Copyright (C) 2011 Li Zhuoyi. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Li Zhuoyi <lz...@gmail.com>
+ * Gregory Nutt <gn...@nuttx.org>
+ *
+ * and arch/arm/src/stm32/stm32_adc.c
+ *
+ * Copyright (C) 2018 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2015 Omni Hoverboards Inc. All rights reserved.
+ * Authors: Gregory Nutt <gn...@nuttx.org>
+ * Diego Sanchez <ds...@nx-engineering.com>
+ * Paul Alexander Patience <pa...@polymtl.ca>
+ * Mateusz Szafoni <ra...@railab.me>
+ *
+ * This file is a part of NuttX:
+ *
+ * Copyright (C) 2010, 2013, 2016 Gregory Nutt. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch/board/board.h>
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/analog/adc.h>
+
+#include "arm_internal.h"
+#include "arm_arch.h"
+
+#include "chip.h"
+#include "hardware/imxrt_adc.h"
+#include "hardware/imxrt_pinmux.h"
+#include "imxrt_gpio.h"
+#include "imxrt_periphclks.h"
+
+#ifdef CONFIG_IMXRT_ADC
+
+/* Some ADC peripheral must be enabled */
+
+#if defined(CONFIG_IMXRT_ADC1) || defined(CONFIG_IMXRT_ADC2)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ADC_MAX_CHANNELS 16
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct imxrt_dev_s
+{
+ FAR const struct adc_callback_s *cb; /* Upper driver callback */
+ uint8_t intf; /* ADC number (i.e. ADC1, ADC2) */
+ uint32_t base; /* ADC register base */
+ uint8_t initialized; /* ADC initialization counter */
+ int irq; /* ADC IRQ number */
+ int nchannels; /* Number of configured ADC channels */
+ uint8_t chanlist[ADC_MAX_CHANNELS]; /* ADC channel list */
+ uint8_t current; /* Current channel being converted */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void adc_putreg(FAR struct imxrt_dev_s *priv, uint32_t offset,
+ uint32_t value);
+static uint32_t adc_getreg(FAR struct imxrt_dev_s *priv, uint32_t offset);
+static void adc_modifyreg(FAR struct imxrt_dev_s *priv, uint32_t offset,
+ uint32_t clearbits, uint32_t setbits);
+
+/* ADC methods */
+
+static int adc_bind(FAR struct adc_dev_s *dev,
+ FAR const struct adc_callback_s *callback);
+static void adc_reset(FAR struct adc_dev_s *dev);
+static int adc_setup(FAR struct adc_dev_s *dev);
+static void adc_shutdown(FAR struct adc_dev_s *dev);
+static void adc_rxint(FAR struct adc_dev_s *dev, bool enable);
+static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg);
+static int adc_interrupt(int irq, void *context, FAR void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct adc_ops_s g_adcops =
+{
+ .ao_bind = adc_bind,
+ .ao_reset = adc_reset,
+ .ao_setup = adc_setup,
+ .ao_shutdown = adc_shutdown,
+ .ao_rxint = adc_rxint,
+ .ao_ioctl = adc_ioctl,
+};
+
+#ifdef CONFIG_IMXRT_ADC1
+static struct imxrt_dev_s g_adcpriv1 =
+{
+ .irq = IMXRT_IRQ_ADC1,
+ .intf = 1,
+ .initialized = 0,
+ .base = IMXRT_ADC1_BASE,
+};
+
+static struct adc_dev_s g_adcdev1 =
+{
+ .ad_ops = &g_adcops,
+ .ad_priv = &g_adcpriv1,
+};
+
+gpio_pinset_t g_adcpinlist1[ADC_MAX_CHANNELS] =
+{
+ GPIO_ADC1_CH0,
+ GPIO_ADC1_CH1,
+ GPIO_ADC1_CH2,
+ GPIO_ADC1_CH3,
+ GPIO_ADC1_CH4,
+ GPIO_ADC1_CH5,
+ GPIO_ADC1_CH6,
+ GPIO_ADC1_CH7,
+ GPIO_ADC1_CH8,
+ GPIO_ADC1_CH9,
+ GPIO_ADC1_CH10,
+ GPIO_ADC1_CH11,
+ GPIO_ADC1_CH12,
+ GPIO_ADC1_CH13,
+ GPIO_ADC1_CH14,
+ GPIO_ADC1_CH15,
+};
+#endif
+
+#ifdef CONFIG_IMXRT_ADC2
+static struct imxrt_dev_s g_adcpriv2 =
+{
+ .irq = IMXRT_IRQ_ADC2,
+ .intf = 2,
+ .initialized = 0,
+ .base = IMXRT_ADC2_BASE,
+};
+
+static struct adc_dev_s g_adcdev2 =
+{
+ .ad_ops = &g_adcops,
+ .ad_priv = &g_adcpriv2,
+};
+
+gpio_pinset_t g_adcpinlist2[ADC_MAX_CHANNELS] =
+{
+ GPIO_ADC2_CH0,
+ GPIO_ADC2_CH1,
+ GPIO_ADC2_CH2,
+ GPIO_ADC2_CH3,
+ GPIO_ADC2_CH4,
+ GPIO_ADC2_CH5,
+ GPIO_ADC2_CH6,
+ GPIO_ADC2_CH7,
+ GPIO_ADC2_CH8,
+ GPIO_ADC2_CH9,
+ GPIO_ADC2_CH10,
+ GPIO_ADC2_CH11,
+ GPIO_ADC2_CH12,
+ GPIO_ADC2_CH13,
+ GPIO_ADC2_CH14,
+ GPIO_ADC2_CH15,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void adc_putreg(FAR struct imxrt_dev_s *priv, uint32_t offset,
+ uint32_t value)
+{
+ putreg32(value, priv->base + offset);
+}
+
+static uint32_t adc_getreg(FAR struct imxrt_dev_s *priv, uint32_t offset)
+{
+ return getreg32(priv->base + offset);
+}
+
+static void adc_modifyreg(FAR struct imxrt_dev_s *priv, uint32_t offset,
+ uint32_t clearbits, uint32_t setbits)
+{
+ modifyreg32(priv->base + offset, clearbits, setbits);
+}
+
+/****************************************************************************
+ * Name: adc_bind
+ *
+ * Description:
+ * Bind the upper-half driver callbacks to the lower-half implementation.
+ * This must be called early in order to receive ADC event notifications.
+ *
+ ****************************************************************************/
+
+static int adc_bind(FAR struct adc_dev_s *dev,
+ FAR const struct adc_callback_s *callback)
+{
+ FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev->ad_priv;
+
+ DEBUGASSERT(priv != NULL);
+ priv->cb = callback;
+ 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.
+ *
+ ****************************************************************************/
+
+static void adc_reset(FAR struct adc_dev_s *dev)
+{
+ FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev->ad_priv;
+ irqstate_t flags;
+
+ flags = enter_critical_section();
+
+ /* Do nothing if ADC instance is currently in use */
+
+ if (priv->initialized > 0)
+ {
+ goto exit_leave_critical;
+ }
+
+ /* Configure clock gating */
+
+ switch (priv->intf)
+ {
+#ifdef CONFIG_IMXRT_ADC1
+ case 1:
+ imxrt_clockall_adc1();
+ break;
+#endif
+#ifdef CONFIG_IMXRT_ADC2
+ case 2:
+ imxrt_clockall_adc2();
+ break;
+#endif
+ default:
+ aerr("ERROR: Tried to reset non-existing ADC: %d\n", priv->intf);
+ goto exit_leave_critical;
+ }
+
+ leave_critical_section(flags);
+
+ /* Configure ADC */
+
+ uint32_t adc_cfg = ADC_CFG_AVGS_4SMPL | ADC_CFG_ADTRG_SW |
+ ADC_CFG_REFSEL_VREF | ADC_CFG_ADSTS_7_21 | ADC_CFG_ADIV_DIV8 | \
+ ADC_CFG_ADLSMP | ADC_CFG_MODE_10BIT | ADC_CFG_ADICLK_IPGDIV2;
+ adc_putreg(priv, IMXRT_ADC_CFG_OFFSET, adc_cfg);
+
+ uint32_t adc_gc = 0;
+ adc_putreg(priv, IMXRT_ADC_GC_OFFSET, adc_gc);
+
+ /* Calibration - After ADC has been configured as desired.
+ * ADTRG in ADC_CFG must be SW (0) during calibration
+ */
+
+ /* Clear calibration error */
+
+ adc_modifyreg(priv, IMXRT_ADC_GS_OFFSET, 0, ADC_GS_CALF);
+
+ /* Start calibration */
+
+ adc_modifyreg(priv, IMXRT_ADC_GC_OFFSET, 0, ADC_GC_CAL);
+
+ while ((adc_getreg(priv, IMXRT_ADC_GC_OFFSET) & ADC_GC_CAL) != 0 &&
+ (adc_getreg(priv, IMXRT_ADC_GS_OFFSET) & ADC_GS_CALF) == 0);
+
+ if ((adc_getreg(priv, IMXRT_ADC_GS_OFFSET) & ADC_GS_CALF) != 0 ||
+ (adc_getreg(priv, IMXRT_ADC_HS_OFFSET) & ADC_HS_COCO0) == 0)
+ {
+ aerr("ERROR: ADC%d calibration failed\n", priv->intf);
+ return;
+ }
+
+ /* Clear "conversion complete" */
+
+ uint32_t adc_r0 = adc_getreg(priv, IMXRT_ADC_R0_OFFSET);
+ UNUSED(adc_r0);
+
+ /* Pad configuration */
+
+ gpio_pinset_t *pinlist = NULL;
+ switch (priv->intf)
+ {
+#ifdef CONFIG_IMXRT_ADC1
+ case 1:
+ pinlist = g_adcpinlist1;
+ break;
+#endif
+#ifdef CONFIG_IMXRT_ADC2
+ case 2:
+ pinlist = g_adcpinlist2;
+ break;
+#endif
+ default:
+ /* We have already checked the intf number earlier in this function,
+ * so we should never get here.
+ */
+
+ return;
+ }
+
+ gpio_pinset_t pinset = 0;
+ for (int i = 0; i < priv->nchannels; i++)
+ {
+ DEBUGASSERT(priv->chanlist[i] < ADC_MAX_CHANNELS);
+ pinset = pinlist[priv->chanlist[i]] | IOMUX_ADC_DEFAULT;
+ imxrt_config_gpio(pinset);
+ }
+
+ return;
+
+exit_leave_critical:
+ leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: adc_setup
+ *
+ * Description:
+ * Configure the ADC. This method is called the first time that the ADC
+ * device is opened. This will occur when the port is first opened.
+ * This setup includes configuring and attaching ADC interrupts.
+ * Interrupts are all disabled upon return.
+ *
+ ****************************************************************************/
+
+static int adc_setup(FAR struct adc_dev_s *dev)
+{
+ FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev->ad_priv;
+
+ /* Do nothing when the ADC device is already set up */
+
+ if (priv->initialized > 0)
+ {
+ return OK;
+ }
+
+ priv->initialized++;
+
+ int ret = irq_attach(priv->irq, adc_interrupt, dev);
+ if (ret < 0)
+ {
+ ainfo("irq_attach failed: %d\n", ret);
+ return ret;
+ }
+
+ up_enable_irq(priv->irq);
+
+ /* Start the first conversion */
+
+ priv->current = 0;
+ adc_putreg(priv, IMXRT_ADC_HC0_OFFSET,
+ ADC_HC_ADCH(priv->chanlist[priv->current]));
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: adc_shutdown
+ *
+ * Description:
+ * Disable the ADC. This method is called when the ADC device is closed.
+ * This method reverses the operation the setup method.
+ *
+ ****************************************************************************/
+
+static void adc_shutdown(FAR struct adc_dev_s *dev)
+{
+ FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev->ad_priv;
+
+ /* Shutdown the ADC device only when not in use */
+
+ priv->initialized--;
+
+ if (priv->initialized > 0)
+ {
+ return;
+ }
+
+ /* Disable ADC interrupts, both at the level of the ADC device and at the
+ * level of the NVIC.
+ */
+
+ /* Disable interrupt and stop any on-going conversion */
+
+ adc_putreg(priv, IMXRT_ADC_HC0_OFFSET, ~ADC_HC_AIEN | ADC_HC_ADCH_DIS);
+
+ up_disable_irq(priv->irq);
+
+ /* Then detach the ADC interrupt handler. */
+
+ irq_detach(priv->irq);
+}
+
+/****************************************************************************
+ * Name: adc_rxint
+ *
+ * Description:
+ * Call to enable or disable RX interrupts
+ *
+ ****************************************************************************/
+
+static void adc_rxint(FAR struct adc_dev_s *dev, bool enable)
+{
+ FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev->ad_priv;
+
+ if (enable)
+ {
+ adc_modifyreg(priv, IMXRT_ADC_HC0_OFFSET, 0, ADC_HC_AIEN);
+ }
+ else
+ {
+ adc_modifyreg(priv, IMXRT_ADC_HC0_OFFSET, ADC_HC_AIEN, 0);
+ }
+}
+
+/****************************************************************************
+ * Name: adc_ioctl
+ *
+ * Description:
+ * All ioctl calls will be routed through this method.
+ *
+ * Input Parameters:
+ * dev - pointer to device structure used by the driver
+ * cmd - command
+ * arg - arguments passed with command
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static int adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
+{
+ /* No ioctl commands supported */
+
+ /* TODO: ANIOC_TRIGGER, for SW triggered conversion */
+
+ return -ENOTTY;
+}
+
+/****************************************************************************
+ * Name: adc_interrupt
+ *
+ * Description:
+ * ADC interrupt handler
+ *
+ ****************************************************************************/
+
+static int adc_interrupt(int irq, void *context, FAR void *arg)
+{
+ FAR struct adc_dev_s *dev = (FAR struct adc_dev_s *)arg;
+ FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev->ad_priv;
+ int32_t data;
+
+ if ((adc_getreg(priv, IMXRT_ADC_HS_OFFSET) & ADC_HS_COCO0) != 0)
+ {
+ /* Read data. This also clears the COCO bit. */
+
+ data = (int32_t)adc_getreg(priv, IMXRT_ADC_R0_OFFSET);
+
+ if (priv->cb != NULL)
+ {
+ DEBUGASSERT(priv->cb->au_receive != NULL);
+ priv->cb->au_receive(dev, priv->chanlist[priv->current], data);
+ }
+
+ /* Set the channel number of the next channel that will complete
+ * conversion.
+ */
+
+ priv->current++;
+
+ if (priv->current >= priv->nchannels)
+ {
+ /* Restart the conversion sequence from the beginning */
+
+ priv->current = 0;
+ }
+
+ /* Start the next conversion */
+
+ adc_modifyreg(priv, IMXRT_ADC_HC0_OFFSET, ADC_HC_ADCH_MASK,
+ ADC_HC_ADCH(priv->chanlist[priv->current]));
+ }
+
+ /* There are no interrupt flags left to clear */
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imxrt_adcinitialize
+ *
+ * Description:
+ * Initialize the adc
+ *
+ * Input Parameters:
+ * intf - ADC number (1 or 2)
+ * chanlist - The list of channels
+ * nchannels - Number of channels
+ *
+ * Returned Value:
+ * Valid can device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct adc_dev_s *imxrt_adcinitialize(int intf,
+ FAR const uint8_t *chanlist,
+ int nchannels)
+{
+ FAR struct adc_dev_s *dev;
+ FAR struct imxrt_dev_s *priv;
+
+ DEBUGASSERT(nchannels > 0);
+
+ switch (intf)
+ {
+#ifdef CONFIG_IMXRT_ADC1
+ case 1:
+ {
+ dev = &g_adcdev1;
+ break;
+ }
+#endif /* CONFIG_IMXRT_ADC1 */
+
+#ifdef CONFIG_IMXRT_ADC2
+ case 2:
+ {
+ dev = &g_adcdev2;
+ break;
+ }
+#endif /* CONFIG_IMXRT_ADC2 */
+
+ default:
+ {
+ aerr("ERROR: Tried to initialize invalid ADC: %d\n", intf);
+ return NULL;
+ }
+ }
+
+ priv = (FAR struct imxrt_dev_s *)dev->ad_priv;
+
+ priv->nchannels = nchannels;
+ memcpy(priv->chanlist, chanlist, nchannels);
+
+ ainfo("intf: %d nchannels: %d\n", priv->intf, priv->nchannels);
+
+ return dev;
+}
+
+#endif /* CONFIG_IMXRT_ADC1 || CONFIG_IMXRT_ADC2 */
+
+#endif /* CONFIG_IMXRT_ADC */
diff --git a/arch/arm/src/imxrt/imxrt_adc.h b/arch/arm/src/imxrt/imxrt_adc.h
new file mode 100644
index 0000000..1525f51
--- /dev/null
+++ b/arch/arm/src/imxrt/imxrt_adc.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * arch/arm/src/lpc17xx_40xx/lpc17_40_adc.h
+ *
+ * Copyright (C) 2020 Actia Nordic AB. All rights reserved.
+ * Author: Thomas Axelsson <th...@actia.se>
+ *
+ * Based on arch/arm/src/lpc_17xx_40xx/imxrt_adc.h
+ *
+ * Copyright (C) 2010, 2012, 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_IMXRT_ADC_H
+#define __ARCH_ARM_SRC_IMXRT_ADC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: imxrt_adcinitialize
+ *
+ * Description:
+ * Initialize the adc
+ *
+ * Input Parameters:
+ * intf - ADC number (1 or 2)
+ * chanlist - The list of channels
+ * nchannels - Number of channels
+ *
+ * Returned Value:
+ * Valid can device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMXRT_ADC
+FAR struct adc_dev_s *imxrt_adcinitialize(int intf,
+ FAR const uint8_t *chanlist,
+ int nchannels);
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ARCH_ARM_SRC_IMXRT_ADC_H */
diff --git a/boards/arm/imxrt/imxrt1060-evk/src/Makefile b/boards/arm/imxrt/imxrt1060-evk/src/Makefile
index 7a073dc..9efc123 100644
--- a/boards/arm/imxrt/imxrt1060-evk/src/Makefile
+++ b/boards/arm/imxrt/imxrt1060-evk/src/Makefile
@@ -73,6 +73,10 @@ ifeq ($(CONFIG_DEV_GPIO),y)
CSRCS += imxrt_gpio.c
endif
+ifeq ($(CONFIG_IMXRT_ADC),y)
+CSRCS += imxrt_adc.c
+endif
+
ifeq ($(CONFIG_INPUT_FT5X06),y)
CSRCS += imxrt_ft5x06.c
endif
diff --git a/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h b/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h
index eb6e011..216b916 100644
--- a/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h
+++ b/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h
@@ -276,6 +276,18 @@ int imxrt_gpio_initialize(void);
#endif
/****************************************************************************
+ * Name: imxrt_adc_initialize
+ *
+ * Description:
+ * Initialize ADC drivers
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_IMXRT_ADC
+int imxrt_adc_initialize(void);
+#endif
+
+/****************************************************************************
* Name: imxrt_ft5x06_register
*
* Description:
diff --git a/boards/arm/imxrt/imxrt1060-evk/src/imxrt_adc.c b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_adc.c
new file mode 100644
index 0000000..119535f
--- /dev/null
+++ b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_adc.c
@@ -0,0 +1,167 @@
+/****************************************************************************
+ * boards/arm/imxrt/imxrt1060-evk/src/imxrt_adc.c
+ *
+ * Copyright (C) 2020 Actia Nordic AB. All rights reserved.
+ * Author: Thomas Axelsson <th...@actia.se>
+ *
+ * Based on boards/arm/lpc17xx_40xx/mbed/src/lpc17_40_adc.c
+ *
+ * Based on boards/zkit-arm-176/src/up-adc
+ *
+ * Copyright (C) 2013 Zilogic Systems. All rights reserved.
+ * Author: Kannan <co...@nuttx.org>
+ *
+ * Based on boards/lpc1720g-eval/src/lpc17_40_adc.c
+ *
+ * Copyright (C) 2012, 2014, 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gn...@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/board.h>
+#include <nuttx/analog/adc.h>
+#include <arch/board/board.h>
+
+#include "chip.h"
+#include "arm_arch.h"
+
+#include "imxrt_adc.h"
+
+#ifdef CONFIG_IMXRT_ADC
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#define ADC1_NCHANNELS 3
+#define ADC2_NCHANNELS 3
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const uint8_t g_chanlist1[ADC1_NCHANNELS] =
+ {
+ /* Arduino Interface pins A0 to A2 */
+
+ 15,
+ 0,
+ 9,
+ };
+
+static const uint8_t g_chanlist2[ADC2_NCHANNELS] =
+ {
+ /* Arduino Interface pins A3 to A5 */
+
+ 10,
+ 6,
+ 5
+ };
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imxrt_adc_setup
+ *
+ * Description:
+ * Initialize ADC and register the ADC driver.
+ *
+ ****************************************************************************/
+
+int imxrt_adc_initialize(void)
+{
+ static bool initialized = false;
+ struct adc_dev_s *adc;
+ int ret;
+
+ /* Check if we have already initialized */
+
+ if (!initialized)
+ {
+ /* Call imxrt_adcinitialize() to get an instance of the ADC interface */
+
+#ifdef CONFIG_IMXRT_ADC1
+ adc = imxrt_adcinitialize(1, g_chanlist1, ADC1_NCHANNELS);
+ if (adc == NULL)
+ {
+ aerr("ERROR: Failed to get ADC interface for ADC1\n");
+ return -ENODEV;
+ }
+
+ /* Register the ADC driver at "/dev/adc1" */
+
+ ret = adc_register("/dev/adc1", adc);
+ if (ret < 0)
+ {
+ aerr("ERROR: adc_register adc1 failed: %d\n", ret);
+ return ret;
+ }
+#endif
+
+#ifdef CONFIG_IMXRT_ADC2
+ adc = imxrt_adcinitialize(2, g_chanlist2, ADC2_NCHANNELS);
+ if (adc == NULL)
+ {
+ aerr("ERROR: Failed to get ADC interface for ADC2\n");
+ return -ENODEV;
+ }
+
+ /* Register the ADC driver at "/dev/adc2" */
+
+ ret = adc_register("/dev/adc2", adc);
+ if (ret < 0)
+ {
+ aerr("ERROR: adc_register adc2 failed: %d\n", ret);
+ return ret;
+ }
+#endif
+
+ /* Now we are initialized */
+
+ initialized = true;
+ }
+
+ return OK;
+}
+
+#endif /* CONFIG_ADC */
diff --git a/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c
index 8584f9e..c0e07ba 100644
--- a/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c
+++ b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c
@@ -223,6 +223,16 @@ int imxrt_bringup(void)
}
#endif
+#ifdef CONFIG_IMXRT_ADC
+ /* Initialize ADC and register the ADC driver. */
+
+ ret = imxrt_adc_initialize();
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: imxrt_adc_initialize() failed: %d\n", ret);
+ }
+#endif
+
#ifdef CONFIG_INPUT_FT5X06
/* Initialize the FT5X06 touchscreen driver */