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

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

commit 3571ff3c54c8cd60b86cfbf100e821e838937715
Author: raiden00pl <raide...@railab.me>
AuthorDate: Mon Mar 13 12:32:56 2023 +0100

    arch/nrf53: add SAADC support
---
 arch/arm/src/nrf53/Kconfig     |  68 ++-
 arch/arm/src/nrf53/Make.defs   |   4 +
 arch/arm/src/nrf53/nrf53_adc.c | 964 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/src/nrf53/nrf53_adc.h | 162 +++++++
 4 files changed, 1197 insertions(+), 1 deletion(-)

diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig
index 7ed9deeb01..d9469c8d89 100644
--- a/arch/arm/src/nrf53/Kconfig
+++ b/arch/arm/src/nrf53/Kconfig
@@ -23,6 +23,7 @@ config NRF53_APPCORE
        select ARM_HAVE_DSP
        select ARCH_HAVE_FPU
        select NRF53_HAVE_PWM
+       select NRF53_HAVE_SAADC
 
 config NRF53_NETCORE
        bool
@@ -36,7 +37,6 @@ choice
 config ARCH_CHIP_NRF5340_CPUAPP
        bool "NRF53 App core"
        select NRF53_APPCORE
-       select ARCH_HAVE_FPU
 
 config ARCH_CHIP_NRF5340_CPUNET
        bool "NRF53 Net core"
@@ -74,6 +74,10 @@ config NRF53_HAVE_PWM
        bool
        default n
 
+config NRF53_HAVE_SAADC
+       bool
+       default n
+
 # Peripheral Selection
 
 config NRF53_IPC
@@ -136,6 +140,10 @@ config NRF53_PWM2
        select NRF53_PWM
        default n
 
+config NRF53_SAADC
+       bool "SAADC"
+       default n
+
 endmenu # NRF53 Peripheral Selection
 
 menu "Clock Configuration"
@@ -332,6 +340,64 @@ endif # !NRF53_PWM_MULTICHAN
 
 endmenu # PWM configuration
 
+menu "SAADC Configuration"
+
+if NRF53_SAADC
+
+choice
+       prompt "SAADC trigger selection"
+       default NRF53_SAADC_TASK
+       ---help---
+               Choose mode for sample rate control
+
+config NRF53_SAADC_TASK
+       bool "SAADC Task trigger"
+
+config NRF53_SAADC_TIMER
+       bool "SAADC Timer trigger"
+
+endchoice # SAADC trigger selection
+
+if NRF53_SAADC_TIMER
+
+config NRF53_SAADC_TIMER_CC
+       int "SAADC Timer CC"
+       default 0
+       range 80 2047
+
+endif #NRF53_SAADC_TIMER
+
+config NRF53_SAADC_OVERSAMPLE
+       int "SAADC oversample"
+       default 0
+       range 0 8
+       ---help---
+               SAADC oversample control
+
+config NRF53_SAADC_RESOLUTION
+       int "SAADC resolution"
+       default 0
+       range 0 3
+       ---help---
+               SAADC resolution 0 - 8 bits, 1 - 10 bits, 2 - 12 bits, 3 - 14 
bits
+
+config NRF53_SAADC_CHANNELS
+       int "SAADC channels"
+       default 8
+       range 0 8
+       ---help---
+               SAADC channels
+
+config NRF53_SAADC_LIMITS
+       bool "SAADC limits enable"
+       default n
+       ---help---
+               SAADC limist enable
+
+endif # NRF53_SAADC
+
+endmenu # SAADC Configuration
+
 menuconfig NRF53_SOFTDEVICE_CONTROLLER
        bool "SoftDevice Controller"
        depends on ALLOW_BSDNORDIC_COMPONENTS
diff --git a/arch/arm/src/nrf53/Make.defs b/arch/arm/src/nrf53/Make.defs
index cef4be459b..ab2ee577a5 100644
--- a/arch/arm/src/nrf53/Make.defs
+++ b/arch/arm/src/nrf53/Make.defs
@@ -62,6 +62,10 @@ ifeq ($(CONFIG_NRF53_PWM),y)
 CHIP_CSRCS += nrf53_pwm.c
 endif
 
