blob: 4156dbf589ef08365c700b8a86fbfcbf13586c5c [file] [log] [blame]
/*
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_pca9422_regulator
#include <errno.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/regulator.h>
#include <zephyr/drivers/mfd/pca9422.h>
#include <zephyr/sys/linear_range.h>
#include <zephyr/sys/util.h>
#include "zephyr/logging/log.h"
LOG_MODULE_REGISTER(pca9422_regulator);
/** Register memory map. See datasheet for more details. */
/** Top level control registers */
/** @brief Top level control0 */
#define PCA9422_REG_TOP_CNTL0 0x09U
#define PCA9422_BIT_WD_TIMER GENMASK(7, 6)
#define PCA9422_BIT_SHIP_MODE BIT(4)
#define PCA9422_BIT_SHIP_MODE_POS 4U
#define PCA9422_BIT_PWR_DN_EN BIT(3)
/** General purpose registers */
/** @brief Power state */
#define PCA9422_REG_PWR_STATE 0x11U
#define PCA9422_BIT_PWR_STAT GENMASK(7, 4)
#define PCA9422_BIT_PWR_MODE GENMASK(3, 0)
/** @brief Reset behavior configuration */
#define PCA9422_REG_RESET_CTRL 0x12U
#define PCA9422_BIT_TRESTART BIT(3)
/** @brief Software reset */
#define PCA9422_REG_SW_RST 0x13U
#define PCA9422_BIT_SW_RST_KEY GENMASK(7, 0)
/** @brief Software reset */
#define PCA9422_REG_PWR_SEQ_CTRL 0x14U
#define PCA9422_BIT_ON_CFG BIT(7)
#define PCA9422_BIT_MODE_SEL_BY_PIN BIT(6)
#define PCA9422_BIT_MODE_I2C GENMASK(5, 4)
#define PCA9422_BIT_MODE_I2C_POS 4U
#define PCA9422_BIT_PSQ_TON_STEP GENMASK(3, 2)
#define PCA9422_BIT_PSQ_TOFF_STEP GENMASK(1, 0)
/** @brief System configuration1 */
#define PCA9422_REG_SYS_CFG1 0x15U
#define PCA9422_BIT_VIN_VALID_CFG BIT(7)
#define PCA9422_BIT_STANDBY_CTRL BIT(6)
#define PCA9422_BIT_STANDBY_CFG BIT(5)
#define PCA9422_BIT_DVS_CTRL2_EN BIT(2)
#define PCA9422_BIT_TFLT_SD_WAIT BIT(1)
#define PCA9422_BIT_THERM_SD_DIS BIT(0)
/** @brief System configuration2 */
#define PCA9422_REG_SYS_CFG2 0x16U
#define PCA9422_BIT_PWR_SAVE GENMASK(5, 4)
#define PCA9422_BIT_GPIO_PULLUP_CFG BIT(3)
#define PCA9422_BIT_POK_PU BIT(2)
#define PCA9422_BIT_VSYS_UVLO_SEL GENMASK(1, 0)
/** @brief Regulator status */
#define PCA9422_REG_REG_STATUS 0x17U
#define PCA9422_BIT_VOUTSW1_OK BIT(7)
#define PCA9422_BIT_VOUTSW2_OK BIT(6)
#define PCA9422_BIT_VOUTSW3_OK BIT(5)
#define PCA9422_BIT_VOUTSW4_OK BIT(4)
#define PCA9422_BIT_VOUTLDO1_OK BIT(3)
#define PCA9422_BIT_VOUTLDO2_OK BIT(2)
#define PCA9422_BIT_VOUTLDO3_OK BIT(1)
#define PCA9422_BIT_VOUTLDO4_OK BIT(0)
/** BUCK configuration registers */
/** @brief Buck1, Buck2 and Buck3 DVS control configuration */
#define PCA9422_REG_BUCK123_DVS_CFG1 0x18U
#define PCA9422_REG_BUCK123_DVS_CFG2 0x19U
#define PCA9422_BIT_B1_DVS_UP BIT(7)
#define PCA9422_BIT_B1_DVS_DN BIT(6)
#define PCA9422_BIT_B2_DVS_UP BIT(5)
#define PCA9422_BIT_B2_DVS_DN BIT(4)
#define PCA9422_BIT_MODE_PULSE BIT(3)
#define PCA9422_BIT_SMART_MODE BIT(2)
#define PCA9422_BIT_BUCK_SEL GENMASK(1, 0)
#define PCA9422_BIT_B1_DVS_CTRL GENMASK(7, 6)
#define PCA9422_BIT_B2_DVS_CTRL GENMASK(5, 4)
#define PCA9422_BIT_B3_DVS_CTRL GENMASK(3, 2)
#define PCA9422_BIT_B1_DVS_CTRL_POS 6U
#define PCA9422_BIT_B2_DVS_CTRL_POS 4U
#define PCA9422_BIT_B3_DVS_CTRL_POS 2U
#define PCA9422_BIT_B3_DVS_UP BIT(1)
#define PCA9422_BIT_B3_DVS_DN BIT(0)
/** @brief Buck control */
#define PCA9422_REG_BUCK1CTRL 0x1AU
#define PCA9422_REG_BUCK2CTRL 0x26U
#define PCA9422_REG_BUCK3CTRL 0x32U
#define PCA9422_BIT_BX_RAMP GENMASK(7, 6)
#define PCA9422_BIT_BX_LPMODE GENMASK(5, 4)
#define PCA9422_BIT_BX_AD BIT(3)
#define PCA9422_BIT_BX_AD_POS 3U
#define PCA9422_BIT_BX_FPWM BIT(2)
#define PCA9422_BIT_BX_ENMODE GENMASK(1, 0)
/** @brief Buck DVS output voltage for DVS_CTRL[2:0] */
#define PCA9422_REG_BUCK1OUT_DVS0 0x1BU
#define PCA9422_REG_BUCK1OUT_DVS1 0x1CU
#define PCA9422_REG_BUCK1OUT_DVS2 0x1DU
#define PCA9422_REG_BUCK1OUT_DVS3 0x1EU
#define PCA9422_REG_BUCK1OUT_DVS4 0x1FU
#define PCA9422_REG_BUCK1OUT_DVS5 0x20U
#define PCA9422_REG_BUCK1OUT_DVS6 0x21U
#define PCA9422_REG_BUCK1OUT_DVS7 0x22U
#define PCA9422_BIT_BUCK1OUT GENMASK(7, 0)
#define PCA9422_REG_BUCK2OUT_DVS0 0x27U
#define PCA9422_REG_BUCK2OUT_DVS1 0x28U
#define PCA9422_REG_BUCK2OUT_DVS2 0x29U
#define PCA9422_REG_BUCK2OUT_DVS3 0x2AU
#define PCA9422_REG_BUCK2OUT_DVS4 0x2BU
#define PCA9422_REG_BUCK2OUT_DVS5 0x2CU
#define PCA9422_REG_BUCK2OUT_DVS6 0x2DU
#define PCA9422_REG_BUCK2OUT_DVS7 0x2EU
#define PCA9422_BIT_BUCK2OUT GENMASK(6, 0)
#define PCA9422_REG_BUCK3OUT_DVS0 0x33U
#define PCA9422_REG_BUCK3OUT_DVS1 0x34U
#define PCA9422_REG_BUCK3OUT_DVS2 0x35U
#define PCA9422_REG_BUCK3OUT_DVS3 0x36U
#define PCA9422_REG_BUCK3OUT_DVS4 0x37U
#define PCA9422_REG_BUCK3OUT_DVS5 0x38U
#define PCA9422_REG_BUCK3OUT_DVS6 0x39U
#define PCA9422_REG_BUCK3OUT_DVS7 0x3AU
#define PCA9422_BIT_BUCK3OUT GENMASK(7, 0)
/** @brief Buck output voltage at STANDBY and DPSTANDBY modes */
#define PCA9422_REG_BUCK1OUT_STBY 0x23U
#define PCA9422_REG_BUCK2OUT_STBY 0x2FU
#define PCA9422_REG_BUCK3OUT_STBY 0x3BU
/** @brief Buck output voltage max limit */
#define PCA9422_REG_BUCK1OUT_MAX_LIMIT 0x24U
#define PCA9422_REG_BUCK2OUT_MAX_LIMIT 0x30U
#define PCA9422_REG_BUCK3OUT_MAX_LIMIT 0x3CU
/** @brief Buck output voltage in SLEEP mode */
#define PCA9422_REG_BUCK1OUT_SLEEP 0x25U
#define PCA9422_REG_BUCK2OUT_SLEEP 0x31U
#define PCA9422_REG_BUCK3OUT_SLEEP 0x3DU
/** @brief Bucks Auto FPWM configuration */
#define PCA9422_REG_LPM_FPWM 0x3EU
#define PCA9422_BIT_B3_LPM_FPWM_EN BIT(2)
#define PCA9422_BIT_B2_LPM_FPWM_EN BIT(1)
#define PCA9422_BIT_B1_LPM_FPWM_EN BIT(0)
/** LDO configuration registers */
/** @brief LDO2 and LDO3 configuration */
#define PCA9422_REG_LDO2_CFG 0x3FU
#define PCA9422_REG_LDO3_CFG 0x42U
#define PCA9422_REG_LDO23_CFG 0x45U
#define PCA9422_BIT_LX_CEL GENMASK(7, 6)
#define PCA9422_BIT_LX_LLSEL GENMASK(5, 4)
#define PCA9422_BIT_LX_LPMODE GENMASK(3, 2)
#define PCA9422_BIT_LX_ENMODE GENMASK(1, 0)
#define PCA9422_BIT_LDO3_MODE BIT(7)
#define PCA9422_BIT_LDO2_MODE BIT(6)
#define PCA9422_BIT_L2_INL2_VSEL BIT(5)
#define PCA9422_BIT_L3_INL3_VSEL BIT(4)
/** @brief LDO4 configuration */
#define PCA9422_REG_LDO4_CFG 0x46U
#define PCA9422_BIT_L4_AD BIT(4)
#define PCA9422_BIT_L4_AD_POS 4U
#define PCA9422_BIT_L4_ENMODE GENMASK(1, 0)
/** @brief LDO1 configuration */
#define PCA9422_REG_LDO1_CFG1 0x49U
#define PCA9422_REG_LDO1_CFG2 0x4AU
#define PCA9422_BIT_L1_AD BIT(7)
#define PCA9422_BIT_L1_AD_POS 7U
#define PCA9422_BIT_L1_OUT GENMASK(6, 0)
#define PCA9422_BIT_L1_ENMODE BIT(0)
/** @brief LDO out voltage */
#define PCA9422_REG_LDO2_OUT 0x40U
#define PCA9422_REG_LDO3_OUT 0x43U
#define PCA9422_REG_LDO4_OUT 0x47U
#define PCA9422_REG_LDO2_OUT_STBY 0x41U
#define PCA9422_REG_LDO3_OUT_STBY 0x44U
#define PCA9422_REG_LDO4_OUT_STBY 0x48U
#define PCA9422_REG_LDO2_OUT_SLEEP 0x4BU
#define PCA9422_REG_LDO3_OUT_SLEEP 0x4CU
#define PCA9422_REG_LDO4_OUT_SLEEP 0x4DU
#define PCA9422_BIT_L2_AD BIT(7)
#define PCA9422_BIT_L2_AD_POS 7U
#define PCA9422_BIT_L2_INL2_MDET BIT(6)
#define PCA9422_BIT_L2_OUT GENMASK(5, 0)
#define PCA9422_BIT_L3_AD BIT(7)
#define PCA9422_BIT_L3_AD_POS 7U
#define PCA9422_BIT_L3_INL3_MDET BIT(6)
#define PCA9422_BIT_L3_OUT GENMASK(5, 0)
#define PCA9422_BIT_L4_OUT GENMASK(6, 0)
#define PCA9422_BIT_L2_OUT_STBY GENMASK(5, 0)
#define PCA9422_BIT_L3_OUT_STBY GENMASK(5, 0)
#define PCA9422_BIT_L4_OUT_STBY GENMASK(6, 0)
#define PCA9422_BIT_L2_OUT_SLEEP GENMASK(5, 0)
#define PCA9422_BIT_L3_OUT_SLEEP GENMASK(5, 0)
#define PCA9422_BIT_L4_OUT_SLEEP GENMASK(6, 0)
/** BUCK-BOOST configuration register */
/** @brief Buck-Boost configuration */
#define PCA9422_REG_SW4_BB_CFG1 0x4EU
#define PCA9422_REG_SW4_BB_CFG2 0x4FU
#define PCA9422_REG_SW4_BB_CFG3 0x50U
#define PCA9422_REG_SW4_BB_CFG4 0x51U
#define PCA9422_REG_SW4_BB_MAX_LIMIT 0x52U
#define PCA9422_REG_SW4_BB_MIN_LIMIT 0x53U
#define PCA9422_REG_SW4_BB_VOUT_SLEEP 0x54U
#define PCA9422_BIT_BB_FPWM BIT(3)
#define PCA9422_BIT_BB_FAULT_OC_CTRL BIT(2)
#define PCA9422_BIT_BB_SOFT_STDN BIT(1)
#define PCA9422_BIT_BB_DIS BIT(0)
#define PCA9422_BIT_BB_DIS_POS 0U
#define PCA9422_BIT_BB_ENABLE BIT(6)
#define PCA9422_BIT_BB_MODESEL GENMASK(5, 4)
#define PCA9422_BIT_BB_ENMODE GENMASK(3, 2)
#define PCA9422_BIT_BB_LPMODE GENMASK(1, 0)
#define PCA9422_BIT_BB_VOUT GENMASK(7, 0)
#define PCA9422_BIT_BB_VOUT_STBY GENMASK(7, 0)
#define PCA9422_BIT_BB_MAX_LMT GENMASK(7, 0)
#define PCA9422_BIT_BB_MIN_LMT GENMASK(7, 0)
#define PCA9422_BIT_BB_VOUT_SLEEP GENMASK(7, 0)
/** @brief Regulator enable register */
#define PCA9422_REG_REGULATOR_EN 0x59U
#define PCA9422_BIT_B1_ENABLE BIT(5)
#define PCA9422_BIT_B2_ENABLE BIT(4)
#define PCA9422_BIT_B3_ENABLE BIT(3)
#define PCA9422_BIT_L2_ENABLE BIT(2)
#define PCA9422_BIT_L3_ENABLE BIT(1)
#define PCA9422_BIT_L4_ENABLE BIT(0)
/** @brief Output voltage configuration unlock key register */
#define PCA9422_REG_REG_LOCK 0x80U
#define PCA9422_UNLOCK_KEY 0x5CU
#define PCA9422_LOCK_KEY 0x00U
/** @brief Not used register */
#define PCA9422_REG_NOT_USED 0xFFU
#define PCA9422_BIT_NOT_USED 0xFFU
/** @brief Buck low power mode */
#define PCA9422_BUCK_LPM_NORMAL 0x00U
#define PCA9422_BUCK_LPM_STANDBY 0x01U
#define PCA9422_BUCK_LPM_DPSTANDBY 0x02U
#define PCA9422_BUCK_LPM_FORCED_LP 0x03U
/*
* @brief Mode control selection value.
* When this bit is set, the external PMIC pins STBY_MODE1 and SLEEP_MODE0
* can be used to select pca9422 mode in RUN state.
*/
#define PCA9422_MODE_SEL_BY_PIN 0x40U
/** @brief Number of power modes */
#define PCA9422_NUM_MODES 4U
/** @brief Power modes */
enum pca9422_power_mode {
PCA9422_ACTIVE_MODE,
PCA9422_SLEEP_MODE,
PCA9422_STANDBY_MODE,
PCA9422_DPSTANDBY_MODE,
};
struct regulator_pca9422_desc {
uint8_t enable_reg;
uint8_t enable_mask;
uint8_t enable_val;
const uint8_t *vsel_reg;
uint8_t vsel_mask;
uint8_t ad_reg;
uint8_t ad_mask;
uint8_t ad_pos;
uint8_t enmode_reg;
uint8_t enmode_mask;
uint8_t lpmode_reg;
uint8_t lpmode_mask;
uint8_t num_ranges;
const struct linear_range *ranges;
};
struct regulator_pca9422_common_config {
const struct device *mfd;
bool modesel_by_pins;
uint8_t vsys_uvlo_sel_mv;
};
struct regulator_pca9422_common_data {
uint8_t dvs_state;
};
struct regulator_pca9422_config {
struct regulator_common_config common;
const struct device *mfd;
const struct device *parent;
const struct regulator_pca9422_desc *desc;
uint8_t low_power_mode;
uint8_t enable_mode;
int32_t modes_uv[3];
};
struct regulator_pca9422_data {
struct regulator_common_data data;
};
static const struct linear_range buck1_ranges[] = {
LINEAR_RANGE_INIT(400000, 6250U, 0x0U, 0xFCU),
LINEAR_RANGE_INIT(1975000, 0U, 0xFDU, 0xFFU),
};
static const struct linear_range buck2_ranges[] = {
LINEAR_RANGE_INIT(400000, 25000U, 0x0U, 0x78U),
LINEAR_RANGE_INIT(3400000, 0U, 0x79U, 0x7FU),
};
static const struct linear_range buck3_ranges[] = {
LINEAR_RANGE_INIT(400000, 6250U, 0x0U, 0xFCU),
LINEAR_RANGE_INIT(1975000, 0U, 0xFDU, 0xFFU),
};
static const struct linear_range ldo1_ranges[] = {
LINEAR_RANGE_INIT(800000, 25000U, 0x0U, 0x58U),
LINEAR_RANGE_INIT(3000000, 0U, 0x59U, 0x7FU),
};
static const struct linear_range ldo2_ranges[] = {
LINEAR_RANGE_INIT(500000, 25000U, 0x0U, 0x3AU),
LINEAR_RANGE_INIT(1950000, 0U, 0x3BU, 0x3FU),
};
static const struct linear_range ldo3_ranges[] = {
LINEAR_RANGE_INIT(500000, 25000U, 0x0U, 0x3AU),
LINEAR_RANGE_INIT(1950000, 0U, 0x3BU, 0x3FU),
};
static const struct linear_range ldo4_ranges[] = {
LINEAR_RANGE_INIT(800000, 25000U, 0x0U, 0x64U),
LINEAR_RANGE_INIT(3300000, 0U, 0x65U, 0x7FU),
};
static const struct linear_range buckboost_ranges[] = {
LINEAR_RANGE_INIT(1800000, 25000U, 0x0U, 0x80U),
LINEAR_RANGE_INIT(5000000, 0U, 0x81U, 0xFFU),
};
static const uint8_t buck1_vsel_reg[3] = {PCA9422_REG_BUCK1OUT_DVS0, PCA9422_REG_BUCK1OUT_SLEEP,
PCA9422_REG_BUCK1OUT_STBY};
static const uint8_t buck2_vsel_reg[3] = {PCA9422_REG_BUCK2OUT_DVS0, PCA9422_REG_BUCK2OUT_SLEEP,
PCA9422_REG_BUCK2OUT_STBY};
static const uint8_t buck3_vsel_reg[3] = {PCA9422_REG_BUCK3OUT_DVS0, PCA9422_REG_BUCK3OUT_SLEEP,
PCA9422_REG_BUCK3OUT_STBY};
static const uint8_t ldo1_vsel_reg[3] = {PCA9422_REG_LDO1_CFG1, PCA9422_REG_LDO1_CFG1,
PCA9422_REG_LDO1_CFG1};
static const uint8_t ldo2_vsel_reg[3] = {PCA9422_REG_LDO2_OUT, PCA9422_REG_LDO2_OUT_SLEEP,
PCA9422_REG_LDO2_OUT_STBY};
static const uint8_t ldo3_vsel_reg[3] = {PCA9422_REG_LDO3_OUT, PCA9422_REG_LDO3_OUT_SLEEP,
PCA9422_REG_LDO3_OUT_STBY};
static const uint8_t ldo4_vsel_reg[3] = {PCA9422_REG_LDO4_OUT, PCA9422_REG_LDO4_OUT_SLEEP,
PCA9422_REG_LDO4_OUT_STBY};
static const uint8_t buckboost_vsel_reg[3] = {
PCA9422_REG_SW4_BB_CFG3, PCA9422_REG_SW4_BB_VOUT_SLEEP, PCA9422_REG_SW4_BB_CFG4};
static const struct regulator_pca9422_desc buck1_desc = {
.enable_reg = PCA9422_REG_REGULATOR_EN,
.enable_mask = PCA9422_BIT_B1_ENABLE,
.enable_val = PCA9422_BIT_B1_ENABLE,
.vsel_reg = buck1_vsel_reg,
.vsel_mask = PCA9422_BIT_BUCK1OUT,
.ad_reg = PCA9422_REG_BUCK1CTRL,
.ad_mask = PCA9422_BIT_BX_AD,
.ad_pos = PCA9422_BIT_BX_AD_POS,
.enmode_reg = PCA9422_REG_BUCK1CTRL,
.enmode_mask = PCA9422_BIT_BX_ENMODE,
.lpmode_reg = PCA9422_REG_BUCK1CTRL,
.lpmode_mask = PCA9422_BIT_BX_LPMODE,
.ranges = buck1_ranges,
.num_ranges = ARRAY_SIZE(buck1_ranges),
};
static const struct regulator_pca9422_desc buck2_desc = {
.enable_reg = PCA9422_REG_REGULATOR_EN,
.enable_mask = PCA9422_BIT_B2_ENABLE,
.enable_val = PCA9422_BIT_B2_ENABLE,
.vsel_reg = buck2_vsel_reg,
.vsel_mask = PCA9422_BIT_BUCK2OUT,
.ad_reg = PCA9422_REG_BUCK2CTRL,
.ad_mask = PCA9422_BIT_BX_AD,
.ad_pos = PCA9422_BIT_BX_AD_POS,
.enmode_reg = PCA9422_REG_BUCK2CTRL,
.enmode_mask = PCA9422_BIT_BX_ENMODE,
.lpmode_reg = PCA9422_REG_BUCK2CTRL,
.lpmode_mask = PCA9422_BIT_BX_LPMODE,
.ranges = buck2_ranges,
.num_ranges = ARRAY_SIZE(buck2_ranges),
};
static const struct regulator_pca9422_desc buck3_desc = {
.enable_reg = PCA9422_REG_REGULATOR_EN,
.enable_mask = PCA9422_BIT_B3_ENABLE,
.enable_val = PCA9422_BIT_B3_ENABLE,
.vsel_reg = buck3_vsel_reg,
.vsel_mask = PCA9422_BIT_BUCK1OUT,
.ad_reg = PCA9422_REG_BUCK3CTRL,
.ad_mask = PCA9422_BIT_BX_AD,
.ad_pos = PCA9422_BIT_BX_AD_POS,
.enmode_reg = PCA9422_REG_BUCK3CTRL,
.enmode_mask = PCA9422_BIT_BX_ENMODE,
.lpmode_reg = PCA9422_REG_BUCK3CTRL,
.lpmode_mask = PCA9422_BIT_BX_LPMODE,
.ranges = buck3_ranges,
.num_ranges = ARRAY_SIZE(buck3_ranges),
};
static const struct regulator_pca9422_desc ldo1_desc = {
.enable_reg = PCA9422_REG_LDO1_CFG2,
.enable_mask = PCA9422_BIT_L1_ENMODE,
.enable_val = PCA9422_BIT_L1_ENMODE,
.vsel_reg = ldo1_vsel_reg,
.vsel_mask = PCA9422_BIT_L1_OUT,
.ad_reg = PCA9422_REG_LDO1_CFG1,
.ad_mask = PCA9422_BIT_L1_AD,
.ad_pos = PCA9422_BIT_L1_AD_POS,
.enmode_reg = PCA9422_REG_NOT_USED,
.enmode_mask = PCA9422_BIT_NOT_USED,
.lpmode_reg = PCA9422_REG_NOT_USED,
.lpmode_mask = PCA9422_BIT_NOT_USED,
.ranges = ldo1_ranges,
.num_ranges = ARRAY_SIZE(ldo1_ranges),
};
static const struct regulator_pca9422_desc ldo2_desc = {
.enable_reg = PCA9422_REG_REGULATOR_EN,
.enable_mask = PCA9422_BIT_L2_ENABLE,
.enable_val = PCA9422_BIT_L2_ENABLE,
.vsel_reg = ldo2_vsel_reg,
.vsel_mask = PCA9422_BIT_L2_OUT,
.ad_reg = PCA9422_REG_LDO2_OUT,
.ad_mask = PCA9422_BIT_L2_AD,
.ad_pos = PCA9422_BIT_L2_AD_POS,
.enmode_reg = PCA9422_REG_LDO2_CFG,
.enmode_mask = PCA9422_BIT_LX_ENMODE,
.lpmode_reg = PCA9422_REG_LDO2_CFG,
.lpmode_mask = PCA9422_BIT_LX_LPMODE,
.ranges = ldo2_ranges,
.num_ranges = ARRAY_SIZE(ldo2_ranges),
};
static const struct regulator_pca9422_desc ldo3_desc = {
.enable_reg = PCA9422_REG_REGULATOR_EN,
.enable_mask = PCA9422_BIT_L3_ENABLE,
.enable_val = PCA9422_BIT_L3_ENABLE,
.vsel_reg = ldo3_vsel_reg,
.vsel_mask = PCA9422_BIT_L3_OUT,
.ad_reg = PCA9422_REG_LDO3_OUT,
.ad_mask = PCA9422_BIT_L3_AD,
.ad_pos = PCA9422_BIT_L3_AD_POS,
.enmode_reg = PCA9422_REG_LDO3_CFG,
.enmode_mask = PCA9422_BIT_LX_ENMODE,
.lpmode_reg = PCA9422_REG_LDO3_CFG,
.lpmode_mask = PCA9422_BIT_LX_LPMODE,
.ranges = ldo3_ranges,
.num_ranges = ARRAY_SIZE(ldo3_ranges),
};
static const struct regulator_pca9422_desc ldo4_desc = {
.enable_reg = PCA9422_REG_REGULATOR_EN,
.enable_mask = PCA9422_BIT_L4_ENABLE,
.enable_val = PCA9422_BIT_L4_ENABLE,
.vsel_reg = ldo4_vsel_reg,
.vsel_mask = PCA9422_BIT_L4_OUT,
.ad_reg = PCA9422_REG_LDO4_CFG,
.ad_mask = PCA9422_BIT_L4_AD,
.ad_pos = PCA9422_BIT_L4_AD_POS,
.enmode_reg = PCA9422_REG_LDO4_CFG,
.enmode_mask = PCA9422_BIT_LX_ENMODE,
.lpmode_reg = PCA9422_REG_NOT_USED,
.lpmode_mask = PCA9422_BIT_NOT_USED,
.ranges = ldo4_ranges,
.num_ranges = ARRAY_SIZE(ldo4_ranges),
};
static const struct regulator_pca9422_desc buckboost_desc = {
.enable_reg = PCA9422_REG_SW4_BB_CFG2,
.enable_mask = PCA9422_BIT_BB_ENABLE,
.enable_val = PCA9422_BIT_BB_ENABLE,
.vsel_reg = buckboost_vsel_reg,
.vsel_mask = PCA9422_BIT_BB_VOUT,
.ad_reg = PCA9422_REG_SW4_BB_CFG1,
.ad_mask = PCA9422_BIT_BB_DIS,
.ad_pos = PCA9422_BIT_BB_DIS_POS,
.enmode_reg = PCA9422_REG_SW4_BB_CFG2,
.enmode_mask = PCA9422_BIT_BB_ENMODE,
.lpmode_reg = PCA9422_REG_SW4_BB_CFG2,
.lpmode_mask = PCA9422_BIT_BB_LPMODE,
.ranges = buckboost_ranges,
.num_ranges = ARRAY_SIZE(buckboost_ranges),
};
static unsigned int regulator_pca9422_count_voltages(const struct device *dev)
{
const struct regulator_pca9422_config *config = dev->config;
return linear_range_group_values_count(config->desc->ranges, config->desc->num_ranges);
}
static int regulator_pca9422_list_voltage(const struct device *dev, unsigned int idx,
int32_t *volt_uv)
{
const struct regulator_pca9422_config *config = dev->config;
return linear_range_group_get_value(config->desc->ranges, config->desc->num_ranges, idx,
volt_uv);
}
static int regulator_pca9422_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv)
{
const struct regulator_pca9422_config *config = dev->config;
struct regulator_pca9422_common_data *cdata = config->parent->data;
uint16_t idx;
int ret;
uint8_t mode_state;
ret = linear_range_group_get_win_index(config->desc->ranges, config->desc->num_ranges,
min_uv, max_uv, &idx);
if (ret == -EINVAL) {
return ret;
}
if (cdata->dvs_state == PCA9422_DPSTANDBY_MODE) {
/* DPSTANDBY mode voltage has same register as STANDBY mode */
mode_state = PCA9422_STANDBY_MODE;
} else {
mode_state = cdata->dvs_state;
}
return mfd_pca9422_reg_update_byte(config->mfd, config->desc->vsel_reg[mode_state],
config->desc->vsel_mask, (uint8_t)idx);
}
static int regulator_pca9422_get_voltage(const struct device *dev, int32_t *volt_uv)
{
const struct regulator_pca9422_config *config = dev->config;
struct regulator_pca9422_common_data *cdata = config->parent->data;
int ret;
uint8_t raw_val;
uint8_t mode_state;
if (cdata->dvs_state == PCA9422_DPSTANDBY_MODE) {
/* DPSTANDBY mode voltage has same register as STANDBY mode */
mode_state = PCA9422_STANDBY_MODE;
} else {
mode_state = cdata->dvs_state;
}
ret = mfd_pca9422_reg_read_byte(config->mfd, config->desc->vsel_reg[mode_state], &raw_val);
if (ret < 0) {
return ret;
}
raw_val = (raw_val & config->desc->vsel_mask);
return linear_range_group_get_value(config->desc->ranges, config->desc->num_ranges, raw_val,
volt_uv);
}
static int regulator_pca9422_set_active_discharge(const struct device *dev, bool active_discharge)
{
const struct regulator_pca9422_config *config = dev->config;
uint8_t dis_val, adsg_val;
adsg_val = (active_discharge == true) ? 1U : 0U;
dis_val = (adsg_val << config->desc->ad_pos);
return mfd_pca9422_reg_update_byte(config->mfd, config->desc->ad_reg, config->desc->ad_mask,
dis_val);
}
static int regulator_pca9422_get_active_discharge(const struct device *dev, bool *active_discharge)
{
const struct regulator_pca9422_config *config = dev->config;
uint8_t raw_reg;
int ret;
ret = mfd_pca9422_reg_read_byte(config->mfd, config->desc->ad_reg, &raw_reg);
if (ret < 0) {
return ret;
}
*active_discharge = ((raw_reg & config->desc->ad_mask) >> config->desc->ad_pos);
return 0;
}
static int regulator_pca9422_enable(const struct device *dev)
{
const struct regulator_pca9422_config *config = dev->config;
uint8_t en_val;
en_val = config->desc->enable_val;
return mfd_pca9422_reg_update_byte(config->mfd, config->desc->enable_reg,
config->desc->enable_mask, en_val);
}
static int regulator_pca9422_disable(const struct device *dev)
{
const struct regulator_pca9422_config *config = dev->config;
uint8_t dis_val;
dis_val = 0;
return mfd_pca9422_reg_update_byte(config->mfd, config->desc->enable_reg,
config->desc->enable_mask, dis_val);
}
static DEVICE_API(regulator, api) = {
.enable = regulator_pca9422_enable,
.disable = regulator_pca9422_disable,
.count_voltages = regulator_pca9422_count_voltages,
.list_voltage = regulator_pca9422_list_voltage,
.set_voltage = regulator_pca9422_set_voltage,
.get_voltage = regulator_pca9422_get_voltage,
.set_active_discharge = regulator_pca9422_set_active_discharge,
.get_active_discharge = regulator_pca9422_get_active_discharge,
};
static int regulator_pca9422_init(const struct device *dev)
{
const struct regulator_pca9422_config *config = dev->config;
uint16_t idx;
int ret;
if (!device_is_ready(config->mfd)) {
return -ENODEV;
}
regulator_common_data_init(dev);
/* Configure power mode voltages */
for (uint8_t i = 0; i < ARRAY_SIZE(config->modes_uv); i++) {
/* program mode voltage */
ret = linear_range_group_get_win_index(
config->desc->ranges, config->desc->num_ranges, config->modes_uv[i],
config->modes_uv[i], &idx);
if (ret == -EINVAL) {
return ret;
}
ret = mfd_pca9422_reg_update_byte(config->mfd, config->desc->vsel_reg[i],
config->desc->vsel_mask, (uint8_t)idx);
if (ret < 0) {
return ret;
}
}
/* Configure enable mode */
if (config->desc->enmode_reg != PCA9422_REG_NOT_USED) {
ret = mfd_pca9422_reg_update_byte(config->mfd, config->desc->enmode_reg,
config->desc->enmode_mask, config->enable_mode);
} else {
/* LDO1 is always ON */
ret = 0;
}
if (ret < 0) {
return ret;
}
/* Configure low power mode */
if (config->desc->lpmode_reg != PCA9422_REG_NOT_USED) {
ret = mfd_pca9422_reg_update_byte(config->mfd, config->desc->lpmode_reg,
config->desc->lpmode_mask,
config->low_power_mode);
} else {
/* LDO1 and LDO4 does not support LP mode */
ret = 0;
}
if (ret < 0) {
return ret;
}
return regulator_common_init(dev, false);
}
int regulator_pca9422_dvs_state_set(const struct device *dev, regulator_dvs_state_t state)
{
const struct regulator_pca9422_common_config *cconfig = dev->config;
struct regulator_pca9422_common_data *cdata = dev->data;
int ret;
/* PCA9422 DVS state means power state */
if (state >= PCA9422_NUM_MODES) {
return -ENOTSUP;
}
if (cconfig->modesel_by_pins) {
/*
* The user cannot set DVS state via this API,
* but they may want to query/set voltages for another mode.
* In this case, STANDBY_MODE1 and SLEEP_MODE0 pin set
* DVS state(power mode).
* Return -EPERM to indicate change failed, but change the
* dvs_state variable so the user can access the alternative
* dvs mode settings.
*/
cdata->dvs_state = state;
return -EPERM;
}
ret = mfd_pca9422_reg_update_byte(cconfig->mfd, PCA9422_REG_PWR_SEQ_CTRL,
PCA9422_BIT_MODE_I2C, state << PCA9422_BIT_MODE_I2C_POS);
if (ret < 0) {
return ret;
}
/* Save new DVS state */
cdata->dvs_state = state;
return 0;
}
int regulator_pca9422_ship_mode(const struct device *dev)
{
const struct regulator_pca9422_common_config *cconfig = dev->config;
return mfd_pca9422_reg_update_byte(cconfig->mfd, PCA9422_REG_TOP_CNTL0,
PCA9422_BIT_SHIP_MODE, PCA9422_BIT_SHIP_MODE);
}
static DEVICE_API(regulator_parent, parent_api) = {
.dvs_state_set = regulator_pca9422_dvs_state_set,
.ship_mode = regulator_pca9422_ship_mode,
};
static int regulator_pca9422_common_init(const struct device *dev)
{
const struct regulator_pca9422_common_config *cconfig = dev->config;
struct regulator_pca9422_common_data *cdata = dev->data;
int ret;
uint8_t reg_val;
if (!device_is_ready(cconfig->mfd)) {
return -ENODEV;
}
/* Set the mode selection method */
reg_val = (cconfig->modesel_by_pins == true) ? PCA9422_MODE_SEL_BY_PIN : 0;
ret = mfd_pca9422_reg_update_byte(cconfig->mfd, PCA9422_REG_PWR_SEQ_CTRL,
PCA9422_BIT_MODE_SEL_BY_PIN, reg_val);
if (ret < 0) {
return ret;
}
/* Configure VSYS UVLO */
reg_val = cconfig->vsys_uvlo_sel_mv;
ret = mfd_pca9422_reg_update_byte(cconfig->mfd, PCA9422_REG_SYS_CFG2,
PCA9422_BIT_VSYS_UVLO_SEL, reg_val);
if (ret < 0) {
return ret;
}
/* Set DVS control method. Refer to datasheet.
* Fix DVS control to 01b, BUCKxOUT_DVS0 Register through I2C in ACTIVE mode,
* and the voltage set to BUCKxOUT_SLEEP when in SLEEP mode
*/
reg_val = (1U << PCA9422_BIT_B1_DVS_CTRL_POS) | (1U << PCA9422_BIT_B2_DVS_CTRL_POS) |
(1U << PCA9422_BIT_B3_DVS_CTRL_POS);
ret = mfd_pca9422_reg_update_byte(cconfig->mfd, PCA9422_REG_BUCK123_DVS_CFG2,
PCA9422_BIT_B1_DVS_CTRL | PCA9422_BIT_B2_DVS_CTRL |
PCA9422_BIT_B3_DVS_CTRL,
reg_val);
if (ret < 0) {
return ret;
}
cdata->dvs_state = PCA9422_ACTIVE_MODE;
/* Unlock regulator output voltage configuration */
reg_val = PCA9422_UNLOCK_KEY;
return mfd_pca9422_reg_write_byte(cconfig->mfd, PCA9422_REG_REG_LOCK, reg_val);
}
#define REGULATOR_PCA9422_DEFINE(node_id, id, name) \
static struct regulator_pca9422_data data_##id; \
\
static const struct regulator_pca9422_config config_##id = { \
.common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \
.mfd = DEVICE_DT_GET(DT_GPARENT(node_id)), \
.parent = DEVICE_DT_GET(DT_PARENT(node_id)), \
.low_power_mode = DT_ENUM_IDX(node_id, low_power_mode), \
.enable_mode = DT_ENUM_IDX(node_id, enable_mode), \
.modes_uv = \
{ \
DT_PROP_OR(node_id, nxp_active_microvolt, -1), \
DT_PROP_OR(node_id, nxp_sleep_microvolt, -1), \
DT_PROP_OR(node_id, nxp_standby_microvolt, -1), \
}, \
.desc = &name##_desc, \
}; \
\
DEVICE_DT_DEFINE(node_id, regulator_pca9422_init, NULL, &data_##id, &config_##id, \
POST_KERNEL, CONFIG_REGULATOR_PCA9422_INIT_PRIORITY, &api);
#define REGULATOR_PCA9422_DEFINE_COND(inst, child) \
COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \
(REGULATOR_PCA9422_DEFINE(DT_INST_CHILD(inst, child), \
child ## inst, child)), \
())
#define REGULATOR_PCA9422_DEFINE_ALL(inst) \
static const struct regulator_pca9422_common_config config_##inst = { \
.mfd = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
.modesel_by_pins = DT_INST_PROP(inst, nxp_enable_modesel_pins), \
.vsys_uvlo_sel_mv = DT_INST_ENUM_IDX(inst, nxp_vsys_uvlo_sel_millivolt), \
}; \
\
static struct regulator_pca9422_common_data data_##inst; \
\
DEVICE_DT_INST_DEFINE(inst, regulator_pca9422_common_init, NULL, &data_##inst, \
&config_##inst, POST_KERNEL, \
CONFIG_REGULATOR_PCA9422_COMMON_INIT_PRIORITY, &parent_api); \
\
REGULATOR_PCA9422_DEFINE_COND(inst, buck1) \
REGULATOR_PCA9422_DEFINE_COND(inst, buck2) \
REGULATOR_PCA9422_DEFINE_COND(inst, buck3) \
REGULATOR_PCA9422_DEFINE_COND(inst, ldo1) \
REGULATOR_PCA9422_DEFINE_COND(inst, ldo2) \
REGULATOR_PCA9422_DEFINE_COND(inst, ldo3) \
REGULATOR_PCA9422_DEFINE_COND(inst, ldo4) \
REGULATOR_PCA9422_DEFINE_COND(inst, buckboost)
DT_INST_FOREACH_STATUS_OKAY(REGULATOR_PCA9422_DEFINE_ALL)