/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016, NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include "fsl_common.h"
#include "fsl_power.h"

/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.power"
#endif

/*******************************************************************************
 * Variables
 ******************************************************************************/

/*******************************************************************************
 * Definitions
 ******************************************************************************/
/** @brief  Low Power main structure */
typedef enum
{
    VD_AON       = 0x0, /*!< Digital Always On power domain */
    VD_MEM       = 0x1, /*!< Memories (SRAM) power domain   */
    VD_DCDC      = 0x2, /*!< Core logic power domain        */
    VD_DEEPSLEEP = 0x3  /*!< Core logic power domain        */
} LPC_POWER_DOMAIN_T;

/**
 * @brief LDO_FLASH_NV & LDO_USB voltage settings
 */
typedef enum _v_flashnv
{
    V_LDOFLASHNV_1P650 = 0, /*!< 0.95  V */
    V_LDOFLASHNV_1P700 = 1, /*!< 0.975 V */
    V_LDOFLASHNV_1P750 = 2, /*!< 1     V */
    V_LDOFLASHNV_0P800 = 3, /*!< 1.025 V */
    V_LDOFLASHNV_1P850 = 4, /*!< 1.050 V */
    V_LDOFLASHNV_1P900 = 5, /*!< 1.075 V */
    V_LDOFLASHNV_1P950 = 6, /*!< 1.1   V */
    V_LDOFLASHNV_2P000 = 7  /*!< 1.125 V */
} v_flashnv_t;

/** @brief  Low Power main structure */
typedef struct
{                              /*     */
    __IO uint32_t CFG;         /*!< Low Power Mode Configuration, and miscallenous options  */
    __IO uint32_t PDCTRL0;     /*!< Power Down control : controls power of various modules
                                 in the different Low power modes, including ROM */
    __IO uint32_t SRAMRETCTRL; /*!< Power Down control : controls power SRAM instances
                                 in the different Low power modes */
    __IO uint32_t CPURETCTRL;  /*!< CPU0 retention control : controls CPU retention parameters in POWER DOWN modes */
    __IO uint64_t VOLTAGE;     /*!< Voltage control in Low Power Modes */
    __IO uint64_t WAKEUPSRC;   /*!< Wake up sources control for sleepcon */
    __IO uint64_t WAKEUPINT;   /*!< Wake up sources control for ARM */
    __IO uint32_t HWWAKE;      /*!< Interrupt that can postpone power down modes
                                 in case an interrupt is pending when the processor request deepsleep */
    __IO uint32_t WAKEUPIOSRC; /*!< Wake up I/O sources in DEEP POWER DOWN mode */
    __IO uint32_t TIMERCFG;    /*!< Wake up timers configuration */
    __IO uint32_t TIMERCOUNT;  /*!< Wake up Timer count*/
    __IO uint32_t POWERCYCLE;  /*!< Cancels entry in Low Power mode if set with 0xDEADABBA (might be used by some
                                 interrupt handlers)*/
} LPC_LOWPOWER_T;

/*   */
#define LOWPOWER_POWERCYCLE_CANCELLED 0xDEADABBAUL /*!<    */

/**
 * @brief SRAM Low Power Modes
 */
#define LOWPOWER_SRAM_LPMODE_MASK      (0xFUL)
#define LOWPOWER_SRAM_LPMODE_ACTIVE    (0x6UL) /*!< SRAM functional mode                                */
#define LOWPOWER_SRAM_LPMODE_SLEEP     (0xFUL) /*!< SRAM Sleep mode (Data retention, fast wake up)      */
#define LOWPOWER_SRAM_LPMODE_DEEPSLEEP (0x8UL) /*!< SRAM Deep Sleep mode (Data retention, slow wake up) */
#define LOWPOWER_SRAM_LPMODE_SHUTDOWN  (0x9UL) /*!< SRAM Shut Down mode (no data retention)             */
#define LOWPOWER_SRAM_LPMODE_POWERUP   (0xAUL) /*!< SRAM is powering up                                 */

/**
 * @brief Wake up timers configuration in Low Power Modes
 */
#define LOWPOWER_TIMERCFG_CTRL_INDEX   0
#define LOWPOWER_TIMERCFG_CTRL_MASK    (0x1UL << LOWPOWER_TIMERCFG_CTRL_INDEX)
#define LOWPOWER_TIMERCFG_TIMER_INDEX  1
#define LOWPOWER_TIMERCFG_TIMER_MASK   (0x7UL << LOWPOWER_TIMERCFG_TIMER_INDEX)
#define LOWPOWER_TIMERCFG_OSC32K_INDEX 4
#define LOWPOWER_TIMERCFG_OSC32K_MASK  (0x1UL << LOWPOWER_TIMERCFG_OSC32K_INDEX)

#define LOWPOWER_TIMERCFG_CTRL_DISABLE 0 /*!< Wake Timer Disable */
#define LOWPOWER_TIMERCFG_CTRL_ENABLE  1 /*!< Wake Timer Enable  */

/**
 * @brief Primary Wake up timers configuration in Low Power Modes
 */
#define LOWPOWER_TIMERCFG_TIMER_RTC1KHZ 0 /*!< 1 KHz Real Time Counter (RTC) used as wake up source */
#define LOWPOWER_TIMERCFG_TIMER_RTC1HZ  1 /*!< 1 Hz Real Time Counter (RTC) used as wake up source  */
#define LOWPOWER_TIMERCFG_TIMER_OSTIMER 2 /*!< OS Event Timer used as wake up source                */

#define LOWPOWER_TIMERCFG_OSC32K_FRO32KHZ  0 /*!< Wake up Timers uses FRO 32 KHz as clock source      */
#define LOWPOWER_TIMERCFG_OSC32K_XTAL32KHZ 1 /*!< Wake up Timers uses Chrystal 32 KHz as clock source */

//! @brief Interface for lowpower functions
typedef struct LowpowerDriverInterface
{
    void (*power_cycle_cpu_and_flash)(void);
    void (*set_lowpower_mode)(LPC_LOWPOWER_T *p_lowpower_cfg);
} lowpower_driver_interface_t;

/**<  DCDC Power Profiles */
typedef enum
{
    DCDC_POWER_PROFILE_LOW,    /**<  LOW (for CPU frequencies below DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ) */
    DCDC_POWER_PROFILE_MEDIUM, /**<  MEDIUM (for CPU frequencies between DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ and
                                  DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ) */
    DCDC_POWER_PROFILE_HIGH,   /**<  HIGH (for CPU frequencies between DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ and
                                  DCDC_POWER_PROFILE_HIGH_MAX_FREQ_HZ) */
} lowpower_dcdc_power_profile_enum;

/**<  Manufacturing Process Corners */
typedef enum
{
    PROCESS_CORNER_SSS,    /**< Slow Corner Process */
    PROCESS_CORNER_NNN,    /**< Nominal Corner Process */
    PROCESS_CORNER_FFF,    /**< Fast Corner Process */
    PROCESS_CORNER_OTHERS, /**< SFN, SNF, NFS, Poly Res ... Corner Process */
} lowpower_process_corner_enum;

/**
 * @brief DCDC voltage settings
 */
typedef enum _v_dcdc
{
    V_DCDC_0P950 = 0, /*!< 0.95  V */
    V_DCDC_0P975 = 1, /*!< 0.975 V */
    V_DCDC_1P000 = 2, /*!< 1     V */
    V_DCDC_1P025 = 3, /*!< 1.025 V */
    V_DCDC_1P050 = 4, /*!< 1.050 V */
    V_DCDC_1P075 = 5, /*!< 1.075 V */
    V_DCDC_1P100 = 6, /*!< 1.1   V */
    V_DCDC_1P125 = 7, /*!< 1.125 V */
    V_DCDC_1P150 = 8, /*!< 1.150 V */
    V_DCDC_1P175 = 9, /*!< 1.175 V */
    V_DCDC_1P200 = 10 /*!< 1.2   V */
} v_dcdc_t;

/**
 * @brief Deep Sleep LDO voltage settings
 */
typedef enum _v_deepsleep
{
    V_DEEPSLEEP_0P900 = 0, /*!< 0.9   V */
    V_DEEPSLEEP_0P925 = 1, /*!< 0.925 V */
    V_DEEPSLEEP_0P950 = 2, /*!< 0.95  V */
    V_DEEPSLEEP_0P975 = 3, /*!< 0.975 V */
    V_DEEPSLEEP_1P000 = 4, /*!< 1.000 V */
    V_DEEPSLEEP_1P025 = 5, /*!< 1.025 V */
    V_DEEPSLEEP_1P050 = 6, /*!< 1.050 V */
    V_DEEPSLEEP_1P075 = 7  /*!< 1.075 V */
} v_deepsleep_t;

/**
 * @brief Always On and Memories LDO voltage settings
 */
typedef enum _v_ao
{
    V_AO_0P700 = 1,  /*!< 0.7   V */
    V_AO_0P725 = 2,  /*!< 0.725 V */
    V_AO_0P750 = 3,  /*!< 0.75  V */
    V_AO_0P775 = 4,  /*!< 0.775 V */
    V_AO_0P800 = 5,  /*!< 0.8   V */
    V_AO_0P825 = 6,  /*!< 0.825 V */
    V_AO_0P850 = 7,  /*!< 0.85  V */
    V_AO_0P875 = 8,  /*!< 0.875 V */
    V_AO_0P900 = 9,  /*!< 0.9   V */
    V_AO_0P960 = 10, /*!< 0.96  V */
    V_AO_0P970 = 11, /*!< 0.97  V */
    V_AO_0P980 = 12, /*!< 0.98  V */
    V_AO_0P990 = 13, /*!< 0.99  V */
    V_AO_1P000 = 14, /*!< 1     V */
    V_AO_1P010 = 15, /*!< 1.01  V */
    V_AO_1P020 = 16, /*!< 1.02  V */
    V_AO_1P030 = 17, /*!< 1.03  V */
    V_AO_1P040 = 18, /*!< 1.04  V */
    V_AO_1P050 = 19, /*!< 1.05  V */
    V_AO_1P060 = 20, /*!< 1.06  V */
    V_AO_1P070 = 21, /*!< 1.07  V */
    V_AO_1P080 = 22, /*!< 1.08  V */
    V_AO_1P090 = 23, /*!< 1.09  V */
    V_AO_1P100 = 24, /*!< 1.1   V */
    V_AO_1P110 = 25, /*!< 1.11  V */
    V_AO_1P120 = 26, /*!< 1.12  V */
    V_AO_1P130 = 27, /*!< 1.13  V */
    V_AO_1P140 = 28, /*!< 1.14  V */
    V_AO_1P150 = 29, /*!< 1.15  V */
    V_AO_1P160 = 30, /*!< 1.16  V */
    V_AO_1P220 = 31  /*!< 1.22  V */
} v_ao_t;

/* Low Power modes  */
#define LOWPOWER_CFG_LPMODE_INDEX          0
#define LOWPOWER_CFG_LPMODE_MASK           (0x3UL << LOWPOWER_CFG_LPMODE_INDEX)
#define LOWPOWER_CFG_SELCLOCK_INDEX        2
#define LOWPOWER_CFG_SELCLOCK_MASK         (0x1UL << LOWPOWER_CFG_SELCLOCK_INDEX)
#define LOWPOWER_CFG_SELMEMSUPPLY_INDEX    3
#define LOWPOWER_CFG_SELMEMSUPPLY_MASK     (0x1UL << LOWPOWER_CFG_SELMEMSUPPLY_INDEX)
#define LOWPOWER_CFG_MEMLOWPOWERMODE_INDEX 4
#define LOWPOWER_CFG_MEMLOWPOWERMODE_MASK  (0x1UL << LOWPOWER_CFG_MEMLOWPOWERMODE_INDEX)
#define LOWPOWER_CFG_LDODEEPSLEEPREF_INDEX 5
#define LOWPOWER_CFG_LDODEEPSLEEPREF_MASK  (0x1UL << LOWPOWER_CFG_LDODEEPSLEEPREF_INDEX)

#define LOWPOWER_CFG_LPMODE_ACTIVE        0 /*!< ACTIVE mode          */
#define LOWPOWER_CFG_LPMODE_DEEPSLEEP     1 /*!< DEEP SLEEP mode      */
#define LOWPOWER_CFG_LPMODE_POWERDOWN     2 /*!< POWER DOWN mode      */
#define LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN 3 /*!< DEEP POWER DOWN mode */
#define LOWPOWER_CFG_LPMODE_SLEEP         4 /*!< SLEEP mode */

#define LOWPOWER_CFG_SELCLOCK_1MHZ 0 /*!< The 1 MHz clock is used during the configuration of the PMC */
#define LOWPOWER_CFG_SELCLOCK_12MHZ \
    1 /*!< The 12 MHz clock is used during the configuration of the PMC (to speed up PMC configuration process)*/

#define LOWPOWER_CFG_SELMEMSUPPLY_LDOMEM 0 /*!< In DEEP SLEEP power mode, the Memories are supplied by the LDO_MEM */
#define LOWPOWER_CFG_SELMEMSUPPLY_LDODEEPSLEEP \
    1 /*!< In DEEP SLEEP power mode, the Memories are supplied by the LDO_DEEP_SLEEP (or DCDC) */

#define LOWPOWER_CFG_MEMLOWPOWERMODE_SOURCEBIASING                                                                     \
    0 /*!< All SRAM instances use "Source Biasing" as low power mode technic (it is recommended to set LDO_MEM as high \
         as possible -- 1.1V typical -- during low power mode) */
#define LOWPOWER_CFG_MEMLOWPOWERMODE_VOLTAGESCALING                                                                    \
    1 /*!< All SRAM instances use "Voltage Scaling" as low power mode technic (it is recommended to set LDO_MEM as low \
         as possible -- down to 0.7V -- during low power mode) */

/* CPU Retention Control*/
#define LOWPOWER_CPURETCTRL_ENA_INDEX           0
#define LOWPOWER_CPURETCTRL_ENA_MASK            (0x1UL << LOWPOWER_CPURETCTRL_ENA_INDEX)
#define LOWPOWER_CPURETCTRL_MEMBASE_INDEX       1
#define LOWPOWER_CPURETCTRL_MEMBASE_MASK        (0x1FFFUL << LOWPOWER_CPURETCTRL_MEMBASE_INDEX)
#define LOWPOWER_CPURETCTRL_RETDATALENGTH_INDEX 14
#define LOWPOWER_CPURETCTRL_RETDATALENGTH_MASK  (0x3FFUL << LOWPOWER_CPURETCTRL_RETDATALENGTH_INDEX)

/* Voltgae setting*/
#define DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ \
    (72000000U) /* Maximum System Frequency allowed with DCDC Power Profile LOW */
#define DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ \
    (100000000U) /* Maximum System Frequency allowed with DCDC Power Profile MEDIUM */
#define DCDC_POWER_PROFILE_HIGH_MAX_FREQ_HZ \
    (150000000U)                       /* Maximum System Frequency allowed with DCDC Power Profile HIGH */
#define PROCESS_NNN_AVG_HZ (19300000U) /* Average Ring OScillator value for Nominal (NNN) Manufacturing Process */
#define PROCESS_NNN_STD_HZ \
    (400000U) /* Standard Deviation Ring OScillator value for Nominal (NNN) Manufacturing Process */
#define PROCESS_NNN_LIMITS \
    (6U) /* Nominal (NNN) Manufacturing Process Ring Oscillator values limit (with respect to the Average value) */
#define PROCESS_NNN_MIN_HZ \
    (PROCESS_NNN_AVG_HZ -  \
     (PROCESS_NNN_LIMITS * \
      PROCESS_NNN_STD_HZ)) /* Minimum Ring OScillator value for Nominal (NNN) Manufacturing Process */
#define PROCESS_NNN_MAX_HZ \
    (PROCESS_NNN_AVG_HZ +  \
     (PROCESS_NNN_LIMITS * \
      PROCESS_NNN_STD_HZ))         /* Maximum Ring OScillator value for Nominal (NNN) Manufacturing Process */
#define VOLTAGE_SSS_LOW_MV (1100U) /* Voltage Settings for : Process=SSS, DCDC Power Profile=LOW */
#define VOLTAGE_SSS_MED_MV (1150U) /* Voltage Settings for : Process=SSS, DCDC Power Profile=MEDIUM */
#define VOLTAGE_SSS_HIG_MV (1200U) /* Voltage Settings for : Process=SSS, DCDC Power Profile=HIGH */
#define VOLTAGE_NNN_LOW_MV (1050U) /* Voltage Settings for : Process=NNN, DCDC Power Profile=LOW */
#define VOLTAGE_NNN_MED_MV (1075U) /* Voltage Settings for : Process=NNN, DCDC Power Profile=MEDIUM */
#define VOLTAGE_NNN_HIG_MV (1150U) /* Voltage Settings for : Process=NNN, DCDC Power Profile=HIGH */
#define VOLTAGE_FFF_LOW_MV (1000U) /* Voltage Settings for : Process=FFF, DCDC Power Profile=LOW */
#define VOLTAGE_FFF_MED_MV (1025U) /* Voltage Settings for : Process=FFF, DCDC Power Profile=MEDIUM */
#define VOLTAGE_FFF_HIG_MV (1050U) /* Voltage Settings for : Process=FFF, DCDC Power Profile=HIGH */

/**
 * @brief LDO Voltage control in Low Power Modes
 */
#define LOWPOWER_VOLTAGE_LDO_PMU_INDEX        0
#define LOWPOWER_VOLTAGE_LDO_PMU_MASK         (0x1FULL << LOWPOWER_VOLTAGE_LDO_PMU_INDEX)
#define LOWPOWER_VOLTAGE_LDO_MEM_INDEX        5
#define LOWPOWER_VOLTAGE_LDO_MEM_MASK         (0x1FULL << LOWPOWER_VOLTAGE_LDO_MEM_INDEX)
#define LOWPOWER_VOLTAGE_LDO_DEEP_SLEEP_INDEX 10
#define LOWPOWER_VOLTAGE_LDO_DEEP_SLEEP_MASK  (0x7ULL << LOWPOWER_VOLTAGE_LDO_DEEP_SLEEP_INDEX)
#define LOWPOWER_VOLTAGE_LDO_PMU_BOOST_INDEX  19
#define LOWPOWER_VOLTAGE_LDO_PMU_BOOST_MASK   (0x1FULL << LOWPOWER_VOLTAGE_LDO_PMU_BOOST_INDEX)
#define LOWPOWER_VOLTAGE_LDO_MEM_BOOST_INDEX  24
#define LOWPOWER_VOLTAGE_LDO_MEM_BOOST_MASK   (0x1FULL << LOWPOWER_VOLTAGE_LDO_MEM_BOOST_INDEX)
#define LOWPOWER_VOLTAGE_DCDC_INDEX           29
#define LOWPOWER_VOLTAGE_DCDC_MASK            (0xFULL << LOWPOWER_VOLTAGE_DCDC_INDEX)

/*! @brief set and clear bit MACRO's. */
#define U32_SET_BITS(P, B) ((*(uint32_t *)P) |= (B))
#define U32_CLR_BITS(P, B) ((*(uint32_t *)P) &= ~(B))
/* Return values from Config (N-2) page of flash */
#define GET_16MXO_TRIM() (*(uint32_t *)(FLASH_NMPA_BASE + 0xC8U)) // (0x3FCC8)
#define GET_32KXO_TRIM() (*(uint32_t *)(FLASH_NMPA_BASE + 0xCCU)) // (0x3FCCC)

#define CPU_RETENTION_RAMX_STORAGE_START_ADDR (0x04002000)

#define XO_SLAVE_EN (1)
/*******************************************************************************
 * Codes
 ******************************************************************************/

/*******************************************************************************
 * LOCAL FUNCTIONS PROTOTYPES
 ******************************************************************************/
static uint32_t lf_set_ldo_ao_ldo_mem_voltage(uint32_t p_lp_mode, uint32_t p_dcdc_voltage);
static uint32_t lf_wakeup_io_ctrl(uint32_t p_wakeup_io_ctrl);
static uint8_t CLOCK_u8OscCapConvert(uint8_t u8OscCap, uint8_t u8CapBankDiscontinuity);

static void lowpower_set_dcdc_power_profile(lowpower_dcdc_power_profile_enum dcdc_power_profile);
static lowpower_process_corner_enum lowpower_get_part_process_corner(void);
static void lowpower_set_voltage_for_process(lowpower_dcdc_power_profile_enum dcdc_power_profile);
static lowpower_driver_interface_t *s_lowpowerDriver = (lowpower_driver_interface_t *)(0x130050e4);

/**
 * @brief   Configures and enters in low power mode
 * @param   p_lowpower_cfg: pointer to a structure that contains all low power mode parameters
 * @return  Nothing
 *
 *          !!! IMPORTANT NOTES :
 *           1 - CPU Interrupt Enable registers are updated with p_lowpower_cfg->WAKEUPINT. They are NOT restored by the
 * API.
 *           2 - The Non Maskable Interrupt (NMI) should be disable before calling this API (otherwise, there is a risk
 * of Dead Lock).
 *           3 - The HARD FAULT handler should execute from SRAM. (The Hard fault handler should initiate a full chip
 * reset)
 */
static void POWER_EnterLowPower(LPC_LOWPOWER_T *p_lowpower_cfg);

/**
 * @brief
 * @param
 * @return
 */
static void lf_set_dcdc_power_profile_low(void)
{
#define DCDC_POWER_PROFILE_LOW_0_ADDRS (FLASH_NMPA_BASE + 0xE0U)
#define DCDC_POWER_PROFILE_LOW_1_ADDRS (FLASH_NMPA_BASE + 0xE4U)

    uint32_t dcdcTrimValue0 = (*((volatile unsigned int *)(DCDC_POWER_PROFILE_LOW_0_ADDRS)));
    uint32_t dcdcTrimValue1 = (*((volatile unsigned int *)(DCDC_POWER_PROFILE_LOW_1_ADDRS)));

    if (0UL != (dcdcTrimValue0 & 0x1UL))
    {
        PMC->DCDC0 = dcdcTrimValue0 >> 1;
        PMC->DCDC1 = dcdcTrimValue1;
    }
}

/**
 * @brief   Configures and enters in low power mode
 * @param           : p_lowpower_cfg
 * @return  Nothing
 */
static void POWER_EnterLowPower(LPC_LOWPOWER_T *p_lowpower_cfg)
{
    /* PMC clk set to 12 MHZ */
    p_lowpower_cfg->CFG |= (uint32_t)LOWPOWER_CFG_SELCLOCK_12MHZ << LOWPOWER_CFG_SELCLOCK_INDEX;

    /* Enable Analog References fast wake-up in case of wake-up from a low power mode (DEEP SLEEP, POWER DOWN and DEEP
     * POWER DOWN) and Hardware Pin reset */
    PMC->REFFASTWKUP = (PMC->REFFASTWKUP & (~PMC_REFFASTWKUP_LPWKUP_MASK) & (~PMC_REFFASTWKUP_HWWKUP_MASK)) |
                       PMC_REFFASTWKUP_LPWKUP(1) | PMC_REFFASTWKUP_HWWKUP(1);

    /* SRAM uses Voltage Scaling in all Low Power modes */
    PMC->SRAMCTRL = (PMC->SRAMCTRL & (~PMC_SRAMCTRL_SMB_MASK)) | PMC_SRAMCTRL_SMB(3);

    /* CPU Retention configuration : preserve the value of FUNCRETENTIONCTRL.RET_LENTH which is a Hardware defined
     * parameter. */
    p_lowpower_cfg->CPURETCTRL = (SYSCON->FUNCRETENTIONCTRL & SYSCON_FUNCRETENTIONCTRL_RET_LENTH_MASK) |
                                 (p_lowpower_cfg->CPURETCTRL & (~SYSCON_FUNCRETENTIONCTRL_RET_LENTH_MASK));

    /* Switch System Clock to FRO12Mhz (the configuration before calling this function will not be restored back) */
    CLOCK_AttachClk(kFRO12M_to_MAIN_CLK);                      /* Switch main clock to FRO12MHz */
    CLOCK_SetClkDiv(kCLOCK_DivAhbClk, 1U, false);              /* Main clock divided by 1 */
    SYSCON->FMCCR = (SYSCON->FMCCR & 0xFFFF0000UL) | 0x201AUL; /* Adjust FMC waiting time cycles */
    lf_set_dcdc_power_profile_low(); /* Align DCDC Power profile with the 12 MHz clock (DCDC Power Profile LOW) */

    (*(s_lowpowerDriver->set_lowpower_mode))(p_lowpower_cfg);

    /* Restore the configuration of the MISCCTRL Register : LDOMEMBLEEDDSLP = 0, LDOMEMHIGHZMODE =
     * 0 */
    PMC->MISCCTRL &= (~PMC_MISCCTRL_DISABLE_BLEED_MASK) & (~PMC_MISCCTRL_LDOMEMHIGHZMODE_MASK);
}

/**
 * @brief   Shut off the Flash and execute the _WFI(), then power up the Flash after wake-up event
 * @param   None
 * @return  Nothing
 */
void POWER_CycleCpuAndFlash(void)
{
    (*(s_lowpowerDriver->power_cycle_cpu_and_flash))();
};

/**
 * brief    PMC Deep Sleep function call
 * return   nothing
 */
void POWER_EnterDeepSleep(uint32_t exclude_from_pd,
                          uint32_t sram_retention_ctrl,
                          uint64_t wakeup_interrupts,
                          uint32_t hardware_wake_ctrl)
{
    LPC_LOWPOWER_T lv_low_power_mode_cfg; /* Low Power Mode configuration structure */
    uint32_t cpu0_nmi_enable;
    uint32_t cpu0_int_enable_0;
    uint32_t cpu0_int_enable_1;
    uint32_t dcdc_voltage;
    uint32_t pmc_reset_ctrl;
    /* Clear Low Power Mode configuration variable */
    (void)memset(&lv_low_power_mode_cfg, 0x0, sizeof(LPC_LOWPOWER_T));

    /* Configure Low Power Mode configuration variable */
    lv_low_power_mode_cfg.CFG |= (uint32_t)LOWPOWER_CFG_LPMODE_DEEPSLEEP
                                 << LOWPOWER_CFG_LPMODE_INDEX; /* DEEPSLEEP mode */

    /* DCDC will be always used during Deep Sleep (instead of LDO Deep Sleep); Make sure LDO MEM & Analog references
     * will stay powered, Shut down ROM */
    lv_low_power_mode_cfg.PDCTRL0 = (~exclude_from_pd & ~(uint32_t)kPDRUNCFG_PD_DCDC & ~(uint32_t)kPDRUNCFG_PD_LDOMEM &
                                     ~(uint32_t)kPDRUNCFG_PD_BIAS) |
                                    (uint32_t)kPDRUNCFG_PD_LDODEEPSLEEP | (uint32_t)kPDRUNCFG_PD_ROM;

    /* Voltage control in DeepSleep Low Power Modes */
    /* The Memories Voltage settings below are for voltage scaling */
    dcdc_voltage                  = (uint32_t)V_DCDC_0P950;
    lv_low_power_mode_cfg.VOLTAGE = lf_set_ldo_ao_ldo_mem_voltage(LOWPOWER_CFG_LPMODE_POWERDOWN, dcdc_voltage);

    /* SRAM retention control during POWERDOWN */
    lv_low_power_mode_cfg.SRAMRETCTRL = sram_retention_ctrl;

    /* CPU Wake up & Interrupt sources control */
    lv_low_power_mode_cfg.WAKEUPINT = wakeup_interrupts;
    lv_low_power_mode_cfg.WAKEUPSRC = wakeup_interrupts;

    /* Interrupts that allow DMA transfers with Flexcomm without waking up the Processor */
    if (0UL != (hardware_wake_ctrl & (LOWPOWER_HWWAKE_PERIPHERALS | LOWPOWER_HWWAKE_SDMA0 | LOWPOWER_HWWAKE_SDMA1)))
    {
        lv_low_power_mode_cfg.HWWAKE = (hardware_wake_ctrl & ~LOWPOWER_HWWAKE_FORCED) | LOWPOWER_HWWAKE_ENABLE_FRO192M;
    }

    cpu0_nmi_enable = SYSCON->NMISRC & SYSCON_NMISRC_NMIENCPU0_MASK; /* Save the configuration of the NMI Register */
    SYSCON->NMISRC &= ~SYSCON_NMISRC_NMIENCPU0_MASK;                 /* Disable NMI of CPU0 */

    /* Save the configuration of the CPU interrupt enable Registers (because they are overwritten inside the low power
     * API */
    cpu0_int_enable_0 = NVIC->ISER[0];
    cpu0_int_enable_1 = NVIC->ISER[1];

    pmc_reset_ctrl = PMC->RESETCTRL;

    if ((pmc_reset_ctrl & (PMC_RESETCTRL_BODCORERESETENA_SECURE_MASK | PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_MASK)) ==
        ((0x1UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_SHIFT) |
         (0x1UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_SHIFT)))
    {
        /* BoD CORE reset is activated, so make sure BoD Core and Biasing won't be shutdown */
        lv_low_power_mode_cfg.PDCTRL0 &= ~(uint32_t)kPDRUNCFG_PD_BODCORE & ~(uint32_t)kPDRUNCFG_PD_BIAS;
    }
    if ((pmc_reset_ctrl & (PMC_RESETCTRL_BODVBATRESETENA_SECURE_MASK | PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_MASK)) ==
        ((0x1UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_SHIFT) |
         (0x1UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_SHIFT)))
    {
        /* BoD VBAT reset is activated, so make sure BoD VBAT and Biasing won't be shutdown */
        lv_low_power_mode_cfg.PDCTRL0 &= ~(uint32_t)kPDRUNCFG_PD_BODVBAT & ~(uint32_t)kPDRUNCFG_PD_BIAS;
    }

    /* Enter low power mode */
    POWER_EnterLowPower(&lv_low_power_mode_cfg);

    /* Restore the configuration of the NMI Register */
    SYSCON->NMISRC |= cpu0_nmi_enable;

    /* Restore the configuration of the CPU interrupt enable Registers (because they have been overwritten inside the
     * low power API */
    NVIC->ISER[0] = cpu0_int_enable_0;
    NVIC->ISER[1] = cpu0_int_enable_1;
}

/**
 * brief    PMC power Down function call
 * return   nothing
 */
void POWER_EnterPowerDown(uint32_t exclude_from_pd,
                          uint32_t sram_retention_ctrl,
                          uint64_t wakeup_interrupts,
                          uint32_t cpu_retention_ctrl)
{
    LPC_LOWPOWER_T lv_low_power_mode_cfg; /* Low Power Mode configuration structure */
    uint32_t cpu0_nmi_enable;
    uint32_t cpu0_int_enable_0;
    uint32_t cpu0_int_enable_1;
    uint64_t wakeup_src_int;
    uint32_t pmc_reset_ctrl;
    uint32_t rng_entropy_save[6];

    uint32_t analog_ctrl_regs[12]; /* To store Analog Controller Regristers */

    /* Clear Low Power Mode configuration variable */
    (void)memset(&lv_low_power_mode_cfg, 0x0, sizeof(LPC_LOWPOWER_T));

    /* Configure Low Power Mode configuration variable */
    lv_low_power_mode_cfg.CFG |= (uint32_t)LOWPOWER_CFG_LPMODE_POWERDOWN
                                 << LOWPOWER_CFG_LPMODE_INDEX; /* POWER DOWN mode */

    /* Only FRO32K, XTAL32K, COMP, BIAS and LDO_MEM can be stay powered during POWERDOWN (valid from application point
     * of view; Hardware allows BODVBAT, LDODEEPSLEEP and FRO1M to stay powered, that's why they are excluded below) */
    lv_low_power_mode_cfg.PDCTRL0 = (~exclude_from_pd) | (uint32_t)kPDRUNCFG_PD_BODVBAT | (uint32_t)kPDRUNCFG_PD_FRO1M |
                                    (uint32_t)kPDRUNCFG_PD_LDODEEPSLEEP;

    /* @TODO Guillaume: add save/restore entropy during PowerDown */
    /* Entropy for RNG need to saved */
    if ((exclude_from_pd & (uint32_t)kPDRUNCFG_PD_RNG) != 0UL)
    {
        CLOCK_EnableClock(kCLOCK_Rng);
        RESET_ClearPeripheralReset(kRNG_RST_SHIFT_RSTn);
        for (int i = 0; i < 6; i++)
        {
            rng_entropy_save[i] = RNG->RANDOM_NUMBER;
        }
    }

    /* CPU0 retention Ctrl.
     * For the time being, we do not allow customer to relocate the CPU retention area in SRAMX, meaning that the
     * retention area range is [0x0400_2000 - 0x0400_2600] (beginning of RAMX2) If required by customer,
     * cpu_retention_ctrl[13:1] will be used for that to modify the default retention area
     */
    lv_low_power_mode_cfg.CPURETCTRL =
        (cpu_retention_ctrl & LOWPOWER_CPURETCTRL_ENA_MASK) |
        ((((uint32_t)CPU_RETENTION_RAMX_STORAGE_START_ADDR >> 2UL) << LOWPOWER_CPURETCTRL_MEMBASE_INDEX) &
         LOWPOWER_CPURETCTRL_MEMBASE_MASK);
    if (0UL != (cpu_retention_ctrl & 0x1UL))
    {
        /* Add RAMX2 for retention */
        sram_retention_ctrl |= LOWPOWER_SRAMRETCTRL_RETEN_RAMX2;
        /* CPU retention is required: store Analog Controller Registers */
        analog_ctrl_regs[0] = ANACTRL->FRO192M_CTRL;
        analog_ctrl_regs[1] = ANACTRL->ANALOG_CTRL_CFG;
        analog_ctrl_regs[2] = ANACTRL->ADC_CTRL;
        analog_ctrl_regs[3] = ANACTRL->XO32M_CTRL;
        analog_ctrl_regs[4] = ANACTRL->BOD_DCDC_INT_CTRL;
        analog_ctrl_regs[5] = ANACTRL->RINGO0_CTRL;
        analog_ctrl_regs[6] = ANACTRL->RINGO1_CTRL;
        analog_ctrl_regs[7] = ANACTRL->RINGO2_CTRL;
        analog_ctrl_regs[8] = ANACTRL->LDO_XO32M;
        analog_ctrl_regs[9] = ANACTRL->AUX_BIAS;
    }

    /* SRAM retention control during POWERDOWN */
    lv_low_power_mode_cfg.SRAMRETCTRL = sram_retention_ctrl;

    /* Sanity check: If retention is required for any of SRAM instances, make sure LDO MEM will stay powered */
    if ((sram_retention_ctrl & 0x7FFFUL) != 0UL)
    {
        lv_low_power_mode_cfg.PDCTRL0 &= ~(uint32_t)kPDRUNCFG_PD_LDOMEM;
    }

    /* Voltage control in Low Power Modes */
    /* The Memories Voltage settings below are for voltage scaling */
    lv_low_power_mode_cfg.VOLTAGE = lf_set_ldo_ao_ldo_mem_voltage(LOWPOWER_CFG_LPMODE_POWERDOWN, 0);

    /* CPU Wake up & Interrupt sources control : only WAKEUP_GPIO_GLOBALINT0, WAKEUP_GPIO_GLOBALINT1, WAKEUP_FLEXCOMM3,
     * WAKEUP_ACMP_CAPT, WAKEUP_RTC_LITE_ALARM_WAKEUP, WAKEUP_OS_EVENT_TIMER, WAKEUP_ALLWAKEUPIOS */
    wakeup_src_int = (uint64_t)(WAKEUP_GPIO_GLOBALINT0 | WAKEUP_GPIO_GLOBALINT1 | WAKEUP_FLEXCOMM3 | WAKEUP_ACMP |
                                WAKEUP_RTC_LITE_ALARM_WAKEUP | WAKEUP_OS_EVENT_TIMER | WAKEUP_ALLWAKEUPIOS);
    lv_low_power_mode_cfg.WAKEUPINT = wakeup_interrupts & wakeup_src_int;
    lv_low_power_mode_cfg.WAKEUPSRC = wakeup_interrupts & wakeup_src_int;

    cpu0_nmi_enable = SYSCON->NMISRC & SYSCON_NMISRC_NMIENCPU0_MASK; /* Save the configuration of the NMI Register */
    SYSCON->NMISRC &= ~SYSCON_NMISRC_NMIENCPU0_MASK;                 /* Disable NMI of CPU0 */

    /* Save the configuration of the CPU interrupt enable Registers */
    cpu0_int_enable_0 = NVIC->ISER[0];
    cpu0_int_enable_1 = NVIC->ISER[1];

    /* Disable BoD VBAT and BoD Core resets */
    /* BOD VBAT disable reset */
    pmc_reset_ctrl =
        PMC->RESETCTRL & (~(PMC_RESETCTRL_BODVBATRESETENA_SECURE_MASK | PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_MASK));
    pmc_reset_ctrl |= (0x2UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_SHIFT) |
                      (0x2UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_SHIFT);

    /* BOD CORE disable reset */
    pmc_reset_ctrl &= (~(PMC_RESETCTRL_BODCORERESETENA_SECURE_MASK | PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_MASK));
    pmc_reset_ctrl |= (0x2UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_SHIFT) |
                      (0x2UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_SHIFT);

    PMC->RESETCTRL = pmc_reset_ctrl;

    /* Enter low power mode */
    POWER_EnterLowPower(&lv_low_power_mode_cfg);

    /* Following code is to reset PUF to remove over consumption */
    /* Enable PUF register clock to access register */
    SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_PUF_MASK;
    /* Release PUF reset */
    SYSCON->PRESETCTRLCLR[2] = SYSCON_PRESETCTRL2_PUF_RST_MASK;
    /* Enable PUF SRAM */
    PUF_SRAM_CTRL->CFG |= PUF_SRAM_CTRL_CFG_ENABLE_MASK | PUF_SRAM_CTRL_CFG_CKGATING_MASK;

    /* Disable PUF register clock. */
    // Delaying the line of code below until the PUF State Machine execution is completed:
    // Shuting down the clock to early will prevent the state machine from reaching the end.
    // => Wait for status bit in PUF Controller Registers before stop PUF clock.
    while (0UL == (PUF_SRAM_CTRL->INT_STATUS & PUF_SRAM_CTRL_INT_STATUS_READY_MASK))
    {
    }

    SYSCON->AHBCLKCTRLCLR[2] = SYSCON_AHBCLKCTRL2_PUF_MASK;

    /* Restore the configuration of the NMI Register */
    SYSCON->NMISRC |= cpu0_nmi_enable;

    /* Restore PMC RESETCTRL register */
    PMC->RESETCTRL = pmc_reset_ctrl;

    /* Restore the configuration of the CPU interrupt enable Registers (because they have been overwritten inside the
     * low power API */
    NVIC->ISER[0] = cpu0_int_enable_0;
    NVIC->ISER[1] = cpu0_int_enable_1;

    if ((cpu_retention_ctrl & 0x1UL) != 0UL)
    {
        /* Restore Analog Controller Registers */
        ANACTRL->FRO192M_CTRL      = analog_ctrl_regs[0] | ANACTRL_FRO192M_CTRL_WRTRIM_MASK;
        ANACTRL->ANALOG_CTRL_CFG   = analog_ctrl_regs[1];
        ANACTRL->ADC_CTRL          = analog_ctrl_regs[2];
        ANACTRL->XO32M_CTRL        = analog_ctrl_regs[3];
        ANACTRL->BOD_DCDC_INT_CTRL = analog_ctrl_regs[4];
        ANACTRL->RINGO0_CTRL       = analog_ctrl_regs[5];
        ANACTRL->RINGO1_CTRL       = analog_ctrl_regs[6];
        ANACTRL->RINGO2_CTRL       = analog_ctrl_regs[7];
        ANACTRL->LDO_XO32M         = analog_ctrl_regs[8];
        ANACTRL->AUX_BIAS          = analog_ctrl_regs[9];
    }

    /* @TODO Guillaume: add save/restore entropy during PowerDown */
    /* Restore Entropy for RNG */
    if ((exclude_from_pd & (uint32_t)kPDRUNCFG_PD_RNG) != 0UL)
    {
        RNG->POWERDOWN &= ~RNG_POWERDOWN_POWERDOWN_MASK;
        for (int i = 0; i < 6; i++)
        {
            RNG->ENTROPY_INJECT = rng_entropy_save[i];
        }
    }
}

