Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: regulator: implement active discharge api #61056

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions drivers/regulator/regulator_common.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright 2022 Nordic Semiconductor ASA
* Copyright 2023 Meta Platforms
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -42,6 +43,15 @@ int regulator_common_init(const struct device *dev, bool is_enabled)
}
}

if (REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags) !=
REGULATOR_ACTIVE_DISCHARGE_DEFAULT) {
ret = regulator_set_active_discharge(dev,
(bool)REGULATOR_ACTIVE_DISCHARGE_GET_BITS(config->flags));
if (ret < 0) {
return ret;
}
}

if (config->init_uv > INT32_MIN) {
ret = regulator_set_voltage(dev, config->init_uv, config->init_uv);
if (ret < 0) {
Expand Down
6 changes: 6 additions & 0 deletions drivers/regulator/regulator_fake.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_set_mode, const struct device *,
regulator_mode_t);
DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_mode, const struct device *,
regulator_mode_t *);
DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_set_active_discharge, const struct device *,
bool);
DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_active_discharge, const struct device *,
bool *);
DEFINE_FAKE_VALUE_FUNC(int, regulator_fake_get_error_flags,
const struct device *, regulator_error_flags_t *);

Expand All @@ -53,6 +57,8 @@ static struct regulator_driver_api api = {
.get_current_limit = regulator_fake_get_current_limit,
.set_mode = regulator_fake_set_mode,
.get_mode = regulator_fake_get_mode,
.set_active_discharge = regulator_fake_set_active_discharge,
.get_active_discharge = regulator_fake_get_active_discharge,
.get_error_flags = regulator_fake_get_error_flags,
};

Expand Down
56 changes: 56 additions & 0 deletions drivers/regulator/regulator_pca9420.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#define PCA9420_TOP_CNTL3 0x0CU

/** Regulator status indication registers */
/** @brief Active Discharge configuration for mode 0_0 */
#define PCA9420_ACT_DISCHARGE_CNTL 0x21U
/** @brief Mode configuration for mode 0_0 */
#define PCA9420_MODECFG_0_0 0x22U
/** @brief Mode configuration for mode 0_1 */
Expand Down Expand Up @@ -81,6 +83,18 @@
/** @brief LDO2_OUT offset and voltage level mask */
#define PCA9420_MODECFG_3_LDO2_OUT_MASK 0x3FU
#define PCA9420_MODECFG_3_LDO2_OUT_POS 0U
/** @brief SW1 active discharge control */
#define PCA9420_ACT_DISCHARGE_CNTL_SW1_MASK 0x08U
#define PCA9420_ACT_DISCHARGE_CNTL_SW1_POS 4U
/** @brief SW2 active discharge control */
#define PCA9420_ACT_DISCHARGE_CNTL_SW2_MASK 0x04U
#define PCA9420_ACT_DISCHARGE_CNTL_SW2_POS 3U
/** @brief LDO1 active discharge control */
#define PCA9420_ACT_DISCHARGE_CNTL_LDO1_MASK 0x02U
#define PCA9420_ACT_DISCHARGE_CNTL_LDO1_POS 2U
/** @brief LDO2 active discharge control */
#define PCA9420_ACT_DISCHARGE_CNTL_LDO2_MASK 0x01U
#define PCA9420_ACT_DISCHARGE_CNTL_LDO2_POS 1U

