drivers: regulator: npm2100: Add driver for npm2100 pmic
Add regulator driver for npm2100 pmic. This pmic has one boost and one ldo regulator. Signed-off-by: Audun Korneliussen <audun.korneliussen@nordicsemi.no>
This commit is contained in:
parent
7fccb646cd
commit
f4443617d8
7 changed files with 965 additions and 0 deletions
|
@ -14,6 +14,7 @@ zephyr_library_sources_ifdef(CONFIG_REGULATOR_GPIO regulator_gpio.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_MAX20335 regulator_max20335.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM1100 regulator_npm1100.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM1300 regulator_npm1300.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM2100 regulator_npm2100.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_NPM6001 regulator_npm6001.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_PCA9420 regulator_pca9420.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_REGULATOR_SHELL regulator_shell.c)
|
||||
|
|
|
@ -36,6 +36,7 @@ source "drivers/regulator/Kconfig.gpio"
|
|||
source "drivers/regulator/Kconfig.max20335"
|
||||
source "drivers/regulator/Kconfig.npm1100"
|
||||
source "drivers/regulator/Kconfig.npm1300"
|
||||
source "drivers/regulator/Kconfig.npm2100"
|
||||
source "drivers/regulator/Kconfig.npm6001"
|
||||
source "drivers/regulator/Kconfig.pca9420"
|
||||
source "drivers/regulator/Kconfig.rpi_pico"
|
||||
|
|
29
drivers/regulator/Kconfig.npm2100
Normal file
29
drivers/regulator/Kconfig.npm2100
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config REGULATOR_NPM2100
|
||||
bool "nPM2100 PMIC regulator driver"
|
||||
default y
|
||||
depends on DT_HAS_NORDIC_NPM2100_REGULATOR_ENABLED
|
||||
select I2C
|
||||
select MFD
|
||||
help
|
||||
Enable the Nordic nPM2100 PMIC regulator driver
|
||||
|
||||
if REGULATOR_NPM2100
|
||||
|
||||
config REGULATOR_NPM2100_COMMON_INIT_PRIORITY
|
||||
int "nPM2100 regulator driver init priority (common part)"
|
||||
default 85
|
||||
help
|
||||
Init priority for the Nordic nPM2100 regulator driver (common part).
|
||||
It must be greater than I2C init priority.
|
||||
|
||||
config REGULATOR_NPM2100_INIT_PRIORITY
|
||||
int "nPM2100 regulator driver init priority"
|
||||
default 86
|
||||
help
|
||||
Init priority for the Nordic nPM2100 regulator driver. It must be
|
||||
greater than REGULATOR_NPM2100_COMMON_INIT_PRIORITY.
|
||||
|
||||
endif
|
791
drivers/regulator/regulator_npm2100.c
Normal file
791
drivers/regulator/regulator_npm2100.c
Normal file
|
@ -0,0 +1,791 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nordic_npm2100_regulator
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/regulator.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/dt-bindings/regulator/npm2100.h>
|
||||
#include <zephyr/sys/linear_range.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
enum npm2100_sources {
|
||||
NPM2100_SOURCE_BOOST,
|
||||
NPM2100_SOURCE_LDOSW,
|
||||
};
|
||||
|
||||
#define BOOST_VOUT 0x22U
|
||||
#define BOOST_VOUTSEL 0x23U
|
||||
#define BOOST_OPER 0x24U
|
||||
#define BOOST_LIMIT 0x26U
|
||||
#define BOOST_GPIO 0x28U
|
||||
#define BOOST_PIN 0x29U
|
||||
#define BOOST_CTRLSET 0x2AU
|
||||
#define BOOST_CTRLCLR 0x2BU
|
||||
#define BOOST_IBATLIM 0x2DU
|
||||
#define BOOST_VBATMINL 0x2FU
|
||||
#define BOOST_VBATMINH 0x30U
|
||||
#define BOOST_VOUTMIN 0x31U
|
||||
#define BOOST_VOUTWRN 0x32U
|
||||
#define BOOST_VOUTDPS 0x33U
|
||||
#define BOOST_STATUS0 0x34U
|
||||
#define BOOST_STATUS1 0x35U
|
||||
#define BOOST_VSET0 0x36U
|
||||
#define BOOST_VSET1 0x37U
|
||||
|
||||
#define LDOSW_VOUT 0x68U
|
||||
#define LDOSW_ENABLE 0x69U
|
||||
#define LDOSW_SEL 0x6AU
|
||||
#define LDOSW_GPIO 0x6BU
|
||||
#define LDOSW_STATUS 0x6EU
|
||||
#define LDOSW_PRGOCP 0x6FU
|
||||
|
||||
#define SHIP_TASK_SHIP 0xC0U
|
||||
|
||||
#define RESET_ALTCONFIG 0xD6U
|
||||
#define RESET_WRITESTICKY 0xDBU
|
||||
#define RESET_STROBESTICKY 0xDCU
|
||||
|
||||
#define BOOST_OPER_MODE_MASK 0x07U
|
||||
#define BOOST_OPER_MODE_AUTO 0x00U
|
||||
#define BOOST_OPER_MODE_HP 0x01U
|
||||
#define BOOST_OPER_MODE_LP 0x02U
|
||||
#define BOOST_OPER_MODE_PASS 0x03U
|
||||
#define BOOST_OPER_MODE_NOHP 0x04U
|
||||
#define BOOST_OPER_DPS_MASK 0x18U
|
||||
#define BOOST_OPER_DPS_DISABLE 0x00U
|
||||
#define BOOST_OPER_DPS_ALLOW 0x01U
|
||||
#define BOOST_OPER_DPS_ALLOWLP 0x02U
|
||||
#define BOOST_OPER_DPSTIMER_MASK 0x60U
|
||||
|
||||
#define BOOST_PIN_FORCE_HP 0x00U
|
||||
#define BOOST_PIN_FORCE_LP 0x01U
|
||||
#define BOOST_PIN_FORCE_PASS 0x02U
|
||||
#define BOOST_PIN_FORCE_NOHP 0x03U
|
||||
|
||||
#define BOOST_STATUS0_MODE_MASK 0x07U
|
||||
#define BOOST_STATUS0_MODE_HP 0x00U
|
||||
#define BOOST_STATUS0_MODE_LP 0x01U
|
||||
#define BOOST_STATUS0_MODE_ULP 0x02U
|
||||
#define BOOST_STATUS0_MODE_PT 0x03U
|
||||
#define BOOST_STATUS0_MODE_DPS 0x04U
|
||||
|
||||
#define BOOST_STATUS1_VSET_MASK 0x40U
|
||||
|
||||
#define LDOSW_SEL_OPER_MASK 0x06U
|
||||
#define LDOSW_SEL_OPER_AUTO 0x00U
|
||||
#define LDOSW_SEL_OPER_ULP 0x02U
|
||||
#define LDOSW_SEL_OPER_HP 0x04U
|
||||
#define LDOSW_SEL_OPER_PIN 0x06U
|
||||
|
||||
#define LDOSW_GPIO_PIN_MASK 0x07U
|
||||
#define LDOSW_GPIO_PINACT_MASK 0x18U
|
||||
#define LDOSW_GPIO_PINACT_HP 0x00U
|
||||
#define LDOSW_GPIO_PINACT_ULP 0x08U
|
||||
#define LDOSW_GPIO_PININACT_OFF 0x00U
|
||||
#define LDOSW_GPIO_PININACT_ULP 0x10U
|
||||
|
||||
#define LDOSW_STATUS_LDO 0x01U
|
||||
#define LDOSW_STATUS_SW 0x02U
|
||||
#define LDOSW_STATUS_HP 0x04U
|
||||
#define LDOSW_STATUS_ULP 0x08U
|
||||
#define LDOSW_STATUS_OCP 0x10U
|
||||
|
||||
#define RESET_ALTCONFIG_LDOSW_OFF 0x01U
|
||||
|
||||
struct regulator_npm2100_pconfig {
|
||||
struct i2c_dt_spec i2c;
|
||||
struct gpio_dt_spec dvs_state_pins[2];
|
||||
};
|
||||
|
||||
struct regulator_npm2100_config {
|
||||
struct regulator_common_config common;
|
||||
struct i2c_dt_spec i2c;
|
||||
uint8_t source;
|
||||
struct gpio_dt_spec mode_gpios;
|
||||
bool ldosw_wd_reset;
|
||||
uint8_t dps_timer;
|
||||
uint8_t dps_pulse_limit;
|
||||
};
|
||||
|
||||
struct regulator_npm2100_data {
|
||||
struct regulator_common_data data;
|
||||
bool ldsw_mode;
|
||||
};
|
||||
|
||||
static const struct linear_range boost_range = LINEAR_RANGE_INIT(1800000, 50000, 0U, 30U);
|
||||
static const struct linear_range ldosw_range = LINEAR_RANGE_INIT(800000, 50000, 8U, 52U);
|
||||
static const struct linear_range vset0_range = LINEAR_RANGE_INIT(1800000, 100000, 0U, 6U);
|
||||
static const struct linear_range vset1_ranges[] = {LINEAR_RANGE_INIT(3000000, 0, 0U, 0U),
|
||||
LINEAR_RANGE_INIT(2700000, 100000, 1U, 3U),
|
||||
LINEAR_RANGE_INIT(3100000, 100000, 4U, 6U)};
|
||||
static const struct linear_range boost_ocp_range = LINEAR_RANGE_INIT(0, 300000, 0U, 1U);
|
||||
|
||||
static const struct linear_range ldsw_ocp_ranges[] = {LINEAR_RANGE_INIT(40000, 0, 0U, 0U),
|
||||
LINEAR_RANGE_INIT(70000, 5000, 1U, 3U),
|
||||
LINEAR_RANGE_INIT(110000, 0, 4U, 4U)};
|
||||
static const uint8_t ldo_ocp_lookup[] = {13, 7, 6, 4, 1};
|
||||
|
||||
static const struct linear_range ldo_ocp_ranges[] = {LINEAR_RANGE_INIT(25000, 13000, 0U, 1U),
|
||||
LINEAR_RANGE_INIT(50000, 25000, 2U, 3U),
|
||||
LINEAR_RANGE_INIT(150000, 0, 4U, 4U)};
|
||||
static const uint8_t ldsw_ocp_lookup[] = {1, 7, 8, 9, 15};
|
||||
|
||||
static unsigned int regulator_npm2100_count_voltages(const struct device *dev)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
return linear_range_values_count(&boost_range);
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
return linear_range_values_count(&ldosw_range);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_list_voltage(const struct device *dev, unsigned int idx,
|
||||
int32_t *volt_uv)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
return linear_range_get_value(&boost_range, idx, volt_uv);
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
return linear_range_get_value(&ldosw_range, idx, volt_uv);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_set_voltage(const struct device *dev, int32_t min_uv, int32_t max_uv)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
uint16_t idx;
|
||||
int ret;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
ret = linear_range_get_win_index(&boost_range, min_uv, max_uv, &idx);
|
||||
if (ret == -EINVAL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_reg_write_byte_dt(&config->i2c, BOOST_VOUT, idx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable SW control of boost voltage */
|
||||
return i2c_reg_write_byte_dt(&config->i2c, BOOST_VOUTSEL, 1U);
|
||||
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
ret = linear_range_get_win_index(&ldosw_range, min_uv, max_uv, &idx);
|
||||
if (ret == -EINVAL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return i2c_reg_write_byte_dt(&config->i2c, LDOSW_VOUT, idx);
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_get_voltage(const struct device *dev, int32_t *volt_uv)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
uint8_t idx;
|
||||
int ret;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, BOOST_VOUTSEL, &idx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (idx == 1U) {
|
||||
/* Voltage is selected by register value */
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, BOOST_VOUT, &idx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return linear_range_get_value(&boost_range, idx, volt_uv);
|
||||
}
|
||||
|
||||
/* Voltage is selected by VSET pin */
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, BOOST_STATUS1, &idx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((idx & BOOST_STATUS1_VSET_MASK) == 0U) {
|
||||
/* VSET low, voltage is selected by VSET0 register */
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, BOOST_VSET0, &idx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return linear_range_get_value(&vset0_range, idx, volt_uv);
|
||||
}
|
||||
|
||||
/* VSET high, voltage is selected by VSET1 register */
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, BOOST_VSET1, &idx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return linear_range_group_get_value(vset1_ranges, ARRAY_SIZE(vset1_ranges), idx,
|
||||
volt_uv);
|
||||
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, LDOSW_VOUT, &idx);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return linear_range_get_value(&ldosw_range, idx, volt_uv);
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int regulator_npm2100_count_currents(const struct device *dev)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
const struct regulator_npm2100_data *data = dev->data;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
return linear_range_values_count(&boost_ocp_range);
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
if (data->ldsw_mode) {
|
||||
return linear_range_group_values_count(ldsw_ocp_ranges,
|
||||
ARRAY_SIZE(ldsw_ocp_ranges));
|
||||
}
|
||||
return linear_range_group_values_count(ldo_ocp_ranges, ARRAY_SIZE(ldo_ocp_ranges));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_list_currents(const struct device *dev, unsigned int idx,
|
||||
int32_t *current_ua)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
const struct regulator_npm2100_data *data = dev->data;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
return linear_range_get_value(&boost_ocp_range, idx, current_ua);
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
if (data->ldsw_mode) {
|
||||
return linear_range_group_get_value(
|
||||
ldsw_ocp_ranges, ARRAY_SIZE(ldsw_ocp_ranges), idx, current_ua);
|
||||
}
|
||||
return linear_range_group_get_value(ldo_ocp_ranges, ARRAY_SIZE(ldo_ocp_ranges), idx,
|
||||
current_ua);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_set_current(const struct device *dev, int32_t min_ua, int32_t max_ua)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
const struct regulator_npm2100_data *data = dev->data;
|
||||
uint16_t idx = 0;
|
||||
uint8_t shift = 0;
|
||||
int ret;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
ret = linear_range_get_win_index(&boost_ocp_range, min_ua, max_ua, &idx);
|
||||
if (ret == -EINVAL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (idx == 1) {
|
||||
return i2c_reg_write_byte_dt(&config->i2c, BOOST_CTRLSET, BIT(3));
|
||||
}
|
||||
return i2c_reg_write_byte_dt(&config->i2c, BOOST_CTRLCLR, BIT(3));
|
||||
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
if (data->ldsw_mode) {
|
||||
ret = linear_range_group_get_win_index(
|
||||
ldsw_ocp_ranges, ARRAY_SIZE(ldsw_ocp_ranges), min_ua, max_ua, &idx);
|
||||
idx = ldsw_ocp_lookup[idx];
|
||||
shift = 4U;
|
||||
} else {
|
||||
ret = linear_range_group_get_win_index(
|
||||
ldo_ocp_ranges, ARRAY_SIZE(ldo_ocp_ranges), min_ua, max_ua, &idx);
|
||||
idx = ldo_ocp_lookup[idx];
|
||||
}
|
||||
|
||||
if (ret == -EINVAL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return i2c_reg_update_byte_dt(&config->i2c, LDOSW_PRGOCP, BIT_MASK(3) << shift,
|
||||
idx << shift);
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
static int set_boost_mode(const struct device *dev, regulator_mode_t mode)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
uint8_t reg;
|
||||
|
||||
/* Normal mode */
|
||||
switch (mode & NPM2100_REG_OPER_MASK) {
|
||||
case NPM2100_REG_OPER_AUTO:
|
||||
reg = BOOST_OPER_MODE_AUTO;
|
||||
break;
|
||||
case NPM2100_REG_OPER_HP:
|
||||
reg = BOOST_OPER_MODE_HP;
|
||||
break;
|
||||
case NPM2100_REG_OPER_LP:
|
||||
reg = BOOST_OPER_MODE_LP;
|
||||
break;
|
||||
case NPM2100_REG_OPER_PASS:
|
||||
reg = BOOST_OPER_MODE_PASS;
|
||||
break;
|
||||
case NPM2100_REG_OPER_NOHP:
|
||||
reg = BOOST_OPER_MODE_NOHP;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Configure DPS mode */
|
||||
if ((mode & NPM2100_REG_DPS_MASK) != 0) {
|
||||
uint8_t dps_val = (mode & NPM2100_REG_DPS_MASK) == NPM2100_REG_DPS_ALLOW
|
||||
? BOOST_OPER_DPS_ALLOW
|
||||
: BOOST_OPER_DPS_ALLOWLP;
|
||||
|
||||
reg |= FIELD_PREP(BOOST_OPER_DPS_MASK, dps_val);
|
||||
}
|
||||
|
||||
/* Update mode and dps fields, but not dpstimer */
|
||||
int ret = i2c_reg_update_byte_dt(&config->i2c, BOOST_OPER,
|
||||
BOOST_OPER_MODE_MASK | BOOST_OPER_DPS_MASK, reg);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Forced mode */
|
||||
switch (mode & NPM2100_REG_FORCE_MASK) {
|
||||
case 0U:
|
||||
return 0;
|
||||
case NPM2100_REG_FORCE_HP:
|
||||
reg = BOOST_PIN_FORCE_HP;
|
||||
break;
|
||||
case NPM2100_REG_FORCE_LP:
|
||||
reg = BOOST_PIN_FORCE_LP;
|
||||
break;
|
||||
case NPM2100_REG_FORCE_PASS:
|
||||
reg = BOOST_PIN_FORCE_PASS;
|
||||
break;
|
||||
case NPM2100_REG_FORCE_NOHP:
|
||||
reg = BOOST_PIN_FORCE_NOHP;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Forced mode is only valid when gpio is configured */
|
||||
if (config->mode_gpios.port == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return i2c_reg_write_byte_dt(&config->i2c, BOOST_PIN, reg);
|
||||
}
|
||||
|
||||
static int get_boost_mode(const struct device *dev, regulator_mode_t *mode)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
uint8_t reg;
|
||||
int ret;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, BOOST_STATUS0, ®);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (reg & BOOST_STATUS0_MODE_MASK) {
|
||||
case BOOST_STATUS0_MODE_HP:
|
||||
*mode = NPM2100_REG_OPER_HP;
|
||||
break;
|
||||
case BOOST_STATUS0_MODE_LP:
|
||||
*mode = NPM2100_REG_OPER_LP;
|
||||
break;
|
||||
case BOOST_STATUS0_MODE_ULP:
|
||||
*mode = NPM2100_REG_OPER_ULP;
|
||||
break;
|
||||
case BOOST_STATUS0_MODE_PT:
|
||||
*mode = NPM2100_REG_OPER_PASS;
|
||||
break;
|
||||
case BOOST_STATUS0_MODE_DPS:
|
||||
/* STATUS0 indicates whether DPS is enabled, regardless of ALLOW/ALLOWLP setting.
|
||||
* BOOST_OPER_DPS_ALLOW chosen instead of creating new enum value.
|
||||
*/
|
||||
*mode = BOOST_OPER_DPS_ALLOW;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ldosw_mode(const struct device *dev, regulator_mode_t *mode)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
uint8_t reg;
|
||||
int ret;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, LDOSW_STATUS, ®);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*mode = 0U;
|
||||
if (reg & LDOSW_STATUS_SW) {
|
||||
*mode |= NPM2100_REG_LDSW_EN;
|
||||
}
|
||||
|
||||
if (reg & LDOSW_STATUS_HP) {
|
||||
*mode |= NPM2100_REG_OPER_HP;
|
||||
} else if (reg & LDOSW_STATUS_ULP) {
|
||||
*mode |= NPM2100_REG_OPER_ULP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_ldosw_gpio_mode(const struct device *dev, uint8_t inact, uint8_t act, uint8_t ldsw)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
int ret;
|
||||
|
||||
ret = i2c_reg_update_byte_dt(&config->i2c, LDOSW_GPIO, LDOSW_GPIO_PINACT_MASK, inact | act);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set operating mode to pin control */
|
||||
return i2c_reg_write_byte_dt(&config->i2c, LDOSW_SEL, LDOSW_SEL_OPER_PIN | ldsw);
|
||||
}
|
||||
|
||||
static int set_ldosw_mode(const struct device *dev, regulator_mode_t mode)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
struct regulator_npm2100_data *data = dev->data;
|
||||
uint8_t ldsw = mode & NPM2100_REG_LDSW_EN;
|
||||
uint8_t oper = mode & NPM2100_REG_OPER_MASK;
|
||||
uint8_t force = mode & NPM2100_REG_FORCE_MASK;
|
||||
|
||||
/* Save load switch state, needed for OCP configuration */
|
||||
data->ldsw_mode = ldsw != 0;
|
||||
|
||||
if (force == 0U) {
|
||||
/* SW control of mode */
|
||||
switch (oper) {
|
||||
case NPM2100_REG_OPER_AUTO:
|
||||
return i2c_reg_write_byte_dt(&config->i2c, LDOSW_SEL,
|
||||
LDOSW_SEL_OPER_AUTO | ldsw);
|
||||
case NPM2100_REG_OPER_ULP:
|
||||
return i2c_reg_write_byte_dt(&config->i2c, LDOSW_SEL,
|
||||
LDOSW_SEL_OPER_ULP | ldsw);
|
||||
case NPM2100_REG_OPER_HP:
|
||||
return i2c_reg_write_byte_dt(&config->i2c, LDOSW_SEL,
|
||||
LDOSW_SEL_OPER_HP | ldsw);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
/* Forced mode is only valid when gpio is configured */
|
||||
if (config->mode_gpios.port == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (oper | force) {
|
||||
case NPM2100_REG_OPER_OFF | NPM2100_REG_FORCE_ULP:
|
||||
return set_ldosw_gpio_mode(dev, LDOSW_GPIO_PININACT_OFF, LDOSW_GPIO_PINACT_ULP,
|
||||
ldsw);
|
||||
case NPM2100_REG_OPER_OFF | NPM2100_REG_FORCE_HP:
|
||||
return set_ldosw_gpio_mode(dev, LDOSW_GPIO_PININACT_OFF, LDOSW_GPIO_PINACT_HP,
|
||||
ldsw);
|
||||
case NPM2100_REG_OPER_ULP | NPM2100_REG_FORCE_HP:
|
||||
return set_ldosw_gpio_mode(dev, LDOSW_GPIO_PININACT_ULP, LDOSW_GPIO_PINACT_HP,
|
||||
ldsw);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_set_mode(const struct device *dev, regulator_mode_t mode)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
return set_boost_mode(dev, mode);
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
return set_ldosw_mode(dev, mode);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_get_mode(const struct device *dev, regulator_mode_t *mode)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
return get_boost_mode(dev, mode);
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
return get_ldosw_mode(dev, mode);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_enable(const struct device *dev)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
|
||||
if (config->source != NPM2100_SOURCE_LDOSW) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return i2c_reg_write_byte_dt(&config->i2c, LDOSW_ENABLE, 1U);
|
||||
}
|
||||
|
||||
static int regulator_npm2100_disable(const struct device *dev)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
|
||||
if (config->source != NPM2100_SOURCE_LDOSW) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return i2c_reg_write_byte_dt(&config->i2c, LDOSW_ENABLE, 0U);
|
||||
}
|
||||
|
||||
static int init_pin_ctrl(const struct device *dev, const struct gpio_dt_spec *spec)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
|
||||
if (spec->port == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = gpio_pin_configure_dt(spec, GPIO_INPUT);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t pin = spec->pin << 1U;
|
||||
uint8_t offset = ((spec->dt_flags & GPIO_ACTIVE_LOW) != 0U) ? 0U : 1U;
|
||||
|
||||
switch (config->source) {
|
||||
case NPM2100_SOURCE_BOOST:
|
||||
return i2c_reg_write_byte_dt(&config->i2c, BOOST_GPIO, pin + offset + 1U);
|
||||
case NPM2100_SOURCE_LDOSW:
|
||||
return i2c_reg_update_byte_dt(&config->i2c, LDOSW_GPIO, LDOSW_GPIO_PIN_MASK,
|
||||
pin + offset);
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
static int regulator_npm2100_dvs_state_set(const struct device *dev, regulator_dvs_state_t state)
|
||||
{
|
||||
const struct regulator_npm2100_pconfig *pconfig = dev->config;
|
||||
const struct gpio_dt_spec *spec;
|
||||
int ret;
|
||||
|
||||
for (size_t idx = 0U; idx < 2U; idx++) {
|
||||
spec = &pconfig->dvs_state_pins[idx];
|
||||
|
||||
if (spec->port != NULL) {
|
||||
ret = gpio_pin_set_dt(spec, ((state >> idx) & 1U) != 0U);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regulator_npm2100_ship_mode(const struct device *dev)
|
||||
{
|
||||
const struct regulator_npm2100_pconfig *pconfig = dev->config;
|
||||
|
||||
/* Ensure shiphold button is enabled so that wakeup will work */
|
||||
int ret = i2c_reg_write_byte_dt(&pconfig->i2c, RESET_WRITESTICKY, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_reg_write_byte_dt(&pconfig->i2c, RESET_STROBESTICKY, 1U);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return i2c_reg_write_byte_dt(&pconfig->i2c, SHIP_TASK_SHIP, 1U);
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_API(regulator_parent, parent_api) = {
|
||||
.dvs_state_set = regulator_npm2100_dvs_state_set,
|
||||
.ship_mode = regulator_npm2100_ship_mode,
|
||||
};
|
||||
|
||||
static int regulator_npm2100_common_init(const struct device *dev)
|
||||
{
|
||||
const struct regulator_npm2100_pconfig *pconfig = dev->config;
|
||||
const struct gpio_dt_spec *spec;
|
||||
int ret;
|
||||
|
||||
for (size_t idx = 0U; idx < 2U; idx++) {
|
||||
spec = &pconfig->dvs_state_pins[idx];
|
||||
|
||||
if (spec->port != NULL) {
|
||||
if (!gpio_is_ready_dt(spec)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(spec, GPIO_OUTPUT);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regulator_npm2100_init(const struct device *dev)
|
||||
{
|
||||
const struct regulator_npm2100_config *config = dev->config;
|
||||
int ret;
|
||||
|
||||
if (!i2c_is_ready_dt(&config->i2c)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Configure GPIO pin control */
|
||||
ret = init_pin_ctrl(dev, &config->mode_gpios);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* BOOST is always enabled */
|
||||
if (config->source == NPM2100_SOURCE_BOOST) {
|
||||
ret = i2c_reg_write_byte_dt(
|
||||
&config->i2c, BOOST_OPER,
|
||||
FIELD_PREP(BOOST_OPER_DPSTIMER_MASK, config->dps_timer));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_reg_write_byte_dt(&config->i2c, BOOST_LIMIT, config->dps_pulse_limit);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return regulator_common_init(dev, true);
|
||||
}
|
||||
|
||||
/* Configure LDOSW behavior during watchdog reset */
|
||||
if (config->ldosw_wd_reset) {
|
||||
ret = i2c_reg_write_byte_dt(&config->i2c, RESET_ALTCONFIG,
|
||||
RESET_ALTCONFIG_LDOSW_OFF);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get enable state for LDOSW */
|
||||
uint8_t enabled;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&config->i2c, LDOSW_ENABLE, &enabled);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return regulator_common_init(dev, enabled != 0U);
|
||||
}
|
||||
|
||||
static DEVICE_API(regulator, api) = {
|
||||
.enable = regulator_npm2100_enable,
|
||||
.disable = regulator_npm2100_disable,
|
||||
.count_voltages = regulator_npm2100_count_voltages,
|
||||
.list_voltage = regulator_npm2100_list_voltage,
|
||||
.set_voltage = regulator_npm2100_set_voltage,
|
||||
.get_voltage = regulator_npm2100_get_voltage,
|
||||
.count_current_limits = regulator_npm2100_count_currents,
|
||||
.list_current_limit = regulator_npm2100_list_currents,
|
||||
.set_current_limit = regulator_npm2100_set_current,
|
||||
.set_mode = regulator_npm2100_set_mode,
|
||||
.get_mode = regulator_npm2100_get_mode};
|
||||
|
||||
#define REGULATOR_NPM2100_DEFINE(node_id, id, _source) \
|
||||
static struct regulator_npm2100_data data_##id; \
|
||||
\
|
||||
static const struct regulator_npm2100_config config_##id = { \
|
||||
.common = REGULATOR_DT_COMMON_CONFIG_INIT(node_id), \
|
||||
.i2c = I2C_DT_SPEC_GET(DT_GPARENT(node_id)), \
|
||||
.source = _source, \
|
||||
.mode_gpios = GPIO_DT_SPEC_GET_OR(node_id, mode_gpios, {0}), \
|
||||
.ldosw_wd_reset = DT_PROP(node_id, ldosw_wd_reset), \
|
||||
.dps_timer = DT_ENUM_IDX_OR(node_id, dps_timer_us, 0), \
|
||||
.dps_pulse_limit = DT_PROP_OR(node_id, dps_pulse_limit, 0)}; \
|
||||
BUILD_ASSERT(DT_PROP_OR(node_id, dps_pulse_limit, 0) >= 3 || \
|
||||
DT_PROP_OR(node_id, dps_pulse_limit, 0) == 0, \
|
||||
"Invalid dps_pulse_limit value"); \
|
||||
\
|
||||
DEVICE_DT_DEFINE(node_id, regulator_npm2100_init, NULL, &data_##id, &config_##id, \
|
||||
POST_KERNEL, CONFIG_REGULATOR_NPM2100_INIT_PRIORITY, &api);
|
||||
|
||||
#define REGULATOR_NPM2100_DEFINE_COND(inst, child, source) \
|
||||
COND_CODE_1(DT_NODE_EXISTS(DT_INST_CHILD(inst, child)), \
|
||||
(REGULATOR_NPM2100_DEFINE(DT_INST_CHILD(inst, child), child##inst, source)), \
|
||||
())
|
||||
|
||||
#define REGULATOR_NPM2100_DEFINE_ALL(inst) \
|
||||
static const struct regulator_npm2100_pconfig config_##inst = { \
|
||||
.i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \
|
||||
.dvs_state_pins = {GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 0, {0}), \
|
||||
GPIO_DT_SPEC_INST_GET_BY_IDX_OR(inst, dvs_gpios, 1, {0})}}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(inst, regulator_npm2100_common_init, NULL, NULL, &config_##inst, \
|
||||
POST_KERNEL, CONFIG_REGULATOR_NPM2100_COMMON_INIT_PRIORITY, \
|
||||
&parent_api); \
|
||||
\
|
||||
REGULATOR_NPM2100_DEFINE_COND(inst, boost, NPM2100_SOURCE_BOOST) \
|
||||
REGULATOR_NPM2100_DEFINE_COND(inst, ldosw, NPM2100_SOURCE_LDOSW)
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(REGULATOR_NPM2100_DEFINE_ALL)
|
81
dts/bindings/regulator/nordic,npm2100-regulator.yaml
Normal file
81
dts/bindings/regulator/nordic,npm2100-regulator.yaml
Normal file
|
@ -0,0 +1,81 @@
|
|||
# Copyright (c), 2024 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
Nordic nPM2100 PMIC
|
||||
|
||||
The PMIC has one boost converter and one LDO/LDSW.
|
||||
The regulators need to be defined as child nodes,
|
||||
strictly following the BOOST, LDOSW node names.
|
||||
For example:
|
||||
|
||||
pmic@74 {
|
||||
reg = <0x74>;
|
||||
...
|
||||
regulators {
|
||||
compatible = "nordic,npm2100-regulator";
|
||||
|
||||
BOOST {
|
||||
/* all properties for BOOST */
|
||||
};
|
||||
LDOSW {
|
||||
/* all properties for LDOSW */
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
compatible: "nordic,npm2100-regulator"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
dvs-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
List of SOC GPIOs connected to PMIC GPIOs.
|
||||
Set_dvs_mode will drive these pins as follows:
|
||||
DVS mode 1 will enable the first pin
|
||||
DVS mode 2 will enable the second pin
|
||||
The effect of the mode change is defined by the mode-gpios
|
||||
fields for each of the regulator blocks.
|
||||
|
||||
child-binding:
|
||||
include:
|
||||
- name: regulator.yaml
|
||||
property-allowlist:
|
||||
- regulator-always-on
|
||||
- regulator-boot-on
|
||||
- regulator-min-microvolt
|
||||
- regulator-max-microvolt
|
||||
- regulator-init-microvolt
|
||||
- regulator-allowed-modes
|
||||
- regulator-initial-mode
|
||||
- regulator-min-microamp
|
||||
- regulator-max-microamp
|
||||
- regulator-init-microamp
|
||||
|
||||
properties:
|
||||
mode-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
Regulator mode controlled by specified regulator GPIO pin.
|
||||
|
||||
ldosw-wd-reset:
|
||||
type: boolean
|
||||
description: |
|
||||
LDOSW turned off by watchdog reset.
|
||||
|
||||
dps-timer-us:
|
||||
type: int
|
||||
description: |
|
||||
Interval between DPS refresh cycles in microseconds.
|
||||
enum:
|
||||
- 100
|
||||
- 200
|
||||
- 400
|
||||
- 800
|
||||
|
||||
dps-pulse-limit:
|
||||
type: int
|
||||
description: |
|
||||
DPS coil pulse limit per refresh cycle.
|
50
include/zephyr/dt-bindings/regulator/npm2100.h
Normal file
50
include/zephyr/dt-bindings/regulator/npm2100.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NPM2100_H_
|
||||
#define ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NPM2100_H_
|
||||
|
||||
/**
|
||||
* @defgroup regulator_npm2100 NPM2100 Devicetree helpers.
|
||||
* @ingroup regulator_interface
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name NPM2100 Regulator modes
|
||||
* @{
|
||||
*/
|
||||
/* Load switch selection, applies to LDOSW only */
|
||||
#define NPM2100_REG_LDSW_EN 0x01U
|
||||
|
||||
/* DPS modes applies to BOOST only */
|
||||
#define NPM2100_REG_DPS_MASK 0x03U
|
||||
#define NPM2100_REG_DPS_ALLOW 0x01U
|
||||
#define NPM2100_REG_DPS_ALLOWLP 0x02U
|
||||
|
||||
/* Operating mode */
|
||||
#define NPM2100_REG_OPER_MASK 0x1CU
|
||||
#define NPM2100_REG_OPER_AUTO 0x00U
|
||||
#define NPM2100_REG_OPER_HP 0x04U
|
||||
#define NPM2100_REG_OPER_LP 0x08U
|
||||
#define NPM2100_REG_OPER_ULP 0x0CU
|
||||
#define NPM2100_REG_OPER_PASS 0x10U
|
||||
#define NPM2100_REG_OPER_NOHP 0x14U
|
||||
#define NPM2100_REG_OPER_OFF 0x18U
|
||||
|
||||
/* Forced mode when GPIO active */
|
||||
#define NPM2100_REG_FORCE_MASK 0xE0U
|
||||
#define NPM2100_REG_FORCE_HP 0x20U
|
||||
#define NPM2100_REG_FORCE_LP 0x40U
|
||||
#define NPM2100_REG_FORCE_ULP 0x60U
|
||||
#define NPM2100_REG_FORCE_PASS 0x80U
|
||||
#define NPM2100_REG_FORCE_NOHP 0xA0U
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_REGULATOR_NPM2100_H_*/
|
|
@ -107,3 +107,15 @@ mpm54304@7 {
|
|||
BUCK3 {};
|
||||
BUCK4 {};
|
||||
};
|
||||
|
||||
npm2100@8 {
|
||||
compatible = "nordic,npm2100";
|
||||
reg = <0x8>;
|
||||
|
||||
regulators {
|
||||
compatible = "nordic,npm2100-regulator";
|
||||
|
||||
BOOST {};
|
||||
LDOSW {};
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue