You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2021/09/15 15:20:33 UTC
[incubator-nuttx] branch master updated: S32K1xx: added PM support
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new b316c67 S32K1xx: added PM support
b316c67 is described below
commit b316c679c14156a5f3c3a0a5e30cbae6b4a817db
Author: Cis van Mierlo <ci...@nxp.com>
AuthorDate: Tue Sep 14 13:28:04 2021 +0200
S32K1xx: added PM support
---
arch/arm/src/s32k1xx/Make.defs | 6 +-
arch/arm/src/s32k1xx/hardware/s32k1xx_pmc.h | 1 +
arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h | 13 +-
arch/arm/src/s32k1xx/s32k1xx_clockconfig.c | 1037 ++++++++++++++++++++++++---
arch/arm/src/s32k1xx/s32k1xx_clockconfig.h | 42 ++
arch/arm/src/s32k1xx/s32k1xx_lpspi.c | 435 +++++++++++
arch/arm/src/s32k1xx/s32k1xx_periphclocks.c | 61 +-
arch/arm/src/s32k1xx/s32k1xx_periphclocks.h | 17 +
arch/arm/src/s32k1xx/s32k1xx_pminitialize.c | 62 ++
arch/arm/src/s32k1xx/s32k1xx_serial.c | 446 +++++++++++-
10 files changed, 1984 insertions(+), 136 deletions(-)
diff --git a/arch/arm/src/s32k1xx/Make.defs b/arch/arm/src/s32k1xx/Make.defs
index 9b34381..fb252ea 100644
--- a/arch/arm/src/s32k1xx/Make.defs
+++ b/arch/arm/src/s32k1xx/Make.defs
@@ -93,7 +93,11 @@ ifeq ($(CONFIG_S32K1XX_EEEPROM),y)
CHIP_CSRCS += s32k1xx_eeeprom.c
endif
-ifeq ($(CONFIG_RESET_CAUSE_PROC_FS), y)
+ifneq ($(CONFIG_ARCH_CUSTOM_PMINIT),y)
+CHIP_CSRCS += s32k1xx_pminitialize.c
+endif
+
+ifeq ($(CONFIG_RESET_CAUSE_PROC_FS), y)
CHIP_CSRCS += s32k1xx_resetcause.c
endif
diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_pmc.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_pmc.h
index d3e2043..4c17c1a 100644
--- a/arch/arm/src/s32k1xx/hardware/s32k1xx_pmc.h
+++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_pmc.h
@@ -63,6 +63,7 @@
/* Regulator Status and Control Register */
+#define PMC_REGSC_BIASEN (1 << 0) /* Bit 0: Bias Enable Bit */
#define PMC_REGSC_CLKBIASDIS (1 << 1) /* Bit 1: Clock Bias Disable Bit */
#define PMC_REGSC_REGFPM (1 << 2) /* Bit 2: Regulator in Full Performance Mode Status Bit */
#define PMC_REGSC_LPOSTAT (1 << 6) /* Bit 6: LPO Status Bit */
diff --git a/arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h b/arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h
index 5da2137..0d3c7b2 100644
--- a/arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h
+++ b/arch/arm/src/s32k1xx/hardware/s32k1xx_smc.h
@@ -54,13 +54,12 @@
/* SMC Version ID Register */
-#define SMC_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Feature Identification Number */
+#define SMC_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Feature Identification Number */
#define SMC_VERID_FEATURE_MASK (0xffff << SMC_VERID_FEATURE_SHIFT)
# define SMC_VERID_FEATURE_STD (1 << SMC_VERID_FEATURE_SHIFT) /* Standard feature set */
-
-#define SMC_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number */
+#define SMC_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number */
#define SMC_VERID_MINOR_MASK (0xff << SMC_VERID_MINOR_SHIFT)
-#define SMC_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number */
+#define SMC_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number */
#define SMC_VERID_MAJOR_MASK (0xff << SMC_VERID_MAJOR_SHIFT)
/* SMC Parameter Register */
@@ -72,8 +71,10 @@
/* SMC Power Mode Protection register */
-#define SMC_PMPROT_AVLP (1 << 5) /* Bit 5: Allow Very-Low-Power Modes */
-#define SMC_PMPROT_AHSRUN (1 << 7) /* Bit 7: Allow High Speed Run mode */
+#define SMC_PMPROT_AVLP_SHIFT (5) /* Bit 5: Allow Very-Low-Power Modes */
+#define SMC_PMPROT_AVLP (1 << SMC_PMPROT_AVLP_SHIFT)
+#define SMC_PMPROT_AHSRUN_SHIFT (7) /* Bit 7: Allow High Speed Run mode */
+#define SMC_PMPROT_AHSRUN (1 << SMC_PMPROT_AHSRUN_SHIFT)
/* SMC Power Mode Control register */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c b/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c
index 04e806e..880ee19 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_clockconfig.c
@@ -63,6 +63,7 @@
#include <debug.h>
#include <nuttx/arch.h>
+#include <nuttx/power/pm.h>
#include "arm_arch.h"
#include "arm_internal.h"
@@ -73,6 +74,7 @@
#include "hardware/s32k1xx_pmc.h"
#include "s32k1xx_periphclocks.h"
#include "s32k1xx_clockconfig.h"
+#include "s32k1xx_start.h"
#include <arch/board/board.h> /* Include last. May have dependencies */
@@ -120,18 +122,32 @@
#define SCG_SPLL_REF_MIN 8000000
#define SCG_SPLL_REF_MAX 32000000
+/* Power management definitions */
+
+#if defined(CONFIG_PM)
+#ifndef PM_IDLE_DOMAIN
+# define PM_IDLE_DOMAIN 0 /* Revisit */
+#endif
+#endif
+
+#ifndef OK
+#define OK 0
+#endif
+
/****************************************************************************
- * Private Types
+ * Private Function Declarations
****************************************************************************/
-enum scg_system_clock_mode_e
-{
- SCG_SYSTEM_CLOCK_MODE_CURRENT = 0, /* Current mode. */
- SCG_SYSTEM_CLOCK_MODE_RUN = 1, /* Run mode. */
- SCG_SYSTEM_CLOCK_MODE_VLPR = 2, /* Very Low Power Run mode. */
- SCG_SYSTEM_CLOCK_MODE_HSRUN = 3, /* High Speed Run mode. */
- SCG_SYSTEM_CLOCK_MODE_NONE /* MAX value. */
-};
+#ifdef CONFIG_PM
+static void up_pm_notify(struct pm_callback_s *cb, int dowmin,
+ enum pm_state_e pmstate);
+static int up_pm_prepare(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate);
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
/****************************************************************************
* Private Data
@@ -212,6 +228,14 @@ static uint32_t g_rtc_clkin; /* RTC CLKIN clock */
static uint32_t g_tclkfreq[NUMBER_OF_TCLK_INPUTS]; /* TCLKx clocks */
#endif
+#ifdef CONFIG_PM
+static struct pm_callback_s g_clock_pmcb =
+{
+ .notify = up_pm_notify,
+ .prepare = up_pm_prepare,
+};
+#endif
+
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -237,59 +261,6 @@ static inline uint32_t s32k1xx_get_scgclk_source(void)
}
/****************************************************************************
- * Name: s32k1xx_get_runmode
- *
- * Description:
- * Get the current running mode.
- *
- * Input Parameters:
- * None
- *
- * Returned Value:
- * The current running mode.
- *
- ****************************************************************************/
-
-static enum scg_system_clock_mode_e s32k1xx_get_runmode(void)
-{
- enum scg_system_clock_mode_e mode;
-
- /* Get the current running mode */
-
- switch (getreg32(S32K1XX_SMC_PMSTAT) & SMC_PMSTAT_PMSTAT_MASK)
- {
- /* Run mode */
-
- case SMC_PMSTAT_PMSTAT_RUN:
- mode = SCG_SYSTEM_CLOCK_MODE_RUN;
- break;
-
- /* Very low power run mode */
-
- case SMC_PMSTAT_PMSTAT_VLPR:
- mode = SCG_SYSTEM_CLOCK_MODE_VLPR;
- break;
-
- /* High speed run mode */
-
- case SMC_PMSTAT_PMSTAT_HSRUN:
- mode = SCG_SYSTEM_CLOCK_MODE_HSRUN;
- break;
-
- /* This should never happen - core has to be in some run mode to
- * execute code
- */
-
- case SMC_PMSTAT_PMSTAT_VLPS:
- default:
- mode = SCG_SYSTEM_CLOCK_MODE_NONE;
- break;
- }
-
- return mode;
-}
-
-/****************************************************************************
* Name: s32k1xx_get_soscfreq
*
* Description:
@@ -783,7 +754,7 @@ static int s32k1xx_firc_config(bool enable,
}
/****************************************************************************
- * Name: s32k11_firc_clocksource
+ * Name: s32k1xx_firc_clocksource
*
* Description:
* Configure to the FIRC clock source.
@@ -797,7 +768,7 @@ static int s32k1xx_firc_config(bool enable,
*
****************************************************************************/
-static int s32k11_firc_clocksource(void)
+static int s32k1xx_firc_clocksource(void)
{
struct scg_system_clock_config_s firccfg;
int ret = OK;
@@ -944,6 +915,61 @@ static int s32k1xx_sirc_config(bool enable,
return ret;
}
+#if defined(CONFIG_VLPR_STANDBY) || defined(CONFIG_VLPR_SLEEP)
+
+/****************************************************************************
+ * Name: s32k1xx_sirc_clocksource
+ *
+ * Description:
+ * Configure to the SIRC clock source.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * Zero (OK) is returned a success; A negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+static int s32k1xx_sirc_clocksource(void)
+{
+ struct scg_system_clock_config_s sirccfg;
+ int ret = OK;
+
+ /* If the current system clock source is not SIRC:
+ * 1. Enable SIRC (if it's not enabled)
+ * 2. Switch to SIRC.
+ */
+
+ if (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC)
+ {
+ /* If SIRC is not on, then SIRC is configured with the default
+ * configuration
+ */
+
+ if (s32k1xx_get_sircfreq() == 0)
+ {
+ ret = s32k1xx_sirc_config(true, NULL);
+ }
+
+ /* SIRC is enabled, transition the system clock source to SIRC. */
+
+ if (ret == OK)
+ {
+ sirccfg.src = SCG_SYSTEM_CLOCK_SRC_SIRC;
+ sirccfg.divcore = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SYS_DIV];
+ sirccfg.divbus = g_tmp_sysclk[TMP_SIRC_CLK][TMP_BUS_DIV];
+ sirccfg.divslow = g_tmp_sysclk[TMP_SIRC_CLK][TMP_SLOW_DIV];
+ ret = s32k1xx_transition_systemclock(&sirccfg);
+ }
+ }
+
+ return ret;
+}
+
+#endif
+
/****************************************************************************
* Name: s32k1xx_sosc_config
*
@@ -1394,9 +1420,10 @@ static int s32k1xx_scg_config(const struct scg_config_s *scgcfg)
DEBUGASSERT(scgcfg != NULL);
- /* Configure a temporary system clock source: FIRC */
+ /* Configure a temporary system clock source: FIRC if enabled */
+
+ ret = s32k1xx_firc_clocksource();
- ret = s32k11_firc_clocksource();
if (ret == OK)
{
/* Configure clock sources from SCG */
@@ -1654,6 +1681,10 @@ static void s32k1xx_pmc_config(const struct pmc_config_s *pmccfg)
regval |= PMC_REGSC_LPODIS;
}
+ /* Enable Biasing (needed for VLPR mode, no effect in RUN mode) */
+
+ regval |= PMC_REGSC_BIASEN;
+
putreg8(regval, S32K1XX_PMC_REGSC);
/* Write trimming value. */
@@ -1663,38 +1694,882 @@ static void s32k1xx_pmc_config(const struct pmc_config_s *pmccfg)
}
/****************************************************************************
- * Public Functions
+ * Name: s32k1xx_allow_vlprmode
+ *
+ * Description:
+ * allow the very low power run mode.
+ *
+ * Input Parameters:
+ * allow - true if allowed, false otherwise.
+ *
+ * Returned Value:
+ * none.
+ *
****************************************************************************/
+void s32k1xx_allow_vlprmode(bool allow)
+{
+ uint32_t regval;
+
+ /* get the SMC_PMPROT register */
+
+ regval = getreg32(S32K1XX_SMC_PMPROT);
+
+ /* mask the AVLP bit */
+
+ regval &= ~SMC_PMPROT_AVLP;
+
+ /* set the new bit */
+
+ regval |= (allow << SMC_PMPROT_AVLP_SHIFT);
+
+ /* set the registervalue */
+
+ putreg32(regval, S32K1XX_SMC_PMPROT);
+}
+
/****************************************************************************
- * Name: s32k1xx_clockconfig
+ * Name: up_pm_notify
*
* Description:
- * Called to initialize the S32K1XX. This does whatever setup is needed
- * to put the MCU in a usable state. This includes the initialization of
- * clocking using the settings in board.h. This function also performs
- * other low-level chip as necessary.
+ * Notify the driver of new power state. This callback is called after
+ * all drivers have had the opportunity to prepare for the new power state.
*
* Input Parameters:
- * clkcfg - Describes the new clock configuration
+ *
+ * cb - Returned to the driver. The driver version of the callback
+ * structure may include additional, driver-specific state data at
+ * the end of the structure.
+ *
+ * pmstate - Identifies the new PM state
*
* Returned Value:
- * Zero (OK) is returned a success; A negated errno value is returned on
- * any failure.
+ * None - The driver already agreed to transition to the low power
+ * consumption state when when it returned OK to the prepare() call.
*
****************************************************************************/
-int s32k1xx_clockconfig(const struct clock_configuration_s *clkcfg)
+#ifdef CONFIG_PM
+static void up_pm_notify(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate)
{
- int ret;
+ int return_value;
- DEBUGASSERT(clkcfg != NULL);
+ /* check if the transition is from the IDLE domain to the NORMAL domain */
- /* Set SCG configuration */
+ if (pm_querystate(PM_IDLE_DOMAIN) == PM_IDLE &&
+ pmstate == PM_NORMAL)
+ {
+ /* return */
- ret = s32k1xx_scg_config(&clkcfg->scg);
- if (ret >= 0)
+ return;
+ }
+
+ /* check what the new power state is */
+
+ switch (pmstate)
{
+ /* if it needs to be set to RUN mode */
+
+ case(PM_NORMAL):
+ {
+ /* Logic for PM_NORMAL goes here */
+
+ /* change the microcontroller to RUN mode */
+
+ /* and wait until in RUN mode */
+
+ return_value = (int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_RUN);
+
+ /* check for debug assertion */
+
+ DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
+
+ /* enable all clock sources again if needed */
+
+ /* these could be the FIRC, PPL, and SOSC */
+
+ /* check if the FIRC was enabled and
+ * it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.firc.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC))
+ {
+ /* enable FIRC */
+
+ return_value = s32k1xx_firc_config(true,
+ &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the FIRC needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.firc.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_FIRC)))
+ {
+ /* disable FIRC */
+
+ return_value = s32k1xx_firc_config(false,
+ &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC was enabled and
+ * it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.sosc.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
+ {
+ /* enable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(true, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.sosc.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_OSC)))
+ {
+ /* disable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SPLL was enabled and
+ * it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.spll.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
+ {
+ /* enable SPLL */
+
+ return_value = s32k1xx_spll_config(true,
+ &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SPLL needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.spll.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_PLL)))
+ {
+ /* disable SPLL */
+
+ return_value = s32k1xx_spll_config(false,
+ &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the RCCR clock source is enabled */
+
+ if (s32k1xx_get_srcfreq(g_initial_clkconfig.scg.clockmode.rccr.src)
+ != 0)
+ {
+ /* change the system clock back to the configured clock */
+
+ /* and wait until clock changed */
+
+ if (s32k1xx_transition_systemclock(
+ &g_initial_clkconfig.scg.clockmode.rccr))
+ {
+ /* error */
+
+ DEBUGASSERT(false);
+ }
+ }
+
+ /* if it is 0 */
+
+ else
+ {
+ /* error */
+
+ DEBUGASSERT(false);
+ }
+
+ /* calculate the new clock ticks */
+
+ up_timer_initialize();
+ }
+ break;
+
+ case(PM_IDLE):
+ {
+ /* Logic for PM_IDLE goes here */
+ }
+ break;
+
+ /* if it needs to be set to VLPR mode */
+
+ case(PM_STANDBY):
+ {
+ /* Logic for PM_STANDBY goes here */
+
+#ifdef CONFIG_RUN_STANDBY
+
+ /* change the microcontroller to RUN mode */
+
+ /* and wait until in RUN mode */
+
+ return_value =
+ (int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_RUN);
+ DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
+
+ /* enable all clock sources again if needed */
+
+ /* these could be the FIRC, PPL, and SOSC */
+
+ /* check if the FIRC was enabled and
+ * it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.firc.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC))
+ {
+ /* enable FIRC */
+
+ return_value = s32k1xx_firc_config(true,
+ &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the FIRC needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.firc.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_FIRC)))
+ {
+ /* disable FIRC */
+
+ return_value = s32k1xx_firc_config(false,
+ &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC was enabled and
+ * it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.sosc.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
+ {
+ /* enable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(true, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.sosc.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_OSC)))
+ {
+ /* disable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SPLL was enabled and
+ * it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.spll.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
+ {
+ /* enable SPLL */
+
+ return_value = s32k1xx_spll_config(true,
+ &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SPLL needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.spll.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_PLL)))
+ {
+ /* disable SPLL */
+
+ return_value = s32k1xx_spll_config(false,
+ &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the RCCR clock source is enabled */
+
+ if (s32k1xx_get_srcfreq(g_initial_clkconfig.scg.clockmode.rccr.src)
+ != 0)
+ {
+ /* change the system clock back to the configured clock */
+
+ /* and wait until clock changed */
+
+ if (s32k1xx_transition_systemclock(
+ &g_initial_clkconfig.scg.clockmode.rccr))
+ {
+ /* error */
+
+ DEBUGASSERT(false);
+ }
+ }
+
+ /* if it is 0 */
+
+ else
+ {
+ /* error */
+
+ DEBUGASSERT(false);
+ }
+
+#endif /* CONFIG_RUN_STANDBY */
+
+#ifdef CONFIG_VLPR_STANDBY
+
+ /* set the system clock to the SIRC 8MHz freq */
+
+ /* this freq will change to the predefined vccr settings
+ * when the mode change occures
+ */
+
+ /* and wait until system clock changed */
+
+ return_value = s32k1xx_sirc_clocksource();
+ DEBUGASSERT(!return_value);
+
+ /* disable the other clock sources if not already disabled */
+
+ /* these are the FIRC, PPL, and SOSC */
+
+ /* check if the SPLL is enabled */
+
+ if (s32k1xx_get_spllfreq() != 0)
+ {
+ /* disable SPLL */
+
+ return_value = s32k1xx_spll_config(false,
+ &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC is enabled */
+
+ if (s32k1xx_get_soscfreq() != 0)
+ {
+ /* disable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the FIRC is enabled */
+
+ if (s32k1xx_get_fircfreq() != 0)
+ {
+ /* disable FIRC */
+
+ return_value = s32k1xx_firc_config(false,
+ &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ #ifdef CONFIG_ARCH_CHIP_S32K11X
+ /* TODO make sure CMU is gated? (only for S32k11x) */
+
+ #error Make sure CMU is gated
+ #endif
+
+ /* change the microcontroller to VLPR mode */
+
+ /* and wait until it is in that runmode */
+
+ return_value =
+ (int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_VLPR);
+ DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
+
+#endif /* CONFIG_VLPR_STANDBY */
+
+ /* calculate the new clock ticks */
+
+ up_timer_initialize();
+ }
+ break;
+
+ case(PM_SLEEP):
+ {
+ /* Logic for PM_SLEEP goes here */
+
+#ifdef CONFIG_RUN_SLEEP
+
+ /* change the microcontroller to RUN mode */
+
+ /* and wait until in RUN mode */
+
+ return_value = (int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_RUN);
+ DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
+
+ /* enable all clock sources again if needed */
+
+ /* these could be the FIRC, PPL, and SOSC */
+
+ /* check if the FIRC was enabled
+ * and it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.firc.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SIRC))
+ {
+ /* enable FIRC */
+
+ return_value = s32k1xx_firc_config(true,
+ &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the FIRC needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.firc.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_FIRC)))
+ {
+ /* disable FIRC */
+
+ return_value = s32k1xx_firc_config(false,
+ &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC was enabled
+ * and it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.sosc.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
+ {
+ /* enable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(true, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.sosc.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_OSC)))
+ {
+ /* disable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SPLL was enabled
+ * and it is not the system clock source
+ */
+
+ if (g_initial_clkconfig.scg.spll.initialize &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_OSC) &&
+ (s32k1xx_get_scgclk_source() != SCG_SYSTEM_CLOCK_SRC_SYS_PLL))
+ {
+ /* enable SPLL */
+
+ return_value = s32k1xx_spll_config(true,
+ &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SPLL needs to be disabled and if it is enabled */
+
+ else if ((!(g_initial_clkconfig.scg.spll.initialize)) &&
+ (s32k1xx_get_srcfreq(SCG_SYSTEM_CLOCK_SRC_SYS_PLL)))
+ {
+ /* disable SPLL */
+
+ return_value = s32k1xx_spll_config(false,
+ &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the RCCR clock source is enabled */
+
+ if (s32k1xx_get_srcfreq(g_initial_clkconfig.scg.clockmode.rccr.src)
+ != 0)
+ {
+ /* change the system clock back to the configured clock */
+
+ /* and wait until clock changed */
+
+ if (s32k1xx_transition_systemclock(
+ &g_initial_clkconfig.scg.clockmode.rccr))
+ {
+ /* error */
+
+ DEBUGASSERT(false);
+ }
+ }
+
+ /* if it is 0 */
+
+ else
+ {
+ /* error */
+
+ DEBUGASSERT(false);
+ }
+
+#endif /* CONFIG_RUN_SLEEP */
+
+#ifdef CONFIG_VLPR_SLEEP
+
+ /* set the system clock to the SIRC 8MHz freq */
+
+ /* this freq will change to the predefined vccr settings
+ * when the mode change occures
+ */
+
+ /* and wait until system clock changed */
+
+ return_value = s32k1xx_sirc_clocksource();
+ DEBUGASSERT(!return_value);
+
+ /* disable the other clock sources if not already disabled */
+
+ /* these are the FIRC, PPL, and SOSC */
+
+ /* check if the SPLL is enabled */
+
+ if (s32k1xx_get_spllfreq() != 0)
+ {
+ /* disable SPLL */
+
+ return_value =
+ s32k1xx_spll_config(false, &g_initial_clkconfig.scg.spll);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the SOSC is enabled */
+
+ if (s32k1xx_get_soscfreq() != 0)
+ {
+ /* disable SOSC */
+
+ return_value =
+ s32k1xx_sosc_config(false, &g_initial_clkconfig.scg.sosc);
+ DEBUGASSERT(!return_value);
+ }
+
+ /* check if the FIRC is enabled */
+
+ if (s32k1xx_get_fircfreq() != 0)
+ {
+ /* disable FIRC */
+
+ return_value =
+ s32k1xx_firc_config(false, &g_initial_clkconfig.scg.firc);
+ DEBUGASSERT(!return_value);
+ }
+
+ #ifdef CONFIG_ARCH_CHIP_S32K11X
+ /* TODO make sure CMU is gated? (only for S32k11x) */
+
+ #error Make sure CMU is gated
+ #endif
+ /* change the microcontroller to VLPR mode */
+
+ /* and wait until it is in that runmode */
+
+ return_value =
+ (int)s32k1xx_set_runmode(SCG_SYSTEM_CLOCK_MODE_VLPR);
+ DEBUGASSERT(return_value != (int)SCG_SYSTEM_CLOCK_MODE_NONE);
+
+#endif /* CONFIG_VLPR_SLEEP */
+
+ /* calculate the new clock ticks */
+
+ up_timer_initialize();
+ }
+ break;
+
+ default:
+
+ /* Should not get here */
+
+ break;
+ }
+}
+#endif
+
+/****************************************************************************
+ * Name: up_pm_prepare
+ *
+ * Description:
+ * Request the driver to prepare for a new power state. This is a warning
+ * that the system is about to enter into a new power state. The driver
+ * should begin whatever operations that may be required to enter power
+ * state. The driver may abort the state change mode by returning a
+ * non-zero value from the callback function.
+ *
+ * Input Parameters:
+ *
+ * cb - Returned to the driver. The driver version of the callback
+ * structure may include additional, driver-specific state data at
+ * the end of the structure.
+ *
+ * pmstate - Identifies the new PM state
+ *
+ * Returned Value:
+ * Zero - (OK) means the event was successfully processed and that the
+ * driver is prepared for the PM state change.
+ *
+ * Non-zero - means that the driver is not prepared to perform the tasks
+ * needed achieve this power setting and will cause the state
+ * change to be aborted. NOTE: The prepare() method will also
+ * be called when reverting from lower back to higher power
+ * consumption modes (say because another driver refused a
+ * lower power state change). Drivers are not permitted to
+ * return non-zero values when reverting back to higher power
+ * consumption modes!
+ *
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_PM
+static int up_pm_prepare(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate)
+{
+ /* Logic to prepare for a reduced power state goes here. */
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: s32k1xx_get_runmode
+ *
+ * Description:
+ * Get the current running mode.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The current running mode.
+ *
+ ****************************************************************************/
+
+enum scg_system_clock_mode_e s32k1xx_get_runmode(void)
+{
+ enum scg_system_clock_mode_e mode;
+
+ /* Get the current running mode */
+
+ switch (getreg32(S32K1XX_SMC_PMSTAT) & SMC_PMSTAT_PMSTAT_MASK)
+ {
+ /* Run mode */
+
+ case SMC_PMSTAT_PMSTAT_RUN:
+ mode = SCG_SYSTEM_CLOCK_MODE_RUN;
+ break;
+
+ /* Very low power run mode */
+
+ case SMC_PMSTAT_PMSTAT_VLPR:
+ mode = SCG_SYSTEM_CLOCK_MODE_VLPR;
+ break;
+
+ /* High speed run mode */
+
+ case SMC_PMSTAT_PMSTAT_HSRUN:
+ mode = SCG_SYSTEM_CLOCK_MODE_HSRUN;
+ break;
+
+ /* This should never happen - core has to be in some run mode to
+ * execute code
+ */
+
+ case SMC_PMSTAT_PMSTAT_VLPS:
+ default:
+ mode = SCG_SYSTEM_CLOCK_MODE_NONE;
+ break;
+ }
+
+ return mode;
+}
+
+/****************************************************************************
+ * Name: s32k1xx_set_runmode
+ *
+ * Description:
+ * Set the running mode.
+ *
+ * Input Parameters:
+ * next_run_mode - The next running mode.
+ *
+ * Returned Value:
+ * The current running mode.
+ *
+ ****************************************************************************/
+
+enum scg_system_clock_mode_e s32k1xx_set_runmode(enum scg_system_clock_mode_e
+ next_run_mode)
+{
+ enum scg_system_clock_mode_e mode;
+
+ /* get the current run mode */
+
+ mode = s32k1xx_get_runmode();
+ uint32_t regval;
+
+ /* check if the current runmode is not the same as the next runmode */
+
+ if (mode != next_run_mode)
+ {
+ /* check what the next mode is */
+
+ switch (next_run_mode)
+ {
+ /* in case of the RUN mode */
+
+ /* it will use the clock configuration from S32K1XX_SCG_RCCR */
+
+ case SCG_SYSTEM_CLOCK_MODE_RUN:
+
+ /* check if in VLPR mode */
+
+ if (mode == SCG_SYSTEM_CLOCK_MODE_VLPR)
+ {
+ /* get the SMC_PMCTRL register */
+
+ regval = getreg32(S32K1XX_SMC_PMCTRL);
+
+ /* mask the RUNM bits */
+
+ regval &= ~SMC_PMCTRL_RUNM_MASK;
+
+ /* change the mode to RUN mode */
+
+ regval |= SMC_PMCTRL_RUNM_RUN;
+
+ /* write the register */
+
+ putreg32(regval, S32K1XX_SMC_PMCTRL);
+
+ /* wait until it is in RUN mode */
+
+ while (s32k1xx_get_runmode() != SCG_SYSTEM_CLOCK_MODE_RUN);
+ }
+
+ break;
+
+ /* in case of the VLPR mode */
+
+ /* it will use the clock configuration from S32K1XX_SCG_VCCR */
+
+ case SCG_SYSTEM_CLOCK_MODE_VLPR:
+
+ /* check if in RUN mode and VLPR mode is allowed */
+
+ if ((mode == SCG_SYSTEM_CLOCK_MODE_RUN) &&
+ (getreg32(S32K1XX_SMC_PMPROT) & SMC_PMPROT_AVLP))
+ {
+ /* get the SMC_PMCTRL register */
+
+ regval = getreg32(S32K1XX_SMC_PMCTRL);
+
+ /* mask the RUNM bits */
+
+ regval &= ~SMC_PMCTRL_RUNM_MASK;
+
+ /* change the mode to VLPR mode */
+
+ regval |= SMC_PMCTRL_RUNM_VLPR;
+
+ /* write the register */
+
+ putreg32(regval, S32K1XX_SMC_PMCTRL);
+
+ /* wait until it is in VLPR mode */
+
+ while (s32k1xx_get_runmode() != SCG_SYSTEM_CLOCK_MODE_VLPR);
+ }
+ break;
+
+ /* others are not implemented */
+
+ default:
+ break;
+ }
+
+ /* get the current run mode */
+
+ mode = s32k1xx_get_runmode();
+ }
+
+ /* return the mode */
+
+ return mode;
+}
+
+/****************************************************************************
+ * Name: s32k1xx_clockconfig
+ *
+ * Description:
+ * Called to initialize the S32K1XX. This does whatever setup is needed
+ * to put the MCU in a usable state. This includes the initialization of
+ * clocking using the settings in board.h. This function also performs
+ * other low-level chip as necessary.
+ *
+ * Input Parameters:
+ * clkcfg - Describes the new clock configuration
+ *
+ * Returned Value:
+ * Zero (OK) is returned a success; A negated errno value is returned on
+ * any failure.
+ *
+ ****************************************************************************/
+
+int s32k1xx_clockconfig(const struct clock_configuration_s *clkcfg)
+{
+ int ret;
+
+ DEBUGASSERT(clkcfg != NULL);
+
+#ifdef CONFIG_PM
+ /* Register to receive power management callbacks */
+
+ ret = pm_register(&g_clock_pmcb);
+ DEBUGASSERT(ret == OK);
+#endif
+
+ /* Set SCG configuration */
+
+ ret = s32k1xx_scg_config(&clkcfg->scg);
+ if (ret >= 0)
+ {
+ /* Allow the VLPR mode */
+
+ s32k1xx_allow_vlprmode(true);
+
/* Set PCC configuration */
s32k1xx_periphclocks(clkcfg->pcc.count, clkcfg->pcc.pclks);
diff --git a/arch/arm/src/s32k1xx/s32k1xx_clockconfig.h b/arch/arm/src/s32k1xx/s32k1xx_clockconfig.h
index 05fdf2e..9ed9d8e 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_clockconfig.h
+++ b/arch/arm/src/s32k1xx/s32k1xx_clockconfig.h
@@ -440,6 +440,15 @@ struct clock_configuration_s
struct pmc_config_s pmc; /* PMC Clock configuration */
};
+enum scg_system_clock_mode_e
+{
+ SCG_SYSTEM_CLOCK_MODE_CURRENT = 0, /* Current mode. */
+ SCG_SYSTEM_CLOCK_MODE_RUN = 1, /* Run mode. */
+ SCG_SYSTEM_CLOCK_MODE_VLPR = 2, /* Very Low Power Run mode. */
+ SCG_SYSTEM_CLOCK_MODE_HSRUN = 3, /* High Speed Run mode. */
+ SCG_SYSTEM_CLOCK_MODE_NONE /* MAX value. */
+};
+
/****************************************************************************
* Inline Functions
****************************************************************************/
@@ -464,6 +473,39 @@ extern "C"
****************************************************************************/
/****************************************************************************
+ * Name: s32k1xx_get_runmode
+ *
+ * Description:
+ * Get the current running mode.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The current running mode.
+ *
+ ****************************************************************************/
+
+enum scg_system_clock_mode_e s32k1xx_get_runmode(void);
+
+/****************************************************************************
+ * Name: s32k1xx_set_runmode
+ *
+ * Description:
+ * Set the running mode.
+ *
+ * Input Parameters:
+ * next_run_mode - The next running mode.
+ *
+ * Returned Value:
+ * The current running mode.
+ *
+ ****************************************************************************/
+
+enum scg_system_clock_mode_e s32k1xx_set_runmode(enum scg_system_clock_mode_e
+ next_run_mode);
+
+/****************************************************************************
* Name: s32k1xx_clockconfig
*
* Description:
diff --git a/arch/arm/src/s32k1xx/s32k1xx_lpspi.c b/arch/arm/src/s32k1xx/s32k1xx_lpspi.c
index 2f90004..60ea04d 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_lpspi.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_lpspi.c
@@ -100,6 +100,25 @@
# error "Cannot enable both interrupt mode and DMA mode for SPI"
#endif
+/* Power management definitions */
+
+#if defined(CONFIG_PM) && !defined(CONFIG_S32K1XX_PM_SPI_ACTIVITY)
+# define CONFIG_S32K1XX_PM_SPI_ACTIVITY 10
+#endif
+
+#if defined(CONFIG_PM)
+#ifndef PM_IDLE_DOMAIN
+# define PM_IDLE_DOMAIN 0 /* Revisit */
+#endif
+#endif
+
+#if defined(CONFIG_PM_SPI0_STANDBY) || defined(CONFIG_PM_SPI0_SLEEP)
+# define CONFIG_PM_SPI0
+#endif
+#if defined(CONFIG_PM_SPI1_STANDBY) || defined(CONFIG_PM_SPI1_SLEEP)
+# define CONFIG_PM_SPI1
+#endif
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -177,6 +196,13 @@ static void s32k1xx_lpspi_recvblock(FAR struct spi_dev_s *dev,
size_t nwords);
#endif
+#ifdef CONFIG_PM
+static void up_pm_notify(struct pm_callback_s *cb, int dowmin,
+ enum pm_state_e pmstate);
+static int up_pm_prepare(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate);
+#endif
+
/* Initialization */
static void
@@ -324,6 +350,14 @@ static struct s32k1xx_lpspidev_s g_lpspi2dev =
};
#endif
+#ifdef CONFIG_PM
+static struct pm_callback_s g_spi1_pmcb =
+{
+ .notify = up_pm_notify,
+ .prepare = up_pm_prepare,
+};
+#endif
+
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -896,6 +930,8 @@ static int s32k1xx_lpspi_lock(FAR struct spi_dev_s *dev, bool lock)
FAR struct s32k1xx_lpspidev_s *priv = (FAR struct s32k1xx_lpspidev_s *)dev;
int ret;
+ /* It could be that this needs to be disabled for low level debugging */
+
if (lock)
{
ret = nxsem_wait_uninterruptible(&priv->exclsem);
@@ -1376,6 +1412,12 @@ static void s32k1xx_lpspi_exchange_nodma(FAR struct spi_dev_s *dev,
spiinfo("txbuffer=%p rxbuffer=%p nwords=%d\n", txbuffer, rxbuffer, nwords);
+#if defined(CONFIG_PM) && CONFIG_S32K1XX_PM_SPI_ACTIVITY > 0
+ /* Report serial activity to the power management logic */
+
+ pm_activity(PM_IDLE_DOMAIN, CONFIG_S32K1XX_PM_SPI_ACTIVITY);
+#endif
+
/* bit mode? */
framesize = s32k1xx_lpspi_9to16bitmode(priv);
@@ -1743,6 +1785,388 @@ static void s32k1xx_lpspi_bus_initialize(struct s32k1xx_lpspidev_s *priv)
}
/****************************************************************************
+ * Name: up_pm_notify
+ *
+ * Description:
+ * Notify the driver of new power state. This callback is called after
+ * all drivers have had the opportunity to prepare for the new power state.
+ *
+ * Input Parameters:
+ *
+ * cb - Returned to the driver. The driver version of the callback
+ * structure may include additional, driver-specific state data at
+ * the end of the structure.
+ *
+ * pmstate - Identifies the new PM state
+ *
+ * Returned Value:
+ * None - The driver already agreed to transition to the low power
+ * consumption state when when it returned OK to the prepare() call.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_PM
+static void up_pm_notify(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate)
+{
+# ifdef CONFIG_PM_SPI0
+
+ FAR struct s32k1xx_lpspidev_s *priv0 = NULL;
+
+ /* make the priv1ate struct for lpspi bus 0 */
+
+ priv0 = &g_lpspi0dev;
+
+# endif
+# ifdef CONFIG_PM_SPI1
+
+ FAR struct s32k1xx_lpspidev_s *priv1 = NULL;
+
+ /* make the priv1ate struct for lpspi bus 1 */
+
+ priv1 = &g_lpspi1dev;
+
+# endif
+
+ unsigned int count = 0; /* the amount of peripheral clocks to change */
+
+ peripheral_clock_source_t clock_source;
+
+ /* check if the transition is from the IDLE domain to the NORMAL domain */
+
+ /* or the mode is already done */
+
+ if (((pm_querystate(PM_IDLE_DOMAIN) == PM_IDLE) &&
+ (pmstate == PM_NORMAL)) ||
+ (((pm_querystate(PM_IDLE_DOMAIN) == pmstate))))
+ {
+ /* return */
+
+ return;
+ }
+
+ /* check which PM it is */
+
+ switch (pmstate)
+ {
+ /* in case it needs to change to the RUN mode */
+
+ case PM_NORMAL:
+ {
+ /* Logic for PM_NORMAL goes here */
+
+ /* set the right clock source to go back to RUN mode */
+
+ clock_source = CLK_SRC_SPLL_DIV2;
+
+# ifdef CONFIG_PM_SPI0
+
+ /* add 1 to count to do it for SPI0 */
+
+ count++;
+# endif
+
+# ifdef CONFIG_PM_SPI1
+
+ /* add 1 to count to do it for SPI1 */
+
+ count++;
+# endif
+ }
+ break;
+
+ default:
+ {
+ /* don't do anything, just return OK */
+ }
+ break;
+ }
+
+ /* check if the LPSPI needs to change */
+
+ if (count)
+ {
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config[] =
+ {
+# ifdef CONFIG_PM_SPI0
+
+ {
+ .clkname = LPSPI0_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ },
+# endif
+# ifdef CONFIG_PM_SPI1
+
+ {
+ .clkname = LPSPI1_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ }
+# endif
+ };
+
+# ifdef CONFIG_PM_SPI0
+
+ /* disable LPSP0 */
+
+ s32k1xx_lpspi_modifyreg32(priv0, S32K1XX_LPSPI_CR_OFFSET, 0,
+ !LPSPI_CR_MEN);
+
+# endif
+# ifdef CONFIG_PM_SPI1
+
+ /* disable LPSPI */
+
+ s32k1xx_lpspi_modifyreg32(priv1, S32K1XX_LPSPI_CR_OFFSET, 0,
+ !LPSPI_CR_MEN);
+
+# endif
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, clock_config);
+
+# ifdef CONFIG_PM_SPI0
+
+ /* Enable LPSP0 */
+
+ s32k1xx_lpspi_modifyreg32(priv0, S32K1XX_LPSPI_CR_OFFSET, 0,
+ LPSPI_CR_MEN);
+
+# endif
+# ifdef CONFIG_PM_SPI1
+
+ /* Enable LPSPI */
+
+ s32k1xx_lpspi_modifyreg32(priv1, S32K1XX_LPSPI_CR_OFFSET, 0,
+ LPSPI_CR_MEN);
+# endif
+
+ /* get the clock freq */
+ }
+
+ /* return */
+
+ return;
+}
+#endif
+
+/****************************************************************************
+ * Name: up_pm_prepare
+ *
+ * Description:
+ * Request the driver to prepare for a new power state. This is a warning
+ * that the system is about to enter into a new power state. The driver
+ * should begin whatever operations that may be required to enter power
+ * state. The driver may abort the state change mode by returning a
+ * non-zero value from the callback function.
+ *
+ * Input Parameters:
+ *
+ * cb - Returned to the driver. The driver version of the callback
+ * structure may include additional, driver-specific state data at
+ * the end of the structure.
+ *
+ * pmstate - Identifies the new PM state
+ *
+ * Returned Value:
+ * Zero - (OK) means the event was successfully processed and that the
+ * driver is prepared for the PM state change.
+ *
+ * Non-zero - means that the driver is not prepared to perform the tasks
+ * needed achieve this power setting and will cause the state
+ * change to be aborted. NOTE: The prepare() method will also
+ * be called when reverting from lower back to higher power
+ * consumption modes (say because another driver refused a
+ * lower power state change). Drivers are not permitted to
+ * return non-zero values when reverting back to higher power
+ * consumption modes!
+ *
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_PM
+static int up_pm_prepare(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate)
+{
+ /* Logic to prepare for a reduced power state goes here. */
+
+# ifdef CONFIG_PM_SPI0
+ FAR struct s32k1xx_lpspidev_s *priv0 = NULL;
+
+ /* make the private struct for lpspi bus 0 */
+
+ priv0 = &g_lpspi0dev;
+# endif
+# ifdef CONFIG_PM_SPI1
+ FAR struct s32k1xx_lpspidev_s *priv1 = NULL;
+
+ /* make the private struct for lpspi bus 1 */
+
+ priv1 = &g_lpspi1dev;
+# endif
+
+ unsigned int count = 0; /* the amount of peripheral clocks to change */
+
+ peripheral_clock_source_t clock_source;
+
+ /* check if the transition to the mode is already done */
+
+ if (pm_querystate(PM_IDLE_DOMAIN) == pmstate)
+ {
+ /* return */
+
+ return OK;
+ }
+
+ /* check which PM it is */
+
+ switch (pmstate)
+ {
+ /* in case it needs to prepare for VLPR mode */
+
+ case PM_STANDBY:
+ {
+ /* Logic for PM_STANDBY goes here */
+
+ /* set the right clock source */
+
+ clock_source = CLK_SRC_SIRC_DIV2;
+
+# ifdef CONFIG_PM_SPI0_STANDBY
+
+ /* increase count to change the SPI0 */
+
+ count++;
+
+# endif
+# ifdef CONFIG_PM_SPI1_STANDBY
+
+ /* increase count to change the SPI1 */
+
+ count++;
+
+# endif
+ }
+ break;
+
+ /* in case it needs to prepare for VLPR mode */
+
+ case PM_SLEEP:
+ {
+ /* Logic for PM_STANDBY goes here */
+
+ /* set the right clock source */
+
+ clock_source = CLK_SRC_SIRC_DIV2;
+
+# ifdef CONFIG_PM_SPI0_SLEEP
+
+ /* increase count to change the SPI0 */
+
+ count++;
+
+# endif
+# ifdef CONFIG_PM_SPI1_SLEEP
+
+ /* increase count to change the SPI1 */
+
+ count++;
+
+# endif
+ }
+ break;
+
+ default:
+ {
+ /* don't do anything, just return OK */
+ }
+ break;
+ }
+
+ /* check if you need to change something */
+
+ if (count)
+ {
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config[] =
+ {
+# ifdef CONFIG_PM_SPI0
+ {
+ .clkname = LPSPI0_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ },
+# endif
+# ifdef CONFIG_PM_SPI1
+ {
+ .clkname = LPSPI1_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ }
+# endif
+ };
+
+# ifdef CONFIG_PM_SPI0
+
+ /* disable LPSPI0 */
+
+ s32k1xx_lpspi_modifyreg32(priv0, S32K1XX_LPSPI_CR_OFFSET, 0,
+ !LPSPI_CR_MEN);
+
+# endif
+# ifdef CONFIG_PM_SPI1
+
+ /* disable LPSPI1 */
+
+ s32k1xx_lpspi_modifyreg32(priv1, S32K1XX_LPSPI_CR_OFFSET, 0,
+ !LPSPI_CR_MEN);
+
+# endif
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, clock_config);
+
+# ifdef CONFIG_PM_SPI0
+
+ /* Enable LPSPI */
+
+ s32k1xx_lpspi_modifyreg32(priv0, S32K1XX_LPSPI_CR_OFFSET, 0,
+ LPSPI_CR_MEN);
+
+# endif
+# ifdef CONFIG_PM_SPI1
+
+ /* Enable LPSPI */
+
+ s32k1xx_lpspi_modifyreg32(priv1, S32K1XX_LPSPI_CR_OFFSET, 0,
+ LPSPI_CR_MEN);
+
+# endif
+ }
+
+ /* get the clock freq */
+
+ /* return OK */
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
* Public Functions
****************************************************************************/
@@ -1794,6 +2218,17 @@ FAR struct spi_dev_s *s32k1xx_lpspibus_initialize(int bus)
#ifdef CONFIG_S32K1XX_LPSPI1
if (bus == 1)
{
+ #ifdef CONFIG_PM
+ #if defined(CONFIG_PM_SPI_STANDBY) || defined(CONFIG_PM_SPI_SLEEP)
+ int ret;
+
+ /* Register to receive power management callbacks */
+
+ ret = pm_register(&g_spi1_pmcb);
+ DEBUGASSERT(ret == OK);
+ UNUSED(ret);
+ #endif
+ #endif
/* Select SPI1 */
priv = &g_lpspi1dev;
diff --git a/arch/arm/src/s32k1xx/s32k1xx_periphclocks.c b/arch/arm/src/s32k1xx/s32k1xx_periphclocks.c
index c05b618..c5c0d15 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_periphclocks.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_periphclocks.c
@@ -107,29 +107,6 @@ static uint32_t *s32k1xx_get_pclkctrl(enum clock_names_e clkname)
}
/****************************************************************************
- * Name: s32k1xx_pclk_disable
- *
- * Description:
- * This function enables/disables the clock for a given peripheral.
- *
- * Input Parameters:
- * clkname - The name of the peripheral clock to be disabled
- * enable - true: Enable the peripheral clock.
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-static void s32k1xx_pclk_disable(enum clock_names_e clkname)
-{
- uint32_t *ctrlp = s32k1xx_get_pclkctrl(clkname);
- DEBUGASSERT(ctrlp != NULL);
-
- *ctrlp &= ~PCC_CGC;
-}
-
-/****************************************************************************
* Name: s32k1xx_set_pclkctrl
*
* Description:
@@ -279,7 +256,7 @@ void s32k1xx_periphclocks(unsigned int count,
{
/* Disable the peripheral clock */
- s32k1xx_pclk_disable(pclks->clkname);
+ s32k1xx_pclk_enable(pclks->clkname, false);
/* Set peripheral clock control */
@@ -398,3 +375,39 @@ int s32k1xx_get_pclkfreq(enum clock_names_e clkname, uint32_t *frequency)
return ret;
}
+
+/****************************************************************************
+ * Name: s32k1xx_pclk_enable
+ *
+ * Description:
+ * This function enables/disables the clock for a given peripheral.
+ *
+ * Input Parameters:
+ * clkname - The name of the peripheral clock to be disabled
+ * enable - true: Enable the peripheral clock.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void s32k1xx_pclk_enable(enum clock_names_e clkname, bool enable)
+{
+ uint32_t *ctrlp = s32k1xx_get_pclkctrl(clkname);
+ DEBUGASSERT(ctrlp != NULL);
+
+ /* check if it needs to be enabled */
+
+ if (enable)
+ {
+ /* enable it */
+
+ *ctrlp |= PCC_CGC;
+ }
+ else
+ {
+ /* disable it */
+
+ *ctrlp &= ~PCC_CGC;
+ }
+}
diff --git a/arch/arm/src/s32k1xx/s32k1xx_periphclocks.h b/arch/arm/src/s32k1xx/s32k1xx_periphclocks.h
index 028a99a..604414e 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_periphclocks.h
+++ b/arch/arm/src/s32k1xx/s32k1xx_periphclocks.h
@@ -267,6 +267,23 @@ void s32k1xx_periphclocks(unsigned int count,
int s32k1xx_get_pclkfreq(enum clock_names_e clkname, uint32_t *frequency);
+/****************************************************************************
+ * Name: s32k1xx_pclk_enable
+ *
+ * Description:
+ * This function enables/disables the clock for a given peripheral.
+ *
+ * Input Parameters:
+ * clkname - The name of the peripheral clock to be disabled
+ * enable - true: Enable the peripheral clock.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void s32k1xx_pclk_enable(enum clock_names_e clkname, bool enable);
+
#undef EXTERN
#if defined(__cplusplus)
}
diff --git a/arch/arm/src/s32k1xx/s32k1xx_pminitialize.c b/arch/arm/src/s32k1xx/s32k1xx_pminitialize.c
new file mode 100644
index 0000000..096d6bb
--- /dev/null
+++ b/arch/arm/src/s32k1xx/s32k1xx_pminitialize.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * arch/arm/src/s32k1xx/s32k1xx_pminitialize.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 <nuttx/power/pm.h>
+
+#include "arm_internal.h"
+
+#ifdef CONFIG_PM
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_pminitialize
+ *
+ * Description:
+ * This function is called by MCU-specific logic at power-on reset in
+ * order to provide one-time initialization the power management subsystem.
+ * This function must be called *very* early in the initialization sequence
+ * *before* any other device drivers are initialized (since they may
+ * attempt to register with the power management subsystem).
+ *
+ * Input Parameters:
+ * None.
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+void arm_pminitialize(void)
+{
+ /* Then initialize the NuttX power management subsystem proper */
+
+ pm_initialize();
+}
+
+#endif /* CONFIG_PM */
diff --git a/arch/arm/src/s32k1xx/s32k1xx_serial.c b/arch/arm/src/s32k1xx/s32k1xx_serial.c
index 6f8c379..63724a6 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_serial.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_serial.c
@@ -57,6 +57,8 @@
#include "s32k1xx_pin.h"
#include "s32k1xx_lowputc.h"
+#include "s32k1xx_periphclocks.h"
+
#ifdef USE_SERIALDRIVER
/****************************************************************************
@@ -132,9 +134,20 @@
#endif
#if defined(CONFIG_PM)
+#ifndef PM_IDLE_DOMAIN
# define PM_IDLE_DOMAIN 0 /* Revisit */
#endif
+#endif
+#if defined(CONFIG_PM_SERIAL0_STANDBY) || defined(CONFIG_PM_SERIAL0_SLEEP)
+# define CONFIG_PM_SERIAL0
+#endif
+#if defined(CONFIG_PM_SERIAL1_STANDBY) || defined(CONFIG_PM_SERIAL1_SLEEP)
+# define CONFIG_PM_SERIAL1
+#endif
+#if defined(CONFIG_PM_SERIAL2_STANDBY) || defined(CONFIG_PM_SERIAL2_SLEEP)
+# define CONFIG_PM_SERIAL2
+#endif
/****************************************************************************
* Private Types
****************************************************************************/
@@ -508,8 +521,14 @@ static int s32k1xx_setup(struct uart_dev_s *dev)
config.invrts = priv->inviflow; /* Inversion of outbound flow control */
#endif
+ /* configure the LPUART */
+
ret = s32k1xx_lpuart_configure(priv->uartbase, &config);
+ /* get the current interrupt bits and place them in ie */
+
+ /* (used to use the interrupts) */
+
priv->ie = s32k1xx_serialin(priv, S32K1XX_LPUART_CTRL_OFFSET) & \
LPUART_ALL_INTS;
return ret;
@@ -536,7 +555,13 @@ static void s32k1xx_shutdown(struct uart_dev_s *dev)
/* Disable the UART */
+ /* set the reset bit */
+
s32k1xx_serialout(priv, S32K1XX_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST);
+
+ /* clear the reset bit again */
+
+ s32k1xx_serialout(priv, S32K1XX_LPUART_GLOBAL_OFFSET, 0);
}
/****************************************************************************
@@ -1114,38 +1139,205 @@ static bool s32k1xx_txempty(struct uart_dev_s *dev)
static void up_pm_notify(struct pm_callback_s *cb, int domain,
enum pm_state_e pmstate)
{
- switch (pmstate)
+ unsigned int count = 0; /* the amount of peripheral clocks to change */
+
+ peripheral_clock_source_t clock_source;
+
+ #ifdef CONFIG_PM_SERIAL0
+ struct s32k1xx_uart_s *priv0 = g_uart0port.priv;
+ #endif
+ #ifdef CONFIG_PM_SERIAL1
+ struct s32k1xx_uart_s *priv1 = g_uart1port.priv;
+ #endif
+ #ifdef CONFIG_PM_SERIAL2
+ struct s32k1xx_uart_s *priv2 = g_uart2port.priv;
+ #endif
+
+ uint32_t ret_reg = 0;
+
+ /* check if the transition is from the IDLE domain to the NORMAL domain */
+
+ /* or the mode is already done */
+
+ if (((pm_querystate(PM_IDLE_DOMAIN) == PM_IDLE) &&
+ (pmstate == PM_NORMAL)) ||
+ (((pm_querystate(PM_IDLE_DOMAIN) == pmstate))))
{
- case(PM_NORMAL):
- {
- /* Logic for PM_NORMAL goes here */
- }
- break;
+ /* return */
- case(PM_IDLE):
- {
- /* Logic for PM_IDLE goes here */
- }
- break;
+ return;
+ }
- case(PM_STANDBY):
- {
- /* Logic for PM_STANDBY goes here */
- }
- break;
+ /* check which PM it is */
- case(PM_SLEEP):
- {
- /* Logic for PM_SLEEP goes here */
- }
- break;
+ switch (pmstate)
+ {
+ /* in case it needs to change to the RUN mode */
+
+ case PM_NORMAL:
+ {
+ /* Logic for PM_NORMAL goes here */
- default:
+ /* set the right clock source to go back to RUN mode */
- /* Should not get here */
+ clock_source = CLK_SRC_SPLL_DIV2;
- break;
+ count = 1;
+ }
+ break;
+ default:
+ {
+ /* don't do anything, just return OK */
}
+ break;
+ }
+
+ /* check if something needs to change */
+
+ if (count)
+ {
+ #ifdef CONFIG_PM_SERIAL0
+
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config0 =
+ {
+ .clkname = LPUART0_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ };
+
+ /* read the FIFO register */
+
+ ret_reg = getreg32(priv0->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* make the value */
+
+ ret_reg |= (LPUART_FIFO_RXFLUSH + LPUART_FIFO_TXFLUSH);
+
+ /* write the new value */
+
+ putreg32(ret_reg, priv0->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart0port);
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, &clock_config0);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart0port);
+
+ /* set up the LPUART1 again for the new mode */
+
+ s32k1xx_setup(&g_uart0port);
+
+ /* enable the interrupts */
+
+ s32k1xx_rxint(&g_uart0port, true);
+ s32k1xx_txint(&g_uart0port, true);
+
+ #endif
+ #ifdef CONFIG_PM_SERIAL1
+
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config1 =
+ {
+ .clkname = LPUART1_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ };
+
+ /* read the FIFO register */
+
+ ret_reg = getreg32(priv1->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* make the value */
+
+ ret_reg |= (LPUART_FIFO_RXFLUSH + LPUART_FIFO_TXFLUSH);
+
+ /* write the new value */
+
+ putreg32(ret_reg, priv1->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart1port);
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, &clock_config1);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart1port);
+
+ /* set up the LPUART1 again for the new mode */
+
+ s32k1xx_setup(&g_uart1port);
+
+ /* enable the interrupts */
+
+ s32k1xx_rxint(&g_uart1port, true);
+ s32k1xx_txint(&g_uart1port, true);
+
+ #endif
+ #ifdef CONFIG_PM_SERIAL2
+
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config2 =
+ {
+ .clkname = LPUART2_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ };
+
+ /* read the FIFO register */
+
+ ret_reg = getreg32(priv2->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* make the value */
+
+ ret_reg |= (LPUART_FIFO_RXFLUSH + LPUART_FIFO_TXFLUSH);
+
+ /* write the new value */
+
+ putreg32(ret_reg, priv2->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart2port);
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, &clock_config2);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart2port);
+
+ /* set up the LPUART1 again for the new mode */
+
+ s32k1xx_setup(&g_uart2port);
+
+ /* enable the interrupts */
+
+ s32k1xx_rxint(&g_uart2port, true);
+ s32k1xx_txint(&g_uart2port, true);
+
+ #endif
+ }
}
#endif
@@ -1189,6 +1381,209 @@ static int up_pm_prepare(struct pm_callback_s *cb, int domain,
{
/* Logic to prepare for a reduced power state goes here. */
+ unsigned int count = 1; /* the amount of peripheral clocks to change */
+
+ peripheral_clock_source_t clock_source;
+
+ #ifdef CONFIG_PM_SERIAL0
+ struct s32k1xx_uart_s *priv0 = (struct s32k1xx_uart_s *)g_uart0port.priv;
+ #endif
+ #ifdef CONFIG_PM_SERIAL1
+ struct s32k1xx_uart_s *priv1 = (struct s32k1xx_uart_s *)g_uart1port.priv;
+ #endif
+ #ifdef CONFIG_PM_SERIAL2
+ struct s32k1xx_uart_s *priv2 = (struct s32k1xx_uart_s *)g_uart2port.priv;
+ #endif
+
+ uint32_t ret_reg = 0;
+
+ /* check if the transition to the mode is already done */
+
+ if (pm_querystate(PM_IDLE_DOMAIN) == pmstate)
+ {
+ /* return */
+
+ return OK;
+ }
+
+ /* check which PM it is */
+
+ switch (pmstate)
+ {
+ /* in case it needs to prepare for VLPR mode */
+
+ case PM_STANDBY:
+ {
+ /* Logic for PM_STANDBY goes here */
+
+ /* set the right clock source */
+
+ clock_source = CLK_SRC_SIRC_DIV2;
+ }
+ break;
+
+ /* in case it needs to prepare for sleep mode */
+
+ case PM_SLEEP:
+ {
+ /* Logic for PM_SLEEP goes here */
+
+ /* set the right clock source */
+
+ clock_source = CLK_SRC_SIRC_DIV2;
+ }
+ break;
+ default:
+ {
+ /* don't do anything, just return OK */
+
+ return OK;
+ }
+ break;
+ }
+
+ #ifdef CONFIG_PM_SERIAL0
+
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config0 =
+ {
+ .clkname = LPUART0_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ };
+
+ /* read the FIFO register */
+
+ ret_reg = getreg32(priv0->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* make the value */
+
+ ret_reg |= (LPUART_FIFO_RXFLUSH + LPUART_FIFO_TXFLUSH);
+
+ /* write the new value */
+
+ putreg32(ret_reg, priv0->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart0port);
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, &clock_config0);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart0port);
+
+ /* set up the LPUART1 again for the new mode */
+
+ s32k1xx_setup(&g_uart0port);
+
+ /* enable the interrupts */
+
+ s32k1xx_rxint(&g_uart0port, true);
+ s32k1xx_txint(&g_uart0port, true);
+
+ #endif
+ #ifdef CONFIG_PM_SERIAL1
+
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config1 =
+ {
+ .clkname = LPUART1_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ };
+
+ /* read the FIFO register */
+
+ ret_reg = getreg32(priv1->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* make the value */
+
+ ret_reg |= (LPUART_FIFO_RXFLUSH + LPUART_FIFO_TXFLUSH);
+
+ /* write the new value */
+
+ putreg32(ret_reg, priv1->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart1port);
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, &clock_config1);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart1port);
+
+ /* set up the LPUART1 again for the new mode */
+
+ s32k1xx_setup(&g_uart1port);
+
+ /* enable the interrupts */
+
+ s32k1xx_rxint(&g_uart1port, true);
+ s32k1xx_txint(&g_uart1port, true);
+
+ #endif
+ #ifdef CONFIG_PM_SERIAL2
+
+ /* make the peripheral clock config struct */
+
+ const struct peripheral_clock_config_s clock_config2 =
+ {
+ .clkname = LPUART2_CLK,
+ .clkgate = true,
+ .clksrc = clock_source,
+ .frac = MULTIPLY_BY_ONE,
+ .divider = 1,
+ };
+
+ /* read the FIFO register */
+
+ ret_reg = getreg32(priv2->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* make the value */
+
+ ret_reg |= (LPUART_FIFO_RXFLUSH + LPUART_FIFO_TXFLUSH);
+
+ /* write the new value */
+
+ putreg32(ret_reg, priv2->uartbase + S32K1XX_LPUART_FIFO_OFFSET);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart2port);
+
+ /* change the clock config for the new mode */
+
+ s32k1xx_periphclocks(count, &clock_config2);
+
+ /* shutdown the LPUART1 (soft reset) */
+
+ s32k1xx_shutdown(&g_uart2port);
+
+ /* set up the LPUART1 again for the new mode */
+
+ s32k1xx_setup(&g_uart2port);
+
+ /* enable the interrupts */
+
+ s32k1xx_rxint(&g_uart2port, true);
+ s32k1xx_txint(&g_uart2port, true);
+
+ #endif
+
return OK;
}
#endif
@@ -1236,6 +1631,8 @@ void s32k1xx_earlyserialinit(void)
void arm_serialinit(void)
{
#ifdef CONFIG_PM
+ #if defined(CONFIG_PM_SERIAL_STANDBY) || defined(CONFIG_PM_SERIAL_SLEEP)
+
int ret;
/* Register to receive power management callbacks */
@@ -1243,6 +1640,7 @@ void arm_serialinit(void)
ret = pm_register(&g_serial_pmcb);
DEBUGASSERT(ret == OK);
UNUSED(ret);
+ #endif
#endif
#ifdef CONSOLE_DEV