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

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

commit addfe182aeb70b57dd48968cac2ad55a64249ac2
Author: Michal Lenc <[email protected]>
AuthorDate: Sat Jun 26 11:49:38 2021 +0200

    arch/arm/src/imxrt: added support for FlexPWM driver
    
    Signed-off-by: Michal Lenc <[email protected]>
---
 arch/arm/src/imxrt/Kconfig                 |  245 +++++++
 arch/arm/src/imxrt/Make.defs               |    4 +
 arch/arm/src/imxrt/hardware/imxrt_iomuxc.h |    3 +
 arch/arm/src/imxrt/imxrt_flexpwm.c         | 1061 ++++++++++++++++++++++++++++
 arch/arm/src/imxrt/imxrt_flexpwm.h         |   78 ++
 5 files changed, 1391 insertions(+)

diff --git a/arch/arm/src/imxrt/Kconfig b/arch/arm/src/imxrt/Kconfig
index 4cff2b4..e1165ea 100644
--- a/arch/arm/src/imxrt/Kconfig
+++ b/arch/arm/src/imxrt/Kconfig
@@ -170,6 +170,11 @@ config IMXRT_FLEXCAN
        default n
        select ARCH_HAVE_NETDEV_STATISTICS
 
+config IMXRT_FLEXPWM
+       bool
+       default n
+       select ARCH_HAVE_PWM_MULTICHAN
+
 config IMXRT_LPI2C
        bool
        default n
@@ -547,6 +552,246 @@ config FLEXCAN3_DATA_SAMPLEP
 
 endmenu # IMXRT_FLEXCAN3
 
+menu "FLEXPWM Peripherals"
+
+config IMXRT_FLEXPWM1
+       bool "FLEXPWM1"
+       default n
+       select IMXRT_FLEXPWM
+
+config IMXRT_FLEXPWM2
+       bool "FLEXPWM2"
+       default n
+       select IMXRT_FLEXPWM
+
+if ARCH_FAMILY_IMXRT105x || ARCH_FAMILY_IMXRT106x
+
+config IMXRT_FLEXPWM3
+       bool "FLEXPWM3"
+       default n
+       select IMXRT_FLEXPWM
+
+config IMXRT_FLEXPWM4
+       bool "FLEXPWM4"
+       default n
+       select IMXRT_FLEXPWM
+
+endif # ARCH_FAMILY_IMXRT105x || ARCH_FAMILY_IMXRT106x
+
+endmenu # FLEXPWM Peripherals
+
+menu "FLEXPWM1 Configuration"
+       depends on IMXRT_FLEXPWM1
+
+config IMXRT_FLEXPWM1_MOD1
+       bool "FLEXPWM1 Module 1"
+       default n
+
+if IMXRT_FLEXPWM1_MOD1
+
+config IMXRT_FLEXPWM1_MOD1_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM1_MOD2
+       bool "FLEXPWM1 Module 2"
+       default n
+
+if IMXRT_FLEXPWM1_MOD2
+
+config IMXRT_FLEXPWM1_MOD2_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM1_MOD3
+       bool "FLEXPWM1 Module 3"
+       default n
+
+if IMXRT_FLEXPWM1_MOD3
+
+config IMXRT_FLEXPWM1_MOD3_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM1_MOD4
+       bool "FLEXPWM1 Module 4"
+       default n
+
+if IMXRT_FLEXPWM1_MOD4
+
+config IMXRT_FLEXPWM1_MOD4_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+endmenu # IMXRT_FLEXPWM1
+
+menu "FLEXPWM2 Configuration"
+       depends on IMXRT_FLEXPWM2
+
+config IMXRT_FLEXPWM2_MOD1
+       bool "FLEXPWM2 Module 1"
+       default n
+
+if IMXRT_FLEXPWM2_MOD1
+
+config IMXRT_FLEXPWM2_MOD1_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM2_MOD2
+       bool "FLEXPWM2 Module 2"
+       default n
+
+if IMXRT_FLEXPWM2_MOD2
+
+config IMXRT_FLEXPWM2_MOD2_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM2_MOD3
+       bool "FLEXPWM2 Module 3"
+       default n
+
+if IMXRT_FLEXPWM2_MOD3
+
+config IMXRT_FLEXPWM2_MOD3_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM2_MOD4
+       bool "FLEXPWM2 Module 4"
+       default n
+
+if IMXRT_FLEXPWM2_MOD4
+
+config IMXRT_FLEXPWM2_MOD4_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+endmenu # IMXRT_FLEXPWM2
+
+menu "FLEXPWM3 Configuration"
+       depends on IMXRT_FLEXPWM3
+
+config IMXRT_FLEXPWM3_MOD1
+       bool "FLEXPWM3 Module 1"
+       default n
+
+if IMXRT_FLEXPWM3_MOD1
+
+config IMXRT_FLEXPWM3_MOD1_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM3_MOD2
+       bool "FLEXPWM3 Module 2"
+       default n
+
+if IMXRT_FLEXPWM3_MOD2
+
+config IMXRT_FLEXPWM3_MOD2_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM3_MOD3
+       bool "FLEXPWM3 Module 3"
+       default n
+
+if IMXRT_FLEXPWM3_MOD3
+
+config IMXRT_FLEXPWM3_MOD3_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM3_MOD4
+       bool "FLEXPWM3 Module 4"
+       default n
+
+if IMXRT_FLEXPWM3_MOD4
+
+config IMXRT_FLEXPWM3_MOD4_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+endmenu # IMXRT_FLEXPWM3
+
+menu "FLEXPWM4 Configuration"
+       depends on IMXRT_FLEXPWM4
+
+config IMXRT_FLEXPWM4_MOD1
+       bool "FLEXPWM4 Module 1"
+       default n
+
+if IMXRT_FLEXPWM4_MOD1
+
+config IMXRT_FLEXPWM4_MOD1_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM4_MOD2
+       bool "FLEXPWM4 Module 2"
+       default n
+
+if IMXRT_FLEXPWM4_MOD2
+
+config IMXRT_FLEXPWM4_MOD2_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM4_MOD3
+       bool "FLEXPWM4 Module 3"
+       default n
+
+if IMXRT_FLEXPWM4_MOD3
+
+config IMXRT_FLEXPWM4_MOD3_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+config IMXRT_FLEXPWM4_MOD4
+       bool "FLEXPWM4 Module 4"
+       default n
+
+if IMXRT_FLEXPWM4_MOD4
+
+config IMXRT_FLEXPWM4_MOD4_COMP
+       bool "Use complementary output"
+       default n
+
+endif
+
+endmenu # IMXRT_FLEXPWM4
+
 menu "LPI2C Peripherals"
 
 menuconfig IMXRT_LPI2C1
diff --git a/arch/arm/src/imxrt/Make.defs b/arch/arm/src/imxrt/Make.defs
index ba9195a..ae90261 100644
--- a/arch/arm/src/imxrt/Make.defs
+++ b/arch/arm/src/imxrt/Make.defs
@@ -116,6 +116,10 @@ ifeq ($(CONFIG_IMXRT_FLEXCAN),y)
 CHIP_CSRCS += imxrt_flexcan.c
 endif
 
+ifeq ($(CONFIG_IMXRT_FLEXPWM),y)
+CHIP_CSRCS += imxrt_flexpwm.c
+endif
+
 ifeq ($(CONFIG_IMXRT_SNVS_LPSRTC),y)
 CHIP_CSRCS += imxrt_lpsrtc.c
 CHIP_CSRCS += imxrt_hprtc.c
diff --git a/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h 
b/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h
index 2987af1..3f06ce7 100644
--- a/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h
+++ b/arch/arm/src/imxrt/hardware/imxrt_iomuxc.h
@@ -154,6 +154,9 @@
 #define IOMUX_CAN_DEFAULT                     (IOMUX_SLEW_SLOW | \
                                                IOMUX_DRIVE_50OHM | 
IOMUX_SPEED_LOW )
 
+#define IOMUX_PWM_DEFAULT                     (IOMUX_SLEW_FAST | \
+                                               IOMUX_DRIVE_50OHM | 
IOMUX_SPEED_LOW )
+
 #define IOMUX_USDHC1_DATAX_DEFAULT            (IOMUX_SLEW_FAST | 
IOMUX_DRIVE_130OHM | \
                                                IOMUX_PULL_UP_47K | 
IOMUX_SCHMITT_TRIGGER)
 #define IOMUX_USDHC1_CMD_DEFAULT              (IOMUX_SLEW_FAST | 
