This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new baf52268cc arch/xmc4: Added pwm driver
baf52268cc is described below
commit baf52268cc05c3e7362a3c64a7a764cefd0c1547
Author: adriendesp <[email protected]>
AuthorDate: Thu Jul 11 12:03:25 2024 +0200
arch/xmc4: Added pwm driver
---
arch/arm/src/xmc4/CMakeLists.txt | 4 +
arch/arm/src/xmc4/Kconfig | 185 ++++-
arch/arm/src/xmc4/Make.defs | 4 +
arch/arm/src/xmc4/hardware/xmc4_ccu4.h | 10 +-
arch/arm/src/xmc4/xmc4_clockconfig.h | 11 +
arch/arm/src/xmc4/xmc4_clockutils.c | 17 +
arch/arm/src/xmc4/xmc4_pwm.c | 1365 ++++++++++++++++++++++++++++++++
arch/arm/src/xmc4/xmc4_pwm.h | 9 +-
8 files changed, 1578 insertions(+), 27 deletions(-)
diff --git a/arch/arm/src/xmc4/CMakeLists.txt b/arch/arm/src/xmc4/CMakeLists.txt
index 2903dbd6ee..d46b1a2dbf 100644
--- a/arch/arm/src/xmc4/CMakeLists.txt
+++ b/arch/arm/src/xmc4/CMakeLists.txt
@@ -51,4 +51,8 @@ if(CONFIG_XMC4_USCI_SPI)
list(APPEND SRCS xmc4_spi.c)
endif()
+if(CONFIG_XMC4_PWM)
+ list(APPEND SRCS xmc4_pwm.c)
+endif()
+
target_sources(arch PRIVATE ${SRCS})
diff --git a/arch/arm/src/xmc4/Kconfig b/arch/arm/src/xmc4/Kconfig
index 77437055d9..c6e5ec4cbd 100644
--- a/arch/arm/src/xmc4/Kconfig
+++ b/arch/arm/src/xmc4/Kconfig
@@ -194,6 +194,12 @@ config XMC4_ECAT_P1
default n
depends on XMC4_ECAT
+config XMC4_PWM
+ bool "Enable Capture Compare Units 4 (CCU4x) for PWM"
+ default n
+ ---help---
+ Support CCU4x
+
endmenu
menu "XMC4xxx USIC Configuration"
@@ -255,7 +261,7 @@ config XMC4_USIC0_CHAN0_TX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
config XMC4_USIC0_CHAN0_RX_BUFFER_SIZE
@@ -264,7 +270,7 @@ config XMC4_USIC0_CHAN0_RX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
endmenu # USIC0 Channel 0 Configuration
@@ -318,7 +324,7 @@ config XMC4_USIC0_CHAN1_ISI2S
---help---
Configure USIC0 Channel 1 for I2S audio
-endchoice # USIC0 Channel 1 Protocol
+endchoice # USIC0 Channel 1 Protocol
config XMC4_USIC0_CHAN1_TX_BUFFER_SIZE
int "Tx Fifo Buffer Size"
@@ -326,7 +332,7 @@ config XMC4_USIC0_CHAN1_TX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
config XMC4_USIC0_CHAN1_RX_BUFFER_SIZE
@@ -335,7 +341,7 @@ config XMC4_USIC0_CHAN1_RX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
endmenu # USIC0 Channel 1 Configuration
@@ -388,7 +394,7 @@ config XMC4_USIC1_CHAN0_ISI2S
---help---
Configure USIC1 Channel 0 for I2S audio
-endchoice # USIC1 Channel 0 Protocol
+endchoice # USIC1 Channel 0 Protocol
config XMC4_USIC1_CHAN0_TX_BUFFER_SIZE
int "Tx Fifo Buffer Size"
@@ -396,7 +402,7 @@ config XMC4_USIC1_CHAN0_TX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
config XMC4_USIC1_CHAN0_RX_BUFFER_SIZE
@@ -405,10 +411,10 @@ config XMC4_USIC1_CHAN0_RX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
-endmenu # USIC1 Channel 0 Configuration
+endmenu # USIC1 Channel 0 Configuration
menu "USIC1 Channel 1 Configuration"
depends on XMC4_USIC
@@ -463,19 +469,19 @@ endchoice # USIC1 Channel 1 Protocol
config XMC4_USIC1_CHAN1_TX_BUFFER_SIZE
int "Tx Fifo Buffer Size"
depends on XMC4_USIC1_CHAN1_ISUART
- default 16
+ default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
config XMC4_USIC1_CHAN1_RX_BUFFER_SIZE
int "Rx Fifo Buffer Size"
depends on XMC4_USIC1_CHAN1_ISUART
- default 16
+ default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
endmenu # USIC1 Channel 1 Configuration
@@ -533,19 +539,19 @@ endchoice # USIC2 Channel 0 Protocol
config XMC4_USIC2_CHAN0_TX_BUFFER_SIZE
int "Tx Fifo Buffer Size"
depends on XMC4_USIC2_CHAN0_ISUART
- default 16
+ default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
config XMC4_USIC2_CHAN0_RX_BUFFER_SIZE
int "Rx Fifo Buffer Size"
depends on XMC4_USIC2_CHAN0_ISUART
- default 16
+ default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
endmenu # USIC2 Channel 0 Configuration
@@ -605,7 +611,7 @@ config XMC4_USIC2_CHAN1_TX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
config XMC4_USIC2_CHAN1_RX_BUFFER_SIZE
@@ -614,9 +620,150 @@ config XMC4_USIC2_CHAN1_RX_BUFFER_SIZE
default 16
---help---
Should be a power of 2 between 2 and 64
- The sum of Rx and Tx buffers sizes of both
+ The sum of Rx and Tx buffers sizes of both
channels should be inferior to 64
endmenu # USIC2 Channel 1 Configuration
endmenu # XMC4xxx USIC Configuration
+
+menu "XMC4xxx PWM Configuration"
+depends on XMC4_PWM
+
+ config XMC4_CCU40
+ bool "Enable CCU40"
+ default n
+ ---help---
+ Support CCU40
+
+ config XMC4_CCU40_CC40
+ bool "Enable CCU40 Slice 0 (not compatible with
tickless)"
+ default n
+ depends on XMC4_CCU40 && !CONFIG_SCHED_TICKLESS
+ ---help---
+ Support CCU40 CC40, cannot be activated when
tickless OS is enabled
+
+ config XMC4_CCU40_CC41
+ bool "Enable CCU40 Slice 1"
+ default n
+ depends on XMC4_CCU40
+ ---help---
+ Support CCU40 CC41
+
+ config XMC4_CCU40_CC42
+ bool "Enable CCU40 Slice 2"
+ default n
+ depends on XMC4_CCU40
+ ---help---
+ Support CCU40 CC42
+
+ config XMC4_CCU40_CC43
+ bool "Enable CCU40 Slice 3"
+ default n
+ depends on XMC4_CCU40
+ ---help---
+ Support CCU40 CC43
+
+ config XMC4_CCU41
+ bool "Enable CCU41"
+ default n
+ ---help---
+ Support CCU41
+
+ config XMC4_CCU41_CC40
+ bool "Enable CCU41 Slice 0 (not compatible with
tickless)"
+ default n
+ depends on XMC4_CCU41 && !CONFIG_SCHED_TICKLESS
+ ---help---
+ Support CCU41 CC40, cannot be activated when
tickless OS is enabled
+
+ config XMC4_CCU41_CC41
+ bool "Enable CCU41 Slice 1"
+ default n
+ depends on XMC4_CCU41
+ ---help---
+ Support CCU41 CC41
+
+ config XMC4_CCU41_CC42
+ bool "Enable CCU41 Slice 2"
+ default n
+ depends on XMC4_CCU41
+ ---help---
+ Support CCU41 CC42
+
+ config XMC4_CCU41_CC43
+ bool "Enable CCU41 Slice 3"
+ default n
+ depends on XMC4_CCU41
+ ---help---
+ Support CCU41 CC43
+
+ config XMC4_CCU42
+ bool "Enable CCU42"
+ default n
+ ---help---
+ Support CCU42
+
+ config XMC4_CCU42_CC40
+ bool "Enable CCU42 Slice 0"
+ default n
+ depends on XMC4_CCU42
+ ---help---
+ Support CCU42 CC40
+
+ config XMC4_CCU42_CC41
+ bool "Enable CCU42 Slice 1"
+ default n
+ depends on XMC4_CCU42
+ ---help---
+ Support CCU42 CC41
+
+ config XMC4_CCU42_CC42
+ bool "Enable CCU42 Slice 2"
+ default n
+ depends on XMC4_CCU42
+ ---help---
+ Support CCU42 CC42
+
+ config XMC4_CCU42_CC43
+ bool "Enable CCU42 Slice 3"
+ default n
+ depends on XMC4_CCU42
+ ---help---
+ Support CCU42 CC43
+
+ config XMC4_CCU43
+ bool "Enable CCU43"
+ default n
+ ---help---
+ Support CCU43
+
+ config XMC4_CCU43_CC40
+ bool "Enable CCU43 Slice 0"
+ default n
+ depends on XMC4_CCU43
+ ---help---
+ Support CCU43 CC40
+
+ config XMC4_CCU43_CC41
+ bool "Enable CCU43 Slice 1"
+ default n
+ depends on XMC4_CCU43
+ ---help---
+ Support CCU43 CC41
+
+ config XMC4_CCU43_CC42
+ bool "Enable CCU43 Slice 2"
+ default n
+ depends on XMC4_CCU43
+ ---help---
+ Support CCU43 CC42
+
+ config XMC4_CCU43_CC43
+ bool "Enable CCU43 Slice 3"
+ default n
+ depends on XMC4_CCU43
+ ---help---
+ Support CCU43 CC43
+
+endmenu # XMC4xxx PWM Configuration
diff --git a/arch/arm/src/xmc4/Make.defs b/arch/arm/src/xmc4/Make.defs
index f83a771f7c..e7cb6d3b22 100644
--- a/arch/arm/src/xmc4/Make.defs
+++ b/arch/arm/src/xmc4/Make.defs
@@ -55,3 +55,7 @@ endif
ifeq ($(CONFIG_XMC4_ECAT),y)
CHIP_CSRCS += xmc4_ecat.c
endif
+
+ifeq ($(CONFIG_XMC4_PWM),y)
+CHIP_CSRCS += xmc4_pwm.c
+endif
diff --git a/arch/arm/src/xmc4/hardware/xmc4_ccu4.h
b/arch/arm/src/xmc4/hardware/xmc4_ccu4.h
index 57ae6f0a1e..45bdde2e24 100644
--- a/arch/arm/src/xmc4/hardware/xmc4_ccu4.h
+++ b/arch/arm/src/xmc4/hardware/xmc4_ccu4.h
@@ -783,9 +783,9 @@
#define CCU4_GSTAT_S2I_SHIFT (2) /* Bits
2: CC42 IDLE status */
#define CCU4_GSTAT_S2I_MASK (1 << CCU4_GSTAT_S2I_SHIFT)
#define CCU4_GSTAT_S3I_SHIFT (3) /* Bits
3: CC43 IDLE status */
-#define CCU4_GSTAT_S3I_MASK (1 << CCU4_GSTAT_SI_SHIFT)
+#define CCU4_GSTAT_S3I_MASK (1 << CCU4_GSTAT_S3I_SHIFT)
#define CCU4_GSTAT_PRB_SHIFT (8) /* Bits
8: Prescaler Run Bit */
-#define CCU4_GSTAT_PRB_MASK (1 << CCU4_GSTAT_SI_SHIFT)
+#define CCU4_GSTAT_PRB_MASK (1 << CCU4_GSTAT_PRB_SHIFT)
/* Global Idle Set (GIDLS) */
@@ -934,7 +934,7 @@
/* Input Selector Configuration (CC4yINS) */
#define CCU4_CC4_INS_EV0IS_SHIFT (0)
/* Bits 0-3: Event 0 signal selection */
-#define CCU4_CC4_INS_EV0IS_MASK (15 <<
CCU4_CC4_INS_EV0IS_SHIFT)
+#define CCU4_CC4_INS_EV0IS_MASK (15 <<
CCU4_CC4_INS_EV0IS_SHIFT)
# define CCU4_CC4_INS_EV0IS_INA (0 <<
CCU4_CC4_INS_EV0IS_SHIFT) /* CCU4x.INyA */
# define CCU4_CC4_INS_EV0IS_INB (1 <<
CCU4_CC4_INS_EV0IS_SHIFT) /* CCU4x.INyB */
# define CCU4_CC4_INS_EV0IS_INC (2 <<
CCU4_CC4_INS_EV0IS_SHIFT) /* CCU4x.INyC */
@@ -952,7 +952,7 @@
# define CCU4_CC4_INS_EV0IS_INO (14 <<
CCU4_CC4_INS_EV0IS_SHIFT) /* CCU4x.INyO */
# define CCU4_CC4_INS_EV0IS_INP (15 <<
CCU4_CC4_INS_EV0IS_SHIFT) /* CCU4x.INyP */
#define CCU4_CC4_INS_EV1IS_SHIFT (4)
/* Bits 4-7: Event 1 signal selection */
-#define CCU4_CC4_INS_EV1IS_MASK (15 <<
CCU4_CC4_INS_EV1IS_SHIFT)
+#define CCU4_CC4_INS_EV1IS_MASK (15 <<
CCU4_CC4_INS_EV1IS_SHIFT)
# define CCU4_CC4_INS_EV1IS_INA (0 <<
CCU4_CC4_INS_EV1IS_SHIFT) /* CCU4x.INyA */
# define CCU4_CC4_INS_EV1IS_INB (1 <<
CCU4_CC4_INS_EV1IS_SHIFT) /* CCU4x.INyB */
# define CCU4_CC4_INS_EV1IS_INC (2 <<
CCU4_CC4_INS_EV1IS_SHIFT) /* CCU4x.INyC */
@@ -970,7 +970,7 @@
# define CCU4_CC4_INS_EV1IS_INO (14 <<
CCU4_CC4_INS_EV1IS_SHIFT) /* CCU4x.INyO */
# define CCU4_CC4_INS_EV1IS_INP (15 <<
CCU4_CC4_INS_EV1IS_SHIFT) /* CCU4x.INyP */
#define CCU4_CC4_INS_EV2IS_SHIFT (8)
/* Bits 8-11: Event 2 signal selection */
-#define CCU4_CC4_INS_EV2IS_MASK (15 <<
CCU4_CC4_INS_EV2IS_SHIFT)
+#define CCU4_CC4_INS_EV2IS_MASK (15 <<
CCU4_CC4_INS_EV2IS_SHIFT)
# define CCU4_CC4_INS_EV2IS_INA (0 <<
CCU4_CC4_INS_EV2IS_SHIFT) /* CCU4x.INyA */
# define CCU4_CC4_INS_EV2IS_INB (1 <<
CCU4_CC4_INS_EV2IS_SHIFT) /* CCU4x.INyB */
# define CCU4_CC4_INS_EV2IS_INC (2 <<
CCU4_CC4_INS_EV2IS_SHIFT) /* CCU4x.INyC */
diff --git a/arch/arm/src/xmc4/xmc4_clockconfig.h
b/arch/arm/src/xmc4/xmc4_clockconfig.h
index 16e8ec7d47..77ccfda046 100644
--- a/arch/arm/src/xmc4/xmc4_clockconfig.h
+++ b/arch/arm/src/xmc4/xmc4_clockconfig.h
@@ -72,4 +72,15 @@ uint32_t xmc4_get_coreclock(void);
uint32_t xmc4_get_periphclock(void);
+/****************************************************************************
+ * Name: xmc4_get_ccuclock
+ *
+ * Description:
+ * The ccu clock is either fCPU or fCPU/2, depending on the state
+ * of the peripheral divider.
+ *
+ ****************************************************************************/
+
+uint32_t xmc4_get_ccuclock(void);
+
#endif /* __ARCH_ARM_SRC_XMC4_XMC4_CLOCKCONFIG_H */
diff --git a/arch/arm/src/xmc4/xmc4_clockutils.c
b/arch/arm/src/xmc4/xmc4_clockutils.c
index 37bd65b99d..3fba1cb3af 100644
--- a/arch/arm/src/xmc4/xmc4_clockutils.c
+++ b/arch/arm/src/xmc4/xmc4_clockutils.c
@@ -186,3 +186,20 @@ uint32_t xmc4_get_periphclock(void)
return periphclock;
}
+
+/****************************************************************************
+ * Name: xmc4_get_ccuclock
+ *
+ * Description:
+ * The ccu clock is either fCPU or fCPU/2, depending on the state
+ * of the peripheral divider.
+ *
+ ****************************************************************************/
+
+uint32_t xmc4_get_ccuclock(void)
+{
+ uint32_t f_cpu = xmc4_get_coreclock();
+ uint32_t f_ccu =
+ f_cpu >> ((uint32_t)(getreg32(XMC4_SCU_CCUCLKCR) & SCU_CCUCLKCR_CCUDIV));
+ return f_ccu;
+}
diff --git a/arch/arm/src/xmc4/xmc4_pwm.c b/arch/arm/src/xmc4/xmc4_pwm.c
new file mode 100644
index 0000000000..261d7ab047
--- /dev/null
+++ b/arch/arm/src/xmc4/xmc4_pwm.c
@@ -0,0 +1,1365 @@
+/*****************************************************************************
+ * arch/arm/src/xmc4/xmc4_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 <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/board/board.h>
+
+#include "arm_internal.h"
+#include "chip.h"
+#include "xmc4_pwm.h"
+#include "xmc4_gpio.h"
+#include "xmc4_clockconfig.h"
+#include "hardware/xmc4_ccu4.h"
+#include "hardware/xmc4_scu.h"
+#include "hardware/xmc4_pinmux.h"
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Types
+ *****************************************************************************/
+
+/* This structure represents the state of one PWM timer */
+
+struct xmc4_pwm_s
+{
+ const struct pwm_ops_s *ops; /* PWM operations */
+ uint8_t module; /* CCU4x Module number {0,...,4} */
+ uint8_t slice; /* CC4y Slice number {0,...,4} */
+ uint8_t prescaler; /* Clock division for f_tclk */
+ uint32_t frequency; /* Current frequency setting */
+ ub16_t duty; /* Current duty setting */
+ uint32_t base; /* The base address of the CCU4x module */
+ uint32_t f_tclk; /* The frequency of the module clock */
+ uint32_t outgpio; /* The output pin config (set in board.h) */
+};
+
+/*****************************************************************************
+ * Private Function Prototypes
+ *****************************************************************************/
+
+/* PWM Register access */
+
+static inline void xmc4_pwm_putreg32(struct xmc4_pwm_s *priv,
+ uint32_t offset,
+ uint32_t value);
+static inline uint32_t xmc4_pwm_getreg32(struct xmc4_pwm_s *priv,
+ uint32_t offset);
+static void xmc4_pwm_modifyreg32(struct xmc4_pwm_s *priv,
+ uint32_t offset,
+ uint32_t clearbits,
+ uint32_t setbits);
+
+/* PWM driver methods */
+
+static int pwm_setup(struct pwm_lowerhalf_s *dev);
+static int pwm_shutdown(struct pwm_lowerhalf_s *dev);
+static int pwm_start(struct pwm_lowerhalf_s *dev,
+ const struct pwm_info_s *info);
+static int pwm_stop(struct pwm_lowerhalf_s *dev);
+static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg);
+
+/* PWM helper method */
+
+static int pwm_set_period_match(struct xmc4_pwm_s *priv, uint16_t period_val);
+static int pwm_set_compare_match(struct xmc4_pwm_s *priv,
+ uint16_t compare_val);
+static int pwm_set_passive_level(struct xmc4_pwm_s *priv, uint8_t level);
+static int pwm_shadow_transfert(struct xmc4_pwm_s *priv);
+static int pwm_enable_slice_clock(struct xmc4_pwm_s *priv);
+static int pwm_disable_slice_clock(struct xmc4_pwm_s *priv);
+static int pwm_start_slice_timer(struct xmc4_pwm_s *priv);
+static int pwm_stop_slice_timer(struct xmc4_pwm_s *priv);
+static bool pwm_is_slice_timer_running(struct xmc4_pwm_s *priv);
+static int pwm_set_slice_prescaler(struct xmc4_pwm_s *priv,
+ uint8_t prescaler);
+static int pwm_start_module_prescaler(struct xmc4_pwm_s *priv);
+static int pwm_stop_module_prescaler(struct xmc4_pwm_s *priv);
+static int pwm_enable_module(struct xmc4_pwm_s *priv);
+static int pwm_disable_module(struct xmc4_pwm_s *priv);
+static bool pwm_is_module_used(struct xmc4_pwm_s *priv);
+static int pwm_compute_config(struct xmc4_pwm_s *priv,
+ const struct pwm_info_s *info,
+ uint8_t *prescaler,
+ uint16_t *period,
+ uint16_t *compare);
+static int pwm_timer(struct xmc4_pwm_s *priv, const struct pwm_info_s *info);
+
+/*****************************************************************************
+ * 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_XMC4_CCU40
+#ifdef CONFIG_XMC4_CCU40_CC40
+static struct xmc4_pwm_s g_pwm00 =
+ {
+ .ops = &g_pwmops,
+ .module = 0,
+ .slice = 0,
+ .base = XMC4_CCU40_BASE,
+ .outgpio = GPIO_CCU40_OUT0,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU40_CC41
+static struct xmc4_pwm_s g_pwm01 =
+ {
+ .ops = &g_pwmops,
+ .module = 0,
+ .slice = 1,
+ .base = XMC4_CCU40_BASE,
+ .outgpio = GPIO_CCU40_OUT1,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU40_CC42
+static struct xmc4_pwm_s g_pwm02 =
+ {
+ .ops = &g_pwmops,
+ .module = 0,
+ .slice = 2,
+ .base = XMC4_CCU40_BASE,
+ .outgpio = GPIO_CCU40_OUT2,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU40_CC43
+static struct xmc4_pwm_s g_pwm03 =
+ {
+ .ops = &g_pwmops,
+ .module = 0,
+ .slice = 3,
+ .base = XMC4_CCU40_BASE,
+ .outgpio = GPIO_CCU40_OUT3,
+};
+#endif
+#endif /* CONFIG_XMC4_CCU40 */
+
+#ifdef CONFIG_XMC4_CCU41
+#ifdef CONFIG_XMC4_CCU41_CC40
+static struct xmc4_pwm_s g_pwm10 =
+ {
+ .ops = &g_pwmops,
+ .module = 1,
+ .slice = 0,
+ .base = XMC4_CCU41_BASE,
+ .outgpio = GPIO_CCU41_OUT0,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU41_CC41
+static struct xmc4_pwm_s g_pwm11 =
+ {
+ .ops = &g_pwmops,
+ .module = 1,
+ .slice = 1,
+ .base = XMC4_CCU41_BASE,
+ .outgpio = GPIO_CCU41_OUT1,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU41_CC42
+static struct xmc4_pwm_s g_pwm12 =
+ {
+ .ops = &g_pwmops,
+ .module = 1,
+ .slice = 2,
+ .base = XMC4_CCU41_BASE,
+ .outgpio = GPIO_CCU41_OUT2,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU41_CC43
+static struct xmc4_pwm_s g_pwm13 =
+ {
+ .ops = &g_pwmops,
+ .module = 1,
+ .slice = 3,
+ .base = XMC4_CCU41_BASE,
+ .outgpio = GPIO_CCU41_OUT3,
+};
+#endif
+#endif /* CONFIG_XMC4_CCU41 */
+
+#ifdef CONFIG_XMC4_CCU42
+#ifdef CONFIG_XMC4_CCU42_CC40
+static struct xmc4_pwm_s g_pwm20 =
+ {
+ .ops = &g_pwmops,
+ .module = 2,
+ .slice = 0,
+ .base = XMC4_CCU42_BASE,
+ .outgpio = GPIO_CCU42_OUT0,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU42_CC41
+static struct xmc4_pwm_s g_pwm21 =
+ {
+ .ops = &g_pwmops,
+ .module = 2,
+ .slice = 1,
+ .base = XMC4_CCU42_BASE,
+ .outgpio = GPIO_CCU42_OUT1,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU42_CC42
+static struct xmc4_pwm_s g_pwm22 =
+ {
+ .ops = &g_pwmops,
+ .module = 2,
+ .slice = 2,
+ .base = XMC4_CCU42_BASE,
+ .outgpio = GPIO_CCU42_OUT2,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU42_CC43
+static struct xmc4_pwm_s g_pwm23 =
+ {
+ .ops = &g_pwmops,
+ .module = 2,
+ .slice = 3,
+ .base = XMC4_CCU42_BASE,
+ .outgpio = GPIO_CCU42_OUT3,
+};
+#endif
+#endif /* CONFIG_XMC4_CCU42 */
+
+#ifdef CONFIG_XMC4_CCU43
+#ifdef CONFIG_XMC4_CCU43_CC40
+static struct xmc4_pwm_s g_pwm30 =
+ {
+ .ops = &g_pwmops,
+ .module = 3,
+ .slice = 0,
+ .base = XMC4_CCU43_BASE,
+ .outgpio = GPIO_CCU43_OUT0,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU43_CC41
+static struct xmc4_pwm_s g_pwm31 =
+ {
+ .ops = &g_pwmops,
+ .module = 3,
+ .slice = 1,
+ .base = XMC4_CCU43_BASE,
+ .outgpio = GPIO_CCU43_OUT1,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU43_CC42
+static struct xmc4_pwm_s g_pwm32 =
+ {
+ .ops = &g_pwmops,
+ .module = 3,
+ .slice = 2,
+ .base = XMC4_CCU43_BASE,
+ .outgpio = GPIO_CCU43_OUT2,
+};
+#endif
+
+#ifdef CONFIG_XMC4_CCU43_CC43
+static struct xmc4_pwm_s g_pwm33 =
+ {
+ .ops = &g_pwmops,
+ .module = 3,
+ .slice = 3,
+ .base = XMC4_CCU43_BASE,
+ .outgpio = GPIO_CCU43_OUT3,
+};
+#endif
+#endif /* CONFIG_XMC4_CCU43 */
+
+/*****************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: xmc4_pwm_putreg32
+ *
+ * Description:
+ * Put a 32-bit register value by offset
+ *
+ *****************************************************************************/
+
+static inline void xmc4_pwm_putreg32(struct xmc4_pwm_s *priv,
+ uint32_t offset,
+ uint32_t value)
+{
+ putreg32(value, priv->base + offset);
+}
+
+/*****************************************************************************
+ * Name: xmc4_pwm_getreg32
+ *
+ * Description:
+ * Get a 32-bit register value by offset
+ *
+ *****************************************************************************/
+
+static inline uint32_t xmc4_pwm_getreg32(struct xmc4_pwm_s *priv,
+ uint32_t offset)
+{
+ return getreg32(priv->base + offset);
+}
+
+/*****************************************************************************
+ * Name: xmc4_pwm_modifyreg32
+ *
+ * Description:
+ * Modify a 32-bit register value by offset
+ *
+ *****************************************************************************/
+
+static void xmc4_pwm_modifyreg32(struct xmc4_pwm_s *priv,
+ uint32_t offset,
+ uint32_t clearbits,
+ uint32_t setbits)
+{
+ modifyreg32(priv->base + offset, clearbits, setbits);
+}
+
+/*****************************************************************************
+ * Name: pwm_set_period_match
+ *
+ * Description:
+ * Set the period match register (CC4yPRS.PRS).
+ * Must call pwm_shadow_transfert() after.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_set_period_match(struct xmc4_pwm_s *priv, uint16_t period_val)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t cc4yprs_offset =
+ (uint32_t)(XMC4_CCU4_CC40PRS_OFFSET + 0x0100 * priv->slice);
+
+ xmc4_pwm_putreg32(priv, cc4yprs_offset, period_val);
+
+ pwminfo("PWM CCU4%d,CC4%d period is : %d\n",
+ priv->module, priv->slice, period_val);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_set_compare_match
+ *
+ * Description:
+ * Set the comapre match register (CC4yCRS.CRS).
+ * Must call pwm_shadow_transfert() after.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_set_compare_match(struct xmc4_pwm_s *priv,
+ uint16_t compare_val)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t cc4ycrs_offset =
+ (uint32_t)(XMC4_CCU4_CC40CRS_OFFSET + 0x0100 * priv->slice);
+
+ xmc4_pwm_putreg32(priv, cc4ycrs_offset, compare_val);
+
+ pwminfo("PWM CCU4%d,CC4%d compare is : %d\n",
+ priv->module, priv->slice, compare_val);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_set_passive_level
+ *
+ * Description:
+ * Set the passive level of the PWM slice.
+ * Must call pwm_shadow_transfert() after.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_set_passive_level(struct xmc4_pwm_s *priv, uint8_t level)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t passive_level = (uint32_t)(level == 1);
+
+ uint32_t cc4ypsl_offset =
+ (uint32_t)(XMC4_CCU4_CC40PSL_OFFSET + 0x0100 * priv->slice);
+
+ xmc4_pwm_putreg32(priv, cc4ypsl_offset, passive_level);
+
+ pwminfo("PWM CCU4%d,CC4%d passive level is : %d\n",
+ priv->module, priv->slice, passive_level);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_shadow_transfert
+ *
+ * Description:
+ * Enable the transfert of the CRS, PRS and PSL registers for the next
+ * period. Must be called if one of these register is changed.
+ * Must call pwm_shadow_transfert() after.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_shadow_transfert(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t shadow_transfert_mask = 1 << (priv->slice * 4);
+
+ xmc4_pwm_modifyreg32(priv, XMC4_CCU4_GCSS_OFFSET, 0,
+ shadow_transfert_mask);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_enable_slice_clock
+ *
+ * Description:
+ * Enable the prescaller clock for the given slice.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_enable_slice_clock(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t mask = (1 << priv->slice);
+
+ xmc4_pwm_modifyreg32(priv, XMC4_CCU4_GIDLC_OFFSET, 0, mask);
+
+ pwminfo("PWM CCU4%d,CC4%d clock is enabled\n", priv->module, priv->slice);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_disable_slice_clock
+ *
+ * Description:
+ * Disable the prescaller clock for the given slice.
+ *
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_disable_slice_clock(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t mask = (1 << priv->slice);
+
+ xmc4_pwm_modifyreg32(priv, XMC4_CCU4_GIDLS_OFFSET, 0, mask);
+
+ pwminfo("PWM CCU4%d,CC4%d clock is disabled\n",
+ priv->module, priv->slice);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_start_slice_timer
+ *
+ * Description:
+ * Start the timer counter for the given slice.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_start_slice_timer(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t cc4ytcset_offset =
+ (uint32_t)(XMC4_CCU4_CC40TCSET_OFFSET + 0x0100 * priv->slice);
+
+ xmc4_pwm_putreg32(priv, cc4ytcset_offset,
+ (uint32_t)CCU4_CC4_TCSET_TRBS_MASK);
+
+ pwminfo("PWM CCU4%d,CC4%d timer is running\n", priv->module, priv->slice);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_stop_slice_timer
+ *
+ * Description:
+ * Stop the timer counter for the given slice. Reset the counter.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_stop_slice_timer(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t cc4ytcclr_offset =
+ (uint32_t)(XMC4_CCU4_CC40TCCLR_OFFSET + 0x0100 * priv->slice);
+
+ xmc4_pwm_putreg32(priv, cc4ytcclr_offset,
+ (uint32_t)(CCU4_CC4_TCCLR_TRBC_MASK |
+ CCU4_CC4_TCCLR_TCC_MASK));
+
+ pwminfo("PWM CCU4%d,CC4%d timer is stopped\n", priv->module, priv->slice);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_is_slice_timer_running
+ *
+ * Description:
+ * Get the state (running timer or not) of the slice.
+ *
+ *
+ * Returned Value:
+ * 0 if slice timer is stopped else true if timmer running.
+ *
+ *****************************************************************************/
+
+static bool pwm_is_slice_timer_running(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t cc4ytst_offset =
+ (uint32_t)(XMC4_CCU4_CC40TST_OFFSET + 0x0100 * priv->slice);
+
+ bool status = (bool)((xmc4_pwm_getreg32(priv, cc4ytst_offset) &
+ (uint32_t)CCU4_CC4_TCST_TRB_MASK) ==
+ (uint32_t)CCU4_CC4_TCST_TRB_MASK);
+
+ pwminfo("PWM CCU4%d,CC4%d timer status is :%d\n",
+ priv->module, priv->slice, status);
+
+ return status;
+}
+
+/*****************************************************************************
+ * Name: pwm_set_slice_prescaler
+ *
+ * Description:
+ * Set the value of the prescaler [0-14] in CC4yPSC.PSIV.
+ * Slice must be restarted for effective change.
+ * Update the value of prescaler in related xmc4_pwm_s.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_set_slice_prescaler(struct xmc4_pwm_s *priv, uint8_t prescaler)
+{
+ DEBUGASSERT(priv != NULL);
+ DEBUGASSERT(prescaler < 15);
+
+ if (prescaler >= 15)
+ {
+ return -EINVAL;
+ }
+
+ uint32_t cc4ypsc_offset =
+ (uint32_t)(XMC4_CCU4_CC40PSC_OFFSET + 0x0100 * priv->slice);
+
+ xmc4_pwm_putreg32(priv, cc4ypsc_offset, (uint32_t)prescaler);
+
+ priv->prescaler = prescaler;
+
+ pwminfo("PWM CCU4%d,CC4%d prescaler is set to : %d\n",
+ priv->module, priv->slice, prescaler);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_start_module_prescaler
+ *
+ * Description:
+ * Start the CCU4x module prescaler (CCU4xGIDLC.SPRB)
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_start_module_prescaler(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ xmc4_pwm_modifyreg32(priv, XMC4_CCU4_GIDLC_OFFSET, 0, CCU4_GIDLC_SPRB_MASK);
+
+ pwminfo("PWM CCU4%d prescaler is started\n", priv->module);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_stop_module_prescaler
+ *
+ * Description:
+ * Stop the CCU4x module prescaler (CCU4xGIDLS.CPRB)
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_stop_module_prescaler(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ xmc4_pwm_modifyreg32(priv, XMC4_CCU4_GIDLS_OFFSET, 0, CCU4_GIDLS_CPRB_MASK);
+
+ pwminfo("PWM CCU4%d prescaler is stopped\n", priv->module);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_enable_module
+ *
+ * Description:
+ * Enable the CCU4x module (ungate and de-assert reset).
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_enable_module(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ if (priv->module == 3)
+ {
+#ifdef XMC4_SCU_GATING
+ /* Check if peripheral is gated */
+
+ if ((getreg32(XMC4_SCU_CGATSTAT1) && SCU_CGAT1_CCU43))
+ {
+ putreg32(SCU_CGAT1_CCU43, XMC4_SCU_CGATCLR1); /* Ungate it */
+ }
+
+#endif
+ /* Check if peripheral reset is asserted */
+
+ if ((getreg32(XMC4_SCU_PRSTAT1) && SCU_PR1_CCU43RS))
+ {
+ putreg32(SCU_PR1_CCU43RS, XMC4_SCU_PRCLR1); /* De-assert reset */
+ }
+ }
+ else
+ {
+ uint32_t scu_ccu4x_mask = (uint32_t)(1 << (priv->module + 2));
+
+#ifdef XMC4_SCU_GATING
+ if ((getreg32(XMC4_SCU_CGATSTAT0) && scu_ccu4x_mask))
+ {
+ putreg32(scu_ccu4x_mask, XMC4_SCU_CGATCLR0);
+ }
+
+#endif
+ if ((getreg32(XMC4_SCU_PRSTAT0) && scu_ccu4x_mask))
+ {
+ putreg32(scu_ccu4x_mask, XMC4_SCU_PRCLR0);
+ }
+ }
+
+ pwminfo("PWM CCU4%d module is enabled\n", priv->module);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_enable_module
+ *
+ * Description:
+ * Disable the CCU4x module (gate and assert reset).
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure.
+ *
+ *****************************************************************************/
+
+static int pwm_disable_module(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ if (priv->module == 3)
+ {
+ /* Assert reset */
+
+ putreg32(SCU_PR1_CCU43RS, XMC4_SCU_PRCLR1);
+
+#ifdef XMC4_SCU_GATING
+ /* Gate clock */
+
+ putreg32(SCU_CGAT1_CCU43, XMC4_SCU_CGATSET1);
+#endif
+ }
+ else
+ {
+ uint32_t scu_ccu4x_mask = (uint32_t)(1 << (priv->module + 2));
+
+ putreg32(scu_ccu4x_mask, XMC4_SCU_PRSET0);
+
+#ifdef XMC4_SCU_GATING
+ putreg32(scu_ccu4x_mask, XMC4_SCU_CGATSET0);
+#endif
+ }
+
+ pwminfo("PWM CCU4%d module is disabled\n", priv->module);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_is_module_used
+ *
+ * Description:
+ * Get the state (running timer or not) of the slice.
+ *
+ * Returned Value:
+ * 0 if module is idle, else true if one slice or more is running.
+ *
+ *****************************************************************************/
+
+static bool pwm_is_module_used(struct xmc4_pwm_s *priv)
+{
+ DEBUGASSERT(priv != NULL);
+
+ uint32_t idle_status = xmc4_pwm_getreg32(priv, XMC4_CCU4_GSTAT_OFFSET);
+ uint32_t mask = (CCU4_GSTAT_S0I_MASK |
+ CCU4_GSTAT_S1I_MASK |
+ CCU4_GSTAT_S2I_MASK |
+ CCU4_GSTAT_S3I_MASK);
+
+ idle_status &= mask;
+
+ bool is_used = !(idle_status == mask);
+
+ pwminfo("PWM CCU4%d is used ? : %d\n", priv->module, is_used);
+
+ return is_used;
+}
+
+/*****************************************************************************
+ * Name: pwm_compute_config
+ *
+ * Description:
+ * Compute the prescaler value, compare and period match for the given
+ * info config.
+ *
+ * Input Parameters:
+ * priv - 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_compute_config(struct xmc4_pwm_s *priv,
+ const struct pwm_info_s *info,
+ uint8_t *prescaler,
+ uint16_t *period,
+ uint16_t *compare)
+{
+ DEBUGASSERT(priv != NULL);
+ DEBUGASSERT(info != NULL);
+ DEBUGASSERT(prescaler != NULL);
+ DEBUGASSERT(period != NULL);
+ DEBUGASSERT(compare != NULL);
+
+ uint32_t f_ccu = xmc4_get_ccuclock();
+
+ pwminfo("PWM f_ccu is %d\n", f_ccu);
+
+ uint32_t f_tclk = 0;
+ uint8_t new_prescaler = 0;
+ uint32_t prs = 0;
+ uint32_t crs = 0;
+
+ uint32_t f_pwm = info->frequency;
+ float duty_cycle = (1.0 - b16tof(info->duty));
+
+ do
+ {
+ f_tclk = f_ccu >> new_prescaler;
+ new_prescaler += 1;
+ prs = f_tclk / f_pwm - 1;
+ crs = (uint32_t)(duty_cycle * (prs + 1));
+ }
+ while ((prs > UINT16_MAX) || (crs > UINT16_MAX));
+
+ if (new_prescaler > 15)
+ {
+ return -EINVAL;
+ }
+
+ *period = (uint16_t)prs;
+ *compare = (uint16_t)crs;
+ *prescaler = (uint8_t)(new_prescaler - 1);
+ priv->f_tclk = f_tclk;
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_timer
+ *
+ * Description:
+ * (Re-)initialize the timer resources and start the pulsed output
+ *
+ * Input Parameters:
+ * priv - 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_timer(struct xmc4_pwm_s *priv, const struct pwm_info_s *info)
+{
+ DEBUGASSERT(priv != NULL);
+ DEBUGASSERT(info != NULL);
+
+ uint8_t new_prescaler;
+ uint16_t crs;
+ uint16_t prs;
+
+ int ret = pwm_compute_config(priv, info, &new_prescaler, &prs, &crs);
+ if (ret < 0)
+ {
+ return -EINVAL;
+ }
+
+ if (info->frequency != priv->frequency)
+ {
+ /* Is slice timer running ? */
+
+ if (pwm_is_slice_timer_running(priv))
+ {
+ /* Slice is running */
+
+ if (new_prescaler == priv->prescaler)
+ {
+ /* Prescaller doesn't change, update shadow transfert */
+
+ pwm_set_period_match(priv, prs);
+ pwm_set_compare_match(priv, crs);
+ pwm_set_passive_level(priv, info->cpol);
+ pwm_shadow_transfert(priv);
+ }
+ else
+ {
+ /* Stop slice to update prescaler */
+
+ pwm_stop_slice_timer(priv);
+ pwm_disable_slice_clock(priv);
+
+ pwm_set_slice_prescaler(priv, new_prescaler);
+
+ pwm_set_compare_match(priv, crs);
+ pwm_set_period_match(priv, prs);
+ pwm_set_passive_level(priv, info->cpol);
+ pwm_shadow_transfert(priv);
+
+ pwm_enable_slice_clock(priv);
+ pwm_start_slice_timer(priv);
+ }
+ }
+ else
+ {
+ /* Slice isn't running, start it */
+
+ pwm_set_slice_prescaler(priv, new_prescaler);
+
+ pwm_set_compare_match(priv, crs);
+ pwm_set_period_match(priv, prs);
+ pwm_set_passive_level(priv, info->cpol);
+ pwm_shadow_transfert(priv);
+
+ pwm_enable_slice_clock(priv);
+ pwm_start_slice_timer(priv);
+ }
+
+ priv->frequency = info->frequency;
+ priv->duty = info->duty;
+ }
+ else
+ {
+ /* Frequency doesn't change, update shadow transfert */
+
+ pwm_set_compare_match(priv, crs);
+ pwm_set_passive_level(priv, info->cpol);
+ pwm_shadow_transfert(priv);
+
+ priv->duty = info->duty;
+ }
+
+ 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(struct pwm_lowerhalf_s *dev)
+{
+ struct xmc4_pwm_s *priv = (struct xmc4_pwm_s *)dev;
+
+ DEBUGASSERT(priv != NULL);
+
+ int ret = OK;
+
+ pwminfo("PWM CCU4%d,CC4%d is being used\n", priv->module, priv->slice);
+
+ /* Set the selected GPIO as the CCU4 output alternate function */
+
+ ret = xmc4_gpio_config((gpioconfig_t)priv->outgpio);
+
+ /* Check if CCU4 is clocked in SCU */
+
+ if ((getreg32(XMC4_SCU_CLKSTAT) & (uint32_t)SCU_CLK_CCUC) == 0)
+ {
+ /* Enable CCU4 clock */
+
+ putreg32(SCU_CLK_CCUC, XMC4_SCU_CLKSET);
+ }
+
+ /* Enable CCU clock during sleep */
+
+ if ((getreg32(XMC4_SCU_SLEEPCR) & (uint32_t)(SCU_SLEEPCR_CCUCR)) == 0)
+ {
+ putreg32(SCU_SLEEPCR_CCUCR | SCU_SLEEPCR_SYSSEL, XMC4_SCU_SLEEPCR);
+ }
+
+ /* Activate CCU4x module */
+
+ ret |= pwm_enable_module(priv);
+
+ /* Start the prescaller of the module */
+
+ ret |= pwm_start_module_prescaler(priv);
+
+ return ret;
+}
+
+static int pwm_start(struct pwm_lowerhalf_s *dev,
+ const struct pwm_info_s *info)
+{
+ struct xmc4_pwm_s *priv = (struct xmc4_pwm_s *)dev;
+
+ DEBUGASSERT(priv != NULL);
+
+ pwminfo("PWM CCU4%d,CC4%d is started\n", priv->module, priv->slice);
+
+ return pwm_timer(priv, info);
+}
+
+/*****************************************************************************
+ * Name: pwm_stop
+ *
+ * Description:
+ * Stop the timer resources.
+ *
+ * Input Parameters:
+ * priv - A reference to the lower half PWM driver state structure
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure
+ *
+ *****************************************************************************/
+
+static int pwm_stop(struct pwm_lowerhalf_s *dev)
+{
+ struct xmc4_pwm_s *priv = (struct xmc4_pwm_s *)dev;
+
+ DEBUGASSERT(priv != NULL);
+
+ pwm_stop_slice_timer(priv);
+ pwm_disable_slice_clock(priv);
+
+ priv->frequency = 0;
+ priv->duty = 0;
+
+ pwminfo("PWM CCU4%d,CC4%d is stopped\n", priv->module, priv->slice);
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_stop
+ *
+ * Description:
+ * Stop the timer resources and disable hardware module.
+ *
+ * Input Parameters:
+ * priv - 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(struct pwm_lowerhalf_s *dev)
+{
+ struct xmc4_pwm_s *priv = (struct xmc4_pwm_s *)dev;
+
+ DEBUGASSERT(priv != NULL);
+
+ /* Disable slice */
+
+ pwm_stop(dev);
+
+ /* Disable module if not used anymore */
+
+ if (!pwm_is_module_used(priv))
+ {
+ pwm_disable_module(priv);
+ }
+
+ priv->f_tclk = 0;
+ priv->prescaler = 0;
+
+ return OK;
+}
+
+/*****************************************************************************
+ * Name: pwm_ioctl
+ *
+ * Description:
+ * Lower-half logic may support platform-specific ioctl commands
+ *
+ *****************************************************************************/
+
+static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg)
+{
+ struct xmc4_pwm_s *priv = (struct xmc4_pwm_s *)dev;
+
+ DEBUGASSERT(dev);
+
+ /* There are no platform-specific ioctl commands */
+
+ UNUSED(priv);
+
+ return -ENOTTY;
+}
+
+/*****************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: xmc4_pwminitialize
+ *
+ * Description:
+ * Initialize one timer for use with the upper_level PWM driver.
+ *
+ * Input Parameters:
+ * module - A number identifying the CCU4x use, in the range of {0,..,3}.
+ * slice - A number identifying the CC4y use, in the range of {0,..,3}.
+ *
+ * Returned Value:
+ * On success, a pointer to the XMC4 lower half PWM driver is returned.
+ * NULL is returned on any failure.
+ *
+ *****************************************************************************/
+
+struct pwm_lowerhalf_s *xmc4_pwminitialize(int module, int slice)
+{
+ struct xmc4_pwm_s *lower = NULL;
+
+ pwminfo("CCU4%u,CC4%u\n", module, slice);
+
+ switch (module)
+ {
+#ifdef CONFIG_XMC4_CCU40
+ case 0:
+ {
+ switch (slice)
+ {
+#ifdef CONFIG_XMC4_CCU40_CC40
+ case 0:
+ {
+ lower = &g_pwm00;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU40_CC41
+ case 1:
+ {
+ lower = &g_pwm01;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU40_CC42
+ case 2:
+ {
+ lower = &g_pwm02;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU40_CC43
+ case 3:
+ {
+ lower = &g_pwm03;
+ break;
+ }
+#endif
+
+ default:
+ {
+ pwmerr("ERROR: No such CCU4%d,CC4%d existing %d\n", module, slice);
+ lower = NULL;
+ goto errout;
+ }
+ }
+
+ break;
+ }
+#endif /* CONFIG_XMC4_CCU40 */
+
+#ifdef CONFIG_XMC4_CCU41
+ case 1:
+ {
+ switch (slice)
+ {
+#ifdef CONFIG_XMC4_CCU41_CC40
+ case 0:
+ {
+ lower = &g_pwm10;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU41_CC41
+ case 1:
+ {
+ lower = &g_pwm11;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU41_CC42
+ case 2:
+ {
+ lower = &g_pwm12;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU41_CC43
+ case 3:
+ {
+ lower = &g_pwm13;
+ break;
+ }
+#endif
+
+ default:
+ {
+ pwmerr("ERROR: No such CCU4%d,CC4%d existing %d\n", module, slice);
+ lower = NULL;
+ goto errout;
+ }
+ }
+
+ break;
+ }
+#endif /* CONFIG_XMC4_CCU41 */
+
+#ifdef CONFIG_XMC4_CCU42
+ case 2:
+ {
+ switch (slice)
+ {
+#ifdef CONFIG_XMC4_CCU42_CC40
+ case 0:
+ {
+ lower = &g_pwm20;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU42_CC41
+ case 1:
+ {
+ lower = &g_pwm21;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU42_CC42
+ case 2:
+ {
+ lower = &g_pwm22;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU42_CC43
+ case 3:
+ {
+ lower = &g_pwm23;
+ break;
+ }
+#endif
+
+ default:
+ {
+ pwmerr("ERROR: No such CCU4%d,CC4%d existing %d\n", module, slice);
+ lower = NULL;
+ goto errout;
+ }
+ }
+
+ break;
+ }
+#endif /* CONFIG_XMC4_CCU42 */
+
+#ifdef CONFIG_XMC4_CCU43
+ case 3:
+ {
+ switch (slice)
+ {
+#ifdef CONFIG_XMC4_CCU43_CC40
+ case 0:
+ {
+ lower = &g_pwm30;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU43_CC41
+ case 1:
+ {
+ lower = &g_pwm31;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU43_CC42
+ case 2:
+ {
+ lower = &g_pwm32;
+ break;
+ }
+#endif
+
+#ifdef CONFIG_XMC4_CCU43_CC43
+ case 3:
+ {
+ lower = &g_pwm33;
+ break;
+ }
+#endif
+
+ default:
+ {
+ pwmerr("ERROR: No such CCU4%d,CC4%d existing %d\n", module, slice);
+ lower = NULL;
+ goto errout;
+ }
+ }
+
+ break;
+ }
+#endif /* CONFIG_XMC4_CCU43 */
+
+ default:
+ {
+ pwmerr("ERROR: No such CCU4%d,CC4%d existing %d\n", module, slice);
+ lower = NULL;
+ goto errout;
+ }
+ }
+
+errout:
+ return (struct pwm_lowerhalf_s *)lower;
+}
diff --git a/arch/arm/src/xmc4/xmc4_pwm.h b/arch/arm/src/xmc4/xmc4_pwm.h
index 644b4ba222..45e92695d1 100644
--- a/arch/arm/src/xmc4/xmc4_pwm.h
+++ b/arch/arm/src/xmc4/xmc4_pwm.h
@@ -29,6 +29,10 @@
#include "chip.h"
+#include <nuttx/timers/pwm.h>
+
+#include <arch/board/board.h>
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@@ -73,7 +77,7 @@ extern "C"
*
****************************************************************************/
-struct pwm_lowerhalf_s *xmc4_pwm_initialize(int timer);
+struct pwm_lowerhalf_s *xmc4_pwminitialize(int module, int slice);
#undef EXTERN
#if defined(__cplusplus)
@@ -81,5 +85,4 @@ struct pwm_lowerhalf_s *xmc4_pwm_initialize(int timer);
#endif
#endif /* __ASSEMBLY__ */
-#endif /* CONFIG_XMC4_FTMx_PWM */
-#endif /* __ARCH_ARM_SRC_XMC4_XMC4_PWM_H */
+#endif /* __ARCH_ARM_SRC_XMC4_XMC4_PWM_H */
\ No newline at end of file