/** VIN ILIM resolution, uA/LSB */
#define PCA9420_VIN_ILIM_UA_LSB 170000
Expand All @@ -99,6 +113,8 @@ struct regulator_pca9420_desc {
uint8_t vsel_reg;
uint8_t vsel_mask;
uint8_t vsel_pos;
uint8_t ad_mask;
uint8_t ad_pos;
int32_t max_ua;
uint8_t num_ranges;
const struct linear_range *ranges;
Expand Down Expand Up @@ -159,6 +175,8 @@ static const struct regulator_pca9420_desc buck1_desc = {
.vsel_mask = PCA9420_MODECFG_0_SW1_OUT_MASK,
.vsel_pos = PCA9420_MODECFG_0_SW1_OUT_POS,
.vsel_reg = PCA9420_MODECFG_0_0,
.ad_mask = PCA9420_ACT_DISCHARGE_CNTL_SW1_MASK,
.ad_pos = PCA9420_ACT_DISCHARGE_CNTL_SW1_POS,
.max_ua = 250000,
.ranges = buck1_ranges,
.num_ranges = ARRAY_SIZE(buck1_ranges),
Expand All @@ -171,6 +189,8 @@ static const struct regulator_pca9420_desc buck2_desc = {
.vsel_mask = PCA9420_MODECFG_1_SW2_OUT_MASK,
.vsel_pos = PCA9420_MODECFG_1_SW2_OUT_POS,
.vsel_reg = PCA9420_MODECFG_0_1,
.ad_mask = PCA9420_ACT_DISCHARGE_CNTL_SW2_MASK,
.ad_pos = PCA9420_ACT_DISCHARGE_CNTL_SW2_POS,
.max_ua = 500000,
.ranges = buck2_ranges,
.num_ranges = ARRAY_SIZE(buck2_ranges),
Expand All @@ -183,6 +203,8 @@ static const struct regulator_pca9420_desc ldo1_desc = {
.vsel_mask = PCA9420_MODECFG_2_LDO1_OUT_MASK,
.vsel_pos = PCA9420_MODECFG_2_LDO1_OUT_POS,
.vsel_reg = PCA9420_MODECFG_0_2,
.ad_mask = PCA9420_ACT_DISCHARGE_CNTL_LDO1_MASK,
.ad_pos = PCA9420_ACT_DISCHARGE_CNTL_LDO1_POS,
.max_ua = 1000,
.ranges = ldo1_ranges,
.num_ranges = ARRAY_SIZE(ldo1_ranges),
Expand All @@ -195,6 +217,8 @@ static const struct regulator_pca9420_desc ldo2_desc = {
.vsel_reg = PCA9420_MODECFG_0_3,
.vsel_mask = PCA9420_MODECFG_3_LDO2_OUT_MASK,
.vsel_pos = PCA9420_MODECFG_3_LDO2_OUT_POS,
.ad_mask = PCA9420_ACT_DISCHARGE_CNTL_LDO2_MASK,
.ad_pos = PCA9420_ACT_DISCHARGE_CNTL_LDO2_POS,
.max_ua = 250000,
.ranges = ldo2_ranges,
.num_ranges = ARRAY_SIZE(ldo2_ranges),
Expand Down Expand Up @@ -279,6 +303,36 @@ static int regulator_pca9420_get_current_limit(const struct device *dev,
return 0;
}

static int regulator_pca9420_set_active_discharge(const struct device *dev,
bool active_discharge)
{
const struct regulator_pca9420_config *config = dev->config;
const struct regulator_pca9420_common_config *cconfig = config->parent->config;
uint8_t dis_val;

dis_val = (!active_discharge) << config->desc->ad_pos;
return i2c_reg_update_byte_dt(&cconfig->i2c, PCA9420_ACT_DISCHARGE_CNTL,
config->desc->ad_mask, dis_val);
}

static int regulator_pca9420_get_active_discharge(const struct device *dev,
bool *active_discharge)
{
const struct regulator_pca9420_config *config = dev->config;
const struct regulator_pca9420_common_config *cconfig = config->parent->config;
uint8_t raw_reg;
int ret;

ret = i2c_reg_read_byte_dt(&cconfig->i2c, PCA9420_ACT_DISCHARGE_CNTL, &raw_reg);
if (ret < 0) {
return ret;
}

*active_discharge = !((raw_reg & config->desc->ad_mask) >> config->desc->ad_pos);

return 0;
}

static int regulator_pca9420_enable(const struct device *dev)
{
const struct regulator_pca9420_config *config = dev->config;
Expand Down Expand Up @@ -313,6 +367,8 @@ static const struct regulator_driver_api api = {
.set_voltage = regulator_pca9420_set_voltage,
.get_voltage = regulator_pca9420_get_voltage,
.get_current_limit = regulator_pca9420_get_current_limit,
.set_active_discharge = regulator_pca9420_set_active_discharge,
.get_active_discharge = regulator_pca9420_get_active_discharge,
};

static int regulator_pca9420_init(const struct device *dev)
Expand Down
65 changes: 65 additions & 0 deletions drivers/regulator/regulator_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,63 @@ static int cmd_modeget(const struct shell *sh, size_t argc, char **argv)
return 0;
}

static int cmd_adset(const struct shell *sh, size_t argc, char **argv)
{
const struct device *dev;
bool ad;
int ret;

ARG_UNUSED(argc);

dev = device_get_binding(argv[1]);
if (dev == NULL) {
shell_error(sh, "Regulator device %s not available", argv[1]);
return -ENODEV;
}

if (strcmp(argv[2], "enable")) {
ad = true;
} else if (strcmp(argv[2], "disable")) {
ad = false;
} else {
shell_error(sh, "Invalid parameter");
return -EINVAL;
}

ret = regulator_set_active_discharge(dev, ad);
if (ret < 0) {
shell_error(sh, "Could not set mode (%d)", ret);
return ret;
}

return 0;
}

static int cmd_adget(const struct shell *sh, size_t argc, char **argv)
{
const struct device *dev;
bool ad;
int ret;

ARG_UNUSED(argc);

dev = device_get_binding(argv[1]);
if (dev == NULL) {
shell_error(sh, "Regulator device %s not available", argv[1]);
return -ENODEV;
}

ret = regulator_get_active_discharge(dev, &ad);
if (ret < 0) {
shell_error(sh, "Could not get active discharge (%d)", ret);
return ret;
}

shell_print(sh, "Active Discharge: %s", ad ? "enabled" : "disabled");

return 0;
}

static int cmd_errors(const struct shell *sh, size_t argc, char **argv)
{
const struct device *dev;
Expand Down Expand Up @@ -503,6 +560,14 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
"Get regulator mode\n"
"Usage: modeget <device>",
cmd_modeget, 2, 0),
SHELL_CMD_ARG(adset, NULL,
"Set active discharge\n"
"Usage: adset <device> <enable/disable>",
cmd_adset, 3, 0),
SHELL_CMD_ARG(adget, NULL,
"Get active discharge\n"
"Usage: adset <device>",
cmd_adget, 2, 0),
SHELL_CMD_ARG(errors, &dsub_device_name,
"Get errors\n"
"Usage: errors <device>",
Expand Down
80 changes: 76 additions & 4 deletions include/zephyr/drivers/regulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright (c) 2021 NXP
* Copyright (c) 2022 Nordic Semiconductor ASA
* Copyright (c) 2023 EPAM Systems
* Copyright (c) 2023 Meta Platforms
* SPDX-License-Identifier: Apache-2.0
*/

Expand Down Expand Up @@ -87,6 +88,10 @@ typedef int (*regulator_set_mode_t)(const struct device *dev,
regulator_mode_t mode);
typedef int (*regulator_get_mode_t)(const struct device *dev,
regulator_mode_t *mode);
typedef int (*regulator_set_active_discharge_t)(const struct device *dev,
bool active_discharge);
typedef int (*regulator_get_active_discharge_t)(const struct device *dev,
bool *active_discharge);
typedef int (*regulator_get_error_flags_t)(
const struct device *dev, regulator_error_flags_t *flags);

Expand All @@ -104,6 +109,8 @@ __subsystem struct regulator_driver_api {
regulator_get_current_limit_t get_current_limit;
regulator_set_mode_t set_mode;
regulator_get_mode_t get_mode;
regulator_set_active_discharge_t set_active_discharge;
regulator_get_active_discharge_t get_active_discharge;
regulator_get_error_flags_t get_error_flags;
};

Expand All @@ -113,11 +120,27 @@ __subsystem struct regulator_driver_api {
* @{
*/
/** Indicates regulator must stay always ON */
#define REGULATOR_ALWAYS_ON BIT(0)
#define REGULATOR_ALWAYS_ON BIT(0)
/** Indicates regulator must be initialized ON */
#define REGULATOR_BOOT_ON BIT(1)
#define REGULATOR_BOOT_ON BIT(1)
/** Indicates if regulator must be enabled when initialized */
#define REGULATOR_INIT_ENABLED (REGULATOR_ALWAYS_ON | REGULATOR_BOOT_ON)
#define REGULATOR_INIT_ENABLED (REGULATOR_ALWAYS_ON | REGULATOR_BOOT_ON)
/** Regulator active discharge state mask */
#define REGULATOR_ACTIVE_DISCHARGE_MASK GENMASK(3, 2)
/** Regulator active discharge state flag position*/
#define REGULATOR_ACTIVE_DISCHARGE_POS 2
/** Disable regulator active discharge */
#define REGULATOR_ACTIVE_DISCHARGE_DISABLE 0
/** Enable regulator active discharge */
#define REGULATOR_ACTIVE_DISCHARGE_ENABLE 1
/** Leave regulator active discharge state as default */
#define REGULATOR_ACTIVE_DISCHARGE_DEFAULT 2
/** Regulator active discharge set bits */
#define REGULATOR_ACTIVE_DISCHARGE_SET_BITS(x) \
(((x) << REGULATOR_ACTIVE_DISCHARGE_POS) & REGULATOR_ACTIVE_DISCHARGE_MASK)
/** Regulator active discharge get bits */
#define REGULATOR_ACTIVE_DISCHARGE_GET_BITS(x) \
(((x) & REGULATOR_ACTIVE_DISCHARGE_MASK) >> REGULATOR_ACTIVE_DISCHARGE_POS)

/** @} */

Expand Down Expand Up @@ -186,7 +209,10 @@ struct regulator_common_config {
.flags = ((DT_PROP_OR(node_id, regulator_always_on, 0U) * \
REGULATOR_ALWAYS_ON) | \
(DT_PROP_OR(node_id, regulator_boot_on, 0U) * \
REGULATOR_BOOT_ON)), \
REGULATOR_BOOT_ON) | \
(REGULATOR_ACTIVE_DISCHARGE_SET_BITS( \
DT_PROP_OR(node_id, regulator_active_discharge, \
REGULATOR_ACTIVE_DISCHARGE_DEFAULT)))), \
}

/**
Expand Down Expand Up @@ -635,6 +661,52 @@ static inline int regulator_get_mode(const struct device *dev,
return api->get_mode(dev, mode);
}

/**
* @brief Set active discharge setting.
*
* @param dev Regulator device instance.
* @param active_discharge Active discharge enable or disable.
*
* @retval 0 If successful.
* @retval -ENOSYS If function is not implemented.
* @retval -errno In case of any other error.
*/
static inline int regulator_set_active_discharge(const struct device *dev,
bool active_discharge)
{
const struct regulator_driver_api *api =
(const struct regulator_driver_api *)dev->api;

if (api->set_active_discharge == NULL) {
return -ENOSYS;
}

return api->set_active_discharge(dev, active_discharge);
}

/**
* @brief Get active discharge setting.
*
* @param dev Regulator device instance.
* @param[out] active_discharge Where active discharge will be stored.
*
* @retval 0 If successful.
* @retval -ENOSYS If function is not implemented.
* @retval -errno In case of any other error.
*/
static inline int regulator_get_active_discharge(const struct device *dev,
bool *active_discharge)
{
const struct regulator_driver_api *api =
(const struct regulator_driver_api *)dev->api;

if (api->get_active_discharge == NULL) {
return -ENOSYS;
}

return api->get_active_discharge(dev, active_discharge);
}

/**
* @brief Get active error flags.
*
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/drivers/regulator/fake.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_set_mode, const struct device *,
regulator_mode_t);
DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_mode, const struct device *,
regulator_mode_t *);
DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_set_active_discharge, const struct device *,
bool);
DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_active_discharge, const struct device *,
bool *);
DECLARE_FAKE_VALUE_FUNC(int, regulator_fake_get_error_flags,
const struct device *, regulator_error_flags_t *);

Expand Down
1 change: 1 addition & 0 deletions tests/drivers/regulator/api/app.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
regulator-max-microamp = <200>;
regulator-allowed-modes = <1 10>;
regulator-initial-mode = <1>;
regulator-active-discharge = <1>;
};
};
};
Loading
Loading