2023-05-21 12:24:18

by Benjamin Bara

[permalink] [raw]
Subject: [PATCH RFC v3 0/5] regulator: dynamic voltage monitoring support

Hi!

This series targets the "automatic" state handling of monitors when the
state of the monitored regulator is changed. This is e.g. necessary for
the da9063, which reaches an invalid state (!PWR_OK) if the voltage
monitor is not disabled before the regulator is disabled. The problem
could also be tackled inside of the driver's "state change ops"
(.enable(), .disable(), ...) but I thought it might be a good idea to
have a "common framework" independent of the driver's implementation.
The new approach takes Matti's feedback regarding the bd718x7 into
account.

1/5 factors out the current monitor handling, to be able to re-use it
during the state changes.
2/5 disables monitoring of disabled regulators, also something mentioned
by Matti as a "requirement" of the bd718x7 driver.
3/5 adds a new op to get the active monitors/protections of a regulator,
which should help users to add enabled protections to their device-tree.
4/5 adds new properties to let the core know on which state changes the
monitors of a regulator need to be en-/disabled.
5/5 is an example how the bd718x7 could be converted to use the new
property (untested, as no hw available).

Thanks & best regards,
Benjamin

---
Changes in v3:
- rebase to v6.4-rc2, to get voltage monitoring of da9063
- re-use the existing monitor handling
- set initial monitoring state to regulator state
- disable monitoring before disabling regulators (if protection is
activated in dt)
- add new op to get the active protections of a regulator
- distinguish between switching to higher or lower voltage
- re-activate old monitoring state if regulator's state change fails
- convert bd718x7 monitor handling to use the state change property

Link to v2: https://lore.kernel.org/r/[email protected]

Changes in v2:
1/2:
- move from board-specific (machine.h) to driver-specific (driver.h)
- move from own struct to fields/properties in regulator_desc
- handle modes as one "unsupported modes" field
- factor out new monitors_set_state() to handle all (activated) monitors
- move re-enabling of monitor after ramp-delay
- add TODOs for error handling when the action fails (return error from
actual action instead, return state of monitoring to pre-action).
- reword commit message
2/2:
- adapting change to the properties approach

Link to v1: https://lore.kernel.org/r/[email protected]

---
Benjamin Bara (5):
regulator: move monitor handling into own function
regulator: disable monitors when regulator is disabled
regulator: add getter for active monitors
regulator: add properties to handle monitoring on state change
regulator: bd718x7: let the core handle the monitors

drivers/regulator/bd718x7-regulator.c | 206 ++++++++++---------------------
drivers/regulator/core.c | 224 ++++++++++++++++++++++++++--------
include/linux/regulator/driver.h | 22 ++++
3 files changed, 262 insertions(+), 190 deletions(-)
---
base-commit: f1fcbaa18b28dec10281551dfe6ed3a3ed80e3d6
change-id: 20230419-dynamic-vmon-e08daa0ac7ad

Best regards,
--
Benjamin Bara <[email protected]>



2023-05-21 12:33:38

by Benjamin Bara

[permalink] [raw]
Subject: [PATCH RFC v3 2/5] regulator: disable monitors when regulator is disabled

From: Benjamin Bara <[email protected]>

This disables all enabled monitors before a regulator is disabled. This
only happens if an protection is enabled in the device-tree. If an error
occurs while disabling the regulator, the monitors are enabled again.

Signed-off-by: Benjamin Bara <[email protected]>
---
drivers/regulator/core.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 76f112817f9d..e59204920d6c 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2828,7 +2828,7 @@ static int _regulator_do_enable(struct regulator_dev *rdev)

trace_regulator_enable_complete(rdev_get_name(rdev));

- return 0;
+ return monitors_set_state(rdev, true);
}

