Skip to content

Commit f404525

Browse files
jbrun3tgroeck
authored andcommitted
hwmon: (pmbus/core) improve handling of write protected regulators
Writing PMBus protected registers does succeed from the smbus perspective, even if the write is ignored by the device and a communication fault is raised. This fault will silently be caught and cleared by pmbus irq if one has been registered. This means that the regulator call may return succeed although the operation was ignored. With this change, the operation which are not supported will be properly flagged as such and the regulator framework won't even try to execute them. Signed-off-by: Jerome Brunet <[email protected]> [groeck: Adjust to EXPORT_SYMBOL_NS_GPL API change] Signed-off-by: Guenter Roeck <[email protected]>
1 parent c26eef8 commit f404525

File tree

4 files changed

+78
-6
lines changed

4 files changed

+78
-6
lines changed

Documentation/hwmon/pmbus-core.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ currently provides a flags field with four bits used::
312312

313313
#define PMBUS_USE_COEFFICIENTS_CMD BIT(5)
314314

315+
#define PMBUS_OP_PROTECTED BIT(6)
316+
317+
#define PMBUS_VOUT_PROTECTED BIT(7)
318+
315319
struct pmbus_platform_data {
316320
u32 flags; /* Device specific flags */
317321

@@ -373,3 +377,13 @@ PMBUS_USE_COEFFICIENTS_CMD
373377

374378
When this flag is set the PMBus core driver will use the COEFFICIENTS
375379
register to initialize the coefficients for the direct mode format.
380+
381+
PMBUS_OP_PROTECTED
382+
383+
Set if the chip OPERATION command is protected and protection is not
384+
determined by the standard WRITE_PROTECT command.
385+
386+
PMBUS_VOUT_PROTECTED
387+
388+
Set if the chip VOUT_COMMAND command is protected and protection is not
389+
determined by the standard WRITE_PROTECT command.

drivers/hwmon/pmbus/pmbus.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,8 @@ struct pmbus_driver_info {
487487
/* Regulator ops */
488488

489489
extern const struct regulator_ops pmbus_regulator_ops;
490+
int pmbus_regulator_init_cb(struct regulator_dev *rdev,
491+
struct regulator_config *config);
490492

491493
/* Macros for filling in array of struct regulator_desc */
492494
#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step, _min_uV) \
@@ -501,6 +503,7 @@ extern const struct regulator_ops pmbus_regulator_ops;
501503
.n_voltages = _voltages, \
502504
.uV_step = _step, \
503505
.min_uV = _min_uV, \
506+
.init_cb = pmbus_regulator_init_cb, \
504507
}
505508

506509
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0)
@@ -516,6 +519,7 @@ extern const struct regulator_ops pmbus_regulator_ops;
516519
.n_voltages = _voltages, \
517520
.uV_step = _step, \
518521
.min_uV = _min_uV, \
522+
.init_cb = pmbus_regulator_init_cb, \
519523
}
520524

521525
#define PMBUS_REGULATOR_ONE(_name) PMBUS_REGULATOR_STEP_ONE(_name, 0, 0, 0)

drivers/hwmon/pmbus/pmbus_core.c

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,6 +2665,30 @@ static void pmbus_remove_pec(void *dev)
26652665
device_remove_file(dev, &dev_attr_pec);
26662666
}
26672667

2668+
static void pmbus_init_wp(struct i2c_client *client, struct pmbus_data *data)
2669+
{
2670+
int ret;
2671+
2672+
ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT);
2673+
if (ret < 0)
2674+
return;
2675+
2676+
switch (ret & PB_WP_ANY) {
2677+
case PB_WP_ALL:
2678+
data->flags |= PMBUS_OP_PROTECTED;
2679+
fallthrough;
2680+
case PB_WP_OP:
2681+
data->flags |= PMBUS_VOUT_PROTECTED;
2682+
fallthrough;
2683+
case PB_WP_VOUT:
2684+
data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
2685+
break;
2686+
2687+
default:
2688+
break;
2689+
}
2690+
}
2691+
26682692
static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
26692693
struct pmbus_driver_info *info)
26702694
{
@@ -2718,12 +2742,8 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
27182742
* faults, and we should not try it. Also, in that case, writes into
27192743
* limit registers need to be disabled.
27202744
*/
2721-
if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) {
2722-
ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT);
2723-
2724-
if (ret > 0 && (ret & PB_WP_ANY))
2725-
data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
2726-
}
2745+
if (!(data->flags & PMBUS_NO_WRITE_PROTECT))
2746+
pmbus_init_wp(client, data);
27272747

27282748
ret = i2c_smbus_read_byte_data(client, PMBUS_REVISION);
27292749
if (ret >= 0)
@@ -3183,8 +3203,12 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
31833203
{
31843204
struct device *dev = rdev_get_dev(rdev);
31853205
struct i2c_client *client = to_i2c_client(dev->parent);
3206+
struct pmbus_data *data = i2c_get_clientdata(client);
31863207
int val, low, high;
31873208

3209+
if (data->flags & PMBUS_VOUT_PROTECTED)
3210+
return 0;
3211+
31883212
if (selector >= rdev->desc->n_voltages ||
31893213
selector < rdev->desc->linear_min_sel)
31903214
return -EINVAL;
@@ -3219,6 +3243,22 @@ const struct regulator_ops pmbus_regulator_ops = {
32193243
};
32203244
EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, "PMBUS");
32213245

3246+
int pmbus_regulator_init_cb(struct regulator_dev *rdev,
3247+
struct regulator_config *config)
3248+
{
3249+
struct pmbus_data *data = config->driver_data;
3250+
struct regulation_constraints *constraints = rdev->constraints;
3251+
3252+
if (data->flags & PMBUS_OP_PROTECTED)
3253+
constraints->valid_ops_mask &= ~REGULATOR_CHANGE_STATUS;
3254+
3255+
if (data->flags & PMBUS_VOUT_PROTECTED)
3256+
constraints->valid_ops_mask &= ~REGULATOR_CHANGE_VOLTAGE;
3257+
3258+
return 0;
3259+
}
3260+
EXPORT_SYMBOL_NS_GPL(pmbus_regulator_init_cb, "PMBUS");
3261+
32223262
static int pmbus_regulator_register(struct pmbus_data *data)
32233263
{
32243264
struct device *dev = data->dev;

include/linux/pmbus.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@
7373
*/
7474
#define PMBUS_USE_COEFFICIENTS_CMD BIT(5)
7575

76+
/*
77+
* PMBUS_OP_PROTECTED
78+
* Set if the chip OPERATION command is protected and protection is not
79+
* determined by the standard WRITE_PROTECT command.
80+
*/
81+
#define PMBUS_OP_PROTECTED BIT(6)
82+
83+
/*
84+
* PMBUS_VOUT_PROTECTED
85+
* Set if the chip VOUT_COMMAND command is protected and protection is not
86+
* determined by the standard WRITE_PROTECT command.
87+
*/
88+
#define PMBUS_VOUT_PROTECTED BIT(7)
89+
7690
struct pmbus_platform_data {
7791
u32 flags; /* Device specific flags */
7892

0 commit comments

Comments
 (0)