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 93ac27ff639e7d38f1ee8f0049a49127957dd951
Author: raiden00pl <[email protected]>
AuthorDate: Mon Mar 13 12:39:14 2023 +0100

    arch/nrf53: add PWM support
---
 arch/arm/Kconfig               |   1 +
 arch/arm/src/nrf53/Kconfig     | 144 +++++++++
 arch/arm/src/nrf53/Make.defs   |   4 +
 arch/arm/src/nrf53/nrf53_pwm.c | 696 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/src/nrf53/nrf53_pwm.h | 115 +++++++
 5 files changed, 960 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b188c62fcc..816ba194bd 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -280,6 +280,7 @@ config ARCH_CHIP_NRF52
 config ARCH_CHIP_NRF53
        bool "Nordic NRF53"
        select ARCH_CORTEXM33
+       select ARCH_HAVE_PWM_MULTICHAN
        depends on EXPERIMENTAL
        ---help---
                Nordic NRF53 architectures (ARM dual Cortex-M33).
diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig
index 607848c9b7..7ed9deeb01 100644
--- a/arch/arm/src/nrf53/Kconfig
+++ b/arch/arm/src/nrf53/Kconfig
@@ -21,6 +21,8 @@ config NRF53_APPCORE
        bool
        default n
        select ARM_HAVE_DSP
+       select ARCH_HAVE_FPU
+       select NRF53_HAVE_PWM
 
 config NRF53_NETCORE
        bool
@@ -66,6 +68,12 @@ config NRF53_ENABLE_APPROTECT
        bool "NRF53 enable APPROTECT"
        default n
 
+# Peripheral support
+
+config NRF53_HAVE_PWM
+       bool
+       default n
+
 # Peripheral Selection
 
 config NRF53_IPC
@@ -80,6 +88,10 @@ config NRF53_TIMER
        bool
        default n
 
+config NRF53_PWM
+       bool
+       default n
+
 menu "NRF53 Peripheral Selection"
 
 config NRF53_UART0
@@ -108,6 +120,20 @@ config NRF53_TIMER1
 config NRF53_TIMER2
        bool "TIMER2"
        select NRF53_TIMER
+
+config NRF53_PWM0
+       bool "PWM0"
+       select NRF53_PWM
+       default n
+
+config NRF53_PWM1
+       bool "PWM1"
+       select NRF53_PWM
+       default n
+
+config NRF53_PWM2
+       bool "PWM2"
+       select NRF53_PWM
        default n
 
 endmenu # NRF53 Peripheral Selection
@@ -188,6 +214,124 @@ endchoice
 
 endmenu # System Timer
 
+menu "PWM configuration"
+
+config NRF53_PWM_MULTICHAN
+       bool "PWM Multiple Output Channels"
+       default n
+
+if NRF53_PWM_MULTICHAN
+
+if NRF53_PWM0
+
+config NRF53_PWM0_CH0
+       bool "PWM0 Channel 0 Output"
+       default n
+       ---help---
+               Enables channel 0 output.
+
+config NRF53_PWM0_CH1
+       bool "PWM0 Channel 1 Output"
+       default n
+       ---help---
+               Enables channel 1 output.
+
+config NRF53_PWM0_CH2
+       bool "PWM0 Channel 2 Output"
+       default n
+       ---help---
+               Enables channel 2 output.
+
+config NRF53_PWM0_CH3
+       bool "PWM0 Channel 3 Output"
+       default n
+       ---help---
+               Enables channel 3 output.
+
+endif # NRF53_PWM0
+
+if NRF53_PWM1
+
+config NRF53_PWM1_CH0
+       bool "PWM1 Channel 0 Output"
+       default n
+       ---help---
+               Enables channel 0 output.
+
+config NRF53_PWM1_CH1
+       bool "PWM1 Channel 1 Output"
+       default n
+       ---help---
+               Enables channel 1 output.
+
+config NRF53_PWM1_CH2
+       bool "PWM1 Channel 2 Output"
+       default n
+       ---help---
+               Enables channel 2 output.
+
+config NRF53_PWM1_CH3
+       bool "PWM1 Channel 3 Output"
+       default n
+       ---help---
+               Enables channel 3 output.
+
+endif # NRF53_PWM1
+
+if NRF53_PWM2
+
+config NRF53_PWM2_CH0
+       bool "PWM2 Channel 0 Output"
+       default n
+       ---help---
+               Enables channel 0 output.
+
+config NRF53_PWM2_CH1
+       bool "PWM2 Channel 1 Output"
+       default n
+       ---help---
+               Enables channel 1 output.
+
+config NRF53_PWM2_CH2
+       bool "PWM2 Channel 2 Output"
+       default n
+       ---help---
+               Enables channel 2 output.
+
+config NRF53_PWM2_CH3
+       bool "PWM2 Channel 3 Output"
+       default n
+       ---help---
+               Enables channel 3 output.
+
+endif # NRF53_PWM2
+
+endif # !NRF53_PWM_MULTICHAN
+
+if !NRF53_PWM_MULTICHAN
+
+config NRF53_PWM0_CHANNEL
+       int "PWM0 Output Channel"
+       depends on NRF53_PWM0
+       default 0
+       range 0 3
+
+config NRF53_PWM1_CHANNEL
+       int "PWM1 Output Channel"
+       depends on NRF53_PWM1
+       default 0
+       range 0 3
+
+config NRF53_PWM2_CHANNEL
+       int "PWM2 Output Channel"
+       depends on NRF53_PWM2
+       default 0
+       range 0 3
+
+endif # !NRF53_PWM_MULTICHAN
+
+endmenu # PWM 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 35d9159adf..cef4be459b 100644
--- a/arch/arm/src/nrf53/Make.defs
+++ b/arch/arm/src/nrf53/Make.defs
@@ -58,6 +58,10 @@ CHIP_CSRCS += nrf53_tim_lowerhalf.c
 endif
 endif
 
+ifeq ($(CONFIG_NRF53_PWM),y)
+CHIP_CSRCS += nrf53_pwm.c
+endif
+
 ifeq ($(CONFIG_PM),y)
 CHIP_CSRCS += nrf53_pminitialize.c
 endif
