diff --git a/Makefile b/Makefile index 21713aa..5fc4d07 100644 --- a/Makefile +++ b/Makefile @@ -85,6 +85,7 @@ SOURCES = \ src/pmic_fsm.c \ src/pmic_io.c \ src/pmic_irq.c \ + src/pmic_power.c \ src/pmic_wdg.c OBJECTS = $(SOURCES:.c=.o) diff --git a/include/pmic_power.h b/include/pmic_power.h new file mode 100644 index 0000000..451c402 --- /dev/null +++ b/include/pmic_power.h @@ -0,0 +1,642 @@ +/****************************************************************************** + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __PMIC_POWER_H__ +#define __PMIC_POWER_H__ + +/** + * @file pmic_power.h + * @brief PMIC Driver Power API/Interface + */ + +/** + * @defgroup DRV_PMIC_PWR_MODULE PMIC Power Module + * @brief Power Resource control, configuration, and status information. + */ + +#include "pmic_common.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* Include Files */ +/* ========================================================================== */ +#include +#include + +/* ========================================================================== */ +/* Macros & Typedefs */ +/* ========================================================================== */ + +/** + * @anchor Pmic_PwrResource + * @name PMIC Power Resource identifiers + * + * @{ + */ +#define PMIC_PWR_RSRC_BUCK1 (0U) +#define PMIC_PWR_RSRC_BUCK2 (1U) +#define PMIC_PWR_RSRC_BUCK3 (2U) +#define PMIC_PWR_RSRC_LDO_LS1_VMON1 (3U) +#define PMIC_PWR_RSRC_LS2_VMON2 (4U) +#define PMIC_PWR_RSRC_VCCA_VMON (5U) +#define PMIC_PWR_RSRC_GPO (6U) +#define PMIC_PWR_RSRC_NRSTOUT (7U) +/** @} */ + +/** + * @anchor Pmic_PwrResourceModeConfig + * @name PMIC Power Resource mode configuration options + * + * @{ + */ +#define PMIC_PWR_RSRC_MODE_REG (0U) +#define PMIC_PWR_RSRC_MODE_BYP (1U) +#define PMIC_PWR_RSRC_MODE_LSW (2U) +#define PMIC_PWR_RSRC_MODE_VMON (3U) +#define PMIC_PWR_RSRC_MODE_MIN (PMIC_PWR_RSRC_MODE_REG) +#define PMIC_PWR_RSRC_MODE_MAX (PMIC_PWR_RSRC_MODE_VMON) +/** @} */ + +/** + * @anchor Pmic_PwrSequenceDelay + * @name PMIC Power resource startup/shutdown sequence delays + * + * @{ + */ +#define PMIC_PWR_SEQ_DLY_0P0MS (0x0U) +#define PMIC_PWR_SEQ_DLY_0P5MS (0x1U) +#define PMIC_PWR_SEQ_DLY_1P0MS (0x2U) +#define PMIC_PWR_SEQ_DLY_1P5MS (0x3U) +#define PMIC_PWR_SEQ_DLY_2P0MS (0x4U) +#define PMIC_PWR_SEQ_DLY_2P5MS (0x5U) +#define PMIC_PWR_SEQ_DLY_3P0MS (0x6U) +#define PMIC_PWR_SEQ_DLY_3P5MS (0x7U) +#define PMIC_PWR_SEQ_DLY_4P0MS (0x8U) +#define PMIC_PWR_SEQ_DLY_4P5MS (0x9U) +#define PMIC_PWR_SEQ_DLY_5P0MS (0xAU) +#define PMIC_PWR_SEQ_DLY_5P5MS (0xBU) +#define PMIC_PWR_SEQ_DLY_6P0MS (0xCU) +#define PMIC_PWR_SEQ_DLY_6P5MS (0xDU) +#define PMIC_PWR_SEQ_DLY_7P0MS (0xEU) +#define PMIC_PWR_SEQ_DLY_7P5MS (0xFU) +#define PMIC_PWR_SEQ_DLY_MIN (PMIC_PWR_SEQ_DLY_0P0MS) +#define PMIC_PWR_SEQ_DLY_MAX (PMIC_PWR_SEQ_DLY_7P5MS) +/** @} */ + +/** + * @anchor Pmic_PwrFaultReaction + * @name PMIC Power resource fault reaction configurations + * + * @{ + */ +#define PMIC_PWR_FAULT_REACT_INT_ONLY (0U) +#define PMIC_PWR_FAULT_REACT_WARM_RESET (1U) +#define PMIC_PWR_FAULT_REACT_POWER_ERROR (2U) +#define PMIC_PWR_FAULT_REACT_REGULATOR_ERROR (3U) +#define PMIC_PWR_FAULT_REACT_MIN (PMIC_PWR_FAULT_REACT_INT_ONLY) +#define PMIC_PWR_FAULT_REACT_MAX (PMIC_PWR_FAULT_REACT_REGULATOR_ERROR) +/** @} */ + +/** + * @anchor Pmic_PwrBuckUvOvThresholds + * @name PMIC Power resource undervoltage and overvoltage thresholds for Buck + * regulators + * + * @{ + */ +#define PMIC_PWR_BUCK_UV_OV_THR_3PERCENT (0U) +#define PMIC_PWR_BUCK_UV_OV_THR_4PERCENT (1U) +#define PMIC_PWR_BUCK_UV_OV_THR_5PERCENT (2U) +#define PMIC_PWR_BUCK_UV_OV_THR_6PERCENT (3U) +#define PMIC_PWR_BUCK_UV_OV_THR_MIN (PMIC_PWR_UV_OV_THR_3PERCENT) +#define PMIC_PWR_BUCK_UV_OV_THR_MAX (PMIC_PWR_UV_OV_THR_6PERCENT) +/** @} */ + +/** + * @anchor Pmic_PwrLswUvOvThresholds + * @name PMIC Power resource undervoltage and overvoltage thresholds for LDO and + * Load switches + * + * @{ + */ +#define PMIC_PWR_LS_UV_OV_THR_3PERCENT (0U) +#define PMIC_PWR_LS_UV_OV_THR_4PERCENT (1U) +#define PMIC_PWR_LS_UV_OV_THR_6PERCENT (2U) +#define PMIC_PWR_LS_UV_OV_THR_8PERCENT (3U) +#define PMIC_PWR_LS_UV_OV_THR_MIN (PMIC_PWR_LS_UV_OV_THR_3PERCENT) +#define PMIC_PWR_LS_UV_OV_THR_MAX (PMIC_PWR_LS_UV_OV_THR_8PERCENT) +/** @} */ + +/** + * @anchor Pmic_PwrVccaUvOvThresholds + * @name PMIC Power resource undervoltage and overvoltage thresholds for VCCA + * VMON. + * + * @{ + */ +#define PMIC_PWR_VCCA_UV_OV_THR_4PERCENT (0U) +#define PMIC_PWR_VCCA_UV_OV_THR_5PERCENT (1U) +#define PMIC_PWR_VCCA_UV_OV_THR_6PERCENT (2U) +#define PMIC_PWR_VCCA_UV_OV_THR_8PERCENT (3U) +#define PMIC_PWR_VCCA_UV_OV_THR_MIN (PMIC_PWR_VCCA_UV_OV_THR_4PERCENT) +#define PMIC_PWR_VCCA_UV_OV_THR_MAX (PMIC_PWR_VCCA_UV_OV_THR_8PERCENT) +/** @} */ + +/** + * @anchor Pmic_PwrRvReaction + * @name PMIC Power resource reverse voltage reaction configuration + * + * @{ + */ +#define PMIC_PWR_RV_CONF_INT_ONLY (0U) +#define PMIC_PWR_RV_CONF_SHUT_DOWN (1U) +/** @} */ + +/** + * @anchor Pmic_PwrIlimConfiguration + * @name PMIC Power resource current limit configuration + * + * @{ + */ +#define PMIC_PWR_ILIM_2P5A (2U) +#define PMIC_PWR_ILIM_3P0A (3U) +#define PMIC_PWR_ILIM_3P5A (4U) +#define PMIC_PWR_ILIM_4P0A (5U) +#define PMIC_PWR_ILIM_4P5A (6U) +#define PMIC_PWR_ILIM_5P0A (7U) +// NOTE: While 2P5A is the lowest recommended ILIM setting, the values for 0 and +// 1 are also supported but are intended for TI use only. The MIN macro is +// defined to support these, though no named macro will be provided. +#define PMIC_PWR_ILIM_MIN (0U) +#define PMIC_PWR_ILIM_MAX (PMIC_PWR_ILIM_5P0A) +/** @} */ + +/** + * @anchor Pmic_PwrDeglitchSelect + * @name PMIC Power resource deglitch filter configuration + * + * @{ + */ +#define PMIC_PWR_DEGLITCH_0P5US (0U) +#define PMIC_PWR_DEGLITCH_5US (1U) +#define PMIC_PWR_DEGLITCH_10US (2U) +#define PMIC_PWR_DEGLITCH_20US (3U) +#define PMIC_PWR_DEGLITCH_MIN (PMIC_PWR_DEGLITCH_0P5US) +#define PMIC_PWR_DEGLITCH_MAX (PMIC_PWR_DEGLITCH_20US) +/** @} */ + +/** + * @anchor Pmic_PwrResourceCfgValidParamBitPos + * @name PMIC Power resource configuration valid params bit positions. + * + * @{ + */ +#define PMIC_PWR_CFG_ENABLE_VALID (0U) +#define PMIC_PWR_CFG_MODE_VALID (1U) +#define PMIC_PWR_CFG_ILIM_VALID (2U) +#define PMIC_PWR_CFG_VOLTAGE_VALID (3U) +#define PMIC_PWR_CFG_DEGLITCH_VALID (4U) +#define PMIC_PWR_CFG_UV_THRESH_VALID (5U) +#define PMIC_PWR_CFG_OV_THRESH_VALID (6U) +#define PMIC_PWR_CFG_UV_REACT_VALID (7U) +#define PMIC_PWR_CFG_OV_REACT_VALID (8U) +#define PMIC_PWR_CFG_RV_REACT_VALID (9U) +#define PMIC_PWR_CFG_SC_REACT_VALID (10U) +/** @} */ + +/** + * @anchor Pmic_PwrResourceCfgValidParamShiftVal + * @name PMIC Power resource configuration valid params bit shift values. + ** + * @brief Application can use these values to set the validParams structure + * member defined in @ref Pmic_PowerResourceCfg_t structure. + * + * @{ + */ +#define PMIC_PWR_CFG_ENABLE_VALID_SHIFT (1U << PMIC_PWR_CFG_ENABLE_VALID) +#define PMIC_PWR_CFG_MODE_VALID_SHIFT (1U << PMIC_PWR_CFG_MODE_VALID) +#define PMIC_PWR_CFG_ILIM_VALID_SHIFT (1U << PMIC_PWR_CFG_ILIM_VALID) +#define PMIC_PWR_CFG_VOLTAGE_VALID_SHIFT (1U << PMIC_PWR_CFG_VOLTAGE_VALID) +#define PMIC_PWR_CFG_DEGLITCH_VALID_SHIFT (1U << PMIC_PWR_CFG_DEGLITCH_VALID) +#define PMIC_PWR_CFG_UV_THRESH_VALID_SHIFT (1U << PMIC_PWR_CFG_UV_THRESH_VALID) +#define PMIC_PWR_CFG_OV_THRESH_VALID_SHIFT (1U << PMIC_PWR_CFG_OV_THRESH_VALID) +#define PMIC_PWR_CFG_UV_REACT_VALID_SHIFT (1U << PMIC_PWR_CFG_UV_REACT_VALID) +#define PMIC_PWR_CFG_OV_REACT_VALID_SHIFT (1U << PMIC_PWR_CFG_OV_REACT_VALID) +#define PMIC_PWR_CFG_RV_REACT_VALID_SHIFT (1U << PMIC_PWR_CFG_RV_REACT_VALID) +#define PMIC_PWR_CFG_SC_REACT_VALID_SHIFT (1U << PMIC_PWR_CFG_SC_REACT_VALID) +#define PMIC_PWR_CFG_ALL_VALID_SHIFT (\ + PMIC_PWR_CFG_ENABLE_VALID_SHIFT |\ + PMIC_PWR_CFG_ILIM_VALID_SHIFT |\ + PMIC_PWR_CFG_VOLTAGE_VALID_SHIFT |\ + PMIC_PWR_CFG_DEGLITCH_VALID_SHIFT |\ + PMIC_PWR_CFG_UV_THRESH_VALID_SHIFT |\ + PMIC_PWR_CFG_OV_THRESH_VALID_SHIFT |\ + PMIC_PWR_CFG_UV_REACT_VALID_SHIFT |\ + PMIC_PWR_CFG_OV_REACT_VALID_SHIFT |\ + PMIC_PWR_CFG_RV_REACT_VALID_SHIFT |\ + PMIC_PWR_CFG_SC_REACT_VALID_SHIFT) +/** @} */ + +/** + * @anchor Pmic_PwrResourceSeqValidParamBitPos + * @name PMIC Power resource sequencing valid params bit positions. + * + * @{ + */ +#define PMIC_PWR_SEQ_STARTUP_VALID (0U) +#define PMIC_PWR_SEQ_SHUTDOWN_VALID (1U) +/** @} */ + +/** + * @anchor Pmic_PwrResourceSeqValidParamShiftVal + * @name PMIC Power resource sequencing valid params bit shift values. + ** + * @brief Application can use these values to set the validParams structure + * member defined in @ref Pmic_PowerSequenceCfg_t structure. + * + * @{ + */ +#define PMIC_PWR_SEQ_STARTUP_VALID_SHIFT (1U << PMIC_PWR_SEQ_STARTUP_VALID) +#define PMIC_PWR_SEQ_SHUTDOWN_VALID_SHIFT (1U << PMIC_PWR_SEQ_SHUTDOWN_VALID) +#define PMIC_PWR_SEQ_ALL_VALID_SHIFT (\ + PMIC_PWR_SEQ_STARTUP_VALID_SHIFT |\ + PMIC_PWR_SEQ_SHUTDOWN_VALID_SHIFT) +/** @} */ + +/* ========================================================================== */ +/* Structures and Enums */ +/* ========================================================================== */ +/** + * @brief This structure is used in setting or getting the Power resource + * configuration of the supported PMICs (Bucks, LDOs, etc.). + * + * @note `validParams` is an input parameter for all Set and Get APIs. Other + * struct members are input params for Set APIs and output params for Get APIs. + * + * @param validParams Selection of structure parameters to be set from the + * combination of the @ref Pmic_PwrResourceCfgValidParamBitPos and the + * corresponding member value will be updated or retrieved. + * + * @param resource Which power resource to apply the other settings to. See @ref + * Pmic_PwrResource. + * + * @param enable Control whether this power resource is enabled or disabled. + * Note that if this bit is set to PMIC_ENABLE, then other configuration will be + * performed prior to enabling the resource, if it is set to PMIC_DISABLE then + * the resource will be disabled prior to performing any other configuration. + * See @ref Pmic_EnableDisable. + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_GPO + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param mode Configure the operating mode of this power resource. + * - Bucks1/2/3 have non-configurable modes and do not require this parameter, + * though no error will be raised if PMIC_PWR_RSRC_MODE_REG is selected (other + * options will raise an error). + * - LDO_LS1_VMON1 can select from all valid modes. + * - LS2_VMON2 can select between PMIC_PWR_RSRC_LSW and PMIC_PWR_RSRC_VMON. + * - VCCA_VMON does not have a configurable mode and does not require this + * parameter, though no error will be raised if PMIC_PWR_RSRC_MODE_VMON is + * selected (other options will raise an error). + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param ilim Set the peak current limit of the selected power resource. Can be + * programmed at any time during operation. Maximum programmable current limit + * may be limited based on device settings. Recommended to be 2A more than + * maximum rated load current. See @ref Pmic_PwrIlimConfiguration. + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * + * @param voltage_mV Set the desired voltage level of the power resource, in + * millivolt units. This parameter has different purposes and ranges depending + * on the power resource being configured. + * - For Bucks1/2/3, this parameter sets the output voltage. + * - For LDO_LS1, this parameter sets the output voltage if configured as LDO, + * or sets the target power-good voltage if configured as LS1. + * - For LS2, this parameter sets the target power-good voltage. + * - For VCCA, this parameter sets the target power-good voltage. + * The range of Bucks1/2/3 are 900mV to 1900mV, in 20mV steps. Attempting to + * set voltages lower, higher, or not of 20mV multiples will result in a + * configuration error. + * The range of LDO_LS1_VMON1, LS2_VMON2, and VCCA_VMON is 600mV to 3400mV in + * 25mV steps. Attempting to set voltages lower, higher, or not of 25mV + * multiples will result in a configuration error. + * The resources for which the parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param deglitch Set the deglitch filter for power resource monitoring. See + * @ref Pmic_PwrDeglitchSelect. + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param uvThresh Set the undervoltage threshold percentage. Note that + * undervoltage thresholds are expressed as a percentage **below** the target + * voltage and different power resources have different supported percentages. + * - For BUCK1/2/3, see @ref Pmic_PwrBuckUvOvThresholds + * - For LDO_LS1 and LS2, see @ref Pmic_PwrLswUvOvThresholds + * - For VCCA VMON, see @ref Pmic_PwrVccaUvOvThresholds + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param uvReaction Set the device reaction to detection of an undervoltage + * event on this power resource. See @ref Pmic_PwrFaultReaction. + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param ovThresh Se the overvoltage threshold percente. Note that overvoltage + * thresholds are expressed as a percentage **above** the target voltage and + * different power resources have different supported percentages. + * - For BUCK1/2/3, see @ref Pmic_PwrBuckUvOvThresholds + * - For LDO_LS1 and LS2, see @ref Pmic_PwrLswUvOvThresholds + * - For VCCA VMON, see @ref Pmic_PwrVccaUvOvThresholds + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param ovReaction Set the device reaction to detection of an overvoltage + * event on this power resource. See @ref Pmic_PwrFaultReaction. + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * - PMIC_PWR_RSRC_VCCA_VMON + * + * @param rvReaction Set the device reaction to detection of a reverse voltage + * event on this power resource. See @ref Pmic_PwrRvReaction. NOTE: This uses a + * different "reaction" enum than the other reaction struct members. + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + * + * @param scReaction Set the device reaction to detection of a short circuit + * event on this power resource. See @ref Pmic_PwrFaultReaction. + * The resources for which this parameter is valid are: + * - PMIC_PWR_RSRC_BUCK1 + * - PMIC_PWR_RSRC_BUCK2 + * - PMIC_PWR_RSRC_BUCK3 + * - PMIC_PWR_RSRC_LDO_LS1_VMON1 + * - PMIC_PWR_RSRC_LS2_VMON2 + */ +typedef struct Pmic_PowerResourceCfg_s { + uint16_t validParams; + uint8_t resource; + + bool enable; + uint8_t mode; + uint8_t ilim; + uint16_t voltage_mV; + uint8_t deglitch; + uint8_t uvThresh; + uint8_t uvReaction; + uint8_t ovThresh; + uint8_t ovReaction; + uint8_t rvReaction; + uint8_t scReaction; +} Pmic_PowerResourceCfg_t; + +/** + * @brief This structure is used in setting or getting the Power resource + * sequencing information of the supported PMICs (Bucks, LDOs, etc.). + * + * @param resource Which power resource to apply sequencing settings to. See + * @ref Pmic_PwrResource. + * + * @param startupDelay Set the delay between rising edge of ENABLE and + * enablement of this power resource. + + * @param shutdownDelay Set the delay between falling edge of ENABLE and + * disablement of this power resource. + */ +typedef struct Pmic_PowerSequenceCfg_s { + uint8_t validParams; + uint8_t resource; + + uint8_t startupDelay; + uint8_t shutdownDelay; +} Pmic_PowerSequenceCfg_t; + +/* ========================================================================== */ +/* Function Declarations */ +/* ========================================================================== */ +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to control the enable state of PMIC power resources. + * + * @param handle [IN] PMIC Interface Handle + * @param resource [IN] Power resource to control, see @ref Pmic_PwrResource. + * @param enable [IN] If set to true (PMIC_ENABLE) the power resource will be + * enabled, otherwise the resource will be disabled. See @ref + * Pmic_EnableDisable. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrSetResourceEnable(Pmic_CoreHandle_t *handle, uint8_t resource, bool enable); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to control the enable state of PMIC power resources. + * + * @param handle [IN] PMIC Interface Handle + * @param resource [IN] Power resource to get status of, see @ref Pmic_PwrResource. + * @param enable [OUT] If set to true (PMIC_ENABLE) the power resource is * + * enabled, otherwise the resource is disabled. See @ref Pmic_EnableDisable. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrGetResourceEnable(Pmic_CoreHandle_t *handle, uint8_t resource, bool *isEnabled); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to set the configuration of a PMIC power resources. + * + * @param handle [IN] PMIC Interface Handle + * @param config [IN] Configuration options for this power resource. See @ref + * Pmic_PowerResourceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrSetResourceCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to get the configuration of a PMIC power resources. + * + * @param handle [IN] PMIC Interface Handle + * @param config [IN/OUT] Configuration options for this power resource. See @ref + * Pmic_PowerResourceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrGetResourceCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to set the configuration of multiple PMIC power resources. + * + * @param handle [IN] PMIC Interface Handle + * @param numConfigs [IN] The number of configurations in the `config` array. + * @param config [IN] An array of configuration options for power resources. + * See @ref Pmic_PowerResourceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrSetResourceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, const Pmic_PowerResourceCfg_t config[]); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to get the configuration of multiple PMIC power resources. + * + * @param handle [IN] PMIC Interface Handle + + * @param numConfigs [IN] The number of configurations to retrieve. NOTE the + * `config` array provided must have enough storage for all configurations + * requested. + + * @param config [IN/OUT] Configuration options for each power resource + * requested. See @ref Pmic_PowerResourceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrGetResourceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, Pmic_PowerResourceCfg_t config[]); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to set the power sequencing configuration of a PMIC power + * resource. + * + * @param handle [IN] PMIC Interface Handle + * @param config [IN] Sequencing configuration options for this power + * resource. See @ref Pmic_PowerSequenceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrSetSequenceCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerSequenceCfg_t *config); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to get the power sequencing configuration of a PMIC power + * resource. + * + * @param handle [IN] PMIC Interface Handle + * @param config [IN/OUT] Sequencing configuration for this power resource. See + * @ref Pmic_PowerSequenceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrGetSequenceCfg(Pmic_CoreHandle_t *handle, Pmic_PowerSequenceCfg_t *config); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to set the power sequencing configuration of multiple PMIC power + * resources. + * + * @param handle [IN] PMIC Interface Handle + * @param numConfigs [IN] The number of configurations in the `config` array. + * @param config [IN] An array of configuration options for power resources. + * See @ref Pmic_PowerSequenceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrSetSequenceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, const Pmic_PowerSequenceCfg_t config[]); + +/** + * @ingroup DRV_PMIC_PWR_MODULE + * @brief API to get the power sequencing configuration of multiple PMIC power + * resources. + * + * @param handle [IN] PMIC Interface Handle + * @param numConfigs [IN] The number of configurations in the `config` array. + * @param config [IN/OUT] Configuration options for each power resource + * requested. See @ref Pmic_PowerSequenceCfg_t. + * + * @return PMIC_ST_SUCCESS in case of success or appropriate error code. For + * possible values, see @ref Pmic_ErrorCodes. + */ +int32_t Pmic_pwrGetSequenceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, Pmic_PowerSequenceCfg_t config[]); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif // __PMIC_POWER_H__ diff --git a/include/regmap/power.h b/include/regmap/power.h new file mode 100644 index 0000000..74cf11e --- /dev/null +++ b/include/regmap/power.h @@ -0,0 +1,237 @@ +/****************************************************************************** + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __REGMAP_POWER_H__ +#define __REGMAP_POWER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ========================================================================== */ +/* Include Files */ +/* ========================================================================== */ +#include + +// Power Control Register Definitions +#define BLOCK_EN_CTRL_REG (0x06U) +#define BUCK1_VOUT_REG (0x11U) +#define BUCK2_VOUT_REG (0x12U) +#define BUCK3_VOUT_REG (0x13U) +#define LDO_LS1_VMON1_PG_LEVEL_REG (0x14U) +#define LS2_VMON2_PG_LEVEL_REG (0x15U) +#define VCCA_PG_LEVEL_REG (0x16U) +#define BUCK1_MON_CONF_REG (0x17U) +#define BUCK2_MON_CONF_REG (0x18U) +#define BUCK3_MON_CONF_REG (0x19U) +#define LDO_LS1_VMON1_MON_CONF_REG (0x1AU) +#define LS2_VMON2_MON_CONF_REG (0x1BU) +#define CLK_CONF_REG (0x1CU) // SS_EN is this needed here? +#define FUNC_CONF_REG (0x1EU) +#define VCCA_MON_CONF_REG (0x1FU) +#define BUCK_LDO_LS1_VMON1_DEGLIT_REG (0x20U) +#define BUCK1_SEQUENCE_REG (0x21U) +#define BUCK2_SEQUENCE_REG (0x22U) +#define BUCK3_SEQUENCE_REG (0x23U) +#define LDO_LS1_VMON1_SEQUENCE_REG (0x24U) +#define LS2_VMON2_SEQUENCE_REG (0x25U) +#define GPO_SEQUENCE_REG (0x26U) +#define NRSTOUT_SEQUENCE_REG (0x27U) +#define REG_OV_CONF_REG (0x28U) +#define REG_UV_CONF_REG (0x29U) +#define REG_SC_CONF_REG (0x2AU) +#define VCCA_LS2_VMON2_OV_CONF_REG (0x2BU) +#define VCCA_LS2_VMON2_UV_CONF_REG (0x2CU) + +// Power Status Register Definitions +#define STAT_BUCK_12_REG (0x53U) +#define STAT_BUCK3_LDO_LS1_VMON1_REG (0x54U) +#define STAT_LS2_VMON2_REG (0x55U) +#define STAT_VCCA_REG (0x56U) +#define STAT_STARTUP_REG (0x57U) +#define STAT_MISC_REG (0x58U) + +// LDO_LS1_VMON1_PG_LEVEL_REG Bitfields +#define LDO_LS1_VMON1_PG_SET_SHIFT (0U) +#define LDO_LS1_BYP_CONFIG_SHIFT (7U) +#define LDO_LS1_VMON1_PG_SET_MASK (0x7FU << LDO_LS1_VMON1_PG_SET_SHIFT) +#define LDO_LS1_BYP_CONFIG_MASK (0x1U << LDO_LS1_BYP_CONFIG_SHIFT) + +// BUCK1_MON_CONF_REG, BUCK2_MON_CONF_REG, BUCK3_MON_CONF_REG Bitfields +#define BUCKx_ILIM_SHIFT (0U) +#define BUCKx_RV_CONF_SHIFT (3U) +#define BUCKx_OV_THR_SHIFT (4U) +#define BUCKx_UV_THR_SHIFT (6U) +#define BUCKx_ILIM_MASK (0x7U << BUCKx_ILIM_SHIFT) +#define BUCKx_RV_CONF_MASK (0x1U << BUCKx_RV_CONF_SHIFT) +#define BUCKx_OV_THR_MASK (0x3U << BUCKx_OV_THR_SHIFT) +#define BUCKx_UV_THR_MASK (0x3U << BUCKx_UV_THR_SHIFT) + +// LDO_LS1_VMON1_MON_CONF_REG, LS2_VMON2_MON_CONF_REG Bitfields +#define LDO_LS12_VMON_RV_CONF_SHIFT (1U) +#define LDO_LS12_VMON_EN_SHIFT (2U) +#define LDO_LS12_VMON_DIS_PD_SHIFT (3U) +#define LDO_LS12_VMON_OV_THR_SHIFT (4U) +#define LDO_LS12_VMON_UV_THR_SHIFT (6U) +#define LDO_LS12_VMON_RV_CONF_MASK (0x1U << LDO_LS12_VMON_RV_CONF_SHIFT) +#define LDO_LS12_VMON_EN_MASK (0x1U << LDO_LS12_VMON_EN_SHIFT) +#define LDO_LS12_VMON_DIS_PD_MASK (0x1U << LDO_LS12_VMON_DIS_PD_SHIFT) +#define LDO_LS12_VMON_OV_THR_MASK (0x3U << LDO_LS12_VMON_OV_THR_SHIFT) +#define LDO_LS12_VMON_UV_THR_MASK (0x3U << LDO_LS12_VMON_UV_THR_SHIFT) + +// FUNC_CONF_REG Bitfields +#define LDO_LS1_VMON1_SEL_SHIFT (0U) +#define LDO_LS1_LSW_CONFIG_SHIFT (1U) +#define LS2_VMON2_GPO_SEL_SHIFT (4U) +#define NINT_GPO_SEL_SHIFT (6U) +#define LDO_LS1_VMON1_SEL_MASK (0x1U << LDO_LS1_VMON1_SEL_SHIFT) +#define LDO_LS1_LSW_CONFIG_MASK (0x1U << LDO_LS1_LSW_CONFIG_SHIFT) +#define LS2_VMON2_GPO_SEL_MASK (0x3U << LS2_VMON2_GPO_SEL_SHIFT) +#define NINT_GPO_SEL_MASK (0x1U << NINT_GPO_SEL_SHIFT) + +// All sequence register bitfields, including: +// - BUCK1_SEQUENCE_REG +// - BUCK2_SEQUENCE_REG +// - BUCK3_SEQUENCE_REG +// - LDO_LS1_VMON1_SEQUENCE_REG +// - LS2_VMON2_SEQUENCE_REG +// - LS2_VMON2_SEQUENCE_REG +// - GPO_SEQUENCE_REG +// - NRSTOUT_SEQUENCE_REG +#define STARTUP_DELAY_SHIFT (0U) +#define SHUTDOWN_DELAY_SHIFT (4U) +#define STARTUP_DELAY_MASK (0x7U << STARTUP_DELAY_SHIFT) +#define SHUTDOWN_DELAY_MASK (0x7U << SHUTDOWN_DELAY_SHIFT) + +// REG_OV_CONF_REG Bitfields +// +// NOTE: These select fields use the same ordering as the definition of the +// PWR_RSRC types, the specific offset in the register can be calculated from +// the requested PWR_RSRC +#define BUCK1_OV_SEL_SHIFT (0U) +#define BUCK2_OV_SEL_SHIFT (2U) +#define BUCK3_OV_SEL_SHIFT (4U) +#define LDO_LS1_VMON1_OV_SEL_SHIFT (6U) +#define BUCK1_OV_SEL_MASK (0x3U << BUCK1_OV_SEL_SHIFT) +#define BUCK2_OV_SEL_MASK (0x3U << BUCK2_OV_SEL_SHIFT) +#define BUCK3_OV_SEL_MASK (0x3U << BUCK3_OV_SEL_SHIFT) +#define LDO_LS1_VMON1_OV_SEL_MASK (0x3U << LDO_LS1_VMON1_OV_SEL_SHIFT) + +// VCCA_LS2_VMON2_OV_CONF_REG Bitfields +#define VCCA_OV_SEL_SHIFT (0U) +#define LS2_VMON2_OV_SEL_SHIFT (4U) +#define PWRERR_OSD_SEL_SHIFT (7U) +#define VCCA_OV_SEL_MASK (0x3U << VCCA_UV_SEL_SHIFT) +#define LS2_VMON2_OV_SEL_MASK (0x3U << LS2_VMON2_UV_SEL_SHIFT) +#define PWRERR_OSD_SEL_MASK (0x1U << PWRERR_OSD_SEL_SHIFT) + +// REG_UV_CONF_REG Bitfields +// +// NOTE: These select fields use the same ordering as the definition of the +// PWR_RSRC types, the specific offset in the register can be calculated from +// the requested PWR_RSRC +#define BUCK1_UV_SEL_SHIFT (0U) +#define BUCK2_UV_SEL_SHIFT (2U) +#define BUCK3_UV_SEL_SHIFT (4U) +#define LDO_LS1_VMON1_UV_SEL_SHIFT (6U) +#define BUCK1_UV_SEL_MASK (0x3U << BUCK1_UV_SEL_SHIFT) +#define BUCK2_UV_SEL_MASK (0x3U << BUCK2_UV_SEL_SHIFT) +#define BUCK3_UV_SEL_MASK (0x3U << BUCK3_UV_SEL_SHIFT) +#define LDO_LS1_VMON1_UV_SEL_MASK (0x3U << LDO_LS1_VMON1_UV_SEL_SHIFT) + +// VCCA_LS2_VMON2_UV_CONF_REG Bitfields +#define VCCA_UV_SEL_SHIFT (0U) +#define LS2_VMON2_UV_SEL_SHIFT (4U) +#define LS2_VMON2_SC_SEL_SHIFT (6U) +#define VCCA_UV_SEL_MASK (0x3U << VCCA_UV_SEL_SHIFT) +#define LS2_VMON2_UV_SEL_MASK (0x3U << LS2_VMON2_UV_SEL_SHIFT) +#define LS2_VMON2_SC_SEL_MASK (0x3U << LS2_VMON2_SC_SEL_SHIFT) + +// REG_SC_CONF_REG Bitfields +// +// NOTE: These select fields use the same ordering as the definition of the +// PWR_RSRC types, the specific offset in the register can be calculated from +// the requested PWR_RSRC +#define BUCK1_SC_SEL_SHIFT (0U) +#define BUCK2_SC_SEL_SHIFT (2U) +#define BUCK3_SC_SEL_SHIFT (4U) +#define LDO_LS1_VMON1_SC_SEL_SHIFT (6U) +#define BUCK1_SC_SEL_MASK (0x3U << BUCK1_SC_SEL_SHIFT) +#define BUCK2_SC_SEL_MASK (0x3U << BUCK2_SC_SEL_SHIFT) +#define BUCK3_SC_SEL_MASK (0x3U << BUCK3_SC_SEL_SHIFT) +#define LDO_LS1_VMON1_SC_SEL_MASK (0x3U << LDO_LS1_VMON1_SC_SEL_SHIFT) + +// LDO_LS1_VMON1_MON_CONF_REG Bitfields +#define LDO_LS1_VMON1_RV_CONF_SHIFT (1U) +#define LDO_LS1_VMON1_VMON_EN_SHIFT (2U) +#define LDO_LS1_VMON1_DIS_PD_SHIFT (3U) +#define LDO_LS1_VMON1_OV_THR_SHIFT (4U) +#define LDO_LS1_VMON1_UV_THR_SHIFT (5U) +#define LDO_LS1_VMON1_OV_THR_MASK (0x3U << LDO_LS1_VMON1_OV_THR_SHIFT) +#define LDO_LS1_VMON1_UV_THR_MASK (0x3U << LDO_LS1_VMON1_UV_THR_SHIFT) + +// LS2_VMON2_MON_CONF_REG Bitfields +#define LS2_VMON2_RV_CONF_SHIFT (1U) +#define LS2_VMON2_VMON_EN_SHIFT (2U) +#define LS2_VMON2_DIS_PD_SHIFT (3U) +#define LS2_VMON2_OV_THR_SHIFT (4U) +#define LS2_VMON2_UV_THR_SHIFT (5U) +#define LS2_VMON2_OV_THR_MASK (0x3U << LS2_VMON2_OV_THR_SHIFT) +#define LS2_VMON2_UV_THR_MASK (0x3U << LS2_VMON2_UV_THR_SHIFT) + +// VCCA_MON_CONF_REG Bitfields +#define LS2_VMON2_DEGLITCH_SEL_SHIFT (0U) +#define VMONIN_DEGLITCH_SEL_SHIFT (2U) +#define VCCA_OV_THR_SHIFT (4U) +#define VCCA_UV_THR_SHIFT (5U) +#define LS2_VMON2_DEGLITCH_SEL_MASK (0x3U << LS2_VMON2_DEGLITCH_SEL_SHIFT) +#define VMONIN_DEGLITCH_SEL_MASK (0x3U << VMONIN_DEGLITCH_SEL_SHIFT) +#define VCCA_OV_THR_MASK (0x3U << VCCA_OV_THR_SHIFT) +#define VCCA_UV_THR_MASK (0x3U << VCCA_UV_THR_SHIFT) + +// Bitfields for all *_SEQUENCE_REG +// - BUCK1_SEQUENCE_REG +// - BUCK2_SEQUENCE_REG +// - BUCK3_SEQUENCE_REG +// - LDO_LS1_VMON1_SEQUENCE_REG +// - LS2_VMON2_SEQUENCE_REG +// - GPO_SEQUENCE_REG +// - NRSTOUT_SEQUENCE_REG +#define SEQ_STARTUP_DELAY_SHIFT (0U) +#define SEQ_SHUTDOWN_DELAY_SHIFT (4U) +#define SEQ_STARTUP_DELAY_MASK (0xFU << SEQ_STARTUP_DELAY_SHIFT) +#define SEQ_SHUTDOWN_DELAY_MASK (0xFU << SEQ_SHUTDOWN_DELAY_SHIFT) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif // __REGMAP_POWER_H__ diff --git a/src/pmic_power.c b/src/pmic_power.c new file mode 100644 index 0000000..3e402b8 --- /dev/null +++ b/src/pmic_power.c @@ -0,0 +1,1669 @@ +/****************************************************************************** + * Copyright (c) 2024 Texas Instruments Incorporated - http://www.ti.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/* ========================================================================== */ +/* Include Files */ +/* ========================================================================== */ +#include +#include +#include + +#include "pmic.h" +#include "pmic_common.h" +#include "pmic_io.h" +#include "pmic_power.h" +#include "regmap/power.h" + +/* ========================================================================== */ +/* Macros & Typedefs */ +/* ========================================================================== */ +// While the UV/OV thresholds have different thresholds depending on whether it +// is for Buck, LDO, LSW, or VCCA, the actual values that go in the register are +// all 2-bit values and have the same range of supported values. +#define UV_OV_THR_MIN_VALUE (0U) +#define UV_OV_THR_MAX_VALUE (3U) + +// Min and max voltages supported for BUCK1/2/3 VSET +#define BUCK_VSET_MIN_MV ((uint16_t)900U) +#define BUCK_VSET_MAX_MV ((uint16_t)1900U) +#define BUCK_VSET_STEP_MV ((uint16_t)20U) + +// Min and max voltages supported for LDO_LS1_VMON1, LS2_VMON2, and VCCA_VMON +// PG_LEVEL +#define VMON_PG_LEVEL_MIN_MV ((uint16_t)600U) +#define VMON_PG_LEVEL_MAX_MV ((uint16_t)3400U) +#define VMON_PG_LEVEL_STEP_MV ((uint16_t)25U) + +// Register mask and shift values for Buck VSET, and VMON PGSET fields. Bucks +// get the whole register, VMONs get all but the highest bit. +#define VSET_PGSET_SHIFT (0U) +#define BUCK_VSET_MASK (0xFFU) +#define VMON_PGSET_MASK (0x7FU) + +typedef struct SetResourceProcessor_s { + uint8_t validParam; + int32_t (*fptr)(Pmic_CoreHandle_t *, const Pmic_PowerResourceCfg_t *); +} SetResourceProcessor_t; + +typedef struct GetResourceProcessor_s { + uint8_t validParam; + int32_t (*fptr)(Pmic_CoreHandle_t *, Pmic_PowerResourceCfg_t *); +} GetResourceProcessor_t; + +static const uint8_t PwrResourceAll[] = { + PMIC_PWR_RSRC_BUCK1, + PMIC_PWR_RSRC_BUCK2, + PMIC_PWR_RSRC_BUCK3, + PMIC_PWR_RSRC_LDO_LS1_VMON1, + PMIC_PWR_RSRC_LS2_VMON2, + PMIC_PWR_RSRC_GPO, + PMIC_PWR_RSRC_VCCA_VMON, +}; + +static const uint8_t PwrResourceBucks[] = { + PMIC_PWR_RSRC_BUCK1, + PMIC_PWR_RSRC_BUCK2, + PMIC_PWR_RSRC_BUCK3, +}; + +static const uint8_t PwrResourceVmonCapable[] = { + PMIC_PWR_RSRC_BUCK1, + PMIC_PWR_RSRC_BUCK2, + PMIC_PWR_RSRC_BUCK3, + PMIC_PWR_RSRC_LDO_LS1_VMON1, + PMIC_PWR_RSRC_LS2_VMON2, + PMIC_PWR_RSRC_VCCA_VMON, +}; + +static const uint8_t PwrResourceImonCapable[] = { + PMIC_PWR_RSRC_BUCK1, + PMIC_PWR_RSRC_BUCK2, + PMIC_PWR_RSRC_BUCK3, + PMIC_PWR_RSRC_LDO_LS1_VMON1, + PMIC_PWR_RSRC_LS2_VMON2, +}; + +/* ========================================================================== */ +/* Function Definitions */ +/* ========================================================================== */ +static bool PWR_isResourceValid(const uint8_t validResources[], uint8_t numValid, uint8_t resource) +{ + bool isValid = false; + + for (uint8_t i = 0U; (i < numValid) && !isValid; i++) { + if (resource == validResources[i]) { + isValid = true; + } + } + + return isValid; +} + +static inline bool PWR_isInRangeU16(uint16_t min, uint16_t max, uint16_t param) +{ + return (param >= min) && (param <= max); +} + +static inline bool PWR_isInRangeU8(uint8_t min, uint8_t max, uint8_t param) +{ + return PWR_isInRangeU16((uint16_t)min, (uint16_t)max, (uint16_t)param); +} + +static int32_t PWR_validateParams(uint8_t resource, + const uint8_t validResources[], + uint8_t numResources, + uint8_t min, + uint8_t max, + uint8_t value) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Validate resource requested supports configuration of this parameter + if (PWR_isResourceValid(validResources, numResources, resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Validate parameter within allowed range + if ((status == PMIC_ST_SUCCESS) && PWR_isInRangeU8(min, max, value)) { + status = PMIC_ST_ERR_INV_PARAM; + } + + return status; +} + +static int32_t PWR_readModifyWrite(Pmic_CoreHandle_t *handle, uint8_t regAddr, uint8_t shift, uint8_t mask, uint8_t value) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regData = 0U; + + Pmic_criticalSectionStart(handle); + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + Pmic_setBitField(®Data, shift, mask, value); + status = Pmic_ioTxByte(handle, regAddr, regData); + } + + Pmic_criticalSectionStop(handle); + + return status; +} + +int32_t Pmic_pwrSetResourceEnable(Pmic_CoreHandle_t *handle, uint8_t resource, bool enable) +{ + int32_t status = Pmic_checkPmicCoreHandle(handle); + uint8_t regData = 0U; + + // Validate that the requested resource is within range and supports + // enablement. All power resource support enable/disable, this is mostly + // just parameter validation. + if ((status == PMIC_ST_SUCCESS) && + (PWR_isResourceValid(PwrResourceAll, COUNT(PwrResourceAll), resource) == false)) { + status = PMIC_ST_ERR_INV_PARAM; + } + + Pmic_criticalSectionStart(handle); + + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte(handle, BLOCK_EN_CTRL_REG, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + // PWR_RSRC types are defined the same as the shift values for each bit in + // this register, therefore the resource can be used directly as the shift + // value + Pmic_setBitField_b(®Data, resource, enable); + status = Pmic_ioTxByte(handle, BLOCK_EN_CTRL_REG, regData); + } + + Pmic_criticalSectionStop(handle); + + return status; +} + +int32_t Pmic_pwrGetResourceEnable(Pmic_CoreHandle_t *handle, uint8_t resource, bool *isEnabled) +{ + int32_t status = Pmic_checkPmicCoreHandle(handle); + uint8_t regData = 0U; + + // Validate that the requested resource is within range and supports + // enablement. All power resource support enable/disable, this is mostly + // just parameter validation. + if ((status == PMIC_ST_SUCCESS) && + (PWR_isResourceValid(PwrResourceAll, COUNT(PwrResourceAll), resource) == false)) { + status = PMIC_ST_ERR_INV_PARAM; + } + + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, BLOCK_EN_CTRL_REG, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + // PWR_RSRC types are defined the same as the shift values for each bit in + // this register, therefore the resource can be used directly as the shift + // value + *isEnabled = Pmic_getBitField_b(regData, resource); + } + + return status; +} + +static int32_t PWR_setModeCfgLdoLs1Vmon1(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regData = 0U; + + struct LdoLs1ModeConfig_s { + uint8_t bypConfig; + uint8_t vmon1Sel; + uint8_t lswConfig; + }; + + // For LDO_LS1_VMON1 + // + // LDO_LS1_VMON1_PG_LEVEL : LDO_LS1_BYP_CONFIG -> Select LDO or Bypass mode (LSW) + // FUNC_CONF : LDO_LS1_VMON1_SEL -> Select LDO or VMON1 mode + // FUNC_CONF : LDO_LS1_LSW_CONFIG -> Select LDO/BYP mode or LSW mode + // "REG" -> LDO_LS1_BYP_CONFIG=0, LDO_LS1_VMON1_SEL=0, LDO_LS1_LSW_CONFIG=0 + // "BYP" -> LDO_LS1_BYP_CONFIG=1, LDO_LS1_VMON1_SEL=0, LDO_LS1_LSW_CONFIG=0 + // "LSW" -> LDO_LS1_BYP_CONFIG=1, LDO_LS1_VMON1_SEL=0, LDO_LS1_LSW_CONFIG=1 + // "VMON" -> LDO_LS1_BYP_CONFIG=1, LDO_LS1_VMON1_SEL=1, LDO_LS1_LSW_CONFIG=1 ??? (unsure about this one) + const struct LdoLs1ModeConfig_s configurations[] = { + // PMIC_PWR_RSRC_MODE_REG + { .bypConfig = 0U, .vmon1Sel = 0U, .lswConfig = 0U }, + // PMIC_PWR_RSRC_MODE_BYP + { .bypConfig = 1U, .vmon1Sel = 0U, .lswConfig = 0U }, + // PMIC_PWR_RSRC_MODE_LSW + { .bypConfig = 1U, .vmon1Sel = 0U, .lswConfig = 1U }, + // PMIC_PWR_RSRC_MODE_VMON + { .bypConfig = 1U, .vmon1Sel = 1U, .lswConfig = 1U }, + }; + + struct LdoLs1ModeConfig_s modeConfig = configurations[config->mode]; + + // Handle LDO_LS1_VMON1_PG_LEVEL fields first, this is only LDO_LS1_BYP_CONFIG + Pmic_criticalSectionStart(handle); + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte(handle, LDO_LS1_VMON1_PG_LEVEL_REG, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + Pmic_setBitField(®Data, LDO_LS1_BYP_CONFIG_SHIFT, LDO_LS1_BYP_CONFIG_MASK, modeConfig.bypConfig); + status = Pmic_ioTxByte(handle, LDO_LS1_VMON1_PG_LEVEL_REG, regData); + } + Pmic_criticalSectionStop(handle); + + // Handle FUNC_CONF fields, this covers the remaining fields + Pmic_criticalSectionStart(handle); + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte(handle, FUNC_CONF_REG, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + Pmic_setBitField(®Data, LDO_LS1_VMON1_SEL_SHIFT, LDO_LS1_VMON1_SEL_MASK, modeConfig.vmon1Sel); + Pmic_setBitField(®Data, LDO_LS1_LSW_CONFIG_SHIFT, LDO_LS1_LSW_CONFIG_MASK, modeConfig.lswConfig); + status = Pmic_ioTxByte(handle, FUNC_CONF_REG, regData); + } + Pmic_criticalSectionStop(handle); + + return status; +} + +static int32_t PWR_setModeCfgLs2Vmon2(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regData = 0U; + + // For LS2_VMON2 + // FUNC_CONF : LS2_VMON2_GPO_SEL -> Select LSW or VMON mode (also has option for SYNCCLKIN) + // 0 = LOAD_SWITCH mode + // 1 = VMON2 mode + const uint8_t mode = (config->mode == PMIC_PWR_RSRC_MODE_LSW) ? 0U : 1U; + + Pmic_criticalSectionStart(handle); + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte(handle, FUNC_CONF_REG, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + Pmic_setBitField(®Data, LS2_VMON2_GPO_SEL_SHIFT, LS2_VMON2_GPO_SEL_MASK, mode); + status = Pmic_ioTxByte(handle, FUNC_CONF_REG, regData); + } + Pmic_criticalSectionStop(handle); + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setModeCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + const uint8_t mode = config->mode; + + // Validate parameter and set up any resource specific variables + switch (config->resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + // BUCKs do not have mode configurability, assert that the user + // requested "REG" mode, as long as that is true proceed without + // error + if (mode != PMIC_PWR_RSRC_MODE_REG) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + break; + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + // LDO_LS1_VMON1 supports all valid configurations, assert that the + // user provided parameter is in range + if (PWR_isInRangeU8(PMIC_PWR_RSRC_MODE_MIN, PMIC_PWR_RSRC_MODE_MAX, mode) == false) { + status = PMIC_ST_ERR_INV_PARAM; + } + + if (status == PMIC_ST_SUCCESS) { + status = PWR_setModeCfgLdoLs1Vmon1(handle, config); + } + + break; + case PMIC_PWR_RSRC_LS2_VMON2: + // LS2_VMON2 supports selection between LSW or VMON, assert that the + // user didn't select "REG" or "BYP" mode + if (PWR_isInRangeU8(PMIC_PWR_RSRC_MODE_REG, PMIC_PWR_RSRC_MODE_BYP, mode)) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + if (status == PMIC_ST_SUCCESS) { + status = PWR_setModeCfgLs2Vmon2(handle, config); + } + + break; + case PMIC_PWR_RSRC_VCCA_VMON: + // VCCA_VMON does not have mode configurability, assert that the + // user requested "VMON" mode, as long as this is true, proceed + // without error. + if (mode != PMIC_PWR_RSRC_MODE_VMON) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + return status; +} + +static int32_t PWR_getModeCfgLdoLs1Vmon1(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t pgLevelReg = 0U; + uint8_t funcConfReg = 0U; + uint8_t resolvedMode = 0U; + + // Perform necessary register reads to decode current state + Pmic_criticalSectionStart(handle); + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte(handle, LDO_LS1_VMON1_PG_LEVEL_REG, &pgLevelReg); + } + + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte(handle, FUNC_CONF_REG, &funcConfReg); + } + Pmic_criticalSectionStop(handle); + + // For LDO_LS1_VMON1 + // + // LDO_LS1_VMON1_PG_LEVEL : LDO_LS1_BYP_CONFIG -> Select LDO or Bypass mode (LSW) + // FUNC_CONF : LDO_LS1_VMON1_SEL -> Select LDO or VMON1 mode + // FUNC_CONF : LDO_LS1_LSW_CONFIG -> Select LDO/BYP mode or LSW mode + // "REG" -> LDO_LS1_BYP_CONFIG=0, LDO_LS1_VMON1_SEL=0, LDO_LS1_LSW_CONFIG=0 + // "BYP" -> LDO_LS1_BYP_CONFIG=1, LDO_LS1_VMON1_SEL=0, LDO_LS1_LSW_CONFIG=0 + // "LSW" -> LDO_LS1_BYP_CONFIG=1, LDO_LS1_VMON1_SEL=0, LDO_LS1_LSW_CONFIG=1 + // "VMON" -> LDO_LS1_BYP_CONFIG=1, LDO_LS1_VMON1_SEL=1, LDO_LS1_LSW_CONFIG=1 ??? (unsure about this one) + if (Pmic_getBitField_b(pgLevelReg, LDO_LS1_BYP_CONFIG_SHIFT)) { + resolvedMode = PMIC_PWR_RSRC_MODE_REG; + } else if (Pmic_getBitField_b(funcConfReg, LDO_LS1_VMON1_SEL_SHIFT)) { + resolvedMode = PMIC_PWR_RSRC_MODE_VMON; + } else if (Pmic_getBitField_b(funcConfReg, LDO_LS1_LSW_CONFIG_SHIFT)) { + resolvedMode = PMIC_PWR_RSRC_MODE_LSW; + } else { + resolvedMode = PMIC_PWR_RSRC_MODE_BYP; + } + + if (status == PMIC_ST_SUCCESS) { + config->mode = resolvedMode; + } + + return status; +} + +static int32_t PWR_getModeCfgLs2Vmon2(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regData = 0U; + uint8_t hwModeVal = 0U; + + // For LS2_VMON2 + // FUNC_CONF : LS2_VMON2_GPO_SEL -> Select LSW or VMON mode (also has option for SYNCCLKIN) + // 0 = LOAD_SWITCH mode + // 1 = VMON2 mode + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, FUNC_CONF_REG, ®Data); + hwModeVal = Pmic_getBitField(regData, LS2_VMON2_GPO_SEL_SHIFT, LS2_VMON2_GPO_SEL_MASK); + } + + if (status == PMIC_ST_SUCCESS) { + if (hwModeVal == 0U) { + config->mode = PMIC_PWR_RSRC_MODE_LSW; + } else { + config->mode = PMIC_PWR_RSRC_MODE_VMON; + } + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getModeCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + + switch (config->resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + // BUCKs do not have mode configurability, report they are in REG + // mode + config->mode = PMIC_PWR_RSRC_MODE_REG; + break; + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + status = PWR_getModeCfgLdoLs1Vmon1(handle, config); + break; + case PMIC_PWR_RSRC_LS2_VMON2: + status = PWR_getModeCfgLs2Vmon2(handle, config); + break; + case PMIC_PWR_RSRC_VCCA_VMON: + // VCCA_CMON does not have mode configurabilite, report that it is + // in VMON mode + config->mode = PMIC_PWR_RSRC_MODE_VMON; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setIlimCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + + const uint8_t regAddr = BUCK1_MON_CONF_REG + config->resource; + const uint8_t value = config->ilim; + + // Validate resource requested supports configuration and that parameter is + // within allowed range + status = PWR_validateParams( + config->resource, PwrResourceBucks, COUNT(PwrResourceBucks), + PMIC_PWR_ILIM_MIN, PMIC_PWR_ILIM_MAX, value); + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, BUCKx_ILIM_SHIFT, BUCKx_ILIM_MASK, value); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getIlimCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + const uint8_t regAddr = BUCK1_MON_CONF_REG + config->resource; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceBucks, COUNT(PwrResourceBucks), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->ilim = Pmic_getBitField(regData, BUCKx_ILIM_SHIFT, BUCKx_ILIM_MASK); + } + + return status; +} + +static int32_t PWR_getDeglitchParamLoc(uint8_t resource, uint8_t *regAddr, uint8_t *shift, uint8_t *mask) { + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register and bitshifts need to be used: + // - BUCKs, and LDO1_LS1_VMON1 are in BUCK_LDO_LS1_VMON1_DEGLIT_REG + // - LS2_VMON2 and VCCA are in VCCA_MON_CONF_REG + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + *regAddr = BUCK_LDO_LS1_VMON1_DEGLIT_REG; + *shift = (uint8_t)(resource << 1U); + break; + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = VCCA_MON_CONF_REG; + *shift = LS2_VMON2_DEGLITCH_SEL_SHIFT; + break; + case PMIC_PWR_RSRC_VCCA_VMON: + *regAddr = VCCA_MON_CONF_REG; + *shift = VMONIN_DEGLITCH_SEL_SHIFT; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // For all resources, this is a 2-bit control, set the mask accordingly + *mask = (uint8_t)(0x3U << *shift); + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setDeglitchCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + const uint8_t value = config->deglitch; + + // Get register address and bit shifts/masks to use for this resource + status = PWR_getDeglitchParamLoc(config->resource, ®Addr, &shift, &mask); + + // Validate resource requested supports configuration and that parameter is + // within allowed range + if (status == PMIC_ST_SUCCESS) { + status = PWR_validateParams( + config->resource, PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), + PMIC_PWR_DEGLITCH_MIN, PMIC_PWR_DEGLITCH_MAX, value); + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, value); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getDeglitchCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Get register address and bit shifts/masks to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getDeglitchParamLoc(config->resource, ®Addr, &shift, &mask); + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->deglitch = Pmic_getBitField(regData, shift, mask); + } + + return status; +} + +static int32_t PWR_getUvThreshParamLoc(uint8_t resource, uint8_t *regAddr, uint8_t *shift, uint8_t *mask) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register needs to be used: + // - BUCKs are in BUCKx_MON_CONF_REG + // - LDO_LS1_VMON1 is in LDO_LS1_VMON1_MON_CONF_REG + // - LS2_VMON2 is in LS2_VMON2_MON_CONF_REG + // - VCCA_VMON is in VCCA_MON_CONF_REG + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + // The BUCK registers are all defined in the same order as the + // PMIC_PWR_RSRC definitions, so the base address of BUCK1_MON_CONF + // can be used and the resource value can be used as an offset + *regAddr = BUCK1_MON_CONF_REG + resource; + *shift = BUCKx_UV_THR_SHIFT; + break; + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + *regAddr = LDO_LS1_VMON1_MON_CONF_REG; + *shift = LDO_LS1_VMON1_UV_THR_SHIFT; + break; + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = LS2_VMON2_MON_CONF_REG; + *shift = LS2_VMON2_UV_THR_SHIFT; + break; + case PMIC_PWR_RSRC_VCCA_VMON: + *regAddr = VCCA_MON_CONF_REG; + *shift = VCCA_UV_THR_SHIFT; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // For all resources, this is a 2-bit control, set the mask accordingly + *mask = (uint8_t)(0x3U << *shift); + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setUvThreshCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + const uint8_t value = config->uvThresh; + + // Get register address and bit shifts/masks to use for this resource + status = PWR_getUvThreshParamLoc(config->resource, ®Addr, &shift, &mask); + + // Validate resource requested supports configuration and that parameter is + // within allowed range + if (status == PMIC_ST_SUCCESS) { + status = PWR_validateParams( + config->resource, PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), + UV_OV_THR_MIN_VALUE, UV_OV_THR_MAX_VALUE, value); + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, value); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getUvThreshCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Get register address and bit shifts/masks to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getUvThreshParamLoc(config->resource, ®Addr, &shift, &mask); + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->uvThresh = Pmic_getBitField(regData, shift, mask); + } + + return status; +} + +static int32_t PWR_getUvReactionParamLoc(uint8_t resource, uint8_t *regAddr, uint8_t *shift, uint8_t *mask) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register and bitshifts need to be used: + // - BUCKs, and LDO1_LS1_VMON1 are in REG_UV_CONF_REG + // - VCCA, and LS2_VMON2 are in VCCA_LS2_VMON2_UV_CONF_REG + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + *regAddr = REG_UV_CONF_REG; + *shift = (uint8_t)(resource << 1U); + break; + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = VCCA_LS2_VMON2_UV_CONF_REG; + *shift = LS2_VMON2_UV_SEL_SHIFT; + break; + case PMIC_PWR_RSRC_VCCA_VMON: + *regAddr = VCCA_LS2_VMON2_UV_CONF_REG; + *shift = VCCA_UV_SEL_SHIFT; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // For all resources, this is a 2-bit control, set the mask accordingly + *mask = (uint8_t)(0x3U << *shift); + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setUvReactionCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + const uint8_t value = config->uvReaction; + + // Get register address and bit shifts/masks to use for this resource + status = PWR_getUvReactionParamLoc(config->resource, ®Addr, &shift, &mask); + + // Validate resource requested supports configuration and that parameter is + // within allowed range + if (status == PMIC_ST_SUCCESS) { + status = PWR_validateParams( + config->resource, PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), + PMIC_PWR_FAULT_REACT_MIN, PMIC_PWR_FAULT_REACT_MAX, value); + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, value); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getUvReactionCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Get register address and bit shifts/masks to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getUvReactionParamLoc(config->resource, ®Addr, &shift, &mask); + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->uvReaction = Pmic_getBitField(regData, shift, mask); + } + + return status; +} + +static int32_t PWR_getOvThreshParamLoc(uint8_t resource, uint8_t *regAddr, uint8_t *shift, uint8_t *mask) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register needs to be used: + // - BUCKs are in BUCKx_MON_CONF_REG + // - LDO_LS1_VMON1 is in LDO_LS1_VMON1_MON_CONF_REG + // - LS2_VMON2 is in LS2_VMON2_MON_CONF_REG + // - VCCA_VMON is in VCCA_MON_CONF_REG + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + // The BUCK registers are all defined in the same order as the + // PMIC_PWR_RSRC definitions, so the base address of BUCK1_MON_CONF + // can be used and the resource value can be used as an offset + *regAddr = BUCK1_MON_CONF_REG + resource; + *shift = BUCKx_OV_THR_SHIFT; + break; + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + *regAddr = LDO_LS1_VMON1_MON_CONF_REG; + *shift = LDO_LS1_VMON1_OV_THR_SHIFT; + break; + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = LS2_VMON2_MON_CONF_REG; + *shift = LS2_VMON2_OV_THR_SHIFT; + break; + case PMIC_PWR_RSRC_VCCA_VMON: + *regAddr = VCCA_MON_CONF_REG; + *shift = VCCA_OV_THR_SHIFT; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // For all resources, this is a 2-bit control, set the mask accordingly + *mask = (uint8_t)(0x3U << *shift); + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setOvThreshCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + const uint8_t value = config->uvThresh; + + // Get register address and bit shifts/masks to use for this resource + status = PWR_getOvThreshParamLoc(config->resource, ®Addr, &shift, &mask); + + // Validate resource requested supports configuration and that parameter is + // within allowed range + if (status == PMIC_ST_SUCCESS) { + status = PWR_validateParams( + config->resource, PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), + UV_OV_THR_MIN_VALUE, UV_OV_THR_MAX_VALUE, value); + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, value); + } + + return status; +} + +static int32_t PWR_getOvThreshCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Get register address and bit shifts/masks to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getOvThreshParamLoc(config->resource, ®Addr, &shift, &mask); + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->ovThresh = Pmic_getBitField(regData, shift, mask); + } + + return status; +} + +static int32_t PWR_getOvReactionParamLoc(uint8_t resource, uint8_t *regAddr, uint8_t *shift, uint8_t *mask) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register and bitshifts need to be used: + // - BUCKs, and LDO1_LS1_VMON1 are in REG_OV_CONF_REG + // - VCCA, and LS2_VMON2 are in VCCA_LS2_VMON2_OV_CONF_REG + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + *regAddr = REG_OV_CONF_REG; + *shift = (uint8_t)(resource << 1U); + break; + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = VCCA_LS2_VMON2_OV_CONF_REG; + *shift = LS2_VMON2_OV_SEL_SHIFT; + break; + case PMIC_PWR_RSRC_VCCA_VMON: + *regAddr = VCCA_LS2_VMON2_OV_CONF_REG; + *shift = VCCA_OV_SEL_SHIFT; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // For all resources, this is a 2-bit control, set the mask accordingly + *mask = (uint8_t)(0x3U << *shift); + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setOvReactionCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + const uint8_t value = config->ovReaction; + + // Get register address and bit shifts/masks to use for this resource + status = PWR_getOvReactionParamLoc(config->resource, ®Addr, &shift, &mask); + + // Validate resource requested supports configuration and that parameter is + // within allowed range + if (status == PMIC_ST_SUCCESS) { + status = PWR_validateParams( + config->resource, PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), + PMIC_PWR_FAULT_REACT_MIN, PMIC_PWR_FAULT_REACT_MAX, value); + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, value); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getOvReactionCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceVmonCapable, COUNT(PwrResourceVmonCapable), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Get register address and bit shifts/masks to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getOvReactionParamLoc(config->resource, ®Addr, &shift, &mask); + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->ovReaction = Pmic_getBitField(regData, shift, mask); + } + + return status; +} + + +static int32_t PWR_getRvReactionParamLoc(uint8_t resource, uint8_t *regAddr, uint8_t *shift, uint8_t *mask) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register and bitshifts need to be used: + // - BUCKs are in sequential BUCKx_MON_CONF_REG + // - LDO1_LS1_VMON1 are in LDO_LS1_VMON1_MON_CONF_REG + // - LS2_VMON2 are in LS2_VMON2_MON_CONF_REG + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + *regAddr = BUCK1_MON_CONF_REG + resource; + *shift = BUCKx_RV_CONF_SHIFT; + break; + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + *regAddr = LDO_LS1_VMON1_MON_CONF_REG; + *shift = LDO_LS12_VMON_RV_CONF_SHIFT; + break; + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = LS2_VMON2_MON_CONF_REG; + *shift = LDO_LS12_VMON_RV_CONF_SHIFT; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // For all resources, this is a 1-bit control, set the mask accordingly + *mask = (uint8_t)(0x1U << *shift); + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setRvReactionCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + const uint8_t value = config->rvReaction; + + // Get register address and bit shifts/masks to use for this resource + status = PWR_getRvReactionParamLoc(config->resource, ®Addr, &shift, &mask); + + // Validate resource requested supports configuration and that parameter is + // within allowed range + if (status == PMIC_ST_SUCCESS) { + status = PWR_validateParams( + config->resource, PwrResourceImonCapable, COUNT(PwrResourceImonCapable), + PMIC_PWR_RV_CONF_INT_ONLY, PMIC_PWR_RV_CONF_SHUT_DOWN, value); + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, value); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getRvReactionCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceImonCapable, COUNT(PwrResourceImonCapable), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Get register address and bit shifts/masks to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getRvReactionParamLoc(config->resource, ®Addr, &shift, &mask); + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->rvReaction = Pmic_getBitField(regData, shift, mask); + } + + return status; +} + +static int32_t PWR_getScReactionParamLoc(uint8_t resource, uint8_t *regAddr, uint8_t *shift, uint8_t *mask) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register and bitshifts need to be used: + // - BUCKs and LDO_LS1_VMON1 are in REG_SC_CONF_REG + // - LS2_VMON2 are in VCCA_LS2_VMON2_UV_CONF_REG + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + *regAddr = REG_SC_CONF_REG; + *shift = (uint8_t)(resource << 1U); + break; + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = VCCA_LS2_VMON2_UV_CONF_REG; + *shift = LS2_VMON2_SC_SEL_SHIFT; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // For all resources, this is a 2-bit control, set the mask accordingly + *mask = (uint8_t)(0x3U << *shift); + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setScReactionCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + const uint8_t value = config->rvReaction; + + // Get register address and bit shifts/masks to use for this resource + status = PWR_getScReactionParamLoc(config->resource, ®Addr, &shift, &mask); + + // Validate resource requested supports configuration and that parameter is + // within allowed range + if (status == PMIC_ST_SUCCESS) { + status = PWR_validateParams( + config->resource, PwrResourceImonCapable, COUNT(PwrResourceImonCapable), + PMIC_PWR_FAULT_REACT_MIN, PMIC_PWR_FAULT_REACT_MAX, value); + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, value); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getScReactionCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t regAddr = 0U; + uint8_t shift = 0U; + uint8_t mask = 0U; + uint8_t regData = 0U; + + // Validate resource requested supports this parameter + if (PWR_isResourceValid(PwrResourceImonCapable, COUNT(PwrResourceImonCapable), config->resource) == false) { + status = PMIC_ST_ERR_NOT_SUPPORTED; + } + + // Get register address and bit shifts/masks to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getScReactionParamLoc(config->resource, ®Addr, &shift, &mask); + } + + // Now read configuration register and update the config struct + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + if (status == PMIC_ST_SUCCESS) { + config->rvReaction = Pmic_getBitField(regData, shift, mask); + } + + return status; +} + +static inline int32_t PWR_convertVoltageMvToCodeBuck(uint16_t voltage_mV, uint8_t *voltageCode) +{ + // Formula for code to Volt is 0.9+VSET*0.020 + // + // NOTE: The device does not limit the BUCK_VSET value to 0x32 (which is the + // highest specified operating range), if a higher value is written then the + // device will be out of the specified operating range. This driver limits + // the code value by limiting the voltage range allowed by the user. + int32_t status = PMIC_ST_SUCCESS; + + // Assert that the voltage is within supported ranges + if (PWR_isInRangeU16(BUCK_VSET_MIN_MV, BUCK_VSET_MAX_MV, voltage_mV) == false) { + status = PMIC_ST_ERR_INV_PARAM; + } + + // Assert that the voltage is in 20mV units + if ((voltage_mV % BUCK_VSET_STEP_MV) != 0U) { + status = PMIC_ST_ERR_INV_PARAM; + } + + // If all assertions passed, we can safely convert the voltage to VSET code + if (status == PMIC_ST_SUCCESS) { + *voltageCode = (uint8_t)((voltage_mV - BUCK_VSET_MIN_MV) / BUCK_VSET_STEP_MV); + } + + return status; +} + +static inline int32_t PWR_convertVoltageMvToCodeVmon(uint16_t voltage_mV, uint8_t *voltageCode) +{ + // Formula for code to Volt is 0.5+PG_SET*0.025 + int32_t status = PMIC_ST_SUCCESS; + + // Assert that the voltage is within supported ranges + if (PWR_isInRangeU16(VMON_PG_LEVEL_MIN_MV, VMON_PG_LEVEL_MAX_MV, voltage_mV) == false) { + status = PMIC_ST_ERR_INV_PARAM; + } + + // Assert that the voltage is in 25mV units + if ((voltage_mV % VMON_PG_LEVEL_STEP_MV) != 0U) { + status = PMIC_ST_ERR_INV_PARAM; + } + + // If all assertions passed, we can safely convert the voltage to VSET code + if (status == PMIC_ST_SUCCESS) { + *voltageCode = (uint8_t)((voltage_mV - VMON_PG_LEVEL_MIN_MV) / VMON_PG_LEVEL_STEP_MV); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_setVoltageCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t voltageCode = 0U; + uint8_t mask = 0U; + + const uint8_t regAddr = BUCK1_VOUT_REG + config->resource; + const uint8_t shift = VSET_PGSET_SHIFT; + + // Attempt to convert the user provided mV into the desired code, and set up + // bit-mask to use depending on requested resource. + switch (config->resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + mask = BUCK_VSET_MASK; + status = PWR_convertVoltageMvToCodeBuck(config->voltage_mV, &voltageCode); + break; + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + case PMIC_PWR_RSRC_LS2_VMON2: + case PMIC_PWR_RSRC_VCCA_VMON: + mask = VMON_PGSET_MASK; + status = PWR_convertVoltageMvToCodeVmon(config->voltage_mV, &voltageCode); + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // Now read configuration register, modify control, and write back with + // critical section + if (status == PMIC_ST_SUCCESS) { + status = PWR_readModifyWrite(handle, regAddr, shift, mask, voltageCode); + } + + return status; +} + +static inline int32_t PWR_convertCodeToVoltageMvBuck(uint16_t *voltage_mV, uint8_t code) +{ + // Formula for code to Volt is 0.9+VSET*0.020 + // + // NOTE: The device does not limit the BUCK_VSET value to 0x32 (which is the + // highest specified operating range). While the "set" API of this driver + // does limit the input values, it is possible that the register would have + // been configured via other means. For this reason, the value in the + // register will be converted to a voltage faithfully and without + // restriction. + *voltage_mV = BUCK_VSET_MIN_MV + (code * BUCK_VSET_STEP_MV); + return PMIC_ST_SUCCESS; +} + +static inline int32_t PWR_convertCodeToVoltageMvVmon(uint16_t *voltage_mV, uint8_t code) +{ + // Formula for code to Volt is 0.5+PG_SET*0.025 + *voltage_mV = VMON_PG_LEVEL_MIN_MV + (code * VMON_PG_LEVEL_STEP_MV); + return PMIC_ST_SUCCESS; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested a change. +static int32_t PWR_getVoltageCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint8_t mask = 0U; + uint8_t regData = 0U; + uint8_t voltageCode = 0U; + uint16_t voltageMv = 0U; + int32_t (*fptr)(uint16_t *, uint8_t) = NULL; + + const uint8_t regAddr = BUCK1_VOUT_REG + config->resource; + const uint8_t shift = VSET_PGSET_SHIFT; + + // Select the correct function to use to convert the code to voltage (mV) + // and the correct mask value + switch (config->resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + mask = BUCK_VSET_MASK; + fptr = PWR_convertCodeToVoltageMvBuck; + break; + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + case PMIC_PWR_RSRC_LS2_VMON2: + case PMIC_PWR_RSRC_VCCA_VMON: + mask = VMON_PGSET_MASK; + fptr = PWR_convertCodeToVoltageMvVmon; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + // Read from the target register + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + // If the read was successful, convert from code to voltage + if ((status == PMIC_ST_SUCCESS) && (fptr != NULL)) { + voltageCode = Pmic_getBitField(regData, shift, mask); + status = fptr(&voltageMv, voltageCode); + } + + // If the conversion was successful, update the config struct + if (status == PMIC_ST_SUCCESS) { + config->voltage_mV = voltageMv; + } + + return status; +} + +static int32_t PWR_setSingleResourceCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) { + int32_t status = PMIC_ST_SUCCESS; + + // Define linkage between user provided valid params and the functions which + // handle setting those configurations + const SetResourceProcessor_t resourceProcessors[] = { + { PMIC_PWR_CFG_MODE_VALID, PWR_setModeCfg }, + { PMIC_PWR_CFG_ILIM_VALID, PWR_setIlimCfg }, + { PMIC_PWR_CFG_VOLTAGE_VALID, PWR_setVoltageCfg }, + { PMIC_PWR_CFG_DEGLITCH_VALID, PWR_setDeglitchCfg }, + { PMIC_PWR_CFG_UV_THRESH_VALID, PWR_setUvThreshCfg }, + { PMIC_PWR_CFG_UV_REACT_VALID, PWR_setUvReactionCfg }, + { PMIC_PWR_CFG_OV_THRESH_VALID, PWR_setOvThreshCfg }, + { PMIC_PWR_CFG_OV_REACT_VALID, PWR_setOvReactionCfg }, + { PMIC_PWR_CFG_RV_REACT_VALID, PWR_setRvReactionCfg }, + { PMIC_PWR_CFG_SC_REACT_VALID, PWR_setScReactionCfg }, + }; + + // First check for the enable bit, if this is valid and the user is + // disabling the resource, set this first. If the user is enabling the power + // resource, do that last. + if (Pmic_validParamStatusCheck(config->validParams, PMIC_PWR_CFG_ENABLE_VALID, status) && + (config->enable == PMIC_DISABLE)) { + status = Pmic_pwrSetResourceEnable(handle, config->resource, config->enable); + } + + // Handle all other potential field modifications + for (uint8_t i = 0U; i < COUNT(resourceProcessors); i++) { + const uint8_t validParam = resourceProcessors[i].validParam; + + if (status != PMIC_ST_SUCCESS) { + break; + } + + if (Pmic_validParamCheck(config->validParams, validParam)) { + status = resourceProcessors[i].fptr(handle, config); + } + } + + // Final check for the enable bit, if this is valid and the user is enabling + // the resource, we skipped configuration at the start of this function and + // need to enable it now. + if (Pmic_validParamStatusCheck(config->validParams, PMIC_PWR_CFG_ENABLE_VALID, status) && + (config->enable == PMIC_ENABLE)) { + status = Pmic_pwrSetResourceEnable(handle, config->resource, config->enable); + } + + return status; +} + +int32_t Pmic_pwrSetResourceCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerResourceCfg_t *config) +{ + return Pmic_pwrSetResourceCfgs(handle, 1U, config); +} + +int32_t Pmic_pwrSetResourceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, const Pmic_PowerResourceCfg_t config[]) +{ + int32_t status = Pmic_checkPmicCoreHandle(handle); + + // Validate parameters + if (config == NULL) { + status = PMIC_ST_ERR_NULL_PARAM; + } + + for (uint8_t i = 0; i < numConfigs; i++) { + status = PWR_setSingleResourceCfg(handle, &config[i]); + } + + return status; +} + +// NOTE: This function expects that the validParam value has already been +// checked and the user requested this param be updated. +static int32_t PWR_getEnableCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + bool isEnabled = false; + int32_t status = Pmic_pwrGetResourceEnable(handle, config->resource, &isEnabled); + + if (status == PMIC_ST_SUCCESS) { + config->enable = isEnabled; + } + + return status; +} + +static int32_t PWR_getSingleResourceCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Define linkage between user provided valid params and the functions which + // handle getting those configurations + const GetResourceProcessor_t resourceProcessors[] = { + { PMIC_PWR_CFG_ENABLE_VALID, PWR_getEnableCfg }, + { PMIC_PWR_CFG_MODE_VALID, PWR_getModeCfg }, + { PMIC_PWR_CFG_ILIM_VALID, PWR_getIlimCfg }, + { PMIC_PWR_CFG_VOLTAGE_VALID, PWR_getVoltageCfg }, + { PMIC_PWR_CFG_DEGLITCH_VALID, PWR_getDeglitchCfg }, + { PMIC_PWR_CFG_UV_THRESH_VALID, PWR_getUvThreshCfg }, + { PMIC_PWR_CFG_UV_REACT_VALID, PWR_getUvReactionCfg }, + { PMIC_PWR_CFG_OV_THRESH_VALID, PWR_getOvThreshCfg }, + { PMIC_PWR_CFG_OV_REACT_VALID, PWR_getOvReactionCfg }, + { PMIC_PWR_CFG_RV_REACT_VALID, PWR_getRvReactionCfg }, + { PMIC_PWR_CFG_SC_REACT_VALID, PWR_getScReactionCfg }, + }; + + // Read all fields requested by the user + for (uint8_t i = 0U; i < COUNT(resourceProcessors); i++) { + const uint8_t validParam = resourceProcessors[i].validParam; + + if (status != PMIC_ST_SUCCESS) { + break; + } + + if (Pmic_validParamCheck(config->validParams, validParam)) { + status = resourceProcessors[i].fptr(handle, config); + } + } + + return status; +} + +int32_t Pmic_pwrGetResourceCfg(Pmic_CoreHandle_t *handle, Pmic_PowerResourceCfg_t *config) +{ + return Pmic_pwrGetResourceCfgs(handle, 1U, config); +} + +int32_t Pmic_pwrGetResourceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, Pmic_PowerResourceCfg_t config[]) +{ + int32_t status = Pmic_checkPmicCoreHandle(handle); + + // Validate parameters + if (config == NULL) { + status = PMIC_ST_ERR_NULL_PARAM; + } + + for (uint8_t i = 0U; i < numConfigs; i++) { + if (status != PMIC_ST_SUCCESS) { + break; + } + + status = PWR_getSingleResourceCfg(handle, &config[i]); + } + + return status; +} + +int32_t Pmic_pwrSetSequenceCfg(Pmic_CoreHandle_t *handle, const Pmic_PowerSequenceCfg_t *config) +{ + return Pmic_pwrSetSequenceCfgs(handle, 1U, config); +} + +int32_t Pmic_pwrGetSequenceCfg(Pmic_CoreHandle_t *handle, Pmic_PowerSequenceCfg_t *config) +{ + return Pmic_pwrGetSequenceCfgs(handle, 1U, config); +} + +static int32_t PWR_getSeqRegister(uint8_t resource, uint16_t *regAddr) +{ + int32_t status = PMIC_ST_SUCCESS; + + // Determine which register to use for this resource + switch (resource) { + case PMIC_PWR_RSRC_BUCK1: + case PMIC_PWR_RSRC_BUCK2: + case PMIC_PWR_RSRC_BUCK3: + case PMIC_PWR_RSRC_LDO_LS1_VMON1: + case PMIC_PWR_RSRC_LS2_VMON2: + *regAddr = BUCK1_SEQUENCE_REG + resource; + break; + case PMIC_PWR_RSRC_GPO: + *regAddr = LDO_LS1_VMON1_SEQUENCE_REG; + break; + case PMIC_PWR_RSRC_NRSTOUT: + *regAddr = NRSTOUT_SEQUENCE_REG; + break; + default: + status = PMIC_ST_ERR_INV_PARAM; + break; + } + + return status; +} + +static int32_t PWR_getSingleSequence(Pmic_CoreHandle_t *handle, Pmic_PowerSequenceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint16_t regAddr = 0U; + uint8_t regData = 0U; + + // Determine which register to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getSeqRegister(config->resource, ®Addr); + } + + // Read the relevant sequencing register + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + // Extract the requested fields + if (Pmic_validParamCheck(config->validParams, PMIC_PWR_SEQ_STARTUP_VALID)) { + config->startupDelay = Pmic_getBitField(regData, SEQ_STARTUP_DELAY_SHIFT, SEQ_STARTUP_DELAY_MASK); + } + + if (Pmic_validParamCheck(config->validParams, PMIC_PWR_SEQ_SHUTDOWN_VALID)) { + config->shutdownDelay = Pmic_getBitField(regData, SEQ_SHUTDOWN_DELAY_SHIFT, SEQ_SHUTDOWN_DELAY_MASK); + } + + return status; +} + +static int32_t PWR_setSingleSequence(Pmic_CoreHandle_t *handle, const Pmic_PowerSequenceCfg_t *config) +{ + int32_t status = PMIC_ST_SUCCESS; + uint16_t regAddr = 0U; + uint8_t regData = 0U; + + // Determine which register to use for this resource + if (status == PMIC_ST_SUCCESS) { + status = PWR_getSeqRegister(config->resource, ®Addr); + } + + // Read the relevant sequencing register + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioRxByte_CS(handle, regAddr, ®Data); + } + + // Modify requested fields, there are no invalid values for startup or + // shutdown delay, they saturate at the maximum size allowed by the mask + if (Pmic_validParamCheck(config->validParams, PMIC_PWR_SEQ_STARTUP_VALID)) { + Pmic_setBitField(®Data, SEQ_STARTUP_DELAY_SHIFT, SEQ_STARTUP_DELAY_MASK, config->startupDelay); + } + + if (Pmic_validParamCheck(config->validParams, PMIC_PWR_SEQ_SHUTDOWN_VALID)) { + Pmic_setBitField(®Data, SEQ_SHUTDOWN_DELAY_SHIFT, SEQ_SHUTDOWN_DELAY_MASK, config->shutdownDelay); + } + + // Write the modifed register contents back + if (status == PMIC_ST_SUCCESS) { + status = Pmic_ioTxByte_CS(handle, regAddr, regData); + } + + return status; +} + +int32_t Pmic_pwrSetSequenceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, const Pmic_PowerSequenceCfg_t config[]) +{ + int32_t status = Pmic_checkPmicCoreHandle(handle); + + // Validate parameters + if (config == NULL) { + status = PMIC_ST_ERR_NULL_PARAM; + } + + for (uint8_t i = 0; i < numConfigs; i++) { + if (status != PMIC_ST_SUCCESS) { + break; + } + + status = PWR_setSingleSequence(handle, &config[i]); + } + + return status; +} + +int32_t Pmic_pwrGetSequenceCfgs(Pmic_CoreHandle_t *handle, uint8_t numConfigs, Pmic_PowerSequenceCfg_t config[]) +{ + int32_t status = Pmic_checkPmicCoreHandle(handle); + + // Validate parameters + if (config == NULL) { + status = PMIC_ST_ERR_NULL_PARAM; + } + + for (uint8_t i = 0; i < numConfigs; i++) { + if (status != PMIC_ST_SUCCESS) { + break; + } + + status = PWR_getSingleSequence(handle, &config[i]); + } + + return status; +}