* [PATCH v2 1/4] dt-bindings: vendor-prefixes: Add TDK Corporation
2026-10-20 7:43 [PATCH v2 0/4] hwmon: (pmbus) Support relative VOUT mode, add TDK FS1412 and FS1525 Abdurrahman Hussain
@ 2026-10-20 7:43 ` Abdurrahman Hussain
2026-10-20 8:39 ` sashiko-bot
2026-10-20 7:43 ` [PATCH v2 2/4] dt-bindings: trivial-devices: Add TDK FS1412 and FS1525 Abdurrahman Hussain
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain @ 2026-10-20 7:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Abdurrahman Hussain, Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: Lars Petter Mostad, devicetree, linux-kernel, linux-hwmon,
linux-doc, Krzysztof Kozlowski
Add the vendor prefix for TDK Corporation, the maker of the FS1412
point-of-load regulator.
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index ba2002969373..a7c484d1113b 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -1680,6 +1680,8 @@ patternProperties:
description: Shenzhen City Tang Cheng Technology Co., Ltd.
"^tcu,.*":
description: TC Unterhaltungselektronik AG
+ "^tdk,.*":
+ description: TDK Corporation
"^tdo,.*":
description: Shangai Top Display Optoelectronics Co., Ltd
"^team-source-display,.*":
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 2/4] dt-bindings: trivial-devices: Add TDK FS1412 and FS1525
2026-10-20 7:43 [PATCH v2 0/4] hwmon: (pmbus) Support relative VOUT mode, add TDK FS1412 and FS1525 Abdurrahman Hussain
2026-10-20 7:43 ` [PATCH v2 1/4] dt-bindings: vendor-prefixes: Add TDK Corporation Abdurrahman Hussain
@ 2026-10-20 7:43 ` Abdurrahman Hussain
2026-10-20 8:40 ` sashiko-bot
2026-10-20 7:43 ` [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands Abdurrahman Hussain
2026-10-20 7:43 ` [PATCH v2 4/4] hwmon: (pmbus/fs1412) Add TDK FS1412 and FS1525 driver Abdurrahman Hussain
3 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain @ 2026-10-20 7:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Abdurrahman Hussain, Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: Lars Petter Mostad, devicetree, linux-kernel, linux-hwmon,
linux-doc
The TDK FS1412 and FS1525 are 12A and 25A uPOL regulators with a PMBus
interface. They need only a reg property, so document them as trivial
devices.
Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
Documentation/devicetree/bindings/trivial-devices.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index 2de8eb09cb7d..996e1eab52bb 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -469,6 +469,10 @@ properties:
- synaptics,synaptics_i2c
# Ambient Light Sensor with SMBUS/Two Wire Serial Interface
- taos,tsl2550
+ # TDK FS1412 12A uPOL regulator with PMBus
+ - tdk,fs1412
+ # TDK FS1525 25A uPOL regulator with PMBus
+ - tdk,fs1525
# Digital PWM System Controller PMBus
- ti,cd9200
# Digital PWM System Controller PMBus
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands
2026-10-20 7:43 [PATCH v2 0/4] hwmon: (pmbus) Support relative VOUT mode, add TDK FS1412 and FS1525 Abdurrahman Hussain
2026-10-20 7:43 ` [PATCH v2 1/4] dt-bindings: vendor-prefixes: Add TDK Corporation Abdurrahman Hussain
2026-10-20 7:43 ` [PATCH v2 2/4] dt-bindings: trivial-devices: Add TDK FS1412 and FS1525 Abdurrahman Hussain
@ 2026-10-20 7:43 ` Abdurrahman Hussain
2026-10-20 8:55 ` sashiko-bot
2026-10-20 7:43 ` [PATCH v2 4/4] hwmon: (pmbus/fs1412) Add TDK FS1412 and FS1525 driver Abdurrahman Hussain
3 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain @ 2026-10-20 7:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Abdurrahman Hussain, Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: Lars Petter Mostad, devicetree, linux-kernel, linux-hwmon,
linux-doc
From: Lars Petter Mostad <lars.petter.mostad@appear.net>
PMBus 1.3 allows for relative encoding of voltages in certain output
voltage related commands. These commands are encoded relative to
VOUT_COMMAND. Support this when encoding/decoding commands.
Signed-off-by: Lars Petter Mostad <lars.petter.mostad@appear.net>
[abdurrahman: rebased; check VOUT_MODE for 0xff before testing the
relative bit; use signed division and clamp the user value before
scaling; reject a zero VOUT_COMMAND at probe; update the cached
VOUT_COMMAND only after a successful write]
Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
drivers/hwmon/pmbus/pmbus.c | 2 +-
drivers/hwmon/pmbus/pmbus_core.c | 103 ++++++++++++++++++++++++++++++++++-----
2 files changed, 91 insertions(+), 14 deletions(-)
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c
index 7a7eac90d62e..dff1ef9c27f9 100644
--- a/drivers/hwmon/pmbus/pmbus.c
+++ b/drivers/hwmon/pmbus/pmbus.c
@@ -121,7 +121,7 @@ static int pmbus_identify(struct i2c_client *client,
vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
if (vout_mode >= 0 && vout_mode != 0xff) {
- switch (vout_mode >> 5) {
+ switch ((vout_mode & 0x60) >> 5) {
case 0:
break;
case 1:
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 5f69c1420b4e..47dff264d28b 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -101,6 +101,9 @@ struct pmbus_data {
int exponent[PMBUS_PAGES];
/* linear mode: exponent for output voltages */
+ bool vout_mode_relative[PMBUS_PAGES];
+ /* VOUT limits relative to VOUT_COMMAND */
+ int vout_command[PMBUS_PAGES]; /* VOUT_COMMAND in mV, relative mode */
const struct pmbus_driver_info *info;
@@ -803,6 +806,26 @@ static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sen
sensor->phase, sensor->reg);
}
+static bool pmbus_sensor_is_vout_relative(struct pmbus_data *data,
+ struct pmbus_sensor *sensor)
+{
+ if (sensor->class != PSC_VOLTAGE_OUT ||
+ !data->vout_mode_relative[sensor->page])
+ return false;
+
+ switch (sensor->reg) {
+ case PMBUS_VOUT_MARGIN_HIGH:
+ case PMBUS_VOUT_MARGIN_LOW:
+ case PMBUS_VOUT_OV_FAULT_LIMIT:
+ case PMBUS_VOUT_OV_WARN_LIMIT:
+ case PMBUS_VOUT_UV_WARN_LIMIT:
+ case PMBUS_VOUT_UV_FAULT_LIMIT:
+ return true;
+ default:
+ return false;
+ }
+}
+
/*
* Convert ieee754 sensor values to milli- or micro-units
* depending on sensor type.
@@ -1005,6 +1028,12 @@ static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
val = pmbus_reg2data_linear(data, sensor);
break;
}
+
+ /* In relative mode, val is a permillage of VOUT_COMMAND */
+ if (pmbus_sensor_is_vout_relative(data, sensor))
+ val = DIV_S64_ROUND_CLOSEST(val * data->vout_command[sensor->page],
+ 1000);
+
return val;
}
@@ -1209,6 +1238,12 @@ static u16 pmbus_data2reg(struct pmbus_data *data,
if (!sensor->convert)
return val;
+ if (pmbus_sensor_is_vout_relative(data, sensor)) {
+ val = clamp_val(val, -INT_MAX, INT_MAX);
+ val = DIV_S64_ROUND_CLOSEST(val * 1000,
+ data->vout_command[sensor->page]);
+ }
+
switch (data->info->format[sensor->class]) {
case direct:
regval = pmbus_data2reg_direct(data, sensor, val);
@@ -2736,6 +2771,20 @@ static int pmbus_init_coefficients(struct i2c_client *client,
return 0;
}
+static void pmbus_init_vout_relative(struct pmbus_data *data, int page,
+ int vout_command_raw)
+{
+ struct pmbus_sensor s = {
+ .page = page,
+ .reg = PMBUS_VOUT_COMMAND,
+ .class = PSC_VOLTAGE_OUT,
+ .convert = true,
+ .data = vout_command_raw,
+ };
+
+ data->vout_command[page] = pmbus_reg2data(data, &s);
+}
+
/*
* Identify chip parameters.
* This function is called for all chips.
@@ -2753,6 +2802,10 @@ static int pmbus_identify_common(struct i2c_client *client,
* Not all chips support the VOUT_MODE command,
* so a failure to read it is not an error.
*/
+ if (vout_mode & 0x80) {
+ data->vout_mode_relative[page] = true;
+ vout_mode &= 0x7f;
+ }
switch (vout_mode >> 5) {
case 0: /* linear mode */
if (data->info->format[PSC_VOLTAGE_OUT] != linear)
@@ -2979,6 +3032,21 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
return ret;
}
+ for (page = 0; page < info->pages; page++) {
+ if (data->vout_mode_relative[page]) {
+ ret = _pmbus_read_word_data(client, page, 0xff,
+ PMBUS_VOUT_COMMAND);
+ if (ret < 0)
+ return ret;
+ pmbus_init_vout_relative(data, page, ret);
+ if (data->vout_command[page] <= 0) {
+ dev_err(dev, "Invalid VOUT_COMMAND 0x%04x for relative VOUT mode\n",
+ ret);
+ return -ENODEV;
+ }
+ }
+ }
+
if (client->flags & I2C_CLIENT_PEC) {
/*
* If I2C_CLIENT_PEC is set here, both the I2C adapter and the
@@ -3351,29 +3419,38 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
.data = -1,
};
int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
- int low, high;
+ int low, high, ret;
*selector = 0;
guard(pmbus_lock)(client);
- low = pmbus_regulator_get_low_margin(client, s.page);
- if (low < 0)
- return low;
+ if (!data->vout_mode_relative[s.page]) {
+ low = pmbus_regulator_get_low_margin(client, s.page);
+ if (low < 0)
+ return low;
- high = pmbus_regulator_get_high_margin(client, s.page);
- if (high < 0)
- return high;
+ high = pmbus_regulator_get_high_margin(client, s.page);
+ if (high < 0)
+ return high;
- /* Make sure we are within margins */
- if (low > val)
- val = low;
- if (high < val)
- val = high;
+ /* Make sure we are within margins */
+ if (low > val)
+ val = low;
+ if (high < val)
+ val = high;
+ }
val = pmbus_data2reg(data, &s, val);
- return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+ ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
+ if (ret < 0)
+ return ret;
+
+ if (data->vout_mode_relative[s.page])
+ pmbus_init_vout_relative(data, s.page, val);
+
+ return 0;
}
static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands
2026-10-20 7:43 ` [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands Abdurrahman Hussain
@ 2026-10-20 8:55 ` sashiko-bot
2026-10-20 15:37 ` Guenter Roeck
0 siblings, 1 reply; 10+ messages in thread
From: sashiko-bot @ 2026-10-20 8:55 UTC (permalink / raw)
To: Abdurrahman Hussain; +Cc: devicetree, linux-hwmon, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] hwmon: (pmbus_core) divide-by-zero after pmbus_regulator_set_voltage()
- [Medium] hwmon: (pmbus_core) broken relative VOUT margin handling in regulator ops
--
commit 8ccb177073557cf9644c419b791da4a5cf494d3e
Author: Lars Petter Mostad <lars.petter.mostad@appear.net>
hwmon: (pmbus_core) Support relative encoding of vout related commands
This patch adds support for PMBus 1.3 relative encoding of output voltage
related commands, scaling limits relative to VOUT_COMMAND in
pmbus_reg2data() and pmbus_data2reg() and updating the cached VOUT_COMMAND
when setting regulator voltage.
> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
> index 5f69c1420b4e1..47dff264d28bf 100644
> --- a/drivers/hwmon/pmbus/pmbus_core.c
> +++ b/drivers/hwmon/pmbus/pmbus_core.c
[ ... ]
> @@ -803,6 +806,26 @@ static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sen
> sensor->phase, sensor->reg);
> }
>
> +static bool pmbus_sensor_is_vout_relative(struct pmbus_data *data,
> + struct pmbus_sensor *sensor)
> +{
> + if (sensor->class != PSC_VOLTAGE_OUT ||
> + !data->vout_mode_relative[sensor->page])
> + return false;
> +
> + switch (sensor->reg) {
> + case PMBUS_VOUT_MARGIN_HIGH:
> + case PMBUS_VOUT_MARGIN_LOW:
> + case PMBUS_VOUT_OV_FAULT_LIMIT:
> + case PMBUS_VOUT_OV_WARN_LIMIT:
> + case PMBUS_VOUT_UV_WARN_LIMIT:
> + case PMBUS_VOUT_UV_FAULT_LIMIT:
> + return true;
> + default:
> + return false;
> + }
> +}
[Severity: Medium]
Can the PMBUS_VOUT_MARGIN_HIGH and PMBUS_VOUT_MARGIN_LOW cases in
pmbus_sensor_is_vout_relative() ever match, and how does
pmbus_regulator_list_voltage() behave in relative mode?
No hwmon sensor attributes are registered for PMBUS_VOUT_MARGIN_LOW or
PMBUS_VOUT_MARGIN_HIGH. The only callers in drivers/hwmon/pmbus/pmbus_core.c
that read these registers and pass them to pmbus_reg2data() are
pmbus_regulator_get_low_margin() and pmbus_regulator_get_high_margin():
static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
{
struct pmbus_data *data = i2c_get_clientdata(client);
struct pmbus_sensor s = {
.page = page,
.class = PSC_VOLTAGE_OUT,
.convert = true,
.data = -1,
};
if (data->vout_low[page] < 0) {
if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MIN))
s.data = _pmbus_read_word_data(client, page, 0xff,
PMBUS_MFR_VOUT_MIN);
if (s.data < 0) {
s.data = _pmbus_read_word_data(client, page, 0xff,
PMBUS_VOUT_MARGIN_LOW);
if (s.data < 0)
return s.data;
}
data->vout_low[page] = pmbus_reg2data(data, &s);
}
return data->vout_low[page];
}
Neither pmbus_regulator_get_low_margin() nor
pmbus_regulator_get_high_margin() initializes s.reg (leaving it as 0), so
when they fall back to PMBUS_VOUT_MARGIN_LOW or PMBUS_VOUT_MARGIN_HIGH,
pmbus_reg2data() -> pmbus_sensor_is_vout_relative() returns false and caches
the unscaled permillage value as mV in data->vout_low[page] and
data->vout_high[page].
In addition, while pmbus_regulator_set_voltage() skips checking these margins
when data->vout_mode_relative[s.page] is true, pmbus_regulator_list_voltage()
still calls pmbus_regulator_get_low_margin() and
pmbus_regulator_get_high_margin() unconditionally:
static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
...
low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
if (low < 0)
return low;
high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
if (high < 0)
return high;
if (val >= low && val <= high)
return val * 1000; /* unit is uV */
return 0;
}
Even if s.reg were populated when reading the margin registers,
data->vout_low[page] and data->vout_high[page] are cached once and not
updated when pmbus_regulator_set_voltage() changes VOUT_COMMAND. Should
pmbus_regulator_get_low_margin(), pmbus_regulator_get_high_margin(), and
pmbus_regulator_list_voltage() also account for relative mode?
[ ... ]
> @@ -3351,29 +3419,38 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
> .data = -1,
> };
> int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
> - int low, high;
> + int low, high, ret;
>
> *selector = 0;
>
> guard(pmbus_lock)(client);
>
> - low = pmbus_regulator_get_low_margin(client, s.page);
> - if (low < 0)
> - return low;
> + if (!data->vout_mode_relative[s.page]) {
> + low = pmbus_regulator_get_low_margin(client, s.page);
> + if (low < 0)
> + return low;
>
> - high = pmbus_regulator_get_high_margin(client, s.page);
> - if (high < 0)
> - return high;
> + high = pmbus_regulator_get_high_margin(client, s.page);
> + if (high < 0)
> + return high;
>
> - /* Make sure we are within margins */
> - if (low > val)
> - val = low;
> - if (high < val)
> - val = high;
> + /* Make sure we are within margins */
> + if (low > val)
> + val = low;
> + if (high < val)
> + val = high;
> + }
>
> val = pmbus_data2reg(data, &s, val);
>
> - return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
> + ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
> + if (ret < 0)
> + return ret;
> +
> + if (data->vout_mode_relative[s.page])
> + pmbus_init_vout_relative(data, s.page, val);
> +
> + return 0;
> }
[Severity: High]
Could updating data->vout_command[s.page] in pmbus_regulator_set_voltage()
lead to a division by zero in pmbus_data2reg()?
At probe time, pmbus_init_common() rejects non-positive values in
data->vout_command[page] after calling pmbus_init_vout_relative(). However,
in pmbus_regulator_set_voltage(), when data->vout_mode_relative[s.page] is
true, margin clamping is skipped and pmbus_init_vout_relative(data, s.page,
val) updates data->vout_command[s.page] without checking whether the decoded
voltage is <= 0.
If a consumer requests a small voltage (for example min_uv < 500 uV, or a
value that rounds to 0 in pmbus_data2reg()), data->vout_command[s.page]
becomes 0. A subsequent write to a relative VOUT limit attribute in sysfs
will then call pmbus_set_sensor() -> pmbus_data2reg() and divide by zero:
if (pmbus_sensor_is_vout_relative(data, sensor)) {
val = clamp_val(val, -INT_MAX, INT_MAX);
val = DIV_S64_ROUND_CLOSEST(val * 1000,
data->vout_command[sensor->page]);
}
Should pmbus_regulator_set_voltage() or pmbus_data2reg() guard against a
non-positive vout_command?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-hwmon-pmbus-fs1412-v2-0-3396c3a08251@nexthop.ai?part=3
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands
2026-10-20 8:55 ` sashiko-bot
@ 2026-10-20 15:37 ` Guenter Roeck
0 siblings, 0 replies; 10+ messages in thread
From: Guenter Roeck @ 2026-10-20 15:37 UTC (permalink / raw)
To: sashiko-reviews, Abdurrahman Hussain
Cc: devicetree, linux-hwmon, robh, conor+dt
On 10/20/26 01:55, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] hwmon: (pmbus_core) divide-by-zero after pmbus_regulator_set_voltage()
> - [Medium] hwmon: (pmbus_core) broken relative VOUT margin handling in regulator ops
> --
Good that I did not just apply this patch. Do you have time to look into
those issues and fix them ?
Thanks,
Guenter
>
> commit 8ccb177073557cf9644c419b791da4a5cf494d3e
> Author: Lars Petter Mostad <lars.petter.mostad@appear.net>
>
> hwmon: (pmbus_core) Support relative encoding of vout related commands
>
> This patch adds support for PMBus 1.3 relative encoding of output voltage
> related commands, scaling limits relative to VOUT_COMMAND in
> pmbus_reg2data() and pmbus_data2reg() and updating the cached VOUT_COMMAND
> when setting regulator voltage.
>
>> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
>> index 5f69c1420b4e1..47dff264d28bf 100644
>> --- a/drivers/hwmon/pmbus/pmbus_core.c
>> +++ b/drivers/hwmon/pmbus/pmbus_core.c
>
> [ ... ]
>
>> @@ -803,6 +806,26 @@ static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sen
>> sensor->phase, sensor->reg);
>> }
>>
>> +static bool pmbus_sensor_is_vout_relative(struct pmbus_data *data,
>> + struct pmbus_sensor *sensor)
>> +{
>> + if (sensor->class != PSC_VOLTAGE_OUT ||
>> + !data->vout_mode_relative[sensor->page])
>> + return false;
>> +
>> + switch (sensor->reg) {
>> + case PMBUS_VOUT_MARGIN_HIGH:
>> + case PMBUS_VOUT_MARGIN_LOW:
>> + case PMBUS_VOUT_OV_FAULT_LIMIT:
>> + case PMBUS_VOUT_OV_WARN_LIMIT:
>> + case PMBUS_VOUT_UV_WARN_LIMIT:
>> + case PMBUS_VOUT_UV_FAULT_LIMIT:
>> + return true;
>> + default:
>> + return false;
>> + }
>> +}
>
> [Severity: Medium]
> Can the PMBUS_VOUT_MARGIN_HIGH and PMBUS_VOUT_MARGIN_LOW cases in
> pmbus_sensor_is_vout_relative() ever match, and how does
> pmbus_regulator_list_voltage() behave in relative mode?
>
> No hwmon sensor attributes are registered for PMBUS_VOUT_MARGIN_LOW or
> PMBUS_VOUT_MARGIN_HIGH. The only callers in drivers/hwmon/pmbus/pmbus_core.c
> that read these registers and pass them to pmbus_reg2data() are
> pmbus_regulator_get_low_margin() and pmbus_regulator_get_high_margin():
>
> static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
> {
> struct pmbus_data *data = i2c_get_clientdata(client);
> struct pmbus_sensor s = {
> .page = page,
> .class = PSC_VOLTAGE_OUT,
> .convert = true,
> .data = -1,
> };
>
> if (data->vout_low[page] < 0) {
> if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MIN))
> s.data = _pmbus_read_word_data(client, page, 0xff,
> PMBUS_MFR_VOUT_MIN);
> if (s.data < 0) {
> s.data = _pmbus_read_word_data(client, page, 0xff,
> PMBUS_VOUT_MARGIN_LOW);
> if (s.data < 0)
> return s.data;
> }
> data->vout_low[page] = pmbus_reg2data(data, &s);
> }
>
> return data->vout_low[page];
> }
>
> Neither pmbus_regulator_get_low_margin() nor
> pmbus_regulator_get_high_margin() initializes s.reg (leaving it as 0), so
> when they fall back to PMBUS_VOUT_MARGIN_LOW or PMBUS_VOUT_MARGIN_HIGH,
> pmbus_reg2data() -> pmbus_sensor_is_vout_relative() returns false and caches
> the unscaled permillage value as mV in data->vout_low[page] and
> data->vout_high[page].
>
> In addition, while pmbus_regulator_set_voltage() skips checking these margins
> when data->vout_mode_relative[s.page] is true, pmbus_regulator_list_voltage()
> still calls pmbus_regulator_get_low_margin() and
> pmbus_regulator_get_high_margin() unconditionally:
>
> static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
> unsigned int selector)
> {
> ...
> low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
> if (low < 0)
> return low;
>
> high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
> if (high < 0)
> return high;
>
> if (val >= low && val <= high)
> return val * 1000; /* unit is uV */
>
> return 0;
> }
>
> Even if s.reg were populated when reading the margin registers,
> data->vout_low[page] and data->vout_high[page] are cached once and not
> updated when pmbus_regulator_set_voltage() changes VOUT_COMMAND. Should
> pmbus_regulator_get_low_margin(), pmbus_regulator_get_high_margin(), and
> pmbus_regulator_list_voltage() also account for relative mode?
>
> [ ... ]
>
>> @@ -3351,29 +3419,38 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
>> .data = -1,
>> };
>> int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
>> - int low, high;
>> + int low, high, ret;
>>
>> *selector = 0;
>>
>> guard(pmbus_lock)(client);
>>
>> - low = pmbus_regulator_get_low_margin(client, s.page);
>> - if (low < 0)
>> - return low;
>> + if (!data->vout_mode_relative[s.page]) {
>> + low = pmbus_regulator_get_low_margin(client, s.page);
>> + if (low < 0)
>> + return low;
>>
>> - high = pmbus_regulator_get_high_margin(client, s.page);
>> - if (high < 0)
>> - return high;
>> + high = pmbus_regulator_get_high_margin(client, s.page);
>> + if (high < 0)
>> + return high;
>>
>> - /* Make sure we are within margins */
>> - if (low > val)
>> - val = low;
>> - if (high < val)
>> - val = high;
>> + /* Make sure we are within margins */
>> + if (low > val)
>> + val = low;
>> + if (high < val)
>> + val = high;
>> + }
>>
>> val = pmbus_data2reg(data, &s, val);
>>
>> - return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
>> + ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (data->vout_mode_relative[s.page])
>> + pmbus_init_vout_relative(data, s.page, val);
>> +
>> + return 0;
>> }
>
> [Severity: High]
> Could updating data->vout_command[s.page] in pmbus_regulator_set_voltage()
> lead to a division by zero in pmbus_data2reg()?
>
> At probe time, pmbus_init_common() rejects non-positive values in
> data->vout_command[page] after calling pmbus_init_vout_relative(). However,
> in pmbus_regulator_set_voltage(), when data->vout_mode_relative[s.page] is
> true, margin clamping is skipped and pmbus_init_vout_relative(data, s.page,
> val) updates data->vout_command[s.page] without checking whether the decoded
> voltage is <= 0.
>
> If a consumer requests a small voltage (for example min_uv < 500 uV, or a
> value that rounds to 0 in pmbus_data2reg()), data->vout_command[s.page]
> becomes 0. A subsequent write to a relative VOUT limit attribute in sysfs
> will then call pmbus_set_sensor() -> pmbus_data2reg() and divide by zero:
>
> if (pmbus_sensor_is_vout_relative(data, sensor)) {
> val = clamp_val(val, -INT_MAX, INT_MAX);
> val = DIV_S64_ROUND_CLOSEST(val * 1000,
> data->vout_command[sensor->page]);
> }
>
> Should pmbus_regulator_set_voltage() or pmbus_data2reg() guard against a
> non-positive vout_command?
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 4/4] hwmon: (pmbus/fs1412) Add TDK FS1412 and FS1525 driver
2026-10-20 7:43 [PATCH v2 0/4] hwmon: (pmbus) Support relative VOUT mode, add TDK FS1412 and FS1525 Abdurrahman Hussain
` (2 preceding siblings ...)
2026-10-20 7:43 ` [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands Abdurrahman Hussain
@ 2026-10-20 7:43 ` Abdurrahman Hussain
2026-10-20 8:58 ` sashiko-bot
3 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain @ 2026-10-20 7:43 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Guenter Roeck,
Abdurrahman Hussain, Jonathan Corbet, Shuah Khan, Randy Dunlap
Cc: Lars Petter Mostad, devicetree, linux-kernel, linux-hwmon,
linux-doc
The TDK FS1412 and FS1525 are 12A and 25A uPOL regulators with PMBus
telemetry for input voltage, output voltage and temperature, plus the
matching status registers. The FS1525 also reports output current and
has an over-temperature warning limit. The FS1412 has neither:
READ_IOUT and OT_WARN_LIMIT are not in its command table. Both read
"KDT" from MFR_ID, which the driver checks before binding, and are
told apart by IC_DEVICE_ID (0x0c for the FS1412, 0x19 for the FS1525).
VOUT_MODE is read-only and has bit 7 set on both: 0x98 on the FS1412
(exponent -8) and 0x96 on the FS1525 (exponent -10). Their output
voltage limits are relative to VOUT_COMMAND, so 0x0133 against a 0.6V
command is a 120% over-voltage limit on the FS1412. The PMBus core
converts them now that it supports relative VOUT encoding.
On the FS1412, OT_WARN_LIMIT answers although it is not in the command
table, but the part reports OT_WARNING at room temperature, so the
driver hides the register from the core and only the OT_FAULT_LIMIT
based attributes are provided.
When the output is set with an external divider, the FS1412 reports
READ_VOUT at the feedback pin, so in2_input and its limits all scale
with the divider in user space. The FS1525 reports READ_VOUT as the
output voltage and compares it against its warning and under-voltage
limits as they are, relative to VOUT_COMMAND; only its over-voltage
fault is an analog comparison at the feedback pin. The documentation
describes both.
Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
Documentation/hwmon/fs1412.rst | 124 +++++++++++++++++++++++++++++++++++
Documentation/hwmon/index.rst | 1 +
MAINTAINERS | 7 ++
drivers/hwmon/pmbus/Kconfig | 9 +++
drivers/hwmon/pmbus/Makefile | 1 +
drivers/hwmon/pmbus/fs1412.c | 144 +++++++++++++++++++++++++++++++++++++++++
6 files changed, 286 insertions(+)
diff --git a/Documentation/hwmon/fs1412.rst b/Documentation/hwmon/fs1412.rst
new file mode 100644
index 000000000000..5e141b0c731f
--- /dev/null
+++ b/Documentation/hwmon/fs1412.rst
@@ -0,0 +1,124 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+Kernel driver fs1412
+====================
+
+Supported chips:
+
+ * TDK FS1412
+
+ Prefix: 'fs1412'
+
+ Addresses scanned: -
+
+ Datasheet: https://product.tdk.com/system/files/dam/doc/product/power/switching-power/micro-pol/data_sheet/fs1412_datasheet.pdf
+
+ * TDK FS1525
+
+ Prefix: 'fs1525'
+
+ Addresses scanned: -
+
+ Datasheet: Publicly available at the TDK website
+
+Authors:
+ Abdurrahman Hussain <abdurrahman@nexthop.ai>
+
+
+Description
+-----------
+
+This driver implements support for the TDK FS1412 and FS1525 uPOL DC/DC
+regulators.
+
+The FS1412 is a 12A part with PMBus monitoring of its input voltage, output
+voltage and temperature. It has over-current and over-temperature protection
+with programmable fault limits but no current telemetry, so no current
+attributes are provided.
+
+The FS1525 is a 25A part that adds output current telemetry and an
+over-temperature warning limit.
+
+Both parts read "KDT" from MFR_ID. The driver tells them apart by
+IC_DEVICE_ID and warns if the detected part does not match the one it was
+instantiated as.
+
+The FS1412 answers on two I2C addresses: a register interface at the I2C
+base address (0x08 by default) and the PMBus interface at the PMBus base
+address (0x70 by default), each plus the offset strapped on the ADDR pin.
+This driver binds to the PMBus address.
+
+The driver is a client driver to the core PMBus driver.
+Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
+details.
+
+Both parts store their output voltage limits relative to VOUT_COMMAND
+(VOUT_MODE bit 7 set). The PMBus core converts them to and from absolute
+voltages, so the output voltage limits read and write in volts. A written
+limit is stored as a fraction of VOUT_COMMAND in the resolution of VOUT_MODE
+(1/256 on the FS1412, 1/1024 on the FS1525), so it may read back rounded. The
+over-voltage protection itself engages at one of four thresholds the device
+rounds the fault limit to; see the datasheet.
+
+When the output voltage is set with an external resistor divider,
+VOUT_COMMAND holds the feedback pin target rather than the output voltage,
+and the two parts differ:
+
+- The FS1412 reports READ_VOUT at the feedback pin, so in2_input and the in2
+ limits are all in the feedback domain. Scale them by the divider ratio in
+ user space.
+
+- The FS1525 reports READ_VOUT as the output voltage. Its warning and
+ under-voltage limits are compared by the device against READ_VOUT but are
+ still relative to VOUT_COMMAND, so in2_max, in2_min and in2_lcrit are the
+ thresholds the device actually applies to in2_input. The over-voltage
+ fault is an analog comparison at the feedback pin, so in2_crit is in the
+ feedback domain and does not compare to in2_input on such boards.
+
+The FS1412 reports an over-temperature warning at room temperature and has
+no OT_WARN_LIMIT in its command table, so temp1_max and its alarm are not
+provided for it; temp1_crit comes from OT_FAULT_LIMIT.
+
+
+Sysfs entries
+-------------
+
+======================= ======================================================
+in1_label "vin"
+in1_input Measured input voltage
+in1_min Minimum input voltage
+in1_min_alarm Input voltage low alarm
+in1_crit Critical high input voltage
+in1_crit_alarm Input voltage critical high alarm
+
+in2_label "vout1"
+in2_input Measured output voltage (FS1412: at the feedback pin)
+in2_min Minimum output voltage
+in2_min_alarm Output voltage low alarm
+in2_max Maximum output voltage
+in2_max_alarm Output voltage high alarm
+in2_lcrit Critical low output voltage
+in2_lcrit_alarm Output voltage critical low alarm
+in2_crit Critical high output voltage
+in2_crit_alarm Output voltage critical high alarm
+
+curr1_label "iout1" (FS1525 only)
+curr1_input Measured output current (FS1525 only)
+curr1_max Maximum output current (FS1525 only)
+curr1_max_alarm Output current high alarm (FS1525 only)
+curr1_crit Critical high output current (FS1525 only)
+curr1_crit_alarm Output current critical high alarm (FS1525 only)
+
+temp1_input Measured temperature
+temp1_max Maximum temperature (FS1525 only)
+temp1_max_alarm Temperature high alarm (FS1525 only)
+temp1_crit Critical high temperature
+temp1_crit_alarm Temperature critical high alarm
+======================= ======================================================
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 9955a525436a..625833374c94 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -79,6 +79,7 @@ Hardware Monitoring Kernel Drivers
f71805f
f71882fg
fam15h_power
+ fs1412
fsp-3y
ftsteutates
g760a
diff --git a/MAINTAINERS b/MAINTAINERS
index 65e8a4b5c90b..73b5a120517e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26778,6 +26778,13 @@ W: https://linuxtv.org
T: git git://linuxtv.org/media.git
F: drivers/media/i2c/tda9840*
+TDK FS1412 AND FS1525 MICRO POL DRIVER
+M: Abdurrahman Hussain <abdurrahman@nexthop.ai>
+L: linux-hwmon@vger.kernel.org
+S: Maintained
+F: Documentation/hwmon/fs1412.rst
+F: drivers/hwmon/pmbus/fs1412.c
+
TEA5761 TUNER DRIVER
M: Mauro Carvalho Chehab <mchehab@kernel.org>
L: linux-media@vger.kernel.org
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index eb71a0ac044b..67bbc87710ee 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -132,6 +132,15 @@ config SENSORS_DELTA_AHE50DC_FAN
This driver can also be built as a module. If so, the module
will be called delta-ahe50dc-fan.
+config SENSORS_FS1412
+ tristate "TDK FS1412 and FS1525"
+ help
+ If you say yes here you get hardware monitoring support for the TDK
+ FS1412 and FS1525 uPOL regulators.
+
+ This driver can also be built as a module. If so, the module will
+ be called fs1412.
+
config SENSORS_FSP_3Y
tristate "FSP/3Y-Power power supplies"
help
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index e288fe72a437..7bbc0d02bfad 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_SENSORS_APS_379) += aps-379.o
obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
obj-$(CONFIG_SENSORS_BPA_RS600) += bpa-rs600.o
obj-$(CONFIG_SENSORS_DELTA_AHE50DC_FAN) += delta-ahe50dc-fan.o
+obj-$(CONFIG_SENSORS_FS1412) += fs1412.o
obj-$(CONFIG_SENSORS_FSP_3Y) += fsp-3y.o
obj-$(CONFIG_SENSORS_HAC300S) += hac300s.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
diff --git a/drivers/hwmon/pmbus/fs1412.c b/drivers/hwmon/pmbus/fs1412.c
new file mode 100644
index 000000000000..58bff773ca58
--- /dev/null
+++ b/drivers/hwmon/pmbus/fs1412.c
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for the TDK FS1412 and FS1525 uPOL regulators
+ *
+ * Copyright 2026 Nexthop Systems.
+ */
+
+#include <linux/array_size.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pmbus.h>
+#include <linux/string.h>
+
+#include "pmbus.h"
+
+#define FS1412_MFR_ID "KDT"
+#define FS1412_MFR_ID_LEN (sizeof(FS1412_MFR_ID) - 1)
+
+/*
+ * OT_WARN_LIMIT is not in the FS1412 command table. The register answers, but the
+ * part has no warning threshold and reports OT_WARNING at room temperature,
+ * so keep the core from exposing either.
+ */
+static int fs1412_read_word_data(struct i2c_client *client, int page,
+ int phase, int reg)
+{
+ if (reg == PMBUS_OT_WARN_LIMIT)
+ return -ENXIO;
+
+ return -ENODATA;
+}
+
+static int fs1412_write_word_data(struct i2c_client *client, int page,
+ int reg, u16 word)
+{
+ if (reg == PMBUS_OT_WARN_LIMIT)
+ return -ENXIO;
+
+ return -ENODATA;
+}
+
+enum chips { fs1412, fs1525 };
+
+/* IC_DEVICE_ID, a one byte block */
+static const u8 fs1412_device_id[] = {
+ [fs1412] = 0x0c,
+ [fs1525] = 0x19,
+};
+
+static struct pmbus_driver_info fs1412_info[] = {
+ [fs1412] = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = linear,
+ .format[PSC_TEMPERATURE] = linear,
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_word_data = fs1412_read_word_data,
+ .write_word_data = fs1412_write_word_data,
+ },
+ [fs1525] = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_TEMPERATURE] = linear,
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ },
+};
+
+static const struct i2c_device_id fs1412_id[] = {
+ { .name = "fs1412", .driver_data = fs1412 },
+ { .name = "fs1525", .driver_data = fs1525 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, fs1412_id);
+
+static int fs1412_probe(struct i2c_client *client)
+{
+ char buf[I2C_SMBUS_BLOCK_MAX + 1] = { 0 };
+ struct device *dev = &client->dev;
+ enum chips chip, detected;
+ int ret;
+
+ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read PMBUS_MFR_ID\n");
+
+ if (ret != FS1412_MFR_ID_LEN ||
+ strncmp(buf, FS1412_MFR_ID, FS1412_MFR_ID_LEN))
+ return dev_err_probe(dev, -ENODEV,
+ "Unsupported Manufacturer ID '%s'\n", buf);
+
+ ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Failed to read PMBUS_IC_DEVICE_ID\n");
+ if (ret != 1)
+ return dev_err_probe(dev, -ENODEV,
+ "Unexpected IC_DEVICE_ID length %d\n", ret);
+
+ for (detected = 0; detected < ARRAY_SIZE(fs1412_device_id); detected++)
+ if (fs1412_device_id[detected] == (u8)buf[0])
+ break;
+ if (detected == ARRAY_SIZE(fs1412_device_id))
+ return dev_err_probe(dev, -ENODEV,
+ "Unsupported IC_DEVICE_ID 0x%02x\n",
+ (u8)buf[0]);
+
+ chip = (uintptr_t)i2c_get_match_data(client);
+ if (chip != detected)
+ dev_warn(dev, "Device mismatch: Configured %s, detected %s\n",
+ client->name, fs1412_id[detected].name);
+
+ return pmbus_do_probe(client, &fs1412_info[detected]);
+}
+
+static const struct of_device_id fs1412_of_match[] = {
+ { .compatible = "tdk,fs1412", .data = (void *)fs1412 },
+ { .compatible = "tdk,fs1525", .data = (void *)fs1525 },
+ { }
+};
+MODULE_DEVICE_TABLE(of, fs1412_of_match);
+
+static struct i2c_driver fs1412_driver = {
+ .driver = {
+ .name = "fs1412",
+ .of_match_table = fs1412_of_match,
+ },
+ .probe = fs1412_probe,
+ .id_table = fs1412_id,
+};
+
+module_i2c_driver(fs1412_driver);
+
+MODULE_AUTHOR("Abdurrahman Hussain <abdurrahman@nexthop.ai>");
+MODULE_DESCRIPTION("PMBus driver for the TDK FS1412 and FS1525 uPOL regulators");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("PMBUS");
--
2.54.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v2 4/4] hwmon: (pmbus/fs1412) Add TDK FS1412 and FS1525 driver
2026-10-20 7:43 ` [PATCH v2 4/4] hwmon: (pmbus/fs1412) Add TDK FS1412 and FS1525 driver Abdurrahman Hussain
@ 2026-10-20 8:58 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-10-20 8:58 UTC (permalink / raw)
To: Abdurrahman Hussain; +Cc: linux-hwmon
> The TDK FS1412 and FS1525 are 12A and 25A uPOL regulators with PMBus
> telemetry for input voltage, output voltage and temperature, plus the
> matching status registers. The FS1525 also reports output current and
> has an over-temperature warning limit. The FS1412 has neither:
> READ_IOUT and OT_WARN_LIMIT are not in its command table. Both read
> "KDT" from MFR_ID, which the driver checks before binding, and are
> told apart by IC_DEVICE_ID (0x0c for the FS1412, 0x19 for the FS1525).
>
> VOUT_MODE is read-only and has bit 7 set on both: 0x98 on the FS1412
> (exponent -8) and 0x96 on the FS1525 (exponent -10). Their output
> voltage limits are relative to VOUT_COMMAND, so 0x0133 against a 0.6V
> command is a 120% over-voltage limit on the FS1412. The PMBus core
> converts them now that it supports relative VOUT encoding.
>
> On the FS1412, OT_WARN_LIMIT answers although it is not in the command
> table, but the part reports OT_WARNING at room temperature, so the
> driver hides the register from the core and only the OT_FAULT_LIMIT
> based attributes are provided.
>
> When the output is set with an external divider, the FS1412 reports
> READ_VOUT at the feedback pin, so in2_input and its limits all scale
> with the divider in user space. The FS1525 reports READ_VOUT as the
> output voltage and compares it against its warning and under-voltage
> limits as they are, relative to VOUT_COMMAND; only its over-voltage
> fault is an analog comparison at the feedback pin. The documentation
> describes both.
>
> Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
Sashiko has reviewed this patch and found no issues.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-hwmon-pmbus-fs1412-v2-0-3396c3a08251@nexthop.ai?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread