/***************************************************************************//**
* \file cyhal_syspm.h
*
* \brief
* Provides a high level interface for interacting with the Infineon power
* management configuration. This interface abstracts out the
* chip specific details. If any chip specific functionality is necessary, or
* performance is critical the low level functions can be used directly.
*
********************************************************************************
* \copyright
* Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
* an affiliate of Cypress Semiconductor Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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.
*******************************************************************************/
/**
* \addtogroup group_hal_syspm System Power Management
* \ingroup group_hal
* \{
* Interface for changing power states and restricting when they are allowed.
*
* Power management is handled both at a system level and at a peripheral driver
* level. The system wide API (this) allows the user to interact with the product
* as a whole. Additionally, each peripheral keeps track of what its state is and
* whether it can safely move to a new state while still maintaining any current
* operations. To initialize the system wide power management, \ref cyhal_syspm_init
* should be called as part of the initial device startup.
*
* At the System level, the APIs are intended to allow the application to specify
* exactly what is happening. It can request changes to both the MCU Power State
* as well as the System Wide Power State. There are three supported MCU Power
* States:
* * Active - This is the normal operating state of the MCU
* * Sleep - In this state the MCU is no longer running. It can be woken up again
* from an interrupt. This state is reached by calling \ref cyhal_syspm_sleep.
* * Deep Sleep - In this state the MCU is no longer running. It can only be woken
* up by select interrupts. This state is reached by calling \ref
* cyhal_syspm_deepsleep.
*
Additionally, there are three supported system states:
* * Normal (\ref CYHAL_SYSPM_SYSTEM_NORMAL) - This is a normal operating state
* for the device. This is exposed by \ref cyhal_syspm_set_system_state.
* * Low (\ref CYHAL_SYSPM_SYSTEM_LOW) - This is a lower power operating state
* that may be supported by the device. This state often imposes specific
* requirements on clock speeds and voltage levels. See the device specific
* documentation for any device specific requirements for this mode, or whether
* it is even supported. If the device supports this mode, it is exposed by
* \ref cyhal_syspm_set_system_state.
* * Hibernate - This is the lowest available power state. In this state most of
* the chip is powered down. It has a very limited number of wakeup sources, and
* may require the device to reboot in order to come back up. It can be accessed
* by calling \ref cyhal_syspm_hibernate.
* Any time a power state transition is requested a series of callbacks are invoked.
* This allows peripherals, or other parts of the application, to confirm they are
* not currently doing something that would not work in the requested power state.
* HAL Peripheral drivers automatically register these callbacks when they are
* initialized. The application also has the option to register a callback
* function(s) to be called on requested state transitions by callling \ref
* cyhal_syspm_register_callback. If registered, the application level callbacks
* are invoked first. This gives the application a chance stop any peripherals, if
* appropriate, to ensure the power transition can actually happen. Alternatively
* it can directly reject the transition. Each callback registered can specify
* the exact set of states ( \ref cyhal_syspm_callback_state_t ) that it should
* be called for. Each callback is invoked multiple times as part of the transition
* process as defined by \ref cyhal_syspm_callback_mode_t.
*
* At any point the code can lock the ability to enter deep sleep by calling \ref
* cyhal_syspm_lock_deepsleep. This should be done in critical blocks that need to
* continue remain active. When the critical work is complete, and the lock is no
* longer needed, it can be released by calling \ref cyhal_syspm_unlock_deepsleep.
* The lock is a counter with a max count of USHRT_MAX. It must be locked/unlocked
* an equal number of times before the device is actually able to enter deep sleep.
*
* All peripherals are expected to operate in the default Active/Normal power
* state. Some peripherals (primarily analog) can operate in lower power states as
* well. These drivers will operate in all power states that the hardware supports.
*
* When power transitions are requested each type of peripheral has a default
* behavior. Peripherals that can continue to operate in the requested power mode
* do not interfere. Peripherals that are not currently active allow the transition,
* but make sure they restore their state if needed for when the device comes back.
* Peripherals that are active and cannot continue to work in the requested power
* state will block the transition.
*
* \note The power management functionality available depends on the availability
* of the features in the hardware. For detailed information about exactly what is
* supported on each device, refer to the Device Datasheet or Technical Reference
* Manual (TRM).
* \section section_syspm_features Features
* This driver provides control over multiple different types of power management
* and when those transitions are allowed:
* * Change CPU Power State: APIs to allow changing the current CPU state into
* one of the lower power CPU states (SLEEP, DEEPSLEEP)
* * Change System Power State: An API allows for changing the system wide power
* state between one of states (NORMAL, LOW)
* - Hibernate: An API that allows to set the hibernate
* wakeup source and set the system state to Hibernate.
* * General Purpose Power State Transition Callback: APIs allow for
* registering/unregistering a callback function to be notified when various power
* state transitions happen. If registered, the application can do anything necessary
* at power transitions. It can even prevent the transition if need-be.
* * Peripheral Specific Power State Transition Callback: APIs allow for
* registering/unregistering a callback function to be called when a peripheral with
* a CUSTOM power mode strategy exists and a power mode transition is requested.
* This allows the application to customize when it is OK for the peripheral to enter
* a low power state.
* - Lock DeepSleep: APIs to prevent/allow the CPU from going to deep sleep. This
* is a convenience API rather than needing to implement a full Transition Callback
* handler.
*
* \section section_syspm_quickstart Quick Start
*
* Unlike most HAL drivers this does not require initializing an instance object. The
* APIs provided here can be called at anytime. See the snippets below for examples
* of how to use this driver.
*
* \section section_syspm_snippets Code Snippets
*
* \subsection subsection_syspm_snippet_1 Snippet 1: Simple deep sleep locking
* The following snippet shows how to use the deep sleep locking APIs to restrict
* when the device can enter deep sleep. In between the lock/unlock calls any
* attempt to change power modes will automatically be canceled.
* \snippet hal_syspm.c snippet_cyhal_syspm_simple_locking
*
* \subsection subsection_syspm_snippet_2 Snippet 2: Calling different power state functions
* The following snippet shows the different functions that exist to change power states
* on the device and how they can each be called.
* \snippet hal_syspm.c snippet_cyhal_syspm_power_transitions
*
* \subsection subsection_syspm_snippet_3 Snippet 3: Using callbacks for application power management
* The following snippet shows how to use the callback mechanisms to manage whether
* it is safe to enter low power modes.
* \snippet hal_syspm.c snippet_cyhal_syspm_app_callback
*/
#pragma once
#include
#include
#include "cy_result.h"
#include "cyhal_general_types.h"
#include "cyhal_hw_types.h"
#if defined(__cplusplus)
extern "C" {
#endif
/** \addtogroup group_hal_results_syspm SYSPM HAL Results
* SYSPM specific return codes
* \ingroup group_hal_results
* \{ *//**
*/
/** Incorrect argument passed into a function. */
#define CYHAL_SYSPM_RSLT_BAD_ARGUMENT \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 0))
/** Driver was unable to be initialized. */
#define CYHAL_SYSPM_RSLT_INIT_ERROR \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 1))
/** Failed to register callback */
#define CYHAL_SYSPM_RSLT_CB_REGISTER_ERROR \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 2))
/** Power Management transition is pending, data cannot be transferred */
#define CYHAL_SYSPM_RSLT_ERR_PM_PENDING \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 3))
/** Functionality not supported on the current platform */
#define CYHAL_SYSPM_RSLT_ERR_NOT_SUPPORTED \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 4))
/** Deepsleep has been locked */
#define CYHAL_SYSPM_RSLT_DEEPSLEEP_LOCKED \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 5))
/**
* \}
*/
/** \cond INTERNAL */
/** Sentinel value to indicate end of callback list */
#define CYHAL_SYSPM_END_OF_LIST ((cyhal_syspm_callback_data_t*)0x789)
/** \endcond */
/** Enumeration of the system wide power modes. These modes are device specifc and
* may not be supported on all devices. Refer to the device specific documentation
* or the Data Sheet to determine what is allowed. Devices that do support these
* modes may have requirements for adjusting system settings such as clocks or
* voltage levels before transition.
*/
typedef enum
{
CYHAL_SYSPM_SYSTEM_NORMAL, /**< Normal Mode. */
CYHAL_SYSPM_SYSTEM_LOW, /**< Low Power Mode. */
} cyhal_syspm_system_state_t;
/** Enumeration of the system Deep Sleep modes. These modes are device specifc and
* may not be supported on all devices. Refer to the device specific documentation
* or the Data Sheet to determine what is allowed.
*/
typedef enum
{
CYHAL_SYSPM_SYSTEM_DEEPSLEEP_NONE, /**< Not Deep Sleep Mode. */
CYHAL_SYSPM_SYSTEM_DEEPSLEEP, /**< Deep Sleep Mode. */
CYHAL_SYSPM_SYSTEM_DEEPSLEEP_RAM, /**< Deep Sleep RAM Mode. */
CYHAL_SYSPM_SYSTEM_DEEPSLEEP_OFF, /**< Deep Sleep OFF Mode. */
} cyhal_syspm_system_deep_sleep_mode_t;
/** Flags enum for the hibernate wakeup sources.
* \note Not all wakeup sources are valid on devices. Refer to the datasheet for
* device specifics.
*/
typedef enum
{
CYHAL_SYSPM_HIBERNATE_LPCOMP0_LOW = 0x01U, /**< Wake on a low logic level for the LPComp0. */
CYHAL_SYSPM_HIBERNATE_LPCOMP0_HIGH = 0x02U, /**< Wake on a high logic level for the LPComp0. */
CYHAL_SYSPM_HIBERNATE_LPCOMP1_LOW = 0x04U, /**< Wake on a low logic level for the LPComp1. */
CYHAL_SYSPM_HIBERNATE_LPCOMP1_HIGH = 0x08U, /**< Wake on a high logic level for the LPComp1. */
CYHAL_SYSPM_HIBERNATE_RTC_ALARM = 0x10U, /**< Configure the RTC alarm as wakeup source. */
CYHAL_SYSPM_HIBERNATE_WDT = 0x20U, /**< Configure the WDT interrupt as wakeup source. */
CYHAL_SYSPM_HIBERNATE_PINA_LOW = 0x40U, /**< Configure a low logic level for the first wakeup-pin.
See device datasheet for specific pin. */
CYHAL_SYSPM_HIBERNATE_PINA_HIGH = 0x80U, /**< Configure a high logic level for the first wakeup-pin.
See device datasheet for specific pin. */
CYHAL_SYSPM_HIBERNATE_PINB_LOW = 0x100U, /**< Configure a low logic level for the second wakeup-pin.
See device datasheet for specific pin. */
CYHAL_SYSPM_HIBERNATE_PINB_HIGH = 0x200U /**< Configure a high logic level for the second wakeup-pin.
See device datasheet for specific pin. */
} cyhal_syspm_hibernate_source_t;
/** Supply voltages whose levels can be specified and queried via \ref cyhal_syspm_set_supply_voltage and
* \ref cyhal_syspm_get_supply_voltage, respectively.
*
* \note Not all supplies which are present are included here. This enum only contains the voltage supplies
* whose values are relevant to the operation of one or more HAL drivers.
*/
typedef enum
{
CYHAL_VOLTAGE_SUPPLY_VDDA = 0u, //!< VDDA - Analog supply voltage
CYHAL_VOLTAGE_SUPPLY_MAX = CYHAL_VOLTAGE_SUPPLY_VDDA //!< Alias for the highest value in this enum
} cyhal_syspm_voltage_supply_t;
/**
* Performs any system wide power management initialization that is needed for future operations.
* This can include things like unlocking IOs that might have been frozen when entering a low
* power state or registering callback functions that are necessary to allow notifications of
* power events. This should be called as part of initializing the device in a Board Support Package
* (BSP).
*
* @return Returns CY_RSLT_SUCCESS if the processor successfully entered the hibernate mode,
* otherwise error.
*/
cy_rslt_t cyhal_syspm_init(void);
/** Sets the system mode to hibernate.
*
* This function configures the sources to wake up the device from hibernate mode
* and then sets the system to hibernate mode.
*
* In hibernate mode, all internal supplies are off and no internal state is retained.
*
* Sources can be wakeup pins, LPComparators, Watchdog (WDT) interrupt, or a Real-Time
* clock (RTC) alarm (interrupt). Wakeup from system hibernate always results in a device
* reset and normal boot process.
*
* Wakeup pins:
*
* A wakeup is supported by pins with programmable polarity. These pins
* are typically connected to the GPIO pins or on-chip peripherals under some
* conditions. See device datasheet to check if this feature is supported and for specific
* pin connections. Setting the wakeup pin to this level will cause a wakeup from
* system hibernate mode.
*
* LPComparators:
*
* A wakeup is supported by LPComps with programmable polarity.
* Setting the LPComp to this level will cause a wakeup from system hibernate
* mode.
*
* Watchdog Timer:
*
* A wakeup is performed by a WDT interrupt.
*
* Real-time Clock:
*
* A wakeup is performed by the RTC alarm.
*
* For information about hibernate behavior, wakeup sources and their assignment in specific
* devices, refer to the appropriate device TRM.
*
* @param[in] wakeup_source
* The source to be configured as a wakeup source from the system hibernate power mode,
* see @ref cyhal_syspm_hibernate_source_t. The input parameter values can be ORed.
* For example, if you want to enable LPComp0 (active high) and WDT, call this function:
* cyhal_syspm_hibernate(CYHAL_SYSPM_HIBERNATE_LPCOMP0_HIGH | CYHAL_SYSPM_HIBERNATE_WDT).
*
* @warning Do not call this function with different polarity levels for the same
* wakeup source. For example, do not call a function like this:
* cyhal_syspm_hibernate(CYHAL_SYSPM_HIBERNATE_LPCOMP0_LOW | CYHAL_SYSPM_HIBERNATE_LPCOMP0_HIGH);
*
* @return Returns CY_RSLT_SUCCESS if the processor successfully entered the hibernate mode,
* otherwise error.
*/
cy_rslt_t cyhal_syspm_hibernate(cyhal_syspm_hibernate_source_t wakeup_source);
/** Set the system-wide state of the device. This is used to change the power state
* within the Active power mode. \ref cyhal_syspm_get_system_state can be used to
* get the current state.
* \note Not all devices support different states within the Active power mode. If
* the device does not support changing state, an error will be returned.
*
* @param[in] state System wide state.
*
* @return Returns CY_RSLT_SUCCESS if the processor successfully entered the requested system state,
* otherwise error.
*/
cy_rslt_t cyhal_syspm_set_system_state(cyhal_syspm_system_state_t state);
/** Gets the system-wide state of the device. States can be changed by calling
* \ref cyhal_syspm_set_system_state.
* \note Not all devices support different states within the Active power mode. If
* the device does not support changing state, this will return \ref
* CYHAL_SYSPM_SYSTEM_NORMAL.
* @return Returns the current system-wide power state of the device.
*/
cyhal_syspm_system_state_t cyhal_syspm_get_system_state(void);
/** Register the specified handler with the power manager to be notified of power
* state changes. This is intended for application wide decisions. Peripherals handle
* their ability to perform power transitions internally. This callback will be called
* before any of the peripheral callbacks for \ref CYHAL_SYSPM_CHECK_READY and
* \ref CYHAL_SYSPM_BEFORE_TRANSITION. This callback will be called after all peripheral
* callback for \ref CYHAL_SYSPM_CHECK_FAIL and \ref CYHAL_SYSPM_AFTER_TRANSITION.
* \note The callback will be executed from a critical section
*
* @param[in] callback_data The data for the callback to register
*/
void cyhal_syspm_register_callback(cyhal_syspm_callback_data_t *callback_data);
/** Removes the registered handler from the power manager so no future notifications are made.
*
* * @param[in] callback_data The data for the callback to unregister
*/
void cyhal_syspm_unregister_callback(cyhal_syspm_callback_data_t *callback_data);
/** Set CPU to sleep mode.
*
* @return Returns CY_RSLT_SUCCESS if the processor successfully entered the sleep mode ,
* otherwise error.
*/
cy_rslt_t cyhal_syspm_sleep(void);
/** Set CPU to deep sleep mode.
*
* @return Returns CY_RSLT_SUCCESS if the processor successfully entered the deep sleep mode,
* otherwise error.
*/
cy_rslt_t cyhal_syspm_deepsleep(void);
/** Lock deep sleep.
*
* This function prevents the CPU from going to deep sleep. The lock is implemented as a counter
* from 0 to USHRT_MAX. Each call to this function increments the counter by 1.
* \ref cyhal_syspm_unlock_deepsleep must be called an equal number of times to fully unlock.
* Deepsleep will only be allowed when the counter is equal to 0.
*/
void cyhal_syspm_lock_deepsleep(void);
/** Unlock deep sleep.
*
* This function decrements the lock counter by 1 and must be called an equal number of times as
* @ref cyhal_syspm_lock_deepsleep is called to fully unlock. Deepsleep will only be allowed
* when the counter is equal to 0.
*/
void cyhal_syspm_unlock_deepsleep(void);
/** Timed deep-sleep without system timer.
*
* Provides a way to deep-sleep for a desired number of milliseconds(ms) with the system timer disabled.
* The system timer is disabled before sleeping and a low power timer is setup to wake
* the device from deep-sleep after the desired number of ms have elapsed.
*
* @note The actual ms in the best case will be 1 ms less than the desired time to
* prevent the device from over-sleeping due to low clock accuracy.
*
* @param[in] lptimer_obj Pre-Initialized LPTimer object.
* @param[in] desired_ms Desired number of ms to deep-sleep.
* @param[out] actual_ms Actual number of ms that was spent in deep-sleep.
* This value can range from 0 to desired_ms - 1
* depending on how long the device was able to deep-sleep.
* @return The status of the deep-sleep request.
*/
cy_rslt_t cyhal_syspm_tickless_deepsleep(cyhal_lptimer_t *lptimer_obj, uint32_t desired_ms, uint32_t *actual_ms);
/** Timed sleep without system timer.
*
* Provides a way to sleep for a desired number of milliseconds(ms) with the system timer disabled.
* The system timer is disabled before sleeping and a low power timer is setup to wake
* the device from sleep after the desired number of ms have elapsed.
*
* @note The actual ms in the best case will be 1 ms less than the desired time to
* prevent the device from over-sleeping due to low clock accuracy.
*
* @param[in] lptimer_obj Pre-Initialized LPTimer object.
* @param[in] desired_ms Desired number of ms to sleep.
* @param[out] actual_ms Actual number of ms that was spent in sleep.
* This value can range from 0 to desired_ms - 1
* depending on how long the device was able to sleep.
* @return The status of the sleep request.
*/
cy_rslt_t cyhal_syspm_tickless_sleep(cyhal_lptimer_t *lptimer_obj, uint32_t desired_ms, uint32_t *actual_ms);
/** Indicates, that \ref cyhal_syspm_get_deepsleep_mode function is available in this version of HAL. */
#define CYHAL_API_AVAILABLE_SYSPM_GET_DEEPSLEEP_MODE
/** Get current deep sleep mode.
*
* Provides a way to get the current deep sleep mode.
* @return The current deep sleep mode.
*/
cyhal_syspm_system_deep_sleep_mode_t cyhal_syspm_get_deepsleep_mode(void);
/** Informs the system of the current voltage level on the specified supply.
*
* This is generally expected to be set once at system startup, but it may be set repeatedly during
* runtime if operating conditions change.
* Once set, this value can be queried via \ref cyhal_syspm_get_supply_voltage.
*
* \note This only informs the system of the voltage level. It does not alter any of the device operating conditions.
*
* @param supply The supply whose voltage is being specified.
* @param mvolts The voltage level on the specified supply, in millivolts.
*/
void cyhal_syspm_set_supply_voltage(cyhal_syspm_voltage_supply_t supply, uint32_t mvolts);
/** Retrieves the current voltage level on the specified supply, as set in \ref cyhal_syspm_set_supply_voltage.
*
* \note This only returns the value provided to \ref cyhal_syspm_set_supply_voltage. It does not perform any
* measurements of the current supply level.
*
* @param supply The supply whose voltage is being specified.
* @return The voltage level on the specified supply, in millivolts. If the voltage has not been specified,
* returns 0.
*/
uint32_t cyhal_syspm_get_supply_voltage(cyhal_syspm_voltage_supply_t supply);
#if defined(__cplusplus)
}
#endif
#ifdef CYHAL_SYSPM_IMPL_HEADER
#include CYHAL_SYSPM_IMPL_HEADER
#endif /* CYHAL_SYSTEM_IMPL_HEADER */
/** \} group_hal_system */