Skip to content

Commit 89a6a5e

Browse files
M-Vaittinenbroonie
authored andcommitted
regulator: add property parsing and callbacks to set protection limits
Add DT property parsing code and setting callback for regulator over/under voltage, over-current and temperature error limits. Signed-off-by: Matti Vaittinen <[email protected]> Link: https://lore.kernel.org/r/e7b8007ba9eae7076178bf3363fb942ccb1cc9a5.1622628334.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Mark Brown <[email protected]>
1 parent 7111c6d commit 89a6a5e

File tree

7 files changed

+274
-9
lines changed

7 files changed

+274
-9
lines changed

drivers/regulator/core.c

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,52 @@ static int machine_constraints_current(struct regulator_dev *rdev,
13051305

13061306
static int _regulator_do_enable(struct regulator_dev *rdev);
13071307

1308+
static int notif_set_limit(struct regulator_dev *rdev,
1309+
int (*set)(struct regulator_dev *, int, int, bool),
1310+
int limit, int severity)
1311+
{
1312+
bool enable;
1313+
1314+
if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
1315+
enable = false;
1316+
limit = 0;
1317+
} else {
1318+
enable = true;
1319+
}
1320+
1321+
if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
1322+
limit = 0;
1323+
1324+
return set(rdev, limit, severity, enable);
1325+
}
1326+
1327+
static int handle_notify_limits(struct regulator_dev *rdev,
1328+
int (*set)(struct regulator_dev *, int, int, bool),
1329+
struct notification_limit *limits)
1330+
{
1331+
int ret = 0;
1332+
1333+
if (!set)
1334+
return -EOPNOTSUPP;
1335+
1336+
if (limits->prot)
1337+
ret = notif_set_limit(rdev, set, limits->prot,
1338+
REGULATOR_SEVERITY_PROT);
1339+
if (ret)
1340+
return ret;
1341+
1342+
if (limits->err)
1343+
ret = notif_set_limit(rdev, set, limits->err,
1344+
REGULATOR_SEVERITY_ERR);
1345+
if (ret)
1346+
return ret;
1347+
1348+
if (limits->warn)
1349+
ret = notif_set_limit(rdev, set, limits->warn,
1350+
REGULATOR_SEVERITY_WARN);
1351+
1352+
return ret;
1353+
}
13081354
/**
13091355
* set_machine_constraints - sets regulator constraints
13101356
* @rdev: regulator source
@@ -1390,16 +1436,90 @@ static int set_machine_constraints(struct regulator_dev *rdev)
13901436
}
13911437
}
13921438

1439+
/*
1440+
* Existing logic does not warn if over_current_protection is given as
1441+
* a constraint but driver does not support that. I think we should
1442+
* warn about this type of issues as it is possible someone changes
1443+
* PMIC on board to another type - and the another PMIC's driver does
1444+
* not support setting protection. Board composer may happily believe
1445+
* the DT limits are respected - especially if the new PMIC HW also
1446+
* supports protection but the driver does not. I won't change the logic
1447+
* without hearing more experienced opinion on this though.
1448+
*
1449+
* If warning is seen as a good idea then we can merge handling the
1450+
* over-curret protection and detection and get rid of this special
1451+
* handling.
1452+
*/
13931453
if (rdev->constraints->over_current_protection
13941454
&& ops->set_over_current_protection) {
1395-
ret = ops->set_over_current_protection(rdev);
1455+
int lim = rdev->constraints->over_curr_limits.prot;
1456+
1457+
ret = ops->set_over_current_protection(rdev, lim,
1458+
REGULATOR_SEVERITY_PROT,
1459+
true);
13961460
if (ret < 0) {
13971461
rdev_err(rdev, "failed to set over current protection: %pe\n",
13981462
ERR_PTR(ret));
13991463
return ret;
14001464
}
14011465
}
14021466