/**
@@ -2989,6 +2989,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
{
int ret;

+ ret = monitors_set_state(rdev, false);
+ if (ret)
+ return ret;
+
trace_regulator_disable(rdev_get_name(rdev));

if (rdev->ena_pin) {
@@ -3043,6 +3047,7 @@ static int _regulator_disable(struct regulator *regulator)
_notifier_call_chain(rdev,
REGULATOR_EVENT_ABORT_DISABLE,
NULL);
+ monitors_set_state(rdev, true);
return ret;
}
_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
@@ -3109,6 +3114,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
rdev_err(rdev, "failed to force disable: %pe\n", ERR_PTR(ret));
_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
REGULATOR_EVENT_ABORT_DISABLE, NULL);
+ monitors_set_state(rdev, true);
return ret;
}

@@ -6251,8 +6257,10 @@ static int regulator_late_cleanup(struct device *dev, void *data)
*/
rdev_info(rdev, "disabling\n");
ret = _regulator_do_disable(rdev);
- if (ret != 0)
+ if (ret != 0) {
rdev_err(rdev, "couldn't disable: %pe\n", ERR_PTR(ret));
+ monitors_set_state(rdev, true);
+ }
} else {
/* The intention is that in future we will
* assume that full constraints are provided

--
2.34.1


2023-05-21 12:33:59

by Benjamin Bara

[permalink] [raw]
Subject: [PATCH RFC v3 4/5] regulator: add properties to handle monitoring on state change

From: Benjamin Bara <[email protected]>

These are useful when the state of the regulator might change during
runtime, but the monitors state (in hardware) are not implicitly changed
with the change of the regulator state or mode (in hardware). Also, when
the monitors should be disabled while ramping after a set_value().

Signed-off-by: Benjamin Bara <[email protected]>
---
drivers/regulator/core.c | 90 ++++++++++++++++++++++++++++++++++++++++
include/linux/regulator/driver.h | 13 ++++++
2 files changed, 103 insertions(+)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e59204920d6c..98a9283a0322 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1638,6 +1638,34 @@ static int set_machine_constraints(struct regulator_dev *rdev)
}
}

+ /*
+ * when the core is in charge of disabling monitors while the regulator
+ * changes its value, it is essential to know if a monitor is active.
+ */
+ if (rdev->desc->mon_disable_reg_set_higher ||
+ rdev->desc->mon_disable_reg_set_lower) {
+ unsigned int monitor_state = REGULATOR_MONITOR_INVALID;
+
+ ret = ops->get_active_protections(rdev, &monitor_state);
+ if (ret)
+ return ret;
+
+ /*
+ * when a monitor is active, without dt knowing, we have to
+ * adapt the constraints to ensure functionality.
+ */
+ if (!rdev->constraints->over_voltage_detection &&
+ (monitor_state & REGULATOR_MONITOR_OVER_VOLTAGE)) {
+ rdev_warn(rdev, "dt unaware of over-voltage protection!\n");
+ rdev->constraints->over_voltage_detection = 1;
+ }
+ if (!rdev->constraints->under_voltage_detection &&
+ (monitor_state & REGULATOR_MONITOR_UNDER_VOLTAGE)) {
+ rdev_warn(rdev, "dt unaware of under-voltage protection!\n");
+ rdev->constraints->under_voltage_detection = 1;
+ }
+ }
+
/* set initial monitor state to current regulator state. */
ret = _regulator_is_enabled(rdev);
if (ret >= 0) {
@@ -3516,6 +3544,15 @@ static int _regulator_call_set_voltage(struct regulator_dev *rdev,
if (ret & NOTIFY_STOP_MASK)
return -EINVAL;

+ if ((rdev->desc->mon_disable_reg_set_higher &&
+ (min_uV > data.old_uV || max_uV > data.old_uV)) ||
+ (rdev->desc->mon_disable_reg_set_lower &&
+ (min_uV < data.old_uV || max_uV < data.old_uV))) {
+ ret = monitors_set_state(rdev, false);
+ if (ret)
+ return ret;
+ }
+
ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, selector);
if (ret >= 0)
return ret;
@@ -3540,6 +3577,13 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
if (ret & NOTIFY_STOP_MASK)
return -EINVAL;

+ if ((rdev->desc->mon_disable_reg_set_higher && uV > data.old_uV) ||
+ (rdev->desc->mon_disable_reg_set_lower && uV < data.old_uV)) {
+ ret = monitors_set_state(rdev, false);
+ if (ret)
+ return ret;
+ }
+
ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
if (ret >= 0)
return ret;
@@ -3736,6 +3780,15 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
out:
trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);

+ if ((rdev->desc->mon_disable_reg_set_higher || rdev->desc->mon_disable_reg_set_lower) &&
+ _regulator_is_enabled(rdev) > 0) {
+ /* if setting voltage failed, ignore monitoring error. */
+ if (ret)
+ monitors_set_state(rdev, true);
+ else
+ ret = monitors_set_state(rdev, true);
+ }
+
return ret;
}

@@ -4645,7 +4698,24 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode)
if (ret < 0)
goto out;

+ if (mode & rdev->desc->mon_unsupported_reg_modes) {
+ ret = monitors_set_state(rdev, false);
+ if (ret)
+ goto out;
+ }
+
ret = rdev->desc->ops->set_mode(rdev, mode);
+ if (ret) {
+ /* get_mode() is required: regulator_curr_mode should be valid. */
+ if ((regulator_curr_mode & ~rdev->desc->mon_unsupported_reg_modes) &&
+ _regulator_is_enabled(rdev) > 0)
+ monitors_set_state(rdev, true);
+ goto out;
+ }
+
+ if ((mode & ~rdev->desc->mon_unsupported_reg_modes) && _regulator_is_enabled(rdev) > 0)
+ ret = monitors_set_state(rdev, true);
+
out:
regulator_unlock(rdev);
return ret;
@@ -5572,6 +5642,26 @@ regulator_register(struct device *dev,
goto rinse;
}

+ /*
+ * mon_unsupported_reg_modes property requires get_mode() to get the old
+ * state in case a state switch is failing.
+ */
+ if (regulator_desc->mon_unsupported_reg_modes &&
+ !regulator_desc->ops->get_mode) {
+ ret = -EINVAL;
+ goto rinse;
+ }
+ /*
+ * mon_disable_reg_set_* property requires get_active_protections() to
+ * know if a regulator is monitored without the device-tree knowing it.
+ */
+ if ((regulator_desc->mon_disable_reg_set_higher ||
+ regulator_desc->mon_disable_reg_set_lower) &&
+ !regulator_desc->ops->get_active_protections) {
+ ret = -EINVAL;
+ goto rinse;
+ }
+
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev == NULL) {
ret = -ENOMEM;
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 35547e9eca48..bf42a5f452c5 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -366,6 +366,15 @@ enum regulator_type {
* the regulator was actually enabled. Max upto enable_time.
*
* @of_map_mode: Maps a hardware mode defined in a DeviceTree to a standard mode
+ *
+ * @mon_disable_reg_set_higher: Disables regulator's monitors while it is
+ * changing its value to a higher one.
+ * @mon_disable_reg_set_lower: Disables regulator's monitors while it is
+ * changing its value to a lower one.
+ * @mon_unsupported_reg_modes: Disables regulator's monitors before an
+ * unsupported mode is entered. REGULATOR_MODE_* are
+ * OR'ed. REGULATOR_MODE_INVALID means all modes can
+ * be monitored.
*/
struct regulator_desc {
const char *name;
@@ -440,6 +449,10 @@ struct regulator_desc {
unsigned int poll_enabled_time;

unsigned int (*of_map_mode)(unsigned int mode);
+
+ unsigned int mon_disable_reg_set_higher;
+ unsigned int mon_disable_reg_set_lower;
+ unsigned int mon_unsupported_reg_modes;
};

/**

--
2.34.1


2023-05-21 12:35:14

by Benjamin Bara

[permalink] [raw]
Subject: [PATCH RFC v3 5/5] regulator: bd718x7: let the core handle the monitors

From: Benjamin Bara <[email protected]>

The monitors of the bd718x7 must be disabled while the respective
regulator is switching to a higher voltage. Use the new property
'.mon_disable_reg_set_higher' to activate the handling in the core.

.mon_disable_reg_set_higher requires get_active_protections() to find
out if a regulator is monitored without the device-tree knowing it.
Otherwise, this might lead to a failure as the core might not be aware
that a regulator is monitored and therefore would not disable it.
Therefore, implement it.

Signed-off-by: Benjamin Bara <[email protected]>
---
drivers/regulator/bd718x7-regulator.c | 206 +++++++++++-----------------------
1 file changed, 66 insertions(+), 140 deletions(-)

diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index b0b9938c20a1..897388d68949 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -56,7 +56,7 @@

#define BD718XX_OPS(name, _list_voltage, _map_voltage, _set_voltage_sel, \
_get_voltage_sel, _set_voltage_time_sel, _set_ramp_delay, \
- _set_uvp, _set_ovp) \
+ _set_uvp, _set_ovp, _get_prot) \
static const struct regulator_ops name = { \
.enable = regulator_enable_regmap, \
.disable = regulator_disable_regmap, \
@@ -69,6 +69,7 @@ static const struct regulator_ops name = { \
.set_ramp_delay = (_set_ramp_delay), \
.set_under_voltage_protection = (_set_uvp), \
.set_over_voltage_protection = (_set_ovp), \
+ .get_active_protections = (_get_prot), \
}; \
\
static const struct regulator_ops BD718XX_HWOPNAME(name) = { \
@@ -81,6 +82,7 @@ static const struct regulator_ops BD718XX_HWOPNAME(name) = { \
.set_ramp_delay = (_set_ramp_delay), \
.set_under_voltage_protection = (_set_uvp), \
.set_over_voltage_protection = (_set_ovp), \
+ .get_active_protections = (_get_prot), \
} \

/*
@@ -126,128 +128,6 @@ static int bd71837_get_buck34_enable_hwctrl(struct regulator_dev *rdev)
return !!(BD718XX_BUCK_RUN_ON & val);
}

-static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel,
- unsigned int *mask)
-{
- int ret;
-
- if (*mask) {
- /*
- * Let's allow scheduling as we use I2C anyways. We just need to
- * guarantee minimum of 1ms sleep - it shouldn't matter if we
- * exceed it due to the scheduling.
- */
- msleep(1);
-
- ret = regmap_clear_bits(rdev->regmap, BD718XX_REG_MVRFLTMASK2,
- *mask);
- if (ret)
- dev_err(&rdev->dev,
- "Failed to re-enable voltage monitoring (%d)\n",
- ret);
- }
-}
-
-static int voltage_change_prepare(struct regulator_dev *rdev, unsigned int sel,
- unsigned int *mask)
-{
- int ret;
-
- *mask = 0;
- if (rdev->desc->ops->is_enabled(rdev)) {
- int now, new;
-
- now = rdev->desc->ops->get_voltage_sel(rdev);
- if (now < 0)
- return now;
-
- now = rdev->desc->ops->list_voltage(rdev, now);
- if (now < 0)
- return now;
-
- new = rdev->desc->ops->list_voltage(rdev, sel);
- if (new < 0)
- return new;
-
- /*
- * If we increase LDO voltage when LDO is enabled we need to
- * disable the power-good detection until voltage has reached
- * the new level. According to HW colleagues the maximum time
- * it takes is 1000us. I assume that on systems with light load
- * this might be less - and we could probably use DT to give
- * system specific delay value if performance matters.
- *
- * Well, knowing we use I2C here and can add scheduling delays
- * I don't think it is worth the hassle and I just add fixed
- * 1ms sleep here (and allow scheduling). If this turns out to
- * be a problem we can change it to delay and make the delay
- * time configurable.
- */
- if (new > now) {
- int tmp;
- int prot_bit;
- int ldo_offset = rdev->desc->id - BD718XX_LDO1;
-
- prot_bit = BD718XX_LDO1_VRMON80 << ldo_offset;
- ret = regmap_read(rdev->regmap, BD718XX_REG_MVRFLTMASK2,
- &tmp);
- if (ret) {
- dev_err(&rdev->dev,
- "Failed to read voltage monitoring state\n");
- return ret;
- }
-
- if (!(tmp & prot_bit)) {
- /* We disable protection if it was enabled... */
- ret = regmap_set_bits(rdev->regmap,
- BD718XX_REG_MVRFLTMASK2,
- prot_bit);
- /* ...and we also want to re-enable it */
- *mask = prot_bit;
- }
- if (ret) {
- dev_err(&rdev->dev,
- "Failed to stop voltage monitoring\n");
- return ret;
- }
- }
- }
-
- return 0;
-}
-
-static int bd718xx_set_voltage_sel_restricted(struct regulator_dev *rdev,
- unsigned int sel)
-{
- int ret;
- int mask;
-
- ret = voltage_change_prepare(rdev, sel, &mask);
- if (ret)
- return ret;
-
- ret = regulator_set_voltage_sel_regmap(rdev, sel);
- voltage_change_done(rdev, sel, &mask);
-
- return ret;
-}
-
-static int bd718xx_set_voltage_sel_pickable_restricted(
- struct regulator_dev *rdev, unsigned int sel)
-{
- int ret;
- int mask;
-
- ret = voltage_change_prepare(rdev, sel, &mask);
- if (ret)
- return ret;
-
- ret = regulator_set_voltage_sel_pickable_regmap(rdev, sel);
- voltage_change_done(rdev, sel, &mask);
-
- return ret;
-}
-
static int bd71837_set_voltage_sel_pickable_restricted(
struct regulator_dev *rdev, unsigned int sel)
{
@@ -457,6 +337,21 @@ static int bd718x7_xvp_sanity_check(struct regulator_dev *rdev, int lim_uV,
return 0;
}

+static int bd717x7_get_ldo_prot(struct regulator_dev *rdev, unsigned int *val)
+{
+ int ldo_offset = rdev->desc->id - BD718XX_LDO1;
+ int prot_bit = BD718XX_LDO1_VRMON80 << ldo_offset;
+ int ret;
+
+ ret = regmap_test_bits(rdev->regmap, BD718XX_REG_MVRFLTMASK2, prot_bit);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ *val |= REGULATOR_MONITOR_UNDER_VOLTAGE;
+
+ return 0;
+}
+
static int bd718x7_set_ldo_uvp(struct regulator_dev *rdev, int lim_uV,
int severity, bool enable)
{
@@ -519,6 +414,31 @@ static int bd718x7_get_buck_uvp_info(int id, int *reg, int *bit)
return 0;
}

+static int bd717x7_get_buck_prot(struct regulator_dev *rdev, unsigned int *val)
+{
+ int ret, reg, bit;
+
+ ret = bd718x7_get_buck_uvp_info(rdev->desc->id, &reg, &bit);
+ if (ret)
+ return ret;
+ ret = regmap_test_bits(rdev->regmap, reg, bit);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ *val |= REGULATOR_MONITOR_UNDER_VOLTAGE;
+
+ ret = bd718x7_get_buck_ovp_info(rdev->desc->id, &reg, &bit);
+ if (ret)
+ return ret;
+ ret = regmap_test_bits(rdev->regmap, reg, bit);
+ if (ret < 0)
+ return ret;
+ if (ret)
+ *val |= REGULATOR_MONITOR_OVER_VOLTAGE;
+
+ return 0;
+}
+
static int bd718x7_set_buck_uvp(struct regulator_dev *rdev, int lim_uV,
int severity, bool enable)
{
@@ -564,15 +484,15 @@ static int bd718x7_set_buck_ovp(struct regulator_dev *rdev, int lim_uV,
*/
BD718XX_OPS(bd718xx_pickable_range_ldo_ops,
regulator_list_voltage_pickable_linear_range, NULL,
- bd718xx_set_voltage_sel_pickable_restricted,
+ regulator_set_voltage_sel_pickable_regmap,
regulator_get_voltage_sel_pickable_regmap, NULL, NULL,
- bd718x7_set_ldo_uvp, NULL);
+ bd718x7_set_ldo_uvp, NULL, bd717x7_get_ldo_prot);

/* BD71847 and BD71850 LDO 5 is by default OFF at RUN state */
static const struct regulator_ops bd718xx_ldo5_ops_hwstate = {
.is_enabled = never_enabled_by_hwstate,
.list_voltage = regulator_list_voltage_pickable_linear_range,
- .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
+ .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
.set_under_voltage_protection = bd718x7_set_ldo_uvp,
};
@@ -582,27 +502,27 @@ BD718XX_OPS(bd718xx_pickable_range_buck_ops,
regulator_set_voltage_sel_pickable_regmap,
regulator_get_voltage_sel_pickable_regmap,
regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp,
- bd718x7_set_buck_ovp);
+ bd718x7_set_buck_ovp, bd717x7_get_buck_prot);

BD718XX_OPS(bd718xx_ldo_regulator_ops, regulator_list_voltage_linear_range,
- NULL, bd718xx_set_voltage_sel_restricted,
+ NULL, regulator_set_voltage_sel_regmap,
regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
- NULL);
+ NULL, bd717x7_get_ldo_prot);

BD718XX_OPS(bd718xx_ldo_regulator_nolinear_ops, regulator_list_voltage_table,
- NULL, bd718xx_set_voltage_sel_restricted,
+ NULL, regulator_set_voltage_sel_regmap,
regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
- NULL);
+ NULL, bd717x7_get_ldo_prot);