+ifeq ($(CONFIG_NRF53_SAADC),y)
+CHIP_CSRCS += nrf53_adc.c
+endif
+
 ifeq ($(CONFIG_PM),y)
 CHIP_CSRCS += nrf53_pminitialize.c
 endif
diff --git a/arch/arm/src/nrf53/nrf53_adc.c b/arch/arm/src/nrf53/nrf53_adc.c
new file mode 100644
index 0000000000..83d988229f
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_adc.c
@@ -0,0 +1,964 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_adc.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/analog/adc.h>
+#include <nuttx/analog/ioctl.h>
+
+#include "arm_internal.h"
+#include "nrf53_gpio.h"
+#include "nrf53_adc.h"
+
+#include "hardware/nrf53_saadc.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct nrf53_adc_s
+{
+  /* Upper-half callback */
+
+  const struct adc_callback_s *cb;
+
+  /* Channels configuration */
+
+  struct nrf53_adc_channel_s channels[CONFIG_NRF53_SAADC_CHANNELS];
+
+  /* Samples buffer */
+
+  int16_t                    buffer[CONFIG_NRF53_SAADC_CHANNELS];
+
+  uint8_t                    chan_len;   /* Configured channels */
+  uint32_t                   base;       /* Base address of ADC register */
+  uint32_t                   irq;        /* ADC interrupt */
+  uint8_t                    resolution; /* ADC resolution */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* ADC Register access */
+
+static inline void nrf53_adc_putreg(struct nrf53_adc_s *priv,
+                                    uint32_t offset,
+                                    uint32_t value);
+static inline uint32_t nrf53_adc_getreg(struct nrf53_adc_s *priv,
+                                        uint32_t offset);
+
+/* ADC helpers */
+
+static int nrf53_adc_configure(struct nrf53_adc_s *priv);
+static int nrf53_adc_calibrate(struct nrf53_adc_s *priv);
+static uint32_t nrf53_adc_ch_config(struct nrf53_adc_channel_s *cfg);
+static uint32_t nrf53_adc_chanpsel(int psel);
+static int nrf53_adc_chancfg(struct nrf53_adc_s *priv, uint8_t chan,
+                             struct nrf53_adc_channel_s *cfg);
+static int nrf53_adc_isr(int irq, void *context, void *arg);
+
+/* ADC Driver Methods */
+
+static int  nrf53_adc_bind(struct adc_dev_s *dev,
+                           const struct adc_callback_s *callback);
+static void nrf53_adc_reset(struct adc_dev_s *dev);
+static int  nrf53_adc_setup(struct adc_dev_s *dev);
+static void nrf53_adc_shutdown(struct adc_dev_s *dev);
+static void nrf53_adc_rxint(struct adc_dev_s *dev, bool enable);
+static int  nrf53_adc_ioctl(struct adc_dev_s *dev, int cmd,
+                            unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* ADC interface operations */
+
+static const struct adc_ops_s g_nrf53_adcops =
+{
+  .ao_bind        = nrf53_adc_bind,
+  .ao_reset       = nrf53_adc_reset,
+  .ao_setup       = nrf53_adc_setup,
+  .ao_shutdown    = nrf53_adc_shutdown,
+  .ao_rxint       = nrf53_adc_rxint,
+  .ao_ioctl       = nrf53_adc_ioctl,
+};
+
+/* SAADC device */
+
+struct nrf53_adc_s g_nrf53_adcpriv =
+{
+  .cb         = NULL,
+  .base       = NRF53_SAADC_BASE,
+  .irq        = NRF53_IRQ_SAADC,
+  .resolution = CONFIG_NRF53_SAADC_RESOLUTION
+};
+
+/* Upper-half ADC device */
+
+static struct adc_dev_s g_nrf53_adc =
+{
+  .ad_ops      = &g_nrf53_adcops,
+  .ad_priv     = &g_nrf53_adcpriv,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_adc_putreg
+ *
+ * Description:
+ *   Put a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void nrf53_adc_putreg(struct nrf53_adc_s *priv,
+                                    uint32_t offset,
+                                    uint32_t value)
+{
+  DEBUGASSERT(priv);
+
+  putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_getreg
+ *
+ * Description:
+ *   Get a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf53_adc_getreg(struct nrf53_adc_s *priv,
+                                        uint32_t offset)
+{
+  DEBUGASSERT(priv);
+
+  return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_isr
+ *
+ * Description:
+ *   Common ADC interrupt service routine
+ *
+ ****************************************************************************/
+
+static int nrf53_adc_isr(int irq, void *context, void *arg)
+{
+  struct adc_dev_s   *dev  = (struct adc_dev_s *) arg;
+  struct nrf53_adc_s *priv = NULL;
+  int                 ret  = OK;
+  int                 i    = 0;
+
+  DEBUGASSERT(dev);
+
+  priv = (struct nrf53_adc_s *) dev->ad_priv;
+  DEBUGASSERT(priv);
+
+  ainfo("nrf53_adc_isr\n");
+
+  /* END event */
+
+  if (nrf53_adc_getreg(priv, NRF53_SAADC_EVENTS_END_OFFSET) == 1)
+    {
+      DEBUGASSERT(priv->cb != NULL);
+      DEBUGASSERT(priv->cb->au_receive != NULL);
+
+      /* Give the ADC data to the ADC driver */
+
+      for (i = 0; i < priv->chan_len; i += 1)
+        {
+          priv->cb->au_receive(dev, i, priv->buffer[i]);
+        }
+
+      /* Clear event */
+
+      nrf53_adc_putreg(priv, NRF53_SAADC_EVENTS_END_OFFSET, 0);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_configure
+ *
+ * Description:
+ *   Configure ADC
+ *
+ ****************************************************************************/
+
+static int nrf53_adc_configure(struct nrf53_adc_s *priv)
+{
+  int regval = 0;
+
+  DEBUGASSERT(priv);
+
+  /* Configure ADC resolution */
+
+  regval = CONFIG_NRF53_SAADC_RESOLUTION;
+  nrf53_adc_putreg(priv, NRF53_SAADC_RESOLUTION_OFFSET, regval);
+
+  /* Configure oversampling */
+
+  regval = CONFIG_NRF53_SAADC_OVERSAMPLE;
+  nrf53_adc_putreg(priv, NRF53_SAADC_OVERSAMPLE_OFFSET, regval);
+
+  /* Configure sample rate */
+
+#if defined(CONFIG_NRF53_SAADC_TIMER)
+  /* Trigger from local timer */
+
+  regval = SAADC_SAMPLERATE_MODE_TIMERS;
+  regval |= ((CONFIG_NRF53_SAADC_TIMER_CC & SAADC_SAMPLERATE_CC_MASK)
+             << SAADC_SAMPLERATE_CC_SHIFT);
+#elif defined(CONFIG_NRF53_SAADC_TASK)
+  /* Trigger on SAMPLE tas */
+
+  regval = SAADC_SAMPLERATE_MODE_TASK;
+#else
+#  error SAADC trigger not selected
+#endif
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_SAMPLERATE_OFFSET, regval);
+
+  /* Configure ADC buffer */
+
+  regval = (uint32_t)&priv->buffer;
+  nrf53_adc_putreg(priv, NRF53_SAADC_PTR_OFFSET, regval);
+
+  regval = priv->chan_len;
+  nrf53_adc_putreg(priv, NRF53_SAADC_MAXCNT_OFFSET, regval);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_calibrate
+ *
+ * Description:
+ *   Calibrate ADC
+ *
+ ****************************************************************************/
+
+static int nrf53_adc_calibrate(struct nrf53_adc_s *priv)
+{
+  /* Clear Event */
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_EVENTS_CALDONE_OFFSET, 0);
+
+  /* Start calibration */
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_CALOFFSET_OFFSET, 1);
+
+  /* Wait for calibration done */
+
+  while (nrf53_adc_getreg(priv, NRF53_SAADC_EVENTS_CALDONE_OFFSET) != 1);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_ch_config
+ ****************************************************************************/
+
+static uint32_t nrf53_adc_ch_config(struct nrf53_adc_channel_s *cfg)
+{
+  uint32_t regval = 0;
+
+  /* Positive channel resistor control */
+
+  switch (cfg->resp)
+    {
+      case NRF53_ADC_RES_BYPASS:
+        {
+          regval |= SAADC_CONFIG_RESP_NONE;
+          break;
+        }
+
+      case NRF53_ADC_RES_PULLDOWN:
+        {
+          regval |= SAADC_CONFIG_RESP_PD;
+          break;
+        }
+
+      case NRF53_ADC_RES_PULLUP:
+        {
+          regval |= SAADC_CONFIG_RESP_PU;
+          break;
+        }
+
+      case NRF53_ADC_RES_VDD_2:
+        {
+          regval |= SAADC_CONFIG_RESP_VDD1P2;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid cfg->resp: %d\n", cfg->resp);
+        }
+    }
+
+  /* Negative channel resistor control */
+
+  switch (cfg->resn)
+    {
+      case NRF53_ADC_RES_BYPASS:
+        {
+          regval |= SAADC_CONFIG_RESN_NONE;
+          break;
+        }
+
+      case NRF53_ADC_RES_PULLDOWN:
+        {
+          regval |= SAADC_CONFIG_RESN_PD;
+          break;
+        }
+
+      case NRF53_ADC_RES_PULLUP:
+        {
+          regval |= SAADC_CONFIG_RESN_PU;
+          break;
+        }
+
+      case NRF53_ADC_RES_VDD_2:
+        {
+          regval |= SAADC_CONFIG_RESN_VDD1P2;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid cfg->resn: %d\n", cfg->resn);
+        }
+    }
+
+  /* Gain control */
+
+  switch (cfg->gain)
+    {
+      case NRF53_ADC_GAIN_1_6:
+        {
+          regval |= SAADC_CONFIG_GAIN_1P6;
+          break;
+        }
+
+      case NRF53_ADC_GAIN_1_5:
+        {
+          regval |= SAADC_CONFIG_GAIN_1P5;
+          break;
+        }
+
+      case NRF53_ADC_GAIN_1_4:
+        {
+          regval |= SAADC_CONFIG_GAIN_1P4;
+          break;
+        }
+
+      case NRF53_ADC_GAIN_1_3:
+        {
+          regval |= SAADC_CONFIG_GAIN_1P3;
+          break;
+        }
+
+      case NRF53_ADC_GAIN_1_2:
+        {
+          regval |= SAADC_CONFIG_GAIN_1P2;
+          break;
+        }
+
+      case NRF53_ADC_GAIN_1:
+        {
+          regval |= SAADC_CONFIG_GAIN_1;
+          break;
+        }
+
+      case NRF53_ADC_GAIN_2:
+        {
+          regval |= SAADC_CONFIG_GAIN_2;
+          break;
+        }
+
+      case NRF53_ADC_GAIN_4:
+        {
+          regval |= SAADC_CONFIG_GAIN_4;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid cfg->gain: %d\n", cfg->gain);
+        }
+    }
+
+  /* Reference control */
+
+  switch (cfg->refsel)
+    {
+      case NRF53_ADC_REFSEL_INTERNAL:
+        {
+          regval |= SAADC_CONFIG_REFSEL_INTERNAL;
+          break;
+        }
+
+      case NRF53_ADC_REFSEL_VDD_4:
+        {
+          regval |= SAADC_CONFIG_REFSEL_VDD1P4;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid cfg->refsel: %d\n", cfg->refsel);
+        }
+    }
+
+  /* Acquisition time */
+
+  switch (cfg->tacq)
+    {
+      case NRF53_ADC_TACQ_3US:
+        {
+          regval |= SAADC_CONFIG_TACQ_3US;
+          break;
+        }
+
+      case NRF53_ADC_TACQ_5US:
+        {
+          regval |= SAADC_CONFIG_TACQ_5US;
+          break;
+        }
+
+      case NRF53_ADC_TACQ_10US:
+        {
+          regval |= SAADC_CONFIG_TACQ_10US;
+          break;
+        }
+
+      case NRF53_ADC_TACQ_15US:
+        {
+          regval |= SAADC_CONFIG_TACQ_15US;
+          break;
+        }
+
+      case NRF53_ADC_TACQ_20US:
+        {
+          regval |= SAADC_CONFIG_TACQ_20US;
+          break;
+        }
+
+      case NRF53_ADC_TACQ_40US:
+        {
+          regval |= SAADC_CONFIG_TACQ_40US;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid cfg->tacq: %d\n", cfg->tacq);
+        }
+    }
+
+  /* Singe-ended or differential mode */
+
+  switch (cfg->mode)
+    {
+      case NRF53_ADC_MODE_SE:
+        {
+          regval |= SAADC_CONFIG_MODE_SE;
+          break;
+        }
+
+      case NRF53_ADC_MODE_DIFF:
+        {
+          regval |= SAADC_CONFIG_MODE_DIFF;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid cfg->mode: %d\n", cfg->mode);
+        }
+    }
+
+  /* Burst mode */
+
+  switch (cfg->burst)
+    {
+      case NRF53_ADC_BURST_DISABLE:
+        {
+          regval |= SAADC_CONFIG_BURS_DIS;
+          break;
+        }
+
+      case NRF53_ADC_BURST_ENABLE:
+        {
+          regval |= SAADC_CONFIG_BURS_EN;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid cfg->burst: %d\n", cfg->burst);
+        }
+    }
+
+  return regval;
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_chanpsel
+ ****************************************************************************/
+
+static uint32_t nrf53_adc_chanpsel(int psel)
+{
+  uint32_t regval = 0;
+
+  switch (psel)
+    {
+      case NRF53_ADC_IN_NC:
+        {
+          regval = SAADC_CHPSEL_NC;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN0:
+        {
+          regval = SAADC_CHPSEL_IN0;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN1:
+        {
+          regval = SAADC_CHPSEL_IN1;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN2:
+        {
+          regval = SAADC_CHPSEL_IN2;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN3:
+        {
+          regval = SAADC_CHPSEL_IN3;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN4:
+        {
+          regval = SAADC_CHPSEL_IN4;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN5:
+        {
+          regval = SAADC_CHPSEL_IN5;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN6:
+        {
+          regval = SAADC_CHPSEL_IN6;
+          break;
+        }
+
+      case NRF53_ADC_IN_IN7:
+        {
+          regval = SAADC_CHPSEL_IN7;
+          break;
+        }
+
+      case NRF53_ADC_IN_VDD:
+        {
+          regval = SAADC_CHPSEL_VDD;
+          break;
+        }
+
+      case NRF53_ADC_IN_VDDHDIV5:
+        {
+          regval = SAADC_CHPSEL_VDDHDIV5;
+          break;
+        }
+
+      default:
+        {
+          aerr("ERROR: invalid psel: %d\n", psel);
+        }
+    }
+
+  return regval;
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_chancfg
+ *
+ * Description:
+ *   Configure ADC channel
+ *
+ ****************************************************************************/
+
+static int nrf53_adc_chancfg(struct nrf53_adc_s *priv, uint8_t chan,
+                             struct nrf53_adc_channel_s *cfg)
+{
+  uint32_t regval = 0;
+  int      ret    = OK;
+
+  DEBUGASSERT(priv);
+
+  /* Configure positive input */
+
+  regval = nrf53_adc_chanpsel(cfg->p_psel);
+  nrf53_adc_putreg(priv, NRF53_SAADC_CHPSELP_OFFSET(chan), regval);
+
+  /* Configure negative input */
+
+  regval = nrf53_adc_chanpsel(cfg->n_psel);
+  nrf53_adc_putreg(priv, NRF53_SAADC_CHPSELN_OFFSET(chan), regval);
+
+  /* Get channel configuration */
+
+  regval = nrf53_adc_ch_config(cfg);
+
+  /* Write channel configuration */
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_CHCONFIG_OFFSET(chan), regval);
+
+#ifdef CONFIG_NRF53_SAADC_LIMITS
+  /* Configure limits */
+
+  regval = (cfg->limith < 16) | (cfg->limith << 0);
+  nrf53_adc_putreg(priv, NRF53_SAADC_CHLIMIT_OFFSET(chan), regval);
+#endif
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_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 nrf53_adc_bind(struct adc_dev_s *dev,
+                          const struct adc_callback_s *callback)
+{
+  struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv;
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(priv);
+
+  priv->cb = callback;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_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 nrf53_adc_reset(struct adc_dev_s *dev)
+{
+  struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv;
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(priv);
+
+  /* TODO */
+
+  UNUSED(priv);
+}
+
+/****************************************************************************
+ * Name: nrf53_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 nrf53_adc_setup(struct adc_dev_s *dev)
+{
+  struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv;
+  int                 i    = 0;
+  int                 ret  = OK;
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(priv);
+
+  /* Disable ADC */
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_ENABLE_OFFSET, 0);
+
+  /* Configure ADC */
+
+  ret = nrf53_adc_configure(priv);
+  if (ret < 0)
+    {
+      aerr("ERROR: nrf53_adc_configure failed: %d\n", ret);
+      goto errout;
+    }
+
+  /* Configure ADC channels */
+
+  for (i = 0; i < priv->chan_len; i += 1)
+    {
+      ret = nrf53_adc_chancfg(priv, i, &priv->channels[i]);
+      if (ret < 0)
+        {
+          aerr("ERROR: chancfg failed: %d %d\n", i, ret);
+          goto errout;
+        }
+    }
+
+  /* Enable ADC */
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_ENABLE_OFFSET, 1);
+
+  /* Calibrate ADC */
+
+  ret = nrf53_adc_calibrate(priv);
+  if (ret < 0)
+    {
+      aerr("ERROR: adc calibration failed: %d\n", ret);
+      goto errout;
+    }
+
+  /* Attach the ADC interrupt */
+
+  ret = irq_attach(priv->irq, nrf53_adc_isr, dev);
+  if (ret < 0)
+    {
+      aerr("ERROR: irq_attach failed: %d\n", ret);
+      goto errout;
+    }
+
+  /* Enable the ADC interrupt */
+
+  up_enable_irq(priv->irq);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_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 nrf53_adc_shutdown(struct adc_dev_s *dev)
+{
+  struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv;
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(priv);
+
+  /* Stop SAADC */
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_STOP_OFFSET, 1);
+
+  /* Wait for SAADC stopped */
+
+  while (nrf53_adc_getreg(priv, NRF53_SAADC_EVENTS_STOPPED_OFFSET) != 1);
+
+  /* Disable SAADC */
+
+  nrf53_adc_putreg(priv, NRF53_SAADC_ENABLE_OFFSET, 0);
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_rxint
+ *
+ * Description:
+ *   Call to enable or disable RX interrupts.
+ *
+ ****************************************************************************/
+
+static void nrf53_adc_rxint(struct adc_dev_s *dev, bool enable)
+{
+  struct nrf53_adc_s *priv   = (struct nrf53_adc_s *) dev->ad_priv;
+  uint32_t            regval = 0;
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(priv);
+
+  ainfo("RXINT enable: %d\n", enable ? 1 : 0);
+
+  regval = SAADC_INT_END;
+
+  if (enable)
+    {
+      nrf53_adc_putreg(priv, NRF53_SAADC_INTENSET_OFFSET, regval);
+    }
+  else
+    {
+      nrf53_adc_putreg(priv, NRF53_SAADC_INTENCLR_OFFSET, regval);
+    }
+}
+
+/****************************************************************************
+ * Name: nrf53_adc_ioctl
+ *
+ * Description:
+ *   All ioctl calls will be routed through this method.
+ *
+ ****************************************************************************/
+
+static int nrf53_adc_ioctl(struct adc_dev_s *dev, int cmd,
+                           unsigned long arg)
+{
+  struct nrf53_adc_s *priv = (struct nrf53_adc_s *) dev->ad_priv;
+  int ret                  = OK;
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(priv);
+
+  switch (cmd)
+    {
+      case ANIOC_TRIGGER:
+        {
+          /* Start ADC */
+
+          nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_START_OFFSET, 1);
+
+          /* Trigger first sample */
+
+          nrf53_adc_putreg(priv, NRF53_SAADC_TASKS_SAMPLE_OFFSET, 1);
+        }
+        break;
+
+      case ANIOC_GET_NCHANNELS:
+        {
+          /* Return the number of configured channels */
+
+          ret = priv->chan_len;
+        }
+        break;
+
+      default:
+        {
+          aerr("ERROR: Unknown cmd: %d\n", cmd);
+          ret = -ENOTTY;
+        }
+        break;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_adcinitialize
+ *
+ * Description:
+ *   Initialize the ADC. See nrf53_adc.c for more details.
+ *
+ * Input Parameters:
+ *   chanlist  - channels configuration
+ *   nchannels - number of channels
+ *
+ * Returned Value:
+ *   Valid ADC device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct adc_dev_s *nrf53_adcinitialize(
+    const struct nrf53_adc_channel_s *chan, int channels)
+{
+  struct adc_dev_s   *dev  = NULL;
+  struct nrf53_adc_s *priv = NULL;
+  int                 i    = 0;
+
+  DEBUGASSERT(chan != NULL);
+  DEBUGASSERT(channels <= CONFIG_NRF53_SAADC_CHANNELS);
+
+#ifdef CONFIG_NRF53_SAADC_TIMER
+  if (channels > 1)
+    {
+      aerr("ERORR: timer trigger works only for 1 channel!\n");
+      goto errout;
+    }
+#endif
+
+  /* Get device */
+
+  dev = &g_nrf53_adc;
+
+  /* Get private data */
+
+  priv = (struct nrf53_adc_s *) dev->ad_priv;
+
+  /* Copy channels configuration */
+
+  ainfo("channels: %d\n", channels);
+
+  for (i = 0; i < channels; i += 1)
+    {
+      memcpy(&priv->channels[i], &chan[i],
+             sizeof(struct nrf53_adc_channel_s));
+    }
+
+  priv->chan_len = channels;
+
+#ifdef CONFIG_NRF53_SAADC_TIMER
+errout:
+#endif
+  return dev;
+}
diff --git a/arch/arm/src/nrf53/nrf53_adc.h b/arch/arm/src/nrf53/nrf53_adc.h
new file mode 100644
index 0000000000..3e31efc1ae
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_adc.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_adc.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF53_NRF53_ADC_H
+#define __ARCH_ARM_SRC_NRF53_NRF53_ADC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "chip.h"
+
+#include <nuttx/analog/adc.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* ADC input */
+
+enum nrf53_adc_ain_e
+{
+  NRF53_ADC_IN_NC       = 0,   /* Not connected */
+  NRF53_ADC_IN_IN0      = 1,   /* Analog input 0 */
+  NRF53_ADC_IN_IN1      = 2,   /* Analog input 1 */
+  NRF53_ADC_IN_IN2      = 3,   /* Analog input 2 */
+  NRF53_ADC_IN_IN3      = 4,   /* Analog input 3 */
+  NRF53_ADC_IN_IN4      = 5,   /* Analog input 4 */
+  NRF53_ADC_IN_IN5      = 6,   /* Analog input 5 */
+  NRF53_ADC_IN_IN6      = 7,   /* Analog input 6 */
+  NRF53_ADC_IN_IN7      = 8,   /* Analog input 7 */
+  NRF53_ADC_IN_VDD      = 9,   /* VDD */
+  NRF53_ADC_IN_VDDHDIV5 = 10,  /* VDDH/5 */
+};
+
+/* Resistor control */
+
+enum nrf53_adc_res_e
+{
+  NRF53_ADC_RES_BYPASS   = 0,   /* Bypass resistor ladder */
+  NRF53_ADC_RES_PULLDOWN = 1,   /* Pull-down to GND */
+  NRF53_ADC_RES_PULLUP   = 2,   /* Pull-up to VDD */
+  NRF53_ADC_RES_VDD_2    = 3    /* Set input at VDD/2 */
+};
+
+/* Gain control */
+
+enum nrf53_adc_gain_e
+{
+  NRF53_ADC_GAIN_1_6 = 0,       /* 1/6 */
+  NRF53_ADC_GAIN_1_5 = 1,       /* 1/5 */
+  NRF53_ADC_GAIN_1_4 = 2,       /* 1/4 */
+  NRF53_ADC_GAIN_1_3 = 3,       /* 1/3 */
+  NRF53_ADC_GAIN_1_2 = 4,       /* 1/2 */
+  NRF53_ADC_GAIN_1   = 5,       /* 1 */
+  NRF53_ADC_GAIN_2   = 6,       /* 2 */
+  NRF53_ADC_GAIN_4   = 7        /* 4 */
+};
+
+/* Reference control */
+
+enum nrf53_adc_refsel_e
+{
+  NRF53_ADC_REFSEL_INTERNAL = 0, /* Internal reference (0.6V) */
+  NRF53_ADC_REFSEL_VDD_4    = 1  /* VDD/4 as reference */
+};
+
+/* Acquisition time control */
+
+enum nrf53_adc_tacq_e
+{
+  NRF53_ADC_TACQ_3US  = 0,      /* 3 us */
+  NRF53_ADC_TACQ_5US  = 1,      /* 5 us */
+  NRF53_ADC_TACQ_10US = 2,      /* 10 us */
+  NRF53_ADC_TACQ_15US = 3,      /* 15 us */
+  NRF53_ADC_TACQ_20US = 4,      /* 20 us */
+  NRF53_ADC_TACQ_40US = 5       /* 40 us */
+};
+
+/* ADC mode control */
+
+enum nrf53_adc_mode_e
+{
+  NRF53_ADC_MODE_SE   = 0,      /* Single-ended mode */
+  NRF53_ADC_MODE_DIFF = 1       /* Differentail mode */
+};
+
+/* ADC burst control */
+
+enum nrf53_adc_burst_e
+{
+  NRF53_ADC_BURST_DISABLE = 0,  /* Disable burst mode */
+  NRF53_ADC_BURST_ENABLE  = 1   /* Enable burst mode */
+};
+
+/* NRF53 ADC channel configuration */
+
+struct nrf53_adc_channel_s
+{
+  uint32_t p_psel;              /* P pin */
+  uint32_t n_psel;              /* N pin */
+#ifdef CONFIG_NRF53_SAADC_LIMITS
+  uint16_t limith;              /* High limit */
+  uint16_t limitl;              /* Low limit */
+#endif
+  uint8_t resp:2;               /* Positive chan resistor */
+  uint8_t resn:2;               /* Negative chan resistor */
+  uint8_t gain:3;               /* Gain control */
+  uint8_t refsel:1;             /* Reference control */
+  uint8_t tacq:3;               /* Acquisition time */
+  uint8_t mode:1;               /* Singe-ended or differential mode */
+  uint8_t burst:1;              /* Burst mode */
+  uint8_t _res:3;               /* Reserved */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_adcinitialize
+ *
+ * Description:
+ *   Initialize the ADC. See nrf53_adc.c for more details.
+ *
+ * Input Parameters:
+ *   chanlist  - channels configuration
+ *   nchannels - number of channels
+ *
+ * Returned Value:
+ *   Valid ADC device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct adc_dev_s *nrf53_adcinitialize(
+    const struct nrf53_adc_channel_s *chan,
+    int channels);
+
+#endif  /* __ARCH_ARM_SRC_NRF53_NRF53_ADC_H */

Reply via email to