IOMUX_DRIVE_130OHM | \
diff --git a/arch/arm/src/imxrt/imxrt_flexpwm.c 
b/arch/arm/src/imxrt/imxrt_flexpwm.c
new file mode 100644
index 0000000..5f4bf25
--- /dev/null
+++ b/arch/arm/src/imxrt/imxrt_flexpwm.c
@@ -0,0 +1,1061 @@
+/****************************************************************************
+ * arch/arm/src/imxrt/imxrt_flexpwm.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 <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/timers/pwm.h>
+
+#include "arm_arch.h"
+#include "chip.h"
+#include "imxrt_config.h"
+#include "imxrt_flexpwm.h"
+#include "imxrt_periphclks.h"
+#include "hardware/imxrt_flexpwm.h"
+#include "hardware/imxrt_pinmux.h"
+#include "hardware/imxrt_ccm.h"
+
+#include <arch/board/board.h>
+
+#include <sys/time.h>
+
+#ifdef CONFIG_IMXRT_FLEXPWM
+
+#ifdef CONFIG_PWM_NCHANNELS
+# define PWM_NCHANNELS CONFIG_PWM_NCHANNELS
+#else
+# define PWM_NCHANNELS 1
+#endif
+
+#define MODULE_OFFSET 0x60
+#define CLK_FREQ  132000000
+#define PWM_RES 65535
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct imxrt_flexpwm_out_s
+{
+  bool used;
+  uint32_t pin;                   /* Output pin */
+};
+
+struct imxrt_flexpwm_module_s
+{
+  uint8_t module;                   /* Number of PWM module */
+  bool used;                        /* True if the module is used */
+  struct imxrt_flexpwm_out_s out_a; /* PWM output */
+  struct imxrt_flexpwm_out_s out_b; /* PWM output */
+  bool complementary;               /* True if outputs are complementary */
+  uint32_t irq;                     /* Combined interrupt */
+};
+
+struct imxrt_flexpwm_s
+{
+  const struct pwm_ops_s *ops;    /* PWM operations */
+  FAR struct imxrt_flexpwm_module_s *modules;
+  uint8_t modules_num;            /* Number of modules */
+  uint32_t frequency;             /* PWM frequency */
+  uint32_t base;                  /* Base addres of peripheral register */
+};
+
+/* PWM driver methods */
+
+static int pwm_setup(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info);
+static int pwm_stop(FAR struct pwm_lowerhalf_s *dev);
+static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
+                     int cmd, unsigned long arg);
+
+/* Helper functions */
+
+static int pwm_set_output(FAR struct pwm_lowerhalf_s *dev, uint8_t channel,
+                           ub16_t duty);
+static int pwm_change_freq(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info, uint8_t channel);
+
+/****************************************************************************
+  * Private Data
+ ****************************************************************************/
+
+static const struct pwm_ops_s g_pwmops =
+{
+  .setup      = pwm_setup,
+  .shutdown   = pwm_shutdown,
+  .start      = pwm_start,
+  .stop       = pwm_stop,
+  .ioctl      = pwm_ioctl,
+};
+
+#ifdef CONFIG_IMXRT_FLEXPWM1
+
+static struct imxrt_flexpwm_module_s g_pwm1_modules[] =
+{
+  /* FlexPWM1 has 4 submodules with 2 outputs for each */
+
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD1
+  {
+    .module = 1,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD1_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD1_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD1_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD2
+  {
+    .module = 2,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD2_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD2_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD2_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD3
+  {
+    .module = 3,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD3_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD3_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD3_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD4
+  {
+    .module = 4,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD4_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM1_MOD4_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM1_MOD4_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+};
+
+static struct imxrt_flexpwm_s g_pwm1 =
+{
+  .ops = &g_pwmops,
+  .modules = g_pwm1_modules,
+  .modules_num = 4,
+  .frequency = 0,
+  .base = IMXRT_FLEXPWM1_BASE,
+};
+#endif /* CONFIG_IMXRT_FLEXPWM1 */
+
+#ifdef CONFIG_IMXRT_FLEXPWM2
+
+static struct imxrt_flexpwm_module_s g_pwm2_modules[] =
+{
+  /* FlexPWM2 has 4 submodules with 2 outputs for each */
+
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD1
+  {
+    .module = 1,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD1_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD1_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD1_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD2
+  {
+    .module = 2,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD2_A,
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD2_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD2_B
+    }
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD3
+  {
+    .module = 3,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD3_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD3_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD3_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD4
+  {
+    .module = 4,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD4_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM2_MOD4_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM2_MOD4_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  }
+#endif
+};
+
+static struct imxrt_flexpwm_s g_pwm2 =
+{
+  .ops = &g_pwmops,
+  .modules = g_pwm2_modules,
+  .modules_num = 4,
+  .frequency = 0,
+  .base = IMXRT_FLEXPWM2_BASE,
+};
+#endif /* CONFIG_IMXRT_FLEXPWM2 */
+
+#ifdef CONFIG_IMXRT_FLEXPWM3
+
+static struct imxrt_flexpwm_module_s g_pwm3_modules[] =
+{
+  /* FlexPWM3 has 4 submodules with 2 outputs for each */
+
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD1
+  {
+    .module = 1,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD1_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD1_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD1_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD2
+  {
+    .module = 2,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD2_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD2_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD2_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD3
+  {
+    .module = 3,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD3_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD3_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD3_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD4
+  {
+    .module = 4,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD4_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM3_MOD4_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM3_MOD4_B
+    },
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+};
+
+static struct imxrt_flexpwm_s g_pwm3 =
+{
+  .ops = &g_pwmops,
+  .modules = g_pwm3_modules,
+  .modules_num = 4,
+  .frequency = 0,
+  .base = IMXRT_FLEXPWM3_BASE,
+};
+#endif /* CONFIG_IMXRT_FLEXPWM3 */
+
+#ifdef CONFIG_IMXRT_FLEXPWM4
+
+static struct imxrt_flexpwm_module_s g_pwm4_modules[] =
+{
+  /* FlexPWM4 has 4 submodules with 2 outputs for each */
+
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD1
+  {
+    .module = 1,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD1_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD1_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD1_B
+    }
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD2
+  {
+    .module = 2,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD2_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD2_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD2_B
+    }
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD3
+  {
+    .module = 3,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD3_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD3_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD3_B
+    }
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD4
+  {
+    .module = 4,
+    .used = true,
+    .out_a =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD4_A
+    },
+#ifdef CONFIG_IMXRT_FLEXPWM4_MOD3_COMP
+    .out_b =
+    {
+      .used = true,
+      .pin = GPIO_FLEXPWM4_MOD4_B
+    }
+    .complementary = true
+#else
+    .complementary = false
+#endif
+  },
+#endif
+};
+
+static struct imxrt_flexpwm_s g_pwm4 =
+{
+  .ops = &g_pwmops,
+  .modules = g_pwm4_modules,
+  .modules_num = 4,
+  .frequency = 0,
+  .base = IMXRT_FLEXPWM4_BASE,
+};
+#endif /* CONFIG_IMXRT_FLEXPWM4 */
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: pwm_change_freq
+ *
+ * Description:
+ *   Set timer frequency and change registers value to respect that
+ *   frequency.
+ *
+ * Input Parameters:
+ *   dev  - A reference to the lower half PWM driver state structure
+ *   info - A reference to the characteristics of the pulsed output
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_change_freq(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info, uint8_t channel)
+{
+  FAR struct imxrt_flexpwm_s *priv = (FAR struct imxrt_flexpwm_s *)dev;
+#ifdef CONFIG_PWM_MULTICHAN
+  uint8_t shift = info->channels[channel].channel - 1;
+#else
+  uint8_t shift = priv->modules[0].module - 1;
+#endif
+  uint16_t regval;
+  uint16_t olddiv = getreg16(priv->base + IMXRT_FLEXPWM_SM0VAL1_OFFSET
+                                        + MODULE_OFFSET * shift);
+  uint16_t newdiv = (uint32_t)((float)CLK_FREQ / info->frequency + 0.5f);
+  uint16_t prescale = 0;
+
+  while (newdiv > PWM_RES && prescale < 7)
+    {
+      newdiv = newdiv >> 1;
+      prescale = prescale + 1;
+    }
+
+  if (newdiv > PWM_RES)
+    {
+      newdiv = PWM_RES;
+    }
+  else if (newdiv < 2)
+    {
+      newdiv = 2;
+    }
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+  regval |= MCTRL_CLDOK(1 << shift);
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
+  regval = SMCTRL_FULL | SMCTRL_PRSC(prescale);
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_SM0CTRL_OFFSET
+                              + MODULE_OFFSET * shift);
+
+  putreg16(newdiv - 1, priv->base + IMXRT_FLEXPWM_SM0VAL1_OFFSET
+                                  + MODULE_OFFSET * shift);
+
+  /* Update VAL0, VAL3 and VAL5 registers */
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_SM0VAL0_OFFSET
+                               + MODULE_OFFSET * shift);
+  regval = regval * newdiv / olddiv;
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_SM0VAL0_OFFSET
+                              + MODULE_OFFSET * shift);
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_SM0VAL3_OFFSET
+                               + MODULE_OFFSET * shift);
+  regval = regval * newdiv / olddiv;
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_SM0VAL3_OFFSET
+                              + MODULE_OFFSET * shift);
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_SM0VAL5_OFFSET
+                               + MODULE_OFFSET * shift);
+  regval = regval * newdiv / olddiv;
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_SM0VAL5_OFFSET
+                              + MODULE_OFFSET * shift);
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+  regval |= MCTRL_LDOK(1 << shift);
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_set_output
+ *
+ * Description:
+ *   Set duty cycle and enable PWM output.
+ *
+ * Input Parameters:
+ *   dev     - A reference to the lower half PWM driver state structure
+ *   channel - Channel to by updated
+ *   duty    - New duty
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_set_output(FAR struct pwm_lowerhalf_s *dev, uint8_t channel,
+                           ub16_t duty)
+{
+  FAR struct imxrt_flexpwm_s *priv = (FAR struct imxrt_flexpwm_s *)dev;
+  uint16_t period;
+  uint16_t width;
+  uint16_t regval;
+  double duty_pct;
+  uint8_t shift = channel - 1;  /* Shift submodle offset addresses */
+
+  /* Get the period value */
+
+  period = getreg16(priv->base + IMXRT_FLEXPWM_SM0VAL1_OFFSET
+                               + MODULE_OFFSET * shift);
+
+  /* Compute PWM width (count value to set PWM low) */
+
+  duty_pct = (duty / 65536.0) * 100;
+  width = (uint16_t)(((uint16_t)duty_pct * period) / 100);
+
+  /* Clear corresponding MCTRL[LDOK] bit  */
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+  regval |= MCTRL_CLDOK(1 << shift);
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
+  /* Write width to value register 3 and enable output A */
+
+  putreg16(width, priv->base + IMXRT_FLEXPWM_SM0VAL3_OFFSET
+                             + MODULE_OFFSET * shift);
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+  regval |= OUTEN_PWMA_EN(1 << shift);
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+
+  /* Enable output B if complementary option is turn on */
+
+  if (priv->modules[shift].complementary)
+    {
+      regval = getreg16(priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+      regval |= OUTEN_PWMB_EN(1 << shift);
+      putreg16(regval, priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+    }
+
+  regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+  regval |= MCTRL_LDOK(1 << shift);
+  putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: 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.
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_setup(FAR struct pwm_lowerhalf_s *dev)
+{
+  FAR struct imxrt_flexpwm_s *priv = (FAR struct imxrt_flexpwm_s *)dev;
+  uint32_t pin = 0;
+  uint16_t regval;
+
+  putreg16(FCTRL0_FLVL(15), priv->base + IMXRT_FLEXPWM_FCTRL0_OFFSET);
+  putreg16(0x000f, priv->base + IMXRT_FLEXPWM_FSTS0_OFFSET);
+  putreg16(0, priv->base + IMXRT_FLEXPWM_FFILT0_OFFSET);
+
+  for (int i = 0; i < priv->modules_num; i++)
+    {
+      /* Configure the module only if is set to be used */
+
+      if (priv->modules[i].used != 1)
+        {
+          continue;
+        }
+
+      if (priv->modules[i].out_a.used)
+        {
+          pin = priv->modules[i].out_a.pin;
+          if (pin != 0)
+            {
+              imxrt_config_gpio(pin);
+            }
+        }
+
+      /* Configure PIN_B if complementary option is turn on */
+
+      if (priv->modules[i].complementary)
+        {
+          if (priv->modules[i].out_b.used)
+            {
+              pin = priv->modules[i].out_b.pin;
+              if (pin != 0)
+                {
+                  imxrt_config_gpio(pin);
+                }
+            }
+        }
+
+      regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+      regval |= MCTRL_CLDOK(1 << i);
+      putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
+      /* Set control registers 1 and 2 */
+
+      if (!priv->modules[i].complementary)
+        {
+          /* Enable independent PWM_A and PWM_B output */
+
+          regval = SMCTRL2_INDEP;
+          putreg16(regval, priv->base + IMXRT_FLEXPWM_SM0CTRL2_OFFSET
+                                    + MODULE_OFFSET * i);
+        }
+
+      regval = SMCTRL_FULL;     /* Enable full read cycle reload */
+      putreg16(regval, priv->base + IMXRT_FLEXPWM_SM0CTRL_OFFSET
+                                  + MODULE_OFFSET * i);
+
+      /* Set output control register */
+
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0OCTRL_OFFSET
+                             + MODULE_OFFSET * i);
+
+      /* Set deadtime count register 0 */
+
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0DTCNT0_OFFSET
+                             + MODULE_OFFSET * i);
+
+      /* Set initial count register */
+
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0INIT_OFFSET
+                             + MODULE_OFFSET * i);
+
+      /* Set value registers */
+
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL0_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0x82b8, priv->base + IMXRT_FLEXPWM_SM0VAL1_OFFSET
+                                  + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL2_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL3_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL4_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL5_OFFSET
+                             + MODULE_OFFSET * i);
+
+      regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+      regval |= MCTRL_LDOK(1 << i);
+      putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
+      regval = getreg16(priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+      regval |= MCTRL_RUN(1 << i);
+      putreg16(regval, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: 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
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_shutdown(FAR struct pwm_lowerhalf_s *dev)
+{
+  FAR struct imxrt_flexpwm_s *priv = (FAR struct imxrt_flexpwm_s *)dev;
+
+  for (int i = 0; i < priv->modules_num; i++)
+    {
+      /* Skip modules that are not used */
+
+      if (priv->modules[i].used != 1)
+        {
+          continue;
+        }
+
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0CTRL_OFFSET
+                                  + MODULE_OFFSET * i);
+
+      /* Reset fractional value registers */
+
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL0_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL1_OFFSET
+                                  + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL2_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL3_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL4_OFFSET
+                             + MODULE_OFFSET * i);
+      putreg16(0, priv->base + IMXRT_FLEXPWM_SM0VAL5_OFFSET
+                             + MODULE_OFFSET * i);
+    }
+
+  /* Stop run */
+
+  putreg16(0, priv->base + IMXRT_FLEXPWM_MCTRL_OFFSET);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_start
+ *
+ * Description:
+ *   (Re-)initialize the timer resources and start the pulsed output
+ *
+ * Input Parameters:
+ *   dev  - A reference to the lower half PWM driver state structure
+ *   info - A reference to the characteristics of the pulsed output
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
+                     FAR const struct pwm_info_s *info)
+{
+  FAR struct imxrt_flexpwm_s *priv = (FAR struct imxrt_flexpwm_s *)dev;
+  int ret = OK;
+
+  /* Change frequency only if it is needed */
+
+  if (info->frequency != priv->frequency)
+    {
+      for (int i = 0; i < PWM_NCHANNELS; i++)
+        {
+          /* Configure the module freq only if is set to be used */
+
+          ret = pwm_change_freq(dev, info, i);
+        }
+
+      /* Save current frequency */
+
+      if (ret == OK)
+        {
+          priv->frequency = info->frequency;
+        }
+    }
+
+#ifdef CONFIG_PWM_MULTICHAN
+  for (int i = 0; ret == OK && i < PWM_NCHANNELS; i++)
+    {
+      /* Enable PWM output for each channel */
+
+      ret = pwm_set_output(dev, info->channels[i].channel,
+                                info->channels[i].duty);
+    }
+#else
+  /* Enable PWM output just for first channel */
+
+  ret = pwm_set_output(dev, priv->modules[0].module, info->duty);
+#endif /* CONFIG_PWM_MULTICHAN */
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: pwm_stop
+ *
+ * Description:
+ *   Stop the pulsed output and reset the timer resources
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ * Assumptions:
+ *   This function is called to stop the pulsed output at anytime.  This
+ *   method is also called from the timer interrupt handler when a repetition
+ *   count expires... automatically stopping the timer.
+ *
+ ****************************************************************************/
+
+static int pwm_stop(FAR struct pwm_lowerhalf_s *dev)
+{
+  FAR struct imxrt_flexpwm_s *priv = (FAR struct imxrt_flexpwm_s *)dev;
+  uint8_t shift;
+  uint16_t regval;
+
+#ifdef CONFIG_PWM_MULTICHAN
+  for (int i = 0; i < priv->modules_num; i++)
+    {
+      /* Skip settings if channel is not configured */
+
+      if (!priv->modules[i].used)
+        {
+          continue;
+        }
+
+      shift = priv->modules[i].module - 1;
+
+      regval = OUTEN_PWMA_EN(0 << shift);
+      putreg16(regval, priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+
+      regval = OUTEN_PWMB_EN(0 << shift);
+      putreg16(regval, priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+    }
+#else
+    shift = priv->modules[0].module - 1;
+
+    regval = OUTEN_PWMA_EN(0 << shift);
+    putreg16(regval, priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+
+    regval = OUTEN_PWMB_EN(0 << shift);
+    putreg16(regval, priv->base + IMXRT_FLEXPWM_OUTEN_OFFSET);
+
+#endif /* CONFIG_PWM_MULTICHAN */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_ioctl
+ *
+ * Description:
+ *   Lower-half logic may support platform-specific ioctl commands
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *   cmd - The ioctl command
+ *   arg - The argument accompanying the ioctl command
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd,
+                     unsigned long arg)
+{
+  return -ENOTTY;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: imxrt_pwminitialize
+ *
+ * Description:
+ *   Initialize the PWM channel for use with the upper level PWM driver.
+ *
+ * Input Parameters:
+ *   channel - a number identifying the PWM channel.
+ *
+ * Returned Value:
+ *   A pointer to the lower half PWM driver is returned on success,
+ *   NULL on failure.
+ *
+ ****************************************************************************/
+
+FAR struct pwm_lowerhalf_s *imxrt_pwminitialize(int pwm)
+{
+  FAR struct imxrt_flexpwm_s *priv;
+
+  pwminfo("Initializing pwm %d\n", pwm);
+
+  switch (pwm)
+  {
+#ifdef CONFIG_IMXRT_FLEXPWM1
+    case 1:
+      imxrt_clockall_pwm1();
+      priv = &g_pwm1;
+      break;
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM2
+    case 2:
+      imxrt_clockall_pwm2();
+      priv = &g_pwm2;
+      break;
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM3
+    case 3:
+      imxrt_clockall_pwm3();
+      priv = &g_pwm3;
+      break;
+#endif
+#ifdef CONFIG_IMXRT_FLEXPWM4
+    case 4:
+      imxrt_clockall_pwm4();
+      priv = &g_pwm4;
+      break;
+#endif
+    default:
+      pwmerr("ERROR: PWM number invalid or not configured %d\n", pwm);
+      return NULL;
+  }
+
+  return (FAR struct pwm_lowerhalf_s *)priv;
+}
+#endif /* CONFIG_IMXRT_FLEXPWM */
diff --git a/arch/arm/src/imxrt/imxrt_flexpwm.h 
b/arch/arm/src/imxrt/imxrt_flexpwm.h
new file mode 100644
index 0000000..591fd8b
--- /dev/null
+++ b/arch/arm/src/imxrt/imxrt_flexpwm.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+ * arch/arm/src/imxrt/imxrt_flexpwm.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_IMXRT_IMXRT_FLEXPWM_H
+#define __ARCH_ARM_SRC_IMXRT_IMXRT_FLEXPWM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/timers/pwm.h>
+
+#include "hardware/imxrt_flexpwm.h"
+
+#ifdef CONFIG_IMXRT_FLEXPWM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Function: imxrt_pwminitialize
+ *
+ * Description:
+ *   Initialize the PWM module for use with the upper level PWM driver.
+ *
+ * Input Parameters:
+ *   pwm - a number identifying the PWM driver.
+ *
+ * Returned Value:
+ *   A pointer to the lower half PWM driver is returned on success,
+ *   NULL on failure.
+ *
+ ****************************************************************************/
+
+FAR struct pwm_lowerhalf_s *imxrt_pwminitialize(int pwm);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_IMXRT_FLEXPWM */
+#endif /* __ARCH_ARM_SRC_IMXRT_IMXRT_FLEXPWM_H */

Reply via email to