1467+
if (rdev->constraints->over_current_detection)
1468+
ret = handle_notify_limits(rdev,
1469+
ops->set_over_current_protection,
1470+
&rdev->constraints->over_curr_limits);
1471+
if (ret) {
1472+
if (ret != -EOPNOTSUPP) {
1473+
rdev_err(rdev, "failed to set over current limits: %pe\n",
1474+
ERR_PTR(ret));
1475+
return ret;
1476+
}
1477+
rdev_warn(rdev,
1478+
"IC does not support requested over-current limits\n");
1479+
}
1480+
1481+
if (rdev->constraints->over_voltage_detection)
1482+
ret = handle_notify_limits(rdev,
1483+
ops->set_over_voltage_protection,
1484+
&rdev->constraints->over_voltage_limits);
1485+
if (ret) {
1486+
if (ret != -EOPNOTSUPP) {
1487+
rdev_err(rdev, "failed to set over voltage limits %pe\n",
1488+
ERR_PTR(ret));
1489+
return ret;
1490+
}
1491+
rdev_warn(rdev,
1492+
"IC does not support requested over voltage limits\n");
1493+
}
1494+
1495+
if (rdev->constraints->under_voltage_detection)
1496+
ret = handle_notify_limits(rdev,
1497+
ops->set_under_voltage_protection,
1498+
&rdev->constraints->under_voltage_limits);
1499+
if (ret) {
1500+
if (ret != -EOPNOTSUPP) {
1501+
rdev_err(rdev, "failed to set under voltage limits %pe\n",
1502+
ERR_PTR(ret));
1503+
return ret;
1504+
}
1505+
rdev_warn(rdev,
1506+
"IC does not support requested under voltage limits\n");
1507+
}
1508+
1509+
if (rdev->constraints->over_temp_detection)
1510+
ret = handle_notify_limits(rdev,
1511+
ops->set_thermal_protection,
1512+
&rdev->constraints->temp_limits);
1513+
if (ret) {
1514+
if (ret != -EOPNOTSUPP) {
1515+
rdev_err(rdev, "failed to set temperature limits %pe\n",
1516+
ERR_PTR(ret));
1517+
return ret;
1518+
}
1519+
rdev_warn(rdev,
1520+
"IC does not support requested temperature limits\n");
1521+
}
1522+
14031523
if (rdev->constraints->active_discharge && ops->set_active_discharge) {
14041524
bool ad_state = (rdev->constraints->active_discharge ==
14051525
REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false;

drivers/regulator/of_regulator.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,62 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
2121
[PM_SUSPEND_MAX] = "regulator-state-disk",
2222
};
2323

24+
static void fill_limit(int *limit, int val)
25+
{
26+
if (val)
27+
if (val == 1)
28+
*limit = REGULATOR_NOTIF_LIMIT_ENABLE;
29+
else
30+
*limit = val;
31+
else
32+
*limit = REGULATOR_NOTIF_LIMIT_DISABLE;
33+
}
34+
35+
static void of_get_regulator_prot_limits(struct device_node *np,
36+
struct regulation_constraints *constraints)
37+
{
38+
u32 pval;
39+
int i;
40+
static const char *const props[] = {
41+
"regulator-oc-%s-microamp",
42+
"regulator-ov-%s-microvolt",
43+
"regulator-temp-%s-kelvin",
44+
"regulator-uv-%s-microvolt",
45+
};
46+
struct notification_limit *limits[] = {
47+
&constraints->over_curr_limits,
48+
&constraints->over_voltage_limits,
49+
&constraints->temp_limits,
50+
&constraints->under_voltage_limits,
51+
};
52+
bool set[4] = {0};
53+
54+
/* Protection limits: */
55+
for (i = 0; i < ARRAY_SIZE(props); i++) {
56+
char prop[255];
57+
bool found;
58+
int j;
59+
static const char *const lvl[] = {
60+
"protection", "error", "warn"
61+
};
62+
int *l[] = {
63+
&limits[i]->prot, &limits[i]->err, &limits[i]->warn,
64+
};
65+
66+
for (j = 0; j < ARRAY_SIZE(lvl); j++) {
67+
snprintf(prop, 255, props[i], lvl[j]);
68+
found = !of_property_read_u32(np, prop, &pval);
69+
if (found)
70+
fill_limit(l[j], pval);
71+
set[i] |= found;
72+
}
73+
}
74+
constraints->over_current_detection = set[0];
75+
constraints->over_voltage_detection = set[1];
76+
constraints->over_temp_detection = set[2];
77+
constraints->under_voltage_detection = set[3];
78+
}
79+
2480
static int of_get_regulation_constraints(struct device *dev,
2581
struct device_node *np,
2682
struct regulator_init_data **init_data,
@@ -188,6 +244,8 @@ static int of_get_regulation_constraints(struct device *dev,
188244
constraints->over_current_protection = of_property_read_bool(np,
189245
"regulator-over-current-protection");
190246

247+
of_get_regulator_prot_limits(np, constraints);
248+
191249
for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
192250
switch (i) {
193251
case PM_SUSPEND_MEM:

drivers/regulator/qcom-labibb-regulator.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,13 +307,21 @@ static irqreturn_t qcom_labibb_ocp_isr(int irq, void *chip)
307307
return IRQ_HANDLED;
308308
}
309309

310-
static int qcom_labibb_set_ocp(struct regulator_dev *rdev)
310+
static int qcom_labibb_set_ocp(struct regulator_dev *rdev, int lim,
311+
int severity, bool enable)
311312
{
312313
struct labibb_regulator *vreg = rdev_get_drvdata(rdev);
313314
char *ocp_irq_name;
314315
u32 irq_flags = IRQF_ONESHOT;
315316
int irq_trig_low, ret;
316317

318+
/*
319+
* labibb supports only protection - and does not support setting
320+
* limit. Furthermore, we don't support disabling protection.
321+
*/
322+
if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
323+
return -EINVAL;
324+
317325
/* If there is no OCP interrupt, there's nothing to set */
318326
if (vreg->ocp_irq <= 0)
319327
return -EINVAL;

drivers/regulator/qcom_spmi-regulator.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,11 +595,15 @@ static int spmi_regulator_vs_enable(struct regulator_dev *rdev)
595595
return regulator_enable_regmap(rdev);
596596
}
597597

598-
static int spmi_regulator_vs_ocp(struct regulator_dev *rdev)
598+
static int spmi_regulator_vs_ocp(struct regulator_dev *rdev, int lim_uA,
599+
int severity, bool enable)
599600
{
600601
struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
601602
u8 reg = SPMI_VS_OCP_OVERRIDE;
602603

604+
if (lim_uA || !enable || severity != REGULATOR_SEVERITY_PROT)
605+
return -EINVAL;
606+
603607
return spmi_vreg_write(vreg, SPMI_VS_REG_OCP, &reg, 1);
604608
}
605609

drivers/regulator/stpmic1_regulator.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ struct stpmic1_regulator_cfg {
3232

3333
static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode);
3434
static unsigned int stpmic1_get_mode(struct regulator_dev *rdev);
35-
static int stpmic1_set_icc(struct regulator_dev *rdev);
35+
static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity,
36+
bool enable);
3637
static unsigned int stpmic1_map_mode(unsigned int mode);
3738

3839
enum {
@@ -491,11 +492,26 @@ static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode)
491492
STPMIC1_BUCK_MODE_LP, value);
492493
}
493494