BD718XX_OPS(bd718xx_buck_regulator_ops, regulator_list_voltage_linear_range,
NULL, regulator_set_voltage_sel_regmap,
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
- NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
+ NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp, bd717x7_get_buck_prot);

BD718XX_OPS(bd718xx_buck_regulator_nolinear_ops, regulator_list_voltage_table,
regulator_map_voltage_ascend, regulator_set_voltage_sel_regmap,
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
- NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
+ NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp, bd717x7_get_buck_prot);

/*
* OPS for BD71837
@@ -611,34 +531,34 @@ BD718XX_OPS(bd71837_pickable_range_ldo_ops,
regulator_list_voltage_pickable_linear_range, NULL,
bd71837_set_voltage_sel_pickable_restricted,
regulator_get_voltage_sel_pickable_regmap, NULL, NULL,
- bd718x7_set_ldo_uvp, NULL);
+ bd718x7_set_ldo_uvp, NULL, bd717x7_get_ldo_prot);

BD718XX_OPS(bd71837_pickable_range_buck_ops,
regulator_list_voltage_pickable_linear_range, NULL,
bd71837_set_voltage_sel_pickable_restricted,
regulator_get_voltage_sel_pickable_regmap,
regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp,
- bd718x7_set_buck_ovp);
+ bd718x7_set_buck_ovp, bd717x7_get_buck_prot);

BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range,
NULL, rohm_regulator_set_voltage_sel_restricted,
regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
- NULL);
+ NULL, bd717x7_get_ldo_prot);

BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table,
NULL, rohm_regulator_set_voltage_sel_restricted,
regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp,
- NULL);
+ NULL, bd717x7_get_ldo_prot);

BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range,
NULL, rohm_regulator_set_voltage_sel_restricted,
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
- NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
+ NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp, bd717x7_get_buck_prot);

BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table,
regulator_map_voltage_ascend, rohm_regulator_set_voltage_sel_restricted,
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
- NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp);
+ NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp, bd717x7_get_buck_prot);
/*
* BD71837 bucks 3 and 4 support defining their enable/disable state also
* when buck enable state is under HW state machine control. In that case the
@@ -662,7 +582,7 @@ BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range,
NULL, regulator_set_voltage_sel_regmap,
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
regulator_set_ramp_delay_regmap, bd718x7_set_buck_uvp,
- bd718x7_set_buck_ovp);
+ bd718x7_set_buck_ovp, bd717x7_get_buck_prot);



@@ -1772,6 +1692,12 @@ static int bd718xx_probe(struct platform_device *pdev)
else
desc->ops = swops[i];

+ /*
+ * bd718x7 requires to disable a regulator's monitors while it
+ * changes to a higher value.
+ */
+ desc->mon_disable_reg_set_higher = 1;
+
rdev = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(rdev))
return dev_err_probe(&pdev->dev, PTR_ERR(rdev),

--
2.34.1


2023-05-21 12:37:08

by Benjamin Bara

[permalink] [raw]
Subject: [PATCH RFC v3 3/5] regulator: add getter for active monitors

From: Benjamin Bara <[email protected]>

Add an op to get all active monitors of a regulator.

Signed-off-by: Benjamin Bara <[email protected]>
---
include/linux/regulator/driver.h | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index d3b4a3d4514a..35547e9eca48 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -25,6 +25,12 @@ struct regulator_config;
struct regulator_init_data;
struct regulator_enable_gpio;

+#define REGULATOR_MONITOR_INVALID 0x0
+#define REGULATOR_MONITOR_OVER_CURRENT 0x1
+#define REGULATOR_MONITOR_OVER_VOLTAGE 0x2
+#define REGULATOR_MONITOR_UNDER_VOLTAGE 0x4
+#define REGULATOR_MONITOR_OVER_TEMPERATURE 0x8
+
enum regulator_status {
REGULATOR_STATUS_OFF,
REGULATOR_STATUS_ON,
@@ -112,6 +118,8 @@ enum regulator_detection_severity {
* @set_thermal_protection: Support enabling of and setting limits for over
* temperature situation detection.Detection can be configured for same
* severities as over current protection. Units of degree Kelvin.
+ * @get_active_protections: Get all enabled monitors of a regulator. OR'ed val
+ * of REGULATOR_MONITOR_*. REGULATOR_MONITOR_INVALID means no one active.
*
* @set_active_discharge: Set active discharge enable/disable of regulators.
*
@@ -183,6 +191,7 @@ struct regulator_ops {
int severity, bool enable);
int (*set_thermal_protection)(struct regulator_dev *, int lim,
int severity, bool enable);
+ int (*get_active_protections)(struct regulator_dev *dev, unsigned int *state);
int (*set_active_discharge)(struct regulator_dev *, bool enable);

/* enable/disable regulator */

--
2.34.1