/**
 * brief    PMC Deep Sleep Power Down function call
 * return   nothing
 */
void POWER_EnterDeepPowerDown(uint32_t exclude_from_pd,
                              uint32_t sram_retention_ctrl,
                              uint64_t wakeup_interrupts,
                              uint32_t wakeup_io_ctrl)
{
    LPC_LOWPOWER_T lv_low_power_mode_cfg; /* Low Power Mode configuration structure */
    uint32_t cpu0_nmi_enable;
    uint32_t cpu0_int_enable_0;
    uint32_t cpu0_int_enable_1;
    uint32_t pmc_reset_ctrl;

    /* Clear Low Power Mode configuration variable */
    (void)memset(&lv_low_power_mode_cfg, 0x0, sizeof(LPC_LOWPOWER_T));

    /* Configure Low Power Mode configuration variable */
    lv_low_power_mode_cfg.CFG |= (uint32_t)LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN
                                 << LOWPOWER_CFG_LPMODE_INDEX; /* DEEP POWER DOWN mode */

    /* Only FRO32K, XTAL32K and LDO_MEM can be stay powered during DEEPPOWERDOWN */
    lv_low_power_mode_cfg.PDCTRL0 = (~exclude_from_pd) | (uint32_t)kPDRUNCFG_PD_BIAS | (uint32_t)kPDRUNCFG_PD_BODVBAT |
                                    (uint32_t)kPDRUNCFG_PD_FRO1M | (uint32_t)kPDRUNCFG_PD_COMP;

    /* SRAM retention control during DEEPPOWERDOWN */
    /* RAM00 used by ROM code to restart. */
    sram_retention_ctrl = sram_retention_ctrl & (~(LOWPOWER_SRAMRETCTRL_RETEN_RAM00));

    /* SRAM retention control during DEEPPOWERDOWN */
    lv_low_power_mode_cfg.SRAMRETCTRL = sram_retention_ctrl;

    /* Sanity check: If retention is required for any of SRAM instances, make sure LDO MEM will stay powered */
    if ((sram_retention_ctrl & 0x7FFFUL) != 0UL)
    {
        lv_low_power_mode_cfg.PDCTRL0 &= ~(uint32_t)kPDRUNCFG_PD_LDOMEM;
    }

    /* Voltage control in Low Power Modes */
    /* The Memories Voltage settings below are for voltage scaling */
    lv_low_power_mode_cfg.VOLTAGE = lf_set_ldo_ao_ldo_mem_voltage(LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN, 0);

    lv_low_power_mode_cfg.WAKEUPINT =
        wakeup_interrupts & (WAKEUP_RTC_LITE_ALARM_WAKEUP |
                             WAKEUP_OS_EVENT_TIMER); /* CPU Wake up sources control : only WAKEUP_RTC_LITE_ALARM_WAKEUP,
                                                        WAKEUP_OS_EVENT_TIMER */
    lv_low_power_mode_cfg.WAKEUPSRC =
        wakeup_interrupts &
        (WAKEUP_RTC_LITE_ALARM_WAKEUP | WAKEUP_OS_EVENT_TIMER |
         WAKEUP_ALLWAKEUPIOS); /*!< Hardware Wake up sources control: : only WAKEUP_RTC_LITE_ALARM_WAKEUP,
                                  WAKEUP_OS_EVENT_TIMER and WAKEUP_ALLWAKEUPIOS */

    /* Wake up I/O sources */
    lv_low_power_mode_cfg.WAKEUPIOSRC = lf_wakeup_io_ctrl(wakeup_io_ctrl);

    cpu0_nmi_enable = SYSCON->NMISRC & SYSCON_NMISRC_NMIENCPU0_MASK; /* Save the configuration of the NMI Register */
    SYSCON->NMISRC &= ~SYSCON_NMISRC_NMIENCPU0_MASK;                 /* Disable NMI of CPU0 */

    /* Save the configuration of the CPU interrupt enable Registers */
    cpu0_int_enable_0 = NVIC->ISER[0];
    cpu0_int_enable_1 = NVIC->ISER[1];

    /* Save the configuration of the PMC RESETCTRL register */
    /* BOD VBAT disable reset */
    pmc_reset_ctrl =
        PMC->RESETCTRL & (~(PMC_RESETCTRL_BODVBATRESETENA_SECURE_MASK | PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_MASK));
    pmc_reset_ctrl |= (0x2UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_SHIFT) |
                      (0x2UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_SHIFT);

    /* BOD CORE disable reset */
    pmc_reset_ctrl &= (~(PMC_RESETCTRL_BODCORERESETENA_SECURE_MASK | PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_MASK));
    pmc_reset_ctrl |= (0x2UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_SHIFT) |
                      (0x2UL << PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_SHIFT);

    PMC->RESETCTRL = pmc_reset_ctrl;

    /* Enter low power mode */
    POWER_EnterLowPower(&lv_low_power_mode_cfg);

    /* Restore the configuration of the NMI Register */
    SYSCON->NMISRC |= cpu0_nmi_enable;

    /* Restore PMC RESETCTRL register */
    PMC->RESETCTRL = pmc_reset_ctrl;

    /* Restore the configuration of the CPU interrupt enable Registers */
    NVIC->ISER[0] = cpu0_int_enable_0;
    NVIC->ISER[1] = cpu0_int_enable_1;
}

/**
 * brief    PMC Sleep function call
 * return   nothing
 */
void POWER_EnterSleep(void)
{
    uint32_t pmsk;
    pmsk = __get_PRIMASK();
    __disable_irq();
    SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
    __set_PRIMASK(pmsk);
}

/**
 * @brief
 * @param
 * @return
 */
static uint32_t lf_set_ldo_ao_ldo_mem_voltage(uint32_t p_lp_mode, uint32_t p_dcdc_voltage)
{
#define FLASH_NMPA_LDO_AO_ADDRS                (FLASH_NMPA_BASE + 0x0F4U)
#define FLASH_NMPA_LDO_AO_DSLP_TRIM_VALID_MASK (0x100U)
#define FLASH_NMPA_LDO_AO_DSLP_TRIM_MASK       (0x3E00U)
#define FLASH_NMPA_LDO_AO_DSLP_TRIM_SHIFT      (9U)
#define FLASH_NMPA_LDO_AO_PDWN_TRIM_VALID_MASK (0x10000U)
#define FLASH_NMPA_LDO_AO_PDWN_TRIM_MASK       (0x3E0000U)
#define FLASH_NMPA_LDO_AO_PDWN_TRIM_SHIFT      (17U)
#define FLASH_NMPA_LDO_AO_DPDW_TRIM_VALID_MASK (0x1000000U)
#define FLASH_NMPA_LDO_AO_DPDW_TRIM_MASK       (0x3E000000U)
#define FLASH_NMPA_LDO_AO_DPDW_TRIM_SHIFT      (25U)

    uint32_t ldo_ao_trim, voltage;
    uint32_t lv_v_ldo_pmu, lv_v_ldo_pmu_boost;

    ldo_ao_trim = (*((volatile unsigned int *)(FLASH_NMPA_LDO_AO_ADDRS)));

    switch (p_lp_mode)
    {
        case LOWPOWER_CFG_LPMODE_DEEPSLEEP:
        {
            if ((ldo_ao_trim & FLASH_NMPA_LDO_AO_DSLP_TRIM_VALID_MASK) != 0UL)
            {
                /* Apply settings coming from Flash */
                lv_v_ldo_pmu = (ldo_ao_trim & FLASH_NMPA_LDO_AO_DSLP_TRIM_MASK) >> FLASH_NMPA_LDO_AO_DSLP_TRIM_SHIFT;
                lv_v_ldo_pmu_boost = lv_v_ldo_pmu - 2UL; /* - 50 mV */
            }
            else
            {
                /* Apply default settings */
                lv_v_ldo_pmu       = (uint32_t)V_AO_0P900;
                lv_v_ldo_pmu_boost = (uint32_t)V_AO_0P850;
            }
        }
        break;

        case LOWPOWER_CFG_LPMODE_POWERDOWN:
        {
            if ((ldo_ao_trim & FLASH_NMPA_LDO_AO_PDWN_TRIM_VALID_MASK) != 0UL)
            {
                /* Apply settings coming from Flash */
                lv_v_ldo_pmu = (ldo_ao_trim & FLASH_NMPA_LDO_AO_PDWN_TRIM_MASK) >> FLASH_NMPA_LDO_AO_PDWN_TRIM_SHIFT;
                lv_v_ldo_pmu_boost = lv_v_ldo_pmu - 2UL; /* - 50 mV */
            }
            else
            {
                /* Apply default settings */
                lv_v_ldo_pmu       = (uint32_t)V_AO_0P800;
                lv_v_ldo_pmu_boost = (uint32_t)V_AO_0P750;
            }
        }
        break;

        case LOWPOWER_CFG_LPMODE_DEEPPOWERDOWN:
        {
            if ((ldo_ao_trim & FLASH_NMPA_LDO_AO_DPDW_TRIM_VALID_MASK) != 0UL)
            {
                /* Apply settings coming from Flash */
                lv_v_ldo_pmu = (ldo_ao_trim & FLASH_NMPA_LDO_AO_DPDW_TRIM_MASK) >> FLASH_NMPA_LDO_AO_DPDW_TRIM_SHIFT;
                lv_v_ldo_pmu_boost = lv_v_ldo_pmu - 2UL; /* - 50 mV */
            }
            else
            {
                /* Apply default settings */
                lv_v_ldo_pmu       = (uint32_t)V_AO_0P800;
                lv_v_ldo_pmu_boost = (uint32_t)V_AO_0P750;
            }
        }
        break;

        default:
            /* Should never reach this point */
            lv_v_ldo_pmu       = (uint32_t)V_AO_1P100;
            lv_v_ldo_pmu_boost = (uint32_t)V_AO_1P050;
            break;
    }

    /* The Memories Voltage settings below are for voltage scaling */
    voltage =
        (lv_v_ldo_pmu << LOWPOWER_VOLTAGE_LDO_PMU_INDEX) |               /*  */
        (lv_v_ldo_pmu_boost << LOWPOWER_VOLTAGE_LDO_PMU_BOOST_INDEX) |   /*  */
        ((uint32_t)V_AO_0P750 << LOWPOWER_VOLTAGE_LDO_MEM_INDEX) |       /* Set to 0.75V (voltage Scaling) */
        ((uint32_t)V_AO_0P700 << LOWPOWER_VOLTAGE_LDO_MEM_BOOST_INDEX) | /* Set to 0.7V  (voltage Scaling) */
        ((uint32_t)V_DEEPSLEEP_0P900
         << LOWPOWER_VOLTAGE_LDO_DEEP_SLEEP_INDEX) |    /* Set to 0.90 V (Not used because LDO_DEEP_SLEEP is disabled)*/
        (p_dcdc_voltage << LOWPOWER_VOLTAGE_DCDC_INDEX) /*  */
        ;

    return (voltage);
}