494-
static int stpmic1_set_icc(struct regulator_dev *rdev)
495+
static int stpmic1_set_icc(struct regulator_dev *rdev, int lim, int severity,
496+
bool enable)
495497
{
496498
struct stpmic1_regulator_cfg *cfg = rdev_get_drvdata(rdev);
497499
struct regmap *regmap = rdev_get_regmap(rdev);
498500

501+
/*
502+
* The code seems like one bit in a register controls whether OCP is
503+
* enabled. So we might be able to turn it off here is if that
504+
* was requested. I won't support this because I don't have the HW.
505+
* Feel free to try and implement if you have the HW and need kernel
506+
* to disable this.
507+
*
508+
* Also, I don't know if limit can be configured or if we support
509+
* error/warning instead of protect. So I just keep existing logic
510+
* and assume no.
511+
*/
512+
if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
513+
return -EINVAL;
514+
499515
/* enable switch off in case of over current */
500516
return regmap_update_bits(regmap, cfg->icc_reg, cfg->icc_mask,
501517
cfg->icc_mask);

include/linux/regulator/driver.h

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ enum regulator_status {
4040
REGULATOR_STATUS_UNDEFINED,
4141
};
4242

43+
enum regulator_detection_severity {
44+
/* Hardware shut down voltage outputs if condition is detected */
45+
REGULATOR_SEVERITY_PROT,
46+
/* Hardware is probably damaged/inoperable */
47+
REGULATOR_SEVERITY_ERR,
48+
/* Hardware is still recoverable but recovery action must be taken */
49+
REGULATOR_SEVERITY_WARN,
50+
};
51+
4352
/* Initialize struct linear_range for regulators */
4453
#define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV) \
4554
{ \
@@ -78,8 +87,25 @@ enum regulator_status {
7887
* @get_current_limit: Get the configured limit for a current-limited regulator.
7988
* @set_input_current_limit: Configure an input limit.
8089
*
81-
* @set_over_current_protection: Support capability of automatically shutting
82-
* down when detecting an over current event.
90+
* @set_over_current_protection: Support enabling of and setting limits for over
91+
* current situation detection. Detection can be configured for three
92+
* levels of severity.
93+
* REGULATOR_SEVERITY_PROT should automatically shut down the regulator(s).
94+
* REGULATOR_SEVERITY_ERR should indicate that over-current situation is
95+
* caused by an unrecoverable error but HW does not perform
96+
* automatic shut down.
97+
* REGULATOR_SEVERITY_WARN should indicate situation where hardware is
98+
* still believed to not be damaged but that a board sepcific
99+
* recovery action is needed. If lim_uA is 0 the limit should not
100+
* be changed but the detection should just be enabled/disabled as
101+
* is requested.
102+
* @set_over_voltage_protection: Support enabling of and setting limits for over
103+
* voltage situation detection. Detection can be configured for same
104+
* severities as over current protection.
105+
* @set_under_voltage_protection: Support enabling of and setting limits for
106+
* under situation detection.
107+
* @set_thermal_protection: Support enabling of and setting limits for over
108+
* temperature situation detection.
83109
*
84110
* @set_active_discharge: Set active discharge enable/disable of regulators.
85111
*
@@ -143,8 +169,15 @@ struct regulator_ops {
143169
int (*get_current_limit) (struct regulator_dev *);
144170

145171
int (*set_input_current_limit) (struct regulator_dev *, int lim_uA);
146-
int (*set_over_current_protection) (struct regulator_dev *);
147-
int (*set_active_discharge) (struct regulator_dev *, bool enable);
172+
int (*set_over_current_protection)(struct regulator_dev *, int lim_uA,
173+
int severity, bool enable);
174+
int (*set_over_voltage_protection)(struct regulator_dev *, int lim_uV,
175+
int severity, bool enable);
176+
int (*set_under_voltage_protection)(struct regulator_dev *, int lim_uV,
177+
int severity, bool enable);
178+
int (*set_thermal_protection)(struct regulator_dev *, int lim,
179+
int severity, bool enable);
180+
int (*set_active_discharge)(struct regulator_dev *, bool enable);
148181

149182
/* enable/disable regulator */
150183
int (*enable) (struct regulator_dev *);

0 commit comments

Comments
 (0)