1 /***************************************************************************//** 2 * \file cyhal_syspm.h 3 * 4 * \brief 5 * Provides a high level interface for interacting with the Infineon power 6 * management configuration. This interface abstracts out the 7 * chip specific details. If any chip specific functionality is necessary, or 8 * performance is critical the low level functions can be used directly. 9 * 10 ******************************************************************************** 11 * \copyright 12 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or 13 * an affiliate of Cypress Semiconductor Corporation 14 * 15 * SPDX-License-Identifier: Apache-2.0 16 * 17 * Licensed under the Apache License, Version 2.0 (the "License"); 18 * you may not use this file except in compliance with the License. 19 * You may obtain a copy of the License at 20 * 21 * http://www.apache.org/licenses/LICENSE-2.0 22 * 23 * Unless required by applicable law or agreed to in writing, software 24 * distributed under the License is distributed on an "AS IS" BASIS, 25 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 * See the License for the specific language governing permissions and 27 * limitations under the License. 28 *******************************************************************************/ 29 30 /** 31 * \addtogroup group_hal_syspm System Power Management 32 * \ingroup group_hal 33 * \{ 34 * Interface for changing power states and restricting when they are allowed. 35 * 36 * Power management is handled both at a system level and at a peripheral driver 37 * level. The system wide API (this) allows the user to interact with the product 38 * as a whole. Additionally, each peripheral keeps track of what its state is and 39 * whether it can safely move to a new state while still maintaining any current 40 * operations. To initialize the system wide power management, \ref cyhal_syspm_init 41 * should be called as part of the initial device startup. 42 * 43 * At the System level, the APIs are intended to allow the application to specify 44 * exactly what is happening. It can request changes to both the MCU Power State 45 * as well as the System Wide Power State. There are three supported MCU Power 46 * States: 47 * * Active - This is the normal operating state of the MCU 48 * * Sleep - In this state the MCU is no longer running. It can be woken up again 49 * from an interrupt. This state is reached by calling \ref cyhal_syspm_sleep. 50 * * Deep Sleep - In this state the MCU is no longer running. It can only be woken 51 * up by select interrupts. This state is reached by calling \ref 52 * cyhal_syspm_deepsleep. 53 * <p>Additionally, there are three supported system states: 54 * * Normal (\ref CYHAL_SYSPM_SYSTEM_NORMAL) - This is a normal operating state 55 * for the device. This is exposed by \ref cyhal_syspm_set_system_state. 56 * * Low (\ref CYHAL_SYSPM_SYSTEM_LOW) - This is a lower power operating state 57 * that may be supported by the device. This state often imposes specific 58 * requirements on clock speeds and voltage levels. See the device specific 59 * documentation for any device specific requirements for this mode, or whether 60 * it is even supported. If the device supports this mode, it is exposed by 61 * \ref cyhal_syspm_set_system_state. 62 * * Hibernate - This is the lowest available power state. In this state most of 63 * the chip is powered down. It has a very limited number of wakeup sources, and 64 * may require the device to reboot in order to come back up. It can be accessed 65 * by calling \ref cyhal_syspm_hibernate. 66 67 * Any time a power state transition is requested a series of callbacks are invoked. 68 * This allows peripherals, or other parts of the application, to confirm they are 69 * not currently doing something that would not work in the requested power state. 70 * HAL Peripheral drivers automatically register these callbacks when they are 71 * initialized. The application also has the option to register a callback 72 * function(s) to be called on requested state transitions by callling \ref 73 * cyhal_syspm_register_callback. If registered, the application level callbacks 74 * are invoked first. This gives the application a chance stop any peripherals, if 75 * appropriate, to ensure the power transition can actually happen. Alternatively 76 * it can directly reject the transition. Each callback registered can specify 77 * the exact set of states ( \ref cyhal_syspm_callback_state_t ) that it should 78 * be called for. Each callback is invoked multiple times as part of the transition 79 * process as defined by \ref cyhal_syspm_callback_mode_t. 80 * 81 * At any point the code can lock the ability to enter deep sleep by calling \ref 82 * cyhal_syspm_lock_deepsleep. This should be done in critical blocks that need to 83 * continue remain active. When the critical work is complete, and the lock is no 84 * longer needed, it can be released by calling \ref cyhal_syspm_unlock_deepsleep. 85 * The lock is a counter with a max count of USHRT_MAX. It must be locked/unlocked 86 * an equal number of times before the device is actually able to enter deep sleep. 87 * 88 * All peripherals are expected to operate in the default Active/Normal power 89 * state. Some peripherals (primarily analog) can operate in lower power states as 90 * well. These drivers will operate in all power states that the hardware supports. 91 * 92 * When power transitions are requested each type of peripheral has a default 93 * behavior. Peripherals that can continue to operate in the requested power mode 94 * do not interfere. Peripherals that are not currently active allow the transition, 95 * but make sure they restore their state if needed for when the device comes back. 96 * Peripherals that are active and cannot continue to work in the requested power 97 * state will block the transition. 98 * 99 * \note The power management functionality available depends on the availability 100 * of the features in the hardware. For detailed information about exactly what is 101 * supported on each device, refer to the Device Datasheet or Technical Reference 102 * Manual (TRM). 103 104 * \section section_syspm_features Features 105 * This driver provides control over multiple different types of power management 106 * and when those transitions are allowed: 107 * * Change CPU Power State: APIs to allow changing the current CPU state into 108 * one of the lower power CPU states (SLEEP, DEEPSLEEP) 109 * * Change System Power State: An API allows for changing the system wide power 110 * state between one of states (NORMAL, LOW) 111 * - Hibernate: An API that allows to set the hibernate 112 * wakeup source and set the system state to Hibernate. 113 * * General Purpose Power State Transition Callback: APIs allow for 114 * registering/unregistering a callback function to be notified when various power 115 * state transitions happen. If registered, the application can do anything necessary 116 * at power transitions. It can even prevent the transition if need-be. 117 * * Peripheral Specific Power State Transition Callback: APIs allow for 118 * registering/unregistering a callback function to be called when a peripheral with 119 * a CUSTOM power mode strategy exists and a power mode transition is requested. 120 * This allows the application to customize when it is OK for the peripheral to enter 121 * a low power state. 122 * - Lock DeepSleep: APIs to prevent/allow the CPU from going to deep sleep. This 123 * is a convenience API rather than needing to implement a full Transition Callback 124 * handler. 125 * 126 * \section section_syspm_quickstart Quick Start 127 * 128 * Unlike most HAL drivers this does not require initializing an instance object. The 129 * APIs provided here can be called at anytime. See the snippets below for examples 130 * of how to use this driver. 131 * 132 * \section section_syspm_snippets Code Snippets 133 * 134 * \subsection subsection_syspm_snippet_1 Snippet 1: Simple deep sleep locking 135 * The following snippet shows how to use the deep sleep locking APIs to restrict 136 * when the device can enter deep sleep. In between the lock/unlock calls any 137 * attempt to change power modes will automatically be canceled. 138 * \snippet hal_syspm.c snippet_cyhal_syspm_simple_locking 139 * 140 * \subsection subsection_syspm_snippet_2 Snippet 2: Calling different power state functions 141 * The following snippet shows the different functions that exist to change power states 142 * on the device and how they can each be called. 143 * \snippet hal_syspm.c snippet_cyhal_syspm_power_transitions 144 * 145 * \subsection subsection_syspm_snippet_3 Snippet 3: Using callbacks for application power management 146 * The following snippet shows how to use the callback mechanisms to manage whether 147 * it is safe to enter low power modes. 148 * \snippet hal_syspm.c snippet_cyhal_syspm_app_callback 149 */ 150 #pragma once 151 152 #include <stdint.h> 153 #include <stdbool.h> 154 #include "cy_result.h" 155 #include "cyhal_general_types.h" 156 #include "cyhal_hw_types.h" 157 158 #if defined(__cplusplus) 159 extern "C" { 160 #endif 161 162 /** \addtogroup group_hal_results_syspm SYSPM HAL Results 163 * SYSPM specific return codes 164 * \ingroup group_hal_results 165 * \{ *//** 166 */ 167 168 /** Incorrect argument passed into a function. */ 169 #define CYHAL_SYSPM_RSLT_BAD_ARGUMENT \ 170 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 0)) 171 /** Driver was unable to be initialized. */ 172 #define CYHAL_SYSPM_RSLT_INIT_ERROR \ 173 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 1)) 174 /** Failed to register callback */ 175 #define CYHAL_SYSPM_RSLT_CB_REGISTER_ERROR \ 176 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 2)) 177 /** Power Management transition is pending, data cannot be transferred */ 178 #define CYHAL_SYSPM_RSLT_ERR_PM_PENDING \ 179 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 3)) 180 /** Functionality not supported on the current platform */ 181 #define CYHAL_SYSPM_RSLT_ERR_NOT_SUPPORTED \ 182 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 4)) 183 /** Deepsleep has been locked */ 184 #define CYHAL_SYSPM_RSLT_DEEPSLEEP_LOCKED \ 185 (CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_SYSPM, 5)) 186 187 /** 188 * \} 189 */ 190 191 /** \cond INTERNAL */ 192 /** Sentinel value to indicate end of callback list */ 193 #define CYHAL_SYSPM_END_OF_LIST ((cyhal_syspm_callback_data_t*)0x789) 194 /** \endcond */ 195 196 /** Enumeration of the system wide power modes. These modes are device specifc and 197 * may not be supported on all devices. Refer to the device specific documentation 198 * or the Data Sheet to determine what is allowed. Devices that do support these 199 * modes may have requirements for adjusting system settings such as clocks or 200 * voltage levels before transition. 201 */ 202 typedef enum 203 { 204 CYHAL_SYSPM_SYSTEM_NORMAL, /**< Normal Mode. */ 205 CYHAL_SYSPM_SYSTEM_LOW, /**< Low Power Mode. */ 206 } cyhal_syspm_system_state_t; 207 208 /** Enumeration of the system Deep Sleep modes. These modes are device specifc and 209 * may not be supported on all devices. Refer to the device specific documentation 210 * or the Data Sheet to determine what is allowed. 211 */ 212 typedef enum 213 { 214 CYHAL_SYSPM_SYSTEM_DEEPSLEEP_NONE, /**< Not Deep Sleep Mode. */ 215 CYHAL_SYSPM_SYSTEM_DEEPSLEEP, /**< Deep Sleep Mode. */ 216 CYHAL_SYSPM_SYSTEM_DEEPSLEEP_RAM, /**< Deep Sleep RAM Mode. */ 217 CYHAL_SYSPM_SYSTEM_DEEPSLEEP_OFF, /**< Deep Sleep OFF Mode. */ 218 } cyhal_syspm_system_deep_sleep_mode_t; 219 220 /** Flags enum for the hibernate wakeup sources. 221 * \note Not all wakeup sources are valid on devices. Refer to the datasheet for 222 * device specifics. 223 */ 224 typedef enum 225 { 226 CYHAL_SYSPM_HIBERNATE_LPCOMP0_LOW = 0x01U, /**< Wake on a low logic level for the LPComp0. */ 227 CYHAL_SYSPM_HIBERNATE_LPCOMP0_HIGH = 0x02U, /**< Wake on a high logic level for the LPComp0. */ 228 CYHAL_SYSPM_HIBERNATE_LPCOMP1_LOW = 0x04U, /**< Wake on a low logic level for the LPComp1. */ 229 CYHAL_SYSPM_HIBERNATE_LPCOMP1_HIGH = 0x08U, /**< Wake on a high logic level for the LPComp1. */ 230 CYHAL_SYSPM_HIBERNATE_RTC_ALARM = 0x10U, /**< Configure the RTC alarm as wakeup source. */ 231 CYHAL_SYSPM_HIBERNATE_WDT = 0x20U, /**< Configure the WDT interrupt as wakeup source. */ 232 CYHAL_SYSPM_HIBERNATE_PINA_LOW = 0x40U, /**< Configure a low logic level for the first wakeup-pin. 233 See device datasheet for specific pin. */ 234 CYHAL_SYSPM_HIBERNATE_PINA_HIGH = 0x80U, /**< Configure a high logic level for the first wakeup-pin. 235 See device datasheet for specific pin. */ 236 CYHAL_SYSPM_HIBERNATE_PINB_LOW = 0x100U, /**< Configure a low logic level for the second wakeup-pin. 237 See device datasheet for specific pin. */ 238 CYHAL_SYSPM_HIBERNATE_PINB_HIGH = 0x200U /**< Configure a high logic level for the second wakeup-pin. 239 See device datasheet for specific pin. */ 240 } cyhal_syspm_hibernate_source_t; 241 242 /** Supply voltages whose levels can be specified and queried via \ref cyhal_syspm_set_supply_voltage and 243 * \ref cyhal_syspm_get_supply_voltage, respectively. 244 * 245 * \note Not all supplies which are present are included here. This enum only contains the voltage supplies 246 * whose values are relevant to the operation of one or more HAL drivers. 247 */ 248 typedef enum 249 { 250 CYHAL_VOLTAGE_SUPPLY_VDDA = 0u, //!< VDDA - Analog supply voltage 251 CYHAL_VOLTAGE_SUPPLY_MAX = CYHAL_VOLTAGE_SUPPLY_VDDA //!< Alias for the highest value in this enum 252 } cyhal_syspm_voltage_supply_t; 253 254 /** 255 * Performs any system wide power management initialization that is needed for future operations. 256 * This can include things like unlocking IOs that might have been frozen when entering a low 257 * power state or registering callback functions that are necessary to allow notifications of 258 * power events. This should be called as part of initializing the device in a Board Support Package 259 * (BSP). 260 * 261 * @return Returns CY_RSLT_SUCCESS if the processor successfully entered the hibernate mode, 262 * otherwise error. 263 */ 264 cy_rslt_t cyhal_syspm_init(void); 265 266 /** Sets the system mode to hibernate. 267 * 268 * This function configures the sources to wake up the device from hibernate mode 269 * and then sets the system to hibernate mode. 270 * 271 * In hibernate mode, all internal supplies are off and no internal state is retained. 272 * 273 * Sources can be wakeup pins, LPComparators, Watchdog (WDT) interrupt, or a Real-Time 274 * clock (RTC) alarm (interrupt). Wakeup from system hibernate always results in a device 275 * reset and normal boot process. 276 * 277 * Wakeup pins: 278 * 279 * A wakeup is supported by pins with programmable polarity. These pins 280 * are typically connected to the GPIO pins or on-chip peripherals under some 281 * conditions. See device datasheet to check if this feature is supported and for specific 282 * pin connections. Setting the wakeup pin to this level will cause a wakeup from 283 * system hibernate mode. 284 * 285 * LPComparators: 286 * 287 * A wakeup is supported by LPComps with programmable polarity. 288 * Setting the LPComp to this level will cause a wakeup from system hibernate 289 * mode. 290 * 291 * Watchdog Timer: 292 * 293 * A wakeup is performed by a WDT interrupt. 294 * 295 * Real-time Clock: 296 * 297 * A wakeup is performed by the RTC alarm. 298 * 299 * For information about hibernate behavior, wakeup sources and their assignment in specific 300 * devices, refer to the appropriate device TRM. 301 * 302 * @param[in] wakeup_source 303 * The source to be configured as a wakeup source from the system hibernate power mode, 304 * see @ref cyhal_syspm_hibernate_source_t. The input parameter values can be ORed. 305 * For example, if you want to enable LPComp0 (active high) and WDT, call this function: 306 * cyhal_syspm_hibernate(CYHAL_SYSPM_HIBERNATE_LPCOMP0_HIGH | CYHAL_SYSPM_HIBERNATE_WDT). 307 * 308 * @warning Do not call this function with different polarity levels for the same 309 * wakeup source. For example, do not call a function like this: 310 * cyhal_syspm_hibernate(CYHAL_SYSPM_HIBERNATE_LPCOMP0_LOW | CYHAL_SYSPM_HIBERNATE_LPCOMP0_HIGH); 311 * 312 * @return Returns CY_RSLT_SUCCESS if the processor successfully entered the hibernate mode, 313 * otherwise error. 314 */ 315 cy_rslt_t cyhal_syspm_hibernate(cyhal_syspm_hibernate_source_t wakeup_source); 316 317 /** Set the system-wide state of the device. This is used to change the power state 318 * within the Active power mode. \ref cyhal_syspm_get_system_state can be used to 319 * get the current state. 320 * \note Not all devices support different states within the Active power mode. If 321 * the device does not support changing state, an error will be returned. 322 * 323 * @param[in] state System wide state. 324 * 325 * @return Returns CY_RSLT_SUCCESS if the processor successfully entered the requested system state, 326 * otherwise error. 327 */ 328 cy_rslt_t cyhal_syspm_set_system_state(cyhal_syspm_system_state_t state); 329 330 /** Gets the system-wide state of the device. States can be changed by calling 331 * \ref cyhal_syspm_set_system_state. 332 * \note Not all devices support different states within the Active power mode. If 333 * the device does not support changing state, this will return \ref 334 * CYHAL_SYSPM_SYSTEM_NORMAL. 335 * @return Returns the current system-wide power state of the device. 336 */ 337 cyhal_syspm_system_state_t cyhal_syspm_get_system_state(void); 338 339 /** Register the specified handler with the power manager to be notified of power 340 * state changes. This is intended for application wide decisions. Peripherals handle 341 * their ability to perform power transitions internally. This callback will be called 342 * before any of the peripheral callbacks for \ref CYHAL_SYSPM_CHECK_READY and 343 * \ref CYHAL_SYSPM_BEFORE_TRANSITION. This callback will be called after all peripheral 344 * callback for \ref CYHAL_SYSPM_CHECK_FAIL and \ref CYHAL_SYSPM_AFTER_TRANSITION. 345 * \note The callback will be executed from a critical section 346 * 347 * @param[in] callback_data The data for the callback to register 348 */ 349 void cyhal_syspm_register_callback(cyhal_syspm_callback_data_t *callback_data); 350 351 /** Removes the registered handler from the power manager so no future notifications are made. 352 * 353 * * @param[in] callback_data The data for the callback to unregister 354 */ 355 void cyhal_syspm_unregister_callback(cyhal_syspm_callback_data_t *callback_data); 356 357 /** Set CPU to sleep mode. 358 * 359 * @return Returns CY_RSLT_SUCCESS if the processor successfully entered the sleep mode , 360 * otherwise error. 361 */ 362 cy_rslt_t cyhal_syspm_sleep(void); 363 364 /** Set CPU to deep sleep mode. 365 * 366 * @return Returns CY_RSLT_SUCCESS if the processor successfully entered the deep sleep mode, 367 * otherwise error. 368 */ 369 cy_rslt_t cyhal_syspm_deepsleep(void); 370 371 /** Lock deep sleep. 372 * 373 * This function prevents the CPU from going to deep sleep. The lock is implemented as a counter 374 * from 0 to USHRT_MAX. Each call to this function increments the counter by 1. 375 * \ref cyhal_syspm_unlock_deepsleep must be called an equal number of times to fully unlock. 376 * Deepsleep will only be allowed when the counter is equal to 0. 377 */ 378 void cyhal_syspm_lock_deepsleep(void); 379 380 /** Unlock deep sleep. 381 * 382 * This function decrements the lock counter by 1 and must be called an equal number of times as 383 * @ref cyhal_syspm_lock_deepsleep is called to fully unlock. Deepsleep will only be allowed 384 * when the counter is equal to 0. 385 */ 386 void cyhal_syspm_unlock_deepsleep(void); 387 388 /** Timed deep-sleep without system timer. 389 * 390 * Provides a way to deep-sleep for a desired number of milliseconds(ms) with the system timer disabled. 391 * The system timer is disabled before sleeping and a low power timer is setup to wake 392 * the device from deep-sleep after the desired number of ms have elapsed. 393 * 394 * @note The actual ms in the best case will be 1 ms less than the desired time to 395 * prevent the device from over-sleeping due to low clock accuracy. 396 * 397 * @param[in] lptimer_obj Pre-Initialized LPTimer object. 398 * @param[in] desired_ms Desired number of ms to deep-sleep. 399 * @param[out] actual_ms Actual number of ms that was spent in deep-sleep. 400 * This value can range from 0 to desired_ms - 1 401 * depending on how long the device was able to deep-sleep. 402 * @return The status of the deep-sleep request. 403 */ 404 cy_rslt_t cyhal_syspm_tickless_deepsleep(cyhal_lptimer_t *lptimer_obj, uint32_t desired_ms, uint32_t *actual_ms); 405 406 /** Timed sleep without system timer. 407 * 408 * Provides a way to sleep for a desired number of milliseconds(ms) with the system timer disabled. 409 * The system timer is disabled before sleeping and a low power timer is setup to wake 410 * the device from sleep after the desired number of ms have elapsed. 411 * 412 * @note The actual ms in the best case will be 1 ms less than the desired time to 413 * prevent the device from over-sleeping due to low clock accuracy. 414 * 415 * @param[in] lptimer_obj Pre-Initialized LPTimer object. 416 * @param[in] desired_ms Desired number of ms to sleep. 417 * @param[out] actual_ms Actual number of ms that was spent in sleep. 418 * This value can range from 0 to desired_ms - 1 419 * depending on how long the device was able to sleep. 420 * @return The status of the sleep request. 421 */ 422 cy_rslt_t cyhal_syspm_tickless_sleep(cyhal_lptimer_t *lptimer_obj, uint32_t desired_ms, uint32_t *actual_ms); 423 424 /** Indicates, that \ref cyhal_syspm_get_deepsleep_mode function is available in this version of HAL. */ 425 #define CYHAL_API_AVAILABLE_SYSPM_GET_DEEPSLEEP_MODE 426 427 /** Get current deep sleep mode. 428 * 429 * Provides a way to get the current deep sleep mode. 430 * @return The current deep sleep mode. 431 */ 432 cyhal_syspm_system_deep_sleep_mode_t cyhal_syspm_get_deepsleep_mode(void); 433 434 /** Informs the system of the current voltage level on the specified supply. 435 * 436 * This is generally expected to be set once at system startup, but it may be set repeatedly during 437 * runtime if operating conditions change. 438 * Once set, this value can be queried via \ref cyhal_syspm_get_supply_voltage. 439 * 440 * \note This only informs the system of the voltage level. It does not alter any of the device operating conditions. 441 * 442 * @param supply The supply whose voltage is being specified. 443 * @param mvolts The voltage level on the specified supply, in millivolts. 444 */ 445 void cyhal_syspm_set_supply_voltage(cyhal_syspm_voltage_supply_t supply, uint32_t mvolts); 446 447 /** Retrieves the current voltage level on the specified supply, as set in \ref cyhal_syspm_set_supply_voltage. 448 * 449 * \note This only returns the value provided to \ref cyhal_syspm_set_supply_voltage. It does not perform any 450 * measurements of the current supply level. 451 * 452 * @param supply The supply whose voltage is being specified. 453 * @return The voltage level on the specified supply, in millivolts. If the voltage has not been specified, 454 * returns 0. 455 */ 456 uint32_t cyhal_syspm_get_supply_voltage(cyhal_syspm_voltage_supply_t supply); 457 458 #if defined(__cplusplus) 459 } 460 #endif 461 462 #ifdef CYHAL_SYSPM_IMPL_HEADER 463 #include CYHAL_SYSPM_IMPL_HEADER 464 #endif /* CYHAL_SYSTEM_IMPL_HEADER */ 465 466 /** \} group_hal_system */ 467