/**
 * @brief
 * @param
 * @return
 */
static uint32_t lf_wakeup_io_ctrl(uint32_t p_wakeup_io_ctrl)
{
    uint32_t wake_up_type;
    uint32_t wakeup_io_ctrl_reg;
    uint8_t use_external_pullupdown = 0;

    /* Configure Pull up & Pull down based on the required wake-up edge */
    CLOCK_EnableClock(kCLOCK_Iocon);

    wakeup_io_ctrl_reg = 0UL;

    /* Wake-up I/O 0 */
    wake_up_type = (p_wakeup_io_ctrl & 0x3UL) >> LOWPOWER_WAKEUPIOSRC_PIO0_INDEX;
    wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO0_INDEX);
    use_external_pullupdown = (uint8_t)((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO0_USEEXTERNALPULLUPDOWN_MASK) >>
                                        LOWPOWER_WAKEUPIO_PIO0_USEEXTERNALPULLUPDOWN_INDEX);

    if (use_external_pullupdown == 0UL)
    {
        if ((wake_up_type == 1UL) || (wake_up_type == 3UL))
        {
            /* Rising edge and both rising and falling edges */
            IOCON->PIO[1][1] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */
            wakeup_io_ctrl_reg |=
                ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX);
        }
        else
        {
            if (wake_up_type == 2UL)
            {
                /* Falling edge only */
                IOCON->PIO[1][1] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */
                wakeup_io_ctrl_reg |=
                    ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX);
            }
            else
            {
                /* Wake-up I/O is disabled : set it as required by the user */
                if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO0_DISABLEPULLUPDOWN_MASK) != 0UL)
                {
                    /* Wake-up I/O is configured as Plain Input */
                    // @TODO not used               p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO0_PULLUPDOWN_MASK;
                    wakeup_io_ctrl_reg |=
                        ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX);
                }
                else
                {
                    /* Wake-up I/O is configured as pull-up or pull-down */
                    // @TODO update for mask name
                    if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO0_PULLUPDOWN_MASK) != 0UL)
                    {
                        /* Wake-up I/O is configured as pull-up */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX);
                    }
                    else
                    {
                        /* Wake-up I/O is configured as pull-down */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX);
                    }
                }
            }
        }
    }
    else
    {
        wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO0MODE_INDEX);
    }

    /* Wake-up I/O 1 */
    wake_up_type = (p_wakeup_io_ctrl & 0xCUL) >> LOWPOWER_WAKEUPIOSRC_PIO1_INDEX;
    wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO1_INDEX);
    use_external_pullupdown = (uint8_t)((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO1_USEEXTERNALPULLUPDOWN_MASK) >>
                                        LOWPOWER_WAKEUPIO_PIO1_USEEXTERNALPULLUPDOWN_INDEX);

    if (use_external_pullupdown == 0UL)
    {
        if ((wake_up_type == 1UL) || (wake_up_type == 3UL))
        {
            /* Rising edge  and both rising and falling edges */
            IOCON->PIO[0][28] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */
            wakeup_io_ctrl_reg |=
                ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX);
        }
        else
        {
            if (wake_up_type == 2UL)
            {
                /* Falling edge only */
                IOCON->PIO[0][28] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */
                wakeup_io_ctrl_reg |=
                    ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX);
            }
            else
            {
                /* Wake-up I/O is disabled : set it as required by the user */
                if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO1_DISABLEPULLUPDOWN_MASK) != 0UL)
                {
                    /* Wake-up I/O is configured as Plain Input */
                    // @TODO not used                p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO1_PULLUPDOWN_MASK;
                    wakeup_io_ctrl_reg |=
                        ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX);
                }
                else
                {
                    /* Wake-up I/O is configured as pull-up or pull-down */
                    // @TODO update for mask name
                    if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO1_PULLUPDOWN_MASK) != 0UL)
                    {
                        /* Wake-up I/O is configured as pull-up */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX);
                    }
                    else
                    {
                        /* Wake-up I/O is configured as pull-down */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX);
                    }
                }
            }
        }
    }
    else
    {
        wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO1MODE_INDEX);
    }

    /* Wake-up I/O 2 */
    wake_up_type = (p_wakeup_io_ctrl & 0x30UL) >> LOWPOWER_WAKEUPIOSRC_PIO2_INDEX;
    wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO2_INDEX);
    use_external_pullupdown = (uint8_t)((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO2_USEEXTERNALPULLUPDOWN_MASK) >>
                                        LOWPOWER_WAKEUPIO_PIO2_USEEXTERNALPULLUPDOWN_INDEX);

    if (use_external_pullupdown == 0UL)
    {
        if ((wake_up_type == 1UL) || (wake_up_type == 3UL))
        {
            /* Rising edge  and both rising and falling edges */
            IOCON->PIO[1][18] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */
            wakeup_io_ctrl_reg |=
                ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX);
        }
        else
        {
            if (wake_up_type == 2UL)
            {
                /* Falling edge only */
                IOCON->PIO[1][18] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */
                wakeup_io_ctrl_reg |=
                    ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX);
            }
            else
            {
                /* Wake-up I/O is disabled : set it as required by the user */
                if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO2_DISABLEPULLUPDOWN_MASK) != 0UL)
                {
                    /* Wake-up I/O is configured as Plain Input */
                    // @TODO not used                p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO2_PULLUPDOWN_MASK;
                    wakeup_io_ctrl_reg |=
                        ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX);
                }
                else
                {
                    /* Wake-up I/O is configured as pull-up or pull-down */
                    // @TODO update for mask name
                    if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO2_PULLUPDOWN_MASK) != 0UL)
                    {
                        /* Wake-up I/O is configured as pull-up */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX);
                    }
                    else
                    {
                        /* Wake-up I/O is configured as pull-down */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX);
                    }
                }
            }
        }
    }
    else
    {
        wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO2MODE_INDEX);
    }

    /* Wake-up I/O 3 */
    wake_up_type = (p_wakeup_io_ctrl & 0xC0UL) >> LOWPOWER_WAKEUPIOSRC_PIO3_INDEX;
    wakeup_io_ctrl_reg |= (wake_up_type << LOWPOWER_WAKEUPIOSRC_PIO3_INDEX);
    use_external_pullupdown = (uint8_t)((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO3_USEEXTERNALPULLUPDOWN_MASK) >>
                                        LOWPOWER_WAKEUPIO_PIO3_USEEXTERNALPULLUPDOWN_INDEX);

    if (use_external_pullupdown == 0UL)
    {
        if ((wake_up_type == 1UL) || (wake_up_type == 3UL))
        {
            /* Rising edge  and both rising and falling edges */
            IOCON->PIO[1][30] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(1); /* Pull down */
            wakeup_io_ctrl_reg |=
                ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX);
        }
        else
        {
            if (wake_up_type == 2UL)
            {
                /* Falling edge only */
                IOCON->PIO[1][30] = IOCON_PIO_DIGIMODE(1) | IOCON_PIO_MODE(2); /* Pull up */
                wakeup_io_ctrl_reg |=
                    ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX);
            }
            else
            {
                /* Wake-up I/O is disabled : set it as required by the user */
                if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO3_DISABLEPULLUPDOWN_MASK) != 0UL)
                {
                    /* Wake-up I/O is configured as Plain Input */
                    // @TODO not used                p_wakeup_io_ctrl &= ~LOWPOWER_WAKEUPIO_PIO3_PULLUPDOWN_MASK;
                    wakeup_io_ctrl_reg |=
                        ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX);
                }
                else
                {
                    /* Wake-up I/O is configured as pull-up or pull-down */
                    // @TODO update for mask name
                    if ((p_wakeup_io_ctrl & LOWPOWER_WAKEUPIO_PIO3_PULLUPDOWN_MASK) != 0UL)
                    {
                        /* Wake-up I/O is configured as pull-up */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLUP << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX);
                    }
                    else
                    {
                        /* Wake-up I/O is configured as pull-down */
                        wakeup_io_ctrl_reg |=
                            ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PULLDOWN << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX);
                    }
                }
            }
        }
    }
    else
    {
        wakeup_io_ctrl_reg |= ((uint32_t)LOWPOWER_WAKEUPIOSRC_IO_MODE_PLAIN << LOWPOWER_WAKEUPIOSRC_PIO3MODE_INDEX);
    }

    return (wakeup_io_ctrl_reg);
}

/**
 * @brief
 * @param
 * @return
 */
static uint8_t CLOCK_u8OscCapConvert(uint8_t u8OscCap, uint8_t u8CapBankDiscontinuity)
{
    /* Compensate for discontinuity in the capacitor banks */
    if (u8OscCap < 64U)
    {
        if (u8OscCap >= u8CapBankDiscontinuity)
        {
            u8OscCap -= u8CapBankDiscontinuity;
        }
        else
        {
            u8OscCap = 0U;
        }
    }
    else
    {
        if (u8OscCap <= (127U - u8CapBankDiscontinuity))
        {
            u8OscCap += u8CapBankDiscontinuity;
        }
        else
        {
            u8OscCap = 127U;
        }
    }
    return u8OscCap;
}

/**
 * @brief             Described in fsl_common.h
 * @param
 * @return
 */
static void lowpower_set_system_voltage(uint32_t system_voltage_mv)
{
    /*
     * Set system voltage
     */
    uint32_t lv_ldo_ao       = (uint32_t)V_AO_1P100;   /* <ldo_ao> */
    uint32_t lv_ldo_ao_boost = (uint32_t)V_AO_1P150;   /* <ldo_ao_boost> */
    uint32_t lv_dcdc         = (uint32_t)V_DCDC_1P100; /* <dcdc> */

    if (system_voltage_mv <= 950UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_0P950;
        lv_ldo_ao       = (uint32_t)V_AO_0P960;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P010;
    }
    else if (system_voltage_mv <= 975UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_0P975;
        lv_ldo_ao       = (uint32_t)V_AO_0P980;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P030;
    }
    else if (system_voltage_mv <= 1000UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P000;
        lv_ldo_ao       = (uint32_t)V_AO_1P000;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P050;
    }
    else if (system_voltage_mv <= 1025UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P025;
        lv_ldo_ao       = (uint32_t)V_AO_1P030;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P080;
    }
    else if (system_voltage_mv <= 1050UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P050;
        lv_ldo_ao       = (uint32_t)V_AO_1P060;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P110;
    }
    else if (system_voltage_mv <= 1075UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P075;
        lv_ldo_ao       = (uint32_t)V_AO_1P080;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P130;
    }
    else if (system_voltage_mv <= 1100UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P100;
        lv_ldo_ao       = (uint32_t)V_AO_1P100;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P150;
    }
    else if (system_voltage_mv <= 1125UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P125;
        lv_ldo_ao       = (uint32_t)V_AO_1P130;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P160;
    }
    else if (system_voltage_mv <= 1150UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P150;
        lv_ldo_ao       = (uint32_t)V_AO_1P160;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P220;
    }
    else if (system_voltage_mv <= 1175UL)
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P175;
        lv_ldo_ao       = (uint32_t)V_AO_1P160;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P220;
    }
    else
    {
        lv_dcdc         = (uint32_t)V_DCDC_1P200;
        lv_ldo_ao       = (uint32_t)V_AO_1P160;
        lv_ldo_ao_boost = (uint32_t)V_AO_1P220;
    }

    /* Set up LDO Always-On voltages */
    PMC->LDOPMU = (PMC->LDOPMU & (~PMC_LDOPMU_VADJ_MASK) & (~PMC_LDOPMU_VADJ_BOOST_MASK)) | PMC_LDOPMU_VADJ(lv_ldo_ao) |
                  PMC_LDOPMU_VADJ_BOOST(lv_ldo_ao_boost);

    /* Set up DCDC voltage */
    PMC->DCDC0 = (PMC->DCDC0 & (~PMC_DCDC0_VOUT_MASK)) | PMC_DCDC0_VOUT(lv_dcdc);
}

/**
 * @brief	Described in fsl_common.h
 * @param
 * @return
 */
static void lowpower_set_dcdc_power_profile(lowpower_dcdc_power_profile_enum dcdc_power_profile)
{
#define FLASH_NMPA_DCDC_POWER_PROFILE_LOW_0_ADDRS    (FLASH_NMPA_BASE + 0xE0U)
#define FLASH_NMPA_DCDC_POWER_PROFILE_LOW_1_ADDRS    (FLASH_NMPA_BASE + 0xE4U)
#define FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_0_ADDRS (FLASH_NMPA_BASE + 0xE8U)
#define FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_1_ADDRS (FLASH_NMPA_BASE + 0xECU)
#define FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_0_ADDRS   (FLASH_NMPA_BASE + 0xD8U)
#define FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_1_ADDRS   (FLASH_NMPA_BASE + 0xDCU)

    const uint32_t PMC_DCDC0_DEFAULT = 0x010C4E68;
    const uint32_t PMC_DCDC1_DEFAULT = 0x01803A98;

    uint32_t dcdcTrimValue0;
    uint32_t dcdcTrimValue1;

    switch (dcdc_power_profile)
    {
        case DCDC_POWER_PROFILE_LOW:
            /* Low */
            dcdcTrimValue0 = (*((volatile unsigned int *)(FLASH_NMPA_DCDC_POWER_PROFILE_LOW_0_ADDRS)));
            dcdcTrimValue1 = (*((volatile unsigned int *)(FLASH_NMPA_DCDC_POWER_PROFILE_LOW_1_ADDRS)));

            if (0UL != (dcdcTrimValue0 & 0x1UL))
            {
                dcdcTrimValue0 = dcdcTrimValue0 >> 1;

                PMC->DCDC0 = dcdcTrimValue0;
                PMC->DCDC1 = dcdcTrimValue1;
#if (defined(NIOBE_DEBUG_LEVEL) && (NIOBE_DEBUG_LEVEL >= 1))
                PRINTF(
                    "\nINFO : DCDC Power Profile set to "
                    "LOW"
                    "\n");
#endif
            }
            break;

        case DCDC_POWER_PROFILE_MEDIUM:
            /* Medium */
            dcdcTrimValue0 = (*((volatile unsigned int *)(FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_0_ADDRS)));
            dcdcTrimValue1 = (*((volatile unsigned int *)(FLASH_NMPA_DCDC_POWER_PROFILE_MEDIUM_1_ADDRS)));

            if (0UL != (dcdcTrimValue0 & 0x1UL))
            {
                dcdcTrimValue0 = dcdcTrimValue0 >> 1;

                PMC->DCDC0 = dcdcTrimValue0;
                PMC->DCDC1 = dcdcTrimValue1;
#if (defined(NIOBE_DEBUG_LEVEL) && (NIOBE_DEBUG_LEVEL >= 1))
                PRINTF(
                    "\nINFO : DCDC Power Profile set to "
                    "MEDIUM"
                    "\n");
#endif
            }
            break;

        case DCDC_POWER_PROFILE_HIGH:
            /* High */
            dcdcTrimValue0 = (*((volatile unsigned int *)(FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_0_ADDRS)));
            dcdcTrimValue1 = (*((volatile unsigned int *)(FLASH_NMPA_DCDC_POWER_PROFILE_HIGH_1_ADDRS)));

            if (0UL != (dcdcTrimValue0 & 0x1UL))
            {
                dcdcTrimValue0 = dcdcTrimValue0 >> 1;

                PMC->DCDC0 = dcdcTrimValue0;
                PMC->DCDC1 = dcdcTrimValue1;
#if (defined(NIOBE_DEBUG_LEVEL) && (NIOBE_DEBUG_LEVEL >= 1))
                PRINTF(
                    "\nINFO : DCDC Power Profile set to "
                    "HIGH"
                    "\n");
#endif
            }
            break;

        default:
            /* Low */
            PMC->DCDC0 = PMC_DCDC0_DEFAULT;
            PMC->DCDC1 = PMC_DCDC1_DEFAULT;
#if (defined(NIOBE_DEBUG_LEVEL) && (NIOBE_DEBUG_LEVEL >= 1))
            PRINTF(
                "\nINFO : DCDC Power Profile set to "
                "LOW"
                "\n");
#endif
            break;
    }
}

/**
 * @brief
 * @param
 * @return
 */
static lowpower_process_corner_enum lowpower_get_part_process_corner(void)
{
#define FLASH_NMPA_PVT_MONITOR_0_RINGO_ADDRS (FLASH_NMPA_BASE + 0x130U)
#define FLASH_NMPA_PVT_MONITOR_1_RINGO_ADDRS (FLASH_NMPA_BASE + 0x140U)

    lowpower_process_corner_enum part_process_corner;
    uint32_t pvt_ringo_hz;
    uint32_t pvt_ringo_0 = (*((volatile unsigned int *)(FLASH_NMPA_PVT_MONITOR_0_RINGO_ADDRS)));
    uint32_t pvt_ringo_1 = (*((volatile unsigned int *)(FLASH_NMPA_PVT_MONITOR_1_RINGO_ADDRS)));

    /*
     * Check that the PVT Monitors Trimmings in flash are valid.
     */
    if (0UL != (pvt_ringo_0 & 0x1UL))
    {
        /* PVT Trimmings in Flash are valid */
        pvt_ringo_0 = pvt_ringo_0 >> 1;
    }
    else
    {
        /* PVT Trimmings in Flash are NOT valid (average value assumed) */
        pvt_ringo_0 = PROCESS_NNN_AVG_HZ;
    }

    if (0UL != (pvt_ringo_1 & 0x1UL))
    {
        /* PVT Trimmings in Flash are valid */
        pvt_ringo_1 = pvt_ringo_1 >> 1;
    }
    else
    {
        /* PVT Trimmings in Flash are NOT valid (average value assumed) */
        pvt_ringo_1 = PROCESS_NNN_AVG_HZ;
    }

    if (pvt_ringo_1 <= pvt_ringo_0)
    {
        pvt_ringo_hz = pvt_ringo_1;
    }
    else
    {
        pvt_ringo_hz = pvt_ringo_0;
    }

    /*
     * Determine the process corner based on the value of the Ring Oscillator frequency
     */
    if (pvt_ringo_hz <= PROCESS_NNN_MIN_HZ)
    {
        /* SSS Process Corner */
        part_process_corner = PROCESS_CORNER_SSS;
#if (defined(NIOBE_DEBUG_LEVEL) && (NIOBE_DEBUG_LEVEL >= 1))
        PRINTF(
            "\nINFO : Process Corner : "
            "SSS"
            "\n");
#endif
    }
    else
    {
        if (pvt_ringo_hz <= PROCESS_NNN_MAX_HZ)
        {
            /* NNN Process Corner */
            part_process_corner = PROCESS_CORNER_NNN;
#if (defined(NIOBE_DEBUG_LEVEL) && (NIOBE_DEBUG_LEVEL >= 1))
            PRINTF(
                "\nINFO : Process Corner : "
                "NNN"
                "\n");
#endif
        }
        else
        {
            /* FFF Process Corner */
            part_process_corner = PROCESS_CORNER_FFF;
#if (defined(NIOBE_DEBUG_LEVEL) && (NIOBE_DEBUG_LEVEL >= 1))
            PRINTF(
                "\nINFO : Process Corner : "
                "FFF"
                "\n");
#endif
        }
    }

    return (part_process_corner);
}

/**
 * @brief	Described in fsl_common.h
 * @param
 * @return
 */
static void lowpower_set_voltage_for_process(lowpower_dcdc_power_profile_enum dcdc_power_profile)
{
    /* Get Sample Process Corner */
    lowpower_process_corner_enum part_process_corner = lowpower_get_part_process_corner();

    switch (part_process_corner)
    {
        case PROCESS_CORNER_SSS:
            /* Slow Corner */
            {
                switch (dcdc_power_profile)
                {
                    case DCDC_POWER_PROFILE_MEDIUM:
                        /* Medium */
                        lowpower_set_system_voltage(VOLTAGE_SSS_MED_MV);
                        break;

                    case DCDC_POWER_PROFILE_HIGH:
                        /* High */
                        lowpower_set_system_voltage(VOLTAGE_SSS_HIG_MV);
                        break;

                    default:
                        /* DCDC_POWER_PROFILE_LOW */
                        lowpower_set_system_voltage(VOLTAGE_SSS_LOW_MV);
                        break;
                } // switch(dcdc_power_profile)
            }
            break;

        case PROCESS_CORNER_FFF:
            /* Fast Corner */
            {
                switch (dcdc_power_profile)
                {
                    case DCDC_POWER_PROFILE_MEDIUM:
                        /* Medium */
                        lowpower_set_system_voltage(VOLTAGE_FFF_MED_MV);
                        break;

                    case DCDC_POWER_PROFILE_HIGH:
                        /* High */
                        lowpower_set_system_voltage(VOLTAGE_FFF_HIG_MV);
                        break;

                    default:
                        /* DCDC_POWER_PROFILE_LOW */
                        lowpower_set_system_voltage(VOLTAGE_FFF_LOW_MV);
                        break;
                } // switch(dcdc_power_profile)
            }
            break;

        default:
            /* Nominal (NNN) and all others Process Corners : assume Nominal Corner */
            {
                switch (dcdc_power_profile)
                {
                    case DCDC_POWER_PROFILE_MEDIUM:
                        /* Medium */
                        lowpower_set_system_voltage(VOLTAGE_NNN_MED_MV);
                        break;

                    case DCDC_POWER_PROFILE_HIGH:
                        /* High */
                        lowpower_set_system_voltage(VOLTAGE_NNN_HIG_MV);
                        break;

                    default:
                        /* DCDC_POWER_PROFILE_LOW */
                        lowpower_set_system_voltage(VOLTAGE_NNN_LOW_MV);
                        break;
                } // switch(dcdc_power_profile)
                break;
            }
    } // switch(part_process_corner)
}

/**
 * @brief             Described in fsl_common.h
 * @param
 * @return
 */
void POWER_SetVoltageForFreq(uint32_t system_freq_hz)
{
    if (system_freq_hz <= DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ)
    {
        /* [0 Hz - DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ Hz] */
        lowpower_set_dcdc_power_profile(DCDC_POWER_PROFILE_LOW); /* DCDC VOUT = 1.05 V by default */
        lowpower_set_voltage_for_process(DCDC_POWER_PROFILE_LOW);
    }
    else
    {
        if (system_freq_hz <= DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ)
        {
            /* ]DCDC_POWER_PROFILE_LOW_MAX_FREQ_HZ Hz - DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ Hz] */
            lowpower_set_dcdc_power_profile(DCDC_POWER_PROFILE_MEDIUM); /* DCDC VOUT = 1.15 V by default */
            lowpower_set_voltage_for_process(DCDC_POWER_PROFILE_MEDIUM);
        }
        else
        {
            /* > DCDC_POWER_PROFILE_MEDIUM_MAX_FREQ_HZ Hz */
            lowpower_set_dcdc_power_profile(DCDC_POWER_PROFILE_HIGH); /* DCDC VOUT = 1.2 V by default */
            lowpower_set_voltage_for_process(DCDC_POWER_PROFILE_HIGH);
        }
    }
}

void POWER_Xtal16mhzCapabankTrim(int32_t pi32_16MfXtalIecLoadpF_x100,
                                 int32_t pi32_16MfXtalPPcbParCappF_x100,
                                 int32_t pi32_16MfXtalNPcbParCappF_x100)
{
    uint32_t u32XOTrimValue;
    uint8_t u8IECXinCapCal6pF, u8IECXinCapCal8pF, u8IECXoutCapCal6pF, u8IECXoutCapCal8pF, u8XOSlave;
    int32_t iaXin_x4, ibXin, iaXout_x4, ibXout;
    int32_t iXOCapInpF_x100, iXOCapOutpF_x100;
    uint8_t u8XOCapInCtrl, u8XOCapOutCtrl;
    uint32_t u32RegVal;
    int32_t i32Tmp;

    /* Enable and set LDO, if not already done */
    POWER_SetXtal16mhzLdo();
    /* Get Cal values from Flash */
    u32XOTrimValue = GET_16MXO_TRIM();
    /* Check validity and apply */
    if ((0UL != (u32XOTrimValue & 1UL)) && (0UL != ((u32XOTrimValue >> 15UL) & 1UL)))
    {
        /* These fields are 7 bits, unsigned */
        u8IECXinCapCal6pF  = (uint8_t)((u32XOTrimValue >> 1UL) & 0x7fUL);
        u8IECXinCapCal8pF  = (uint8_t)((u32XOTrimValue >> 8UL) & 0x7fUL);
        u8IECXoutCapCal6pF = (uint8_t)((u32XOTrimValue >> 16UL) & 0x7fUL);
        u8IECXoutCapCal8pF = (uint8_t)((u32XOTrimValue >> 23UL) & 0x7fUL);
        /* This field is 1 bit */
        u8XOSlave = (uint8_t)((u32XOTrimValue >> 30UL) & 0x1UL);
        /* Linear fit coefficients calculation */
        iaXin_x4  = (int)u8IECXinCapCal8pF - (int)u8IECXinCapCal6pF;
        ibXin     = (int)u8IECXinCapCal6pF - iaXin_x4 * 3;
        iaXout_x4 = (int)u8IECXoutCapCal8pF - (int)u8IECXoutCapCal6pF;
        ibXout    = (int)u8IECXoutCapCal6pF - iaXout_x4 * 3;
    }
    else
    {
        iaXin_x4  = 20;  // gain in LSB/pF
        ibXin     = -9;  // offset in LSB
        iaXout_x4 = 20;  // gain in LSB/pF
        ibXout    = -13; // offset in LSB
        u8XOSlave = 0;
    }
    /* In & out load cap calculation with derating */
    iXOCapInpF_x100 = 2 * pi32_16MfXtalIecLoadpF_x100 - pi32_16MfXtalNPcbParCappF_x100 +
                      39 * ((int32_t)XO_SLAVE_EN - (int32_t)u8XOSlave) - 15;
    iXOCapOutpF_x100 = 2 * pi32_16MfXtalIecLoadpF_x100 - pi32_16MfXtalPPcbParCappF_x100 - 21;
    /* In & out XO_OSC_CAP_Code_CTRL calculation, with rounding */
    i32Tmp         = ((iXOCapInpF_x100 * iaXin_x4 + ibXin * 400) + 200) / 400;
    u8XOCapInCtrl  = (uint8_t)i32Tmp;
    i32Tmp         = ((iXOCapOutpF_x100 * iaXout_x4 + ibXout * 400) + 200) / 400;
    u8XOCapOutCtrl = (uint8_t)i32Tmp;
    /* Read register and clear fields to be written */
    u32RegVal = ANACTRL->XO32M_CTRL;
    u32RegVal &= ~(ANACTRL_XO32M_CTRL_OSC_CAP_IN_MASK | ANACTRL_XO32M_CTRL_OSC_CAP_OUT_MASK);
    /* Configuration of 32 MHz XO output buffers */
#if (XO_SLAVE_EN == 0)
    u32RegVal &= ~(ANACTRL_XO32M_CTRL_SLAVE_MASK | ANACTRL_XO32M_CTRL_ACBUF_PASS_ENABLE_MASK);
#else
    u32RegVal |= ANACTRL_XO32M_CTRL_SLAVE_MASK | ANACTRL_XO32M_CTRL_ACBUF_PASS_ENABLE_MASK;
#endif
    /* XO_OSC_CAP_Code_CTRL to XO_OSC_CAP_Code conversion */
    u32RegVal |= (uint32_t)CLOCK_u8OscCapConvert(u8XOCapInCtrl, 13) << ANACTRL_XO32M_CTRL_OSC_CAP_IN_SHIFT;
    u32RegVal |= (uint32_t)CLOCK_u8OscCapConvert(u8XOCapOutCtrl, 13) << ANACTRL_XO32M_CTRL_OSC_CAP_OUT_SHIFT;
    /* Write back to register */
    ANACTRL->XO32M_CTRL = u32RegVal;
}

void POWER_Xtal32khzCapabankTrim(int32_t pi32_32kfXtalIecLoadpF_x100,
                                 int32_t pi32_32kfXtalPPcbParCappF_x100,
                                 int32_t pi32_32kfXtalNPcbParCappF_x100)
{
    uint32_t u32XOTrimValue;
    uint8_t u8IECXinCapCal6pF, u8IECXinCapCal8pF, u8IECXoutCapCal6pF, u8IECXoutCapCal8pF;
    int32_t iaXin_x4, ibXin, iaXout_x4, ibXout;
    int32_t iXOCapInpF_x100, iXOCapOutpF_x100;
    uint8_t u8XOCapInCtrl, u8XOCapOutCtrl;
    uint32_t u32RegVal;
    int32_t i32Tmp;
    /* Get Cal values from Flash */
    u32XOTrimValue = GET_32KXO_TRIM();
    /* check validity and apply */
    if ((0UL != (u32XOTrimValue & 1UL)) && (0UL != ((u32XOTrimValue >> 15UL) & 1UL)))
    {
        /* These fields are 7 bits, unsigned */
        u8IECXinCapCal6pF  = (uint8_t)((u32XOTrimValue >> 1UL) & 0x7fUL);
        u8IECXinCapCal8pF  = (uint8_t)((u32XOTrimValue >> 8UL) & 0x7fUL);
        u8IECXoutCapCal6pF = (uint8_t)((u32XOTrimValue >> 16UL) & 0x7fUL);
        u8IECXoutCapCal8pF = (uint8_t)((u32XOTrimValue >> 23UL) & 0x7fUL);
        /* Linear fit coefficients calculation */
        iaXin_x4  = (int)u8IECXinCapCal8pF - (int)u8IECXinCapCal6pF;
        ibXin     = (int)u8IECXinCapCal6pF - iaXin_x4 * 3;
        iaXout_x4 = (int)u8IECXoutCapCal8pF - (int)u8IECXoutCapCal6pF;
        ibXout    = (int)u8IECXoutCapCal6pF - iaXout_x4 * 3;
    }
    else
    {
        iaXin_x4  = 16; // gain in LSB/pF
        ibXin     = 12; // offset in LSB
        iaXout_x4 = 16; // gain in LSB/pF
        ibXout    = 11; // offset in LSB
    }

    /* In & out load cap calculation with derating */
    iXOCapInpF_x100  = 2 * pi32_32kfXtalIecLoadpF_x100 - pi32_32kfXtalNPcbParCappF_x100 - 130;
    iXOCapOutpF_x100 = 2 * pi32_32kfXtalIecLoadpF_x100 - pi32_32kfXtalPPcbParCappF_x100 - 41;

    /* In & out XO_OSC_CAP_Code_CTRL calculation, with rounding */
    i32Tmp         = ((iXOCapInpF_x100 * iaXin_x4 + ibXin * 400) + 200) / 400;
    u8XOCapInCtrl  = (uint8_t)i32Tmp;
    i32Tmp         = ((iXOCapOutpF_x100 * iaXout_x4 + ibXout * 400) + 200) / 400;
    u8XOCapOutCtrl = (uint8_t)i32Tmp;

    /* Read register and clear fields to be written */
    u32RegVal = PMC->XTAL32K;
    u32RegVal &= ~(PMC_XTAL32K_CAPBANKIN_MASK | PMC_XTAL32K_CAPBANKOUT_MASK);

    /* XO_OSC_CAP_Code_CTRL to XO_OSC_CAP_Code conversion */
    u32RegVal |= (uint32_t)CLOCK_u8OscCapConvert(u8XOCapInCtrl, 23) << PMC_XTAL32K_CAPBANKIN_SHIFT;
    u32RegVal |= (uint32_t)CLOCK_u8OscCapConvert(u8XOCapOutCtrl, 23) << PMC_XTAL32K_CAPBANKOUT_SHIFT;

    /* Write back to register */
    PMC->XTAL32K = u32RegVal;
}

void POWER_SetXtal16mhzLdo(void)
{
    uint32_t temp;
    const uint32_t u32Mask =
        (ANACTRL_LDO_XO32M_VOUT_MASK | ANACTRL_LDO_XO32M_IBIAS_MASK | ANACTRL_LDO_XO32M_STABMODE_MASK);

    const uint32_t u32Value =
        (ANACTRL_LDO_XO32M_VOUT(0x5) | ANACTRL_LDO_XO32M_IBIAS(0x2) | ANACTRL_LDO_XO32M_STABMODE(0x1));

    /* Enable & set-up XTAL 32 MHz clock LDO */
    temp = ANACTRL->LDO_XO32M;

    if ((temp & u32Mask) != u32Value)
    {
        temp &= ~u32Mask;

        /*
         * Enable the XTAL32M LDO
         * Adjust the output voltage level, 0x5 for 1.1V
         * Adjust the biasing current, 0x2 value
         * Stability configuration, 0x1 default mode
         */
        temp |= u32Value;

        ANACTRL->LDO_XO32M = temp;

        /* Delay for LDO to be up */
        // CLOCK_uDelay(20);
    }

    /* Enable LDO XO32M */
    PMC->PDRUNCFGCLR0 = PMC_PDRUNCFG0_PDEN_LDOXO32M_MASK;
}

void POWER_SetXtal16mhzTrim(uint32_t amp, uint32_t gm)
{
    uint32_t temp;
    const uint32_t u32Mask  = (ANACTRL_XO32M_CTRL_AMP_MASK | ANACTRL_XO32M_CTRL_GM_MASK);
    const uint32_t u32Value = (ANACTRL_XO32M_CTRL_AMP(amp) | ANACTRL_XO32M_CTRL_GM(gm));

    /* Set-up XTAL 16-MHz Trimmings */
    temp = ANACTRL->XO32M_CTRL;
    temp &= ~u32Mask;
    temp |= u32Value;
    ANACTRL->XO32M_CTRL = temp;
}

/*!
 * @brief set BOD VBAT level.
 *
 * @param level BOD detect level
 * @param hyst BoD Hysteresis control
 * @param enBodVbatReset VBAT brown out detect reset
 */
void POWER_SetBodVbatLevel(power_bod_vbat_level_t level, power_bod_hyst_t hyst, bool enBodVbatReset)
{
    uint32_t pmc_reset_ctrl;
    /* BOD VBAT disable reset */
    pmc_reset_ctrl =
        PMC->RESETCTRL & (~(PMC_RESETCTRL_BODVBATRESETENA_SECURE_MASK | PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_MASK));
    pmc_reset_ctrl |= (0x2UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_SHIFT) |
                      (0x2UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_SHIFT);

    PMC->RESETCTRL = pmc_reset_ctrl;

    PMC->BODVBAT = (PMC->BODVBAT & (~(PMC_BODVBAT_TRIGLVL_MASK | PMC_BODVBAT_HYST_MASK))) | PMC_BODVBAT_TRIGLVL(level) |
                   PMC_BODVBAT_HYST(hyst);

    /* BOD VBAT enable reset */
    if ((uint32_t)enBodVbatReset == 1UL)
    {
        pmc_reset_ctrl &= (~(PMC_RESETCTRL_BODVBATRESETENA_SECURE_MASK | PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_MASK));
        pmc_reset_ctrl |= (0x1UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_SHIFT) |
                          (0x1UL << PMC_RESETCTRL_BODVBATRESETENA_SECURE_DP_SHIFT);
        PMC->RESETCTRL = pmc_reset_ctrl;
    }
}

#if defined(PMC_BODCORE_TRIGLVL_MASK)
/*!
 * @brief set BOD core level.
 *
 * @param level BOD detect level
 * @param hyst BoD Hysteresis control
 * @param enBodCoreReset core brown out detect reset
 */
void POWER_SetBodCoreLevel(power_bod_core_level_t level, power_bod_hyst_t hyst, bool enBodCoreReset)
{
    uint32_t pmc_reset_ctrl;
    /* BOD CORE disable reset */
    pmc_reset_ctrl =
        PMC->RESETCTRL & (~(PMC_RESETCTRL_BODCORERESETENA_SECURE_MASK | PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_MASK));
    pmc_reset_ctrl |=
        (0x2 << PMC_RESETCTRL_BODCORERESETENA_SECURE_SHIFT) | (0x2 << PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_SHIFT);

    PMC->RESETCTRL = pmc_reset_ctrl;

    PMC->BODCORE = (PMC->BODCORE & (~(PMC_BODCORE_TRIGLVL_MASK | PMC_BODCORE_HYST_MASK))) | PMC_BODCORE_TRIGLVL(level) |
                   PMC_BODCORE_HYST(hyst);

    /* BOD CORE enable reset */
    if (enBodCoreReset == 1)
    {
        pmc_reset_ctrl &= (~(PMC_RESETCTRL_BODCORERESETENA_SECURE_MASK | PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_MASK));
        pmc_reset_ctrl |= (0x1 << PMC_RESETCTRL_BODCORERESETENA_SECURE_SHIFT) |
                          (0x1 << PMC_RESETCTRL_BODCORERESETENA_SECURE_DP_SHIFT);
        PMC->RESETCTRL = pmc_reset_ctrl;
    }
}
#endif

/**
 * @brief   Return some key information related to the device reset causes / wake-up sources, for all power modes.
 * @param   p_reset_cause   : the device reset cause, according to the definition of power_device_reset_cause_t type.
 * @param   p_boot_mode     : the device boot mode, according to the definition of power_device_boot_mode_t type.
 * @param   p_wakeupio_cause: the wake-up pin sources, according to the definition of register PMC->WAKEIOCAUSE[3:0].

 * @return  Nothing
 *
 *         !!!  IMPORTANT ERRATA - IMPORTANT ERRATA - IMPORTANT ERRATA     !!!
 *         !!!   valid ONLY for LPC55S69 (not for LPC55S16 and LPC55S06)   !!!
 *         !!!   when FALLING EDGE DETECTION is enabled on wake-up pins:   !!!
 *         - 1. p_wakeupio_cause is NOT ACCURATE
 *         - 2. Spurious kRESET_CAUSE_DPDRESET_WAKEUPIO* event is reported when
 *              several wake-up sources are enabled during DEEP-POWER-DOWN
 *              (like enabling wake-up on RTC and Falling edge wake-up pins)
 *
 */
void POWER_GetWakeUpCause(power_device_reset_cause_t *p_reset_cause,
                          power_device_boot_mode_t *p_boot_mode,
                          uint32_t *p_wakeupio_cause)
{
    uint32_t reset_cause_reg;
    uint32_t boot_mode_reg;

#if (defined(LPC55S06_SERIES) || defined(LPC55S04_SERIES) || defined(LPC5506_SERIES) || defined(LPC5504_SERIES) || \
     defined(LPC5502_SERIES) || defined(LPC55S16_SERIES) || defined(LPC55S14_SERIES) || defined(LPC5516_SERIES) || \
     defined(LPC5514_SERIES) || defined(LPC5512_SERIES))
    reset_cause_reg = (PMC->AOREG1) & 0x3FF0UL;
#else /* LPC55S69/28 */
    reset_cause_reg = (PMC->AOREG1) & 0x1FF0UL;
#endif

    /*
     * Prioritize interrupts source with respect to their critical level
     */
#if (defined(LPC55S06_SERIES) || defined(LPC55S04_SERIES) || defined(LPC5506_SERIES) || defined(LPC5504_SERIES) || \
     defined(LPC5502_SERIES) || defined(LPC55S16_SERIES) || defined(LPC55S14_SERIES) || defined(LPC5516_SERIES) || \
     defined(LPC5514_SERIES) || defined(LPC5512_SERIES))
    if (0UL != (reset_cause_reg & PMC_AOREG1_CDOGRESET_MASK))
    { /* Code Watchdog Reset */
        *p_reset_cause    = kRESET_CAUSE_CDOGRESET;
        *p_boot_mode      = kBOOT_MODE_POWER_UP;
        *p_wakeupio_cause = 0; /* Device has not been waked-up by any wake-up pins */
    }
    else
#endif
    {
        if (0UL != (reset_cause_reg & PMC_AOREG1_WDTRESET_MASK))
        { /* Watchdog Timer Reset */
            *p_reset_cause    = kRESET_CAUSE_WDTRESET;
            *p_boot_mode      = kBOOT_MODE_POWER_UP;
            *p_wakeupio_cause = 0; /* Device has not been waked-up by any wake-up pins */
        }
        else
        {
            if (0UL != (reset_cause_reg & PMC_AOREG1_SYSTEMRESET_MASK))
            { /* ARM System Reset */
                *p_reset_cause    = kRESET_CAUSE_ARMSYSTEMRESET;
                *p_boot_mode      = kBOOT_MODE_POWER_UP;
                *p_wakeupio_cause = 0; /* Device has not been waked-up by any wake-up pins */
            }
            else
            {
                boot_mode_reg = (PMC->STATUS & PMC_STATUS_BOOTMODE_MASK) >> PMC_STATUS_BOOTMODE_SHIFT;

                if (boot_mode_reg == 0UL) /* POWER-UP: Power On Reset, Pin reset, Brown Out Detectors, Software Reset */
                {
                    *p_boot_mode      = kBOOT_MODE_POWER_UP; /* All non wake-up from a Low Power mode */
                    *p_wakeupio_cause = 0;                   /* Device has not been waked-up by any wake-up pins */

                    /*
                     * Prioritise Reset causes, starting from the strongest (Power On Reset)
                     */
                    if (0UL != (reset_cause_reg & PMC_AOREG1_POR_MASK))
                    { /* Power On Reset */
                        *p_reset_cause = kRESET_CAUSE_POR;
                    }
                    else
                    {
                        if (0UL != (reset_cause_reg & PMC_AOREG1_BODRESET_MASK))
                        { /* Brown-out Detector reset (either BODVBAT or BODCORE) */
                            *p_reset_cause = kRESET_CAUSE_BODRESET;
                        }
                        else
                        {
                            if (0UL != (reset_cause_reg & PMC_AOREG1_PADRESET_MASK))
                            { /* Hardware Pin Reset */
                                *p_reset_cause = kRESET_CAUSE_PADRESET;
                            }
                            else
                            {
                                if (0UL != (reset_cause_reg & PMC_AOREG1_SWRRESET_MASK))
                                { /* Software triggered Reset */
                                    *p_reset_cause = kRESET_CAUSE_SWRRESET;
                                }
                                else
                                { /* Unknown Reset Cause */
                                    *p_reset_cause = kRESET_CAUSE_NOT_DETERMINISTIC;
                                }
                            }
                        }
                    }

#if (defined(LPC55S06_SERIES) || defined(LPC55S04_SERIES) || defined(LPC5506_SERIES) || defined(LPC5504_SERIES) || \
     defined(LPC5502_SERIES) || defined(LPC55S16_SERIES) || defined(LPC55S14_SERIES) || defined(LPC5516_SERIES) || \
     defined(LPC5514_SERIES) || defined(LPC5512_SERIES))
                    /* Transfer the control of the 4 wake-up pins to IOCON (instead of the Power Management Controller
                     */
                    PMC->WAKEUPIOCTRL = PMC->WAKEUPIOCTRL & (~PMC_WAKEUPIOCTRL_WAKEUPIO_ENABLE_CTRL_MASK);
#endif
                }
                else /* DEEP-SLEEP, POWER-DOWN and DEEP-POWER-DOWN */
                {
                    /*
                     * 1- First, save wakeup_io_cause register ...
                     */
                    *p_wakeupio_cause = PMC->WAKEIOCAUSE;

                    if (boot_mode_reg == 3UL) /* DEEP-POWER-DOWN */
                    {
                        *p_boot_mode = kBOOT_MODE_LP_DEEP_POWER_DOWN;

                        switch (((reset_cause_reg >> PMC_AOREG1_DPDRESET_WAKEUPIO_SHIFT) & 0x7UL))
                        {
                            case 1:
                                *p_reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO;
                                break;
                            case 2:
                                *p_reset_cause = kRESET_CAUSE_DPDRESET_RTC;
                                break;
                            case 3:
                                *p_reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO_RTC;
                                break;
                            case 4:
                                *p_reset_cause = kRESET_CAUSE_DPDRESET_OSTIMER;
                                break;
                            case 5:
                                *p_reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO_OSTIMER;
                                break;
                            case 6:
                                *p_reset_cause = kRESET_CAUSE_DPDRESET_RTC_OSTIMER;
                                break;
                            case 7:
                                *p_reset_cause = kRESET_CAUSE_DPDRESET_WAKEUPIO_RTC_OSTIMER;
                                break;
                            default:
                                /* Unknown Reset Cause */
                                *p_reset_cause = kRESET_CAUSE_NOT_DETERMINISTIC;
                                break;
                        }

#if (defined(LPC55S06_SERIES) || defined(LPC55S04_SERIES) || defined(LPC5506_SERIES) || defined(LPC5504_SERIES) || \
     defined(LPC5502_SERIES) || defined(LPC55S16_SERIES) || defined(LPC55S14_SERIES) || defined(LPC5516_SERIES) || \
     defined(LPC5514_SERIES) || defined(LPC5512_SERIES))
                        /*
                         * 2- Next, transfer the control of the 4 wake-up pins
                         * to IOCON (instead of the Power Management Controller)
                         */
                        PMC->WAKEUPIOCTRL = PMC->WAKEUPIOCTRL & (~PMC_WAKEUPIOCTRL_WAKEUPIO_ENABLE_CTRL_MASK);
#endif
                    }
                    else /* DEEP-SLEEP and POWER-DOWN */
                    {
                        *p_reset_cause = kRESET_CAUSE_NOT_RELEVANT;

                        /*
                         * The control of the 4 wake-up pins is already in IOCON,
                         * so there is nothing special to do.
                         */

                        if (boot_mode_reg == 1UL) /* DEEP-SLEEP */
                        {
                            *p_boot_mode = kBOOT_MODE_LP_DEEP_SLEEP;
                        }
                        else /* POWER-DOWN */
                        {
                            *p_boot_mode = kBOOT_MODE_LP_POWER_DOWN;

                        } /* if ( boot_mode_reg == 1 ) DEEP-SLEEP */

                    } /* if ( boot_mode == 3 )  DEEP-POWER-DOWN */

                } /* if ( boot_mode == 0 )  POWER-UP */

            } /* if ( reset_cause_reg & PMC_AOREG1_CDOGRESET_MASK ) */

        } /* if ( reset_cause_reg & PMC_AOREG1_WDTRESET_MASK ) */

    } /* if ( reset_cause_reg & PMC_AOREG1_SYSTEMRESET_MASK ) */
}