diff --git a/arch/arm/src/nrf53/nrf53_pwm.c b/arch/arm/src/nrf53/nrf53_pwm.c
new file mode 100644
index 0000000000..b2c40d9527
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_pwm.c
@@ -0,0 +1,696 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_pwm.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 <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "nrf53_gpio.h"
+#include "nrf53_pwm.h"
+
+#include "hardware/nrf53_pwm.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Default PWM polarity */
+
+#define PWM_POLARITY_DEFAULT (PWM_DECODER_POL_FALLING)
+
+/* Sequence 0 length */
+
+#define PWM_SEQ0_LEN         (4)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct nrf53_pwm_s
+{
+  const struct pwm_ops_s *ops;       /* PWM operations */
+  uint32_t                base;      /* Base address of PWM register */
+  uint32_t                frequency; /* Current frequency setting */
+  uint32_t                cntrtop;   /* Counter top */
+  uint32_t                ch0_pin;   /* Channel 1 pin */
+  uint32_t                ch1_pin;   /* Channel 2 pin */
+  uint32_t                ch2_pin;   /* Channel 3 pin */
+  uint32_t                ch3_pin;   /* Channel 4 pin */
+
+  /* Sequence 0 */
+
+  uint16_t                    seq0[PWM_SEQ0_LEN];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* PWM Register access */
+
+static inline void nrf53_pwm_putreg(struct nrf53_pwm_s *priv,
+                                    uint32_t offset,
+                                    uint32_t value);
+static inline uint32_t nrf53_pwm_getreg(struct nrf53_pwm_s *priv,
+                                        uint32_t offset);
+
+/* PWM helpers */
+
+static int nrf53_pwm_configure(struct nrf53_pwm_s *priv);
+static int nrf53_pwm_duty(struct nrf53_pwm_s *priv, uint8_t chan,
+                          ub16_t duty);
+static int nrf53_pwm_freq(struct nrf53_pwm_s *priv, uint32_t freq);
+
+/* PWM driver methods */
+
+static int nrf53_pwm_setup(struct pwm_lowerhalf_s *dev);
+static int nrf53_pwm_shutdown(struct pwm_lowerhalf_s *dev);
+#ifdef CONFIG_PWM_PULSECOUNT
+static int nrf53_pwm_start(struct pwm_lowerhalf_s *dev,
+                           const struct pwm_info_s *info,
+                           void *handle);
+#else
+static int nrf53_pwm_start(struct pwm_lowerhalf_s *dev,
+                           const struct pwm_info_s *info);
+#endif
+static int nrf53_pwm_stop(struct pwm_lowerhalf_s *dev);
+static int nrf53_pwm_ioctl(struct pwm_lowerhalf_s *dev,
+                           int cmd, unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This is the list of lower half PWM driver methods used by the upper half
+ * driver.
+ */
+
+static const struct pwm_ops_s g_nrf53_pwmops =
+{
+  .setup       = nrf53_pwm_setup,
+  .shutdown    = nrf53_pwm_shutdown,
+  .start       = nrf53_pwm_start,
+  .stop        = nrf53_pwm_stop,
+  .ioctl       = nrf53_pwm_ioctl,
+};
+
+#ifdef CONFIG_NRF53_PWM0
+/* PWM 0 */
+
+struct nrf53_pwm_s g_nrf53_pwm0 =
+{
+  .ops     = &g_nrf53_pwmops,
+  .base    = NRF53_PWM0_BASE,
+#ifdef CONFIG_NRF53_PWM0_CH0
+  .ch0_pin = NRF53_PWM0_CH0_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM0_CH1
+  .ch1_pin = NRF53_PWM0_CH1_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM0_CH2
+  .ch2_pin = NRF53_PWM0_CH2_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM0_CH3
+  .ch3_pin = NRF53_PWM0_CH3_PIN,
+#endif
+};
+#endif
+
+#ifdef CONFIG_NRF53_PWM1
+/* PWM 1 */
+
+struct nrf53_pwm_s g_nrf53_pwm1 =
+{
+  .ops     = &g_nrf53_pwmops,
+  .base    = NRF53_PWM1_BASE,
+#ifdef CONFIG_NRF53_PWM1_CH0
+  .ch0_pin = NRF53_PWM1_CH0_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM1_CH1
+  .ch1_pin = NRF53_PWM1_CH1_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM1_CH2
+  .ch2_pin = NRF53_PWM1_CH2_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM1_CH3
+  .ch3_pin = NRF53_PWM1_CH3_PIN,
+#endif
+};
+#endif
+
+#ifdef CONFIG_NRF53_PWM2
+/* PWM 2 */
+
+struct nrf53_pwm_s g_nrf53_pwm2 =
+{
+  .ops     = &g_nrf53_pwmops,
+  .base    = NRF53_PWM2_BASE,
+#ifdef CONFIG_NRF53_PWM2_CH0
+  .ch0_pin = NRF53_PWM2_CH0_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM2_CH1
+  .ch1_pin = NRF53_PWM2_CH1_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM2_CH2
+  .ch2_pin = NRF53_PWM2_CH2_PIN,
+#endif
+#ifdef CONFIG_NRF53_PWM2_CH3
+  .ch3_pin = NRF53_PWM2_CH3_PIN,
+#endif
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_pwm_putreg
+ *
+ * Description:
+ *   Put a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void nrf53_pwm_putreg(struct nrf53_pwm_s *priv,
+                                    uint32_t offset,
+                                    uint32_t value)
+{
+  putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_getreg
+ *
+ * Description:
+ *   Get a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf53_pwm_getreg(struct nrf53_pwm_s *priv,
+                                        uint32_t offset)
+{
+  return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_configure
+ *
+ * Description:
+ *   Configure PWM
+ *
+ ****************************************************************************/
+
+static int nrf53_pwm_configure(struct nrf53_pwm_s *priv)
+{
+  uint32_t regval = 0;
+  int      ret    = OK;
+
+  DEBUGASSERT(priv);
+
+  /* Configure PWM mode */
+
+  nrf53_pwm_putreg(priv, NRF53_PWM_MODE_OFFSET, PWM_MODE_UP);
+
+  /* Configure decoder  */
+
+  regval = PWM_DECODER_LOAD_INDIVIDUAL | PWM_DECODER_MODE_REFRESH;
+  nrf53_pwm_putreg(priv, NRF53_PWM_DECODER_OFFSET, regval);
+
+  /* Configure sequence 0 */
+
+  regval = (uint32_t)priv->seq0;
+  nrf53_pwm_putreg(priv, NRF53_PWM_SEQ0PTR_OFFSET, regval);
+
+  regval = PWM_SEQ0_LEN;
+  nrf53_pwm_putreg(priv, NRF53_PWM_SEQ0CNT_OFFSET, regval);
+
+  regval = 0;
+  nrf53_pwm_putreg(priv, NRF53_PWM_SEQ0REFRESH_OFFSET, regval);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_duty
+ *
+ * Description:
+ *   Configure PWM duty
+ *
+ ****************************************************************************/
+
+static int nrf53_pwm_duty(struct nrf53_pwm_s *priv, uint8_t chan,
+                          ub16_t duty)
+{
+  uint16_t compare = 0;
+
+  DEBUGASSERT(priv);
+
+  pwminfo("PWM channel: %d duty: %" PRId32 "\n", chan, duty);
+
+  /* Get compare
+   *
+   * duty cycle = compare / reload (fractional value)
+   */
+
+  compare = b16toi(duty * priv->cntrtop + b16HALF);
+
+  /* Configure channel sequence */
+
+  priv->seq0[chan] = PWM_POLARITY_DEFAULT | compare;
+
+  pwminfo("seq0[%d]: %d %d\n", chan, compare, priv->seq0[chan]);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_freq
+ *
+ * Description:
+ *   Configure PWM frequency
+ *
+ ****************************************************************************/
+
+static int nrf53_pwm_freq(struct nrf53_pwm_s *priv, uint32_t freq)
+{
+  uint32_t regval    = 0;
+  uint32_t pwm_clk   = 0;
+  uint32_t top       = 0;
+  uint32_t prescaler = 0;
+  uint64_t tmp       = 0;
+  int      ret       = OK;
+
+  DEBUGASSERT(priv);
+
+  /* Get best prescaler */
+
+  tmp = PWM_COUNTERTOP_MASK * freq;
+
+  if (tmp >= 16000000)
+    {
+      pwm_clk   = 16000000;
+      prescaler = PWM_PRESCALER_16MHZ;
+    }
+  else if (tmp >= 8000000)
+    {
+      pwm_clk   = 8000000;
+      prescaler = PWM_PRESCALER_8MHZ;
+    }
+  else if (tmp >= 4000000)
+    {
+      pwm_clk   = 4000000;
+      prescaler = PWM_PRESCALER_4MHZ;
+    }
+  else if (tmp >= 2000000)
+    {
+      pwm_clk   = 2000000;
+      prescaler = PWM_PRESCALER_2MHZ;
+    }
+  else if (tmp >= 1000000)
+    {
+      pwm_clk   = 1000000;
+      prescaler = PWM_PRESCALER_1MHZ;
+    }
+  else if (tmp >= 500000)
+    {
+      pwm_clk   = 500000;
+      prescaler = PWM_PRESCALER_500KHZ;
+    }
+  else if (tmp >= 250000)
+    {
+      pwm_clk   = 250000;
+      prescaler = PWM_PRESCALER_250KHZ;
+    }
+  else
+    {
+      pwm_clk   = 125000;
+      prescaler = PWM_PRESCALER_125KHZ;
+    }
+
+  /* Configure prescaler */
+
+  nrf53_pwm_putreg(priv, NRF53_PWM_PRESCALER_OFFSET, prescaler);
+
+  /* Get counter max */
+
+  top = pwm_clk / freq;
+  if (top < 2)
+    {
+      top = 1;
+    }
+  else if (top > PWM_COUNTERTOP_MASK)
+    {
+      top = PWM_COUNTERTOP_MASK;
+    }
+  else
+    {
+      top = top - 1;
+    }
+
+  /* Configure counter max */
+
+  regval = top;
+  nrf53_pwm_putreg(priv, NRF53_PWM_COUNTERTOP_OFFSET, regval);
+
+  priv->cntrtop = top;
+
+  pwminfo("PWM frequency: %" PRId32 " pwm_clk: %" PRId32
+          " pwm_prescaler: %" PRId32 " top: %" PRId32 "\n",
+          freq, pwm_clk, prescaler, top);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_setup
+ *
+ * Description:
+ *   This method is called when the driver is opened.  The lower half driver
+ *   should configure and initialize the device so that it is ready for use.
+ *   It should not, however, output pulses until the start method is called.
+ *
+ ****************************************************************************/
+
+static int nrf53_pwm_setup(struct pwm_lowerhalf_s *dev)
+{
+  struct nrf53_pwm_s *priv = (struct nrf53_pwm_s *)dev;
+  int                 ret  = OK;
+  uint32_t            regval = 0;
+  uint32_t            pin = 0;
+  uint32_t            port = 0;
+
+  DEBUGASSERT(dev);
+
+  /* Configure channels */
+
+  if (priv->ch0_pin != 0)
+    {
+      nrf53_gpio_config(priv->ch0_pin);
+
+      pin  = GPIO_PIN_DECODE(priv->ch0_pin);
+      port = GPIO_PORT_DECODE(priv->ch0_pin);
+
+      regval = (port << PWM_PSEL_PORT_SHIFT);
+      regval |= (pin << PWM_PSEL_PIN_SHIFT);
+
+      nrf53_pwm_putreg(priv, NRF53_PWM_PSEL0_OFFSET, regval);
+    }
+
+  if (priv->ch1_pin != 0)
+    {
+      nrf53_gpio_config(priv->ch1_pin);
+
+      pin  = GPIO_PIN_DECODE(priv->ch1_pin);
+      port = GPIO_PORT_DECODE(priv->ch1_pin);
+
+      regval = (port << PWM_PSEL_PORT_SHIFT);
+      regval |= (pin << PWM_PSEL_PIN_SHIFT);
+
+      nrf53_pwm_putreg(priv, NRF53_PWM_PSEL1_OFFSET, regval);
+    }
+
+  if (priv->ch2_pin != 0)
+    {
+      nrf53_gpio_config(priv->ch2_pin);
+
+      pin  = GPIO_PIN_DECODE(priv->ch2_pin);
+      port = GPIO_PORT_DECODE(priv->ch2_pin);
+
+      regval = (port << PWM_PSEL_PORT_SHIFT);
+      regval |= (pin << PWM_PSEL_PIN_SHIFT);
+
+      nrf53_pwm_putreg(priv, NRF53_PWM_PSEL2_OFFSET, regval);
+    }
+
+  if (priv->ch3_pin != 0)
+    {
+      nrf53_gpio_config(priv->ch3_pin);
+
+      pin  = GPIO_PIN_DECODE(priv->ch3_pin);
+      port = GPIO_PORT_DECODE(priv->ch3_pin);
+
+      regval = (port << PWM_PSEL_PORT_SHIFT);
+      regval |= (pin << PWM_PSEL_PIN_SHIFT);
+
+      nrf53_pwm_putreg(priv, NRF53_PWM_PSEL3_OFFSET, regval);
+    }
+
+  /* Configure PWM */
+
+  ret = nrf53_pwm_configure(priv);
+  if (ret < 0)
+    {
+      pwmerr("ERROR: nrf53_pwm_configure failed %d\n", ret);
+      goto errout;
+    }
+
+  /* Enable PWM */
+
+  nrf53_pwm_putreg(priv, NRF53_PWM_ENABLE_OFFSET, 1);
+
+errout:
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_shutdown
+ *
+ * Description:
+ *   This method is called when the driver is closed.  The lower half driver
+ *   stop pulsed output, free any resources, disable the timer hardware, and
+ *   put the system into the lowest possible power usage state
+ *
+ ****************************************************************************/
+
+static int nrf53_pwm_shutdown(struct pwm_lowerhalf_s *dev)
+{
+  struct nrf53_pwm_s *priv = (struct nrf53_pwm_s *)dev;
+  int                 ret  = OK;
+
+  DEBUGASSERT(dev);
+
+  /* Disable PWM */
+
+  nrf53_pwm_putreg(priv, NRF53_PWM_ENABLE_OFFSET, 0);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_start
+ *
+ * Description:
+ *   (Re-)initialize the PWM and start the pulsed output
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_PWM_PULSECOUNT
+static int nrf53_pwm_start(struct pwm_lowerhalf_s *dev,
+                           const struct pwm_info_s *info,
+                           void *handle)
+{
+#error Not supported
+}
+#else
+static int nrf53_pwm_start(struct pwm_lowerhalf_s *dev,
+                           const struct pwm_info_s *info)
+{
+  struct nrf53_pwm_s *priv = (struct nrf53_pwm_s *)dev;
+  int                 ret  = OK;
+#ifdef CONFIG_PWM_MULTICHAN
+  int                 i    = 0;
+#endif
+
+  DEBUGASSERT(dev);
+
+  /* If frequency has not changed we just update duty */
+
+  if (info->frequency != priv->frequency)
+    {
+      /* Update frequency */
+
+      ret = nrf53_pwm_freq(priv, info->frequency);
+
+      if (ret == OK)
+        {
+          priv->frequency = info->frequency;
+        }
+    }
+
+#ifdef CONFIG_PWM_MULTICHAN
+      for (i = 0; ret == OK && i < CONFIG_PWM_NCHANNELS; i++)
+        {
+          /* Break the loop if all following channels are not configured */
+
+          if (info->channels[i].channel == -1)
+            {
+              break;
+            }
+
+          /* Set output if channel configured */
+
+          if (info->channels[i].channel != 0)
+            {
+              ret = nrf53_pwm_duty(priv,
+                                   (info->channels[i].channel - 1),
+                                   info->channels[i].duty);
+            }
+        }
+
+#else
+      ret = nrf53_pwm_duty(dev,
+                           (info->channels[0].channel - 1),
+                           info->duty);
+#endif /* CONFIG_PWM_MULTICHAN */
+
+  /* Start sequence 0 */
+
+  nrf53_pwm_putreg(priv, NRF53_PWM_TASKS_SEQSTART0_OFFSET, 1);
+
+  /* Wait for sequence started */
+
+  while (nrf53_pwm_getreg(priv, NRF53_PWM_EVENTS_SEQSTARTED0_OFFSET) != 1);
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf53_pwm_stop
+ *
+ * Description:
+ *   Stop the PWM
+ *
+ ****************************************************************************/
+
+static int nrf53_pwm_stop(struct pwm_lowerhalf_s *dev)
+{
+  struct nrf53_pwm_s *priv = (struct nrf53_pwm_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  /* Stop PWM */
+
+  nrf53_pwm_putreg(priv, NRF53_PWM_TASKS_STOP_OFFSET, 1);
+
+  /* Wait for PWM stopped */
+
+  while (nrf53_pwm_getreg(priv, NRF53_PWM_EVENTS_STOPPED_OFFSET) != 1);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_pwm_ioctl
+ *
+ * Description:
+ *   Lower-half logic may support platform-specific ioctl commands
+ *
+ ****************************************************************************/
+
+static int nrf53_pwm_ioctl(struct pwm_lowerhalf_s *dev,
+                           int cmd, unsigned long arg)
+{
+  struct nrf53_pwm_s *priv = (struct nrf53_pwm_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  /* There are no platform-specific ioctl commands */
+
+  UNUSED(priv);
+
+  return -ENOTTY;
+}
+
+/****************************************************************************
+ * Public Function
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_pwminitialize
+ *
+ * Description:
+ *   Initialize one timer for use with the upper_level PWM driver.
+ *
+ * Input Parameters:
+ *   pwm - A number identifying the pwm instance.
+ *
+ * Returned Value:
+ *   On success, a pointer to the NRF53 lower half PWM driver is returned.
+ *   NULL is returned on any failure.
+ *
+ ****************************************************************************/
+
+struct pwm_lowerhalf_s *nrf53_pwminitialize(int pwm)
+{
+  struct nrf53_pwm_s *lower = NULL;
+
+  pwminfo("Initialize PWM%u\n", pwm);
+
+  switch (pwm)
+    {
+#ifdef CONFIG_NRF53_PWM0
+      case 0:
+        {
+          lower = &g_nrf53_pwm0;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF53_PWM1
+      case 1:
+        {
+          lower = &g_nrf53_pwm1;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF53_PWM2
+      case 2:
+        {
+          lower = &g_nrf53_pwm2;
+          break;
+        }
+#endif
+
+      default:
+        {
+          pwmerr("ERROR: No such PWM device %d\n", pwm);
+          lower = NULL;
+          goto errout;
+        }
+    }
+
+errout:
+  return (struct pwm_lowerhalf_s *)lower;
+}
diff --git a/arch/arm/src/nrf53/nrf53_pwm.h b/arch/arm/src/nrf53/nrf53_pwm.h
new file mode 100644
index 0000000000..c577e45178
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_pwm.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_pwm.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_PWM_H
+#define __ARCH_ARM_SRC_NRF53_NRF53_PWM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/timers/pwm.h>
+
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* Enable the specified PWM channel if multichannel PWM is disabled */
+
+#ifndef CONFIG_NRF53_PWM_MULTICHAN
+
+#  ifdef CONFIG_NRF53_PWM0
+#    if !defined(CONFIG_NRF53_PWM0_CHANNEL)
+#      error "CONFIG_NRF53_PWM0_CHANNEL must be provided"
+#    elif CONFIG_NRF53_PWM0_CHANNEL == 0
+#      define CONFIG_NRF53_PWM0_CH0 1
+#    elif CONFIG_NRF53_PWM0_CHANNEL == 1
+#      define CONFIG_NRF53_PWM0_CH1 1
+#    elif CONFIG_NRF53_PWM0_CHANNEL == 2
+#      define CONFIG_NRF53_PWM0_CH2 1
+#    elif CONFIG_NRF53_PWM0_CHANNEL == 3
+#      define CONFIG_NRF53_PWM0_CH3 1
+#    else
+#      error "Unsupported value of CONFIG_NRF53_PWM0_CHANNEL"
+#    endif
+#  endif
+
+#  ifdef CONFIG_NRF53_PWM1
+#    if !defined(CONFIG_NRF53_PWM1_CHANNEL)
+#      error "CONFIG_NRF53_PWM1_CHANNEL must be provided"
+#    elif CONFIG_NRF53_PWM1_CHANNEL == 0
+#      define CONFIG_NRF53_PWM1_CH0 1
+#    elif CONFIG_NRF53_PWM1_CHANNEL == 1
+#      define CONFIG_NRF53_PWM1_CH1 1
+#    elif CONFIG_NRF53_PWM1_CHANNEL == 2
+#      define CONFIG_NRF53_PWM1_CH2 1
+#    elif CONFIG_NRF53_PWM1_CHANNEL == 3
+#      define CONFIG_NRF53_PWM1_CH3 1
+#    else
+#      error "Unsupported value of CONFIG_NRF53_PWM1_CHANNEL"
+#    endif
+#  endif
+
+#  ifdef CONFIG_NRF53_PWM2
+#    if !defined(CONFIG_NRF53_PWM2_CHANNEL)
+#      error "CONFIG_NRF53_PWM2_CHANNEL must be provided"
+#    elif CONFIG_NRF53_PWM2_CHANNEL == 0
+#      define CONFIG_NRF53_PWM2_CH0 1
+#    elif CONFIG_NRF53_PWM2_CHANNEL == 1
+#      define CONFIG_NRF53_PWM2_CH1 1
+#    elif CONFIG_NRF53_PWM2_CHANNEL == 2
+#      define CONFIG_NRF53_PWM2_CH2 1
+#    elif CONFIG_NRF53_PWM2_CHANNEL == 3
+#      define CONFIG_NRF53_PWM2_CH3 1
+#    else
+#      error "Unsupported value of CONFIG_NRF53_PWM2_CHANNEL"
+#    endif
+#  endif
+
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_pwminitialize
+ *
+ * Description:
+ *   Initialize one timer for use with the upper_level PWM driver.
+ *
+ * Input Parameters:
+ *   pwm - A number identifying the pwm instance.
+ *
+ * Returned Value:
+ *   On success, a pointer to the NRF53 lower half PWM driver is returned.
+ *   NULL is returned on any failure.
+ *
+ ****************************************************************************/
+
+struct pwm_lowerhalf_s *nrf53_pwminitialize(int pwm);
+
+#endif /* __ARCH_ARM_SRC_NRF53_NRF53_PWM_H */

Reply via email to