* [PATCH 1/3] hwmon: (pmbus/max34440): block unsupported VIN and IIN limit registers
2026-07-16 8:25 [PATCH 0/3] hwmon: (pmbus/max34440): Bug fixes and supporting new device Alexis Czezar Torreno
@ 2026-07-16 8:25 ` Alexis Czezar Torreno
2026-07-16 8:38 ` sashiko-bot
2026-07-16 8:25 ` [PATCH 2/3] hwmon: (pmbus/max34440): add support for newer version of max34451 Alexis Czezar Torreno
2026-07-16 8:25 ` [PATCH 3/3] hwmon: (pmbus/max34440): Add support for MAX34452 Alexis Czezar Torreno
2 siblings, 1 reply; 7+ messages in thread
From: Alexis Czezar Torreno @ 2026-07-16 8:25 UTC (permalink / raw)
To: Guenter Roeck, Kun Yi, Nuno Sá, Jonathan Corbet, Shuah Khan
Cc: linux-hwmon, linux-kernel, linux-doc, Alexis Czezar Torreno
MAX34451 and ADPM chips do not support standard PMBus VIN/IIN limit
registers, manufacturer specific min/max registers, or undercurrent
or undertemperature fault limits. STATUS_BYTE and STATUS_OTHER are also
not available. Accessing these non-existent registers during driver
initialization triggers a CML error and asserts ALERT. Handled by
blocking these functions during read/write.
Fixes: 7a001dbab4ad ("hwmon: (pmbus/max34440) Add support for MAX34451.")
Fixes: 629cf8f6c23a ("hwmon: (pmbus/max34440) Add support for ADPM12160")
Fixes: 2e0b52f1ae88 ("hwmon: (pmbus/max34440): add support adpm12200")
Fixes: 479bfeba2eb6 ("hwmon: (pmbus/max34440): add support adpm12250")
Tested-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
Signed-off-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
---
drivers/hwmon/pmbus/max34440.c | 80 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
index 74876d2207fbe4014b8b54a9fd9682370fc3bbed..e56057e9273c1639bddbaf4e665ea159f1d7c3ed 100644
--- a/drivers/hwmon/pmbus/max34440.c
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -88,6 +88,33 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
ret = pmbus_read_word_data(client, page, phase,
data->iout_oc_warn_limit);
break;
+ case PMBUS_VIN_OV_FAULT_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ case PMBUS_VIN_UV_WARN_LIMIT:
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_MFR_VIN_MIN:
+ case PMBUS_MFR_VIN_MAX:
+ case PMBUS_IIN_OC_WARN_LIMIT:
+ case PMBUS_IIN_OC_FAULT_LIMIT:
+ case PMBUS_MFR_IIN_MAX:
+ case PMBUS_MFR_VOUT_MIN:
+ case PMBUS_MFR_VOUT_MAX:
+ case PMBUS_IOUT_UC_FAULT_LIMIT:
+ case PMBUS_MFR_IOUT_MAX:
+ case PMBUS_UT_WARN_LIMIT:
+ case PMBUS_UT_FAULT_LIMIT:
+ case PMBUS_MFR_MAX_TEMP_1:
+ /*
+ * MAX34451/ADPM family do not support VIN/IIN limit registers,
+ * manufacturer-specific min/max registers, or undercurrent/
+ * undertemperature fault limits. Accessing these triggers CML
+ * error and asserts ALERT.
+ */
+ if (data->id == max34451 || data->id == adpm12160 ||
+ data->id == adpm12200 || data->id == adpm12250)
+ return -ENXIO;
+ ret = -ENODATA;
+ break;
case PMBUS_VIRT_READ_VOUT_MIN:
ret = pmbus_read_word_data(client, page, phase,
MAX34440_MFR_VOUT_MIN);
@@ -244,6 +271,51 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
return ret;
}
+static int max34451_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct max34440_data *data = to_max34440_data(info);
+
+ switch (reg) {
+ case PMBUS_STATUS_BYTE:
+ case PMBUS_STATUS_OTHER:
+ /*
+ * MAX34451/ADPM family do not support STATUS_BYTE or
+ * STATUS_OTHER registers. Accessing them triggers CML
+ * error and asserts ALERT.
+ */
+ if (data->id == max34451 || data->id == adpm12160 ||
+ data->id == adpm12200 || data->id == adpm12250)
+ return -ENXIO;
+ return -ENODATA;
+ default:
+ return -ENODATA;
+ }
+}
+
+static int max34451_write_byte_data(struct i2c_client *client, int page,
+ int reg, u8 byte)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ const struct max34440_data *data = to_max34440_data(info);
+
+ switch (reg) {
+ case PMBUS_STATUS_BYTE:
+ case PMBUS_STATUS_OTHER:
+ /*
+ * MAX34451/ADPM family do not support STATUS_BYTE or
+ * STATUS_OTHER registers. Writing to them triggers CML
+ * error and asserts ALERT.
+ */
+ if (data->id == max34451 || data->id == adpm12160 ||
+ data->id == adpm12200 || data->id == adpm12250)
+ return -ENXIO;
+ return -ENODATA;
+ default:
+ return -ENODATA;
+ }
+}
+
static int max34451_set_supported_funcs(struct i2c_client *client,
struct max34440_data *data)
{
@@ -363,7 +435,9 @@ static struct pmbus_driver_info max34440_info[] = {
.func[9] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT,
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
},
[adpm12200] = {
@@ -399,7 +473,9 @@ static struct pmbus_driver_info max34440_info[] = {
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
.func[14] = PMBUS_HAVE_IOUT,
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
},
[adpm12250] = {
@@ -433,7 +509,9 @@ static struct pmbus_driver_info max34440_info[] = {
.func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT,
.func[14] = PMBUS_HAVE_IOUT,
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
},
[max34440] = {
@@ -581,7 +659,9 @@ static struct pmbus_driver_info max34440_info[] = {
.func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
.read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
.write_word_data = max34440_write_word_data,
.page_change_delay = MAX34440_PAGE_CHANGE_DELAY,
},
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/3] hwmon: (pmbus/max34440): Add support for MAX34452
2026-07-16 8:25 [PATCH 0/3] hwmon: (pmbus/max34440): Bug fixes and supporting new device Alexis Czezar Torreno
2026-07-16 8:25 ` [PATCH 1/3] hwmon: (pmbus/max34440): block unsupported VIN and IIN limit registers Alexis Czezar Torreno
2026-07-16 8:25 ` [PATCH 2/3] hwmon: (pmbus/max34440): add support for newer version of max34451 Alexis Czezar Torreno
@ 2026-07-16 8:25 ` Alexis Czezar Torreno
2026-07-16 8:38 ` sashiko-bot
2 siblings, 1 reply; 7+ messages in thread
From: Alexis Czezar Torreno @ 2026-07-16 8:25 UTC (permalink / raw)
To: Guenter Roeck, Kun Yi, Nuno Sá, Jonathan Corbet, Shuah Khan
Cc: linux-hwmon, linux-kernel, linux-doc, Alexis Czezar Torreno,
Carlos Jones Jr
From: Carlos Jones Jr <carlosjr.jones@analog.com>
Add support for Maxim MAX34452 PMBus 16-Channel V/I Monitor and
12-Channel Sequencer/Marginer. The device is similar to MAX34451
and shares the same configuration function.
The MAX34452 supports:
- 16 configurable voltage/current monitoring channels
- 5 temperature sensors (pages 16-20)
- Dynamic channel configuration via MFR_CHANNEL_CONFIG
- IOUT average monitoring
Signed-off-by: Carlos Jones Jr <carlosjr.jones@analog.com>
Co-Developed by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
Signed-off-by: Alexis Czezar Torreno <alexisczezar.torreno@analog.com>
---
Documentation/hwmon/max34440.rst | 26 +++++++++++------
drivers/hwmon/pmbus/Kconfig | 5 ++--
drivers/hwmon/pmbus/max34440.c | 61 ++++++++++++++++++++++++++++++++--------
3 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/Documentation/hwmon/max34440.rst b/Documentation/hwmon/max34440.rst
index e7421f4dbf38fc1436bbaeba71d4461a00f8cefb..866f22b88e9b360ff54aa52807484bb3e859e56e 100644
--- a/Documentation/hwmon/max34440.rst
+++ b/Documentation/hwmon/max34440.rst
@@ -65,6 +65,16 @@ Supported chips:
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max34451.pdf
+ * Maxim MAX34452
+
+ PMBus 16-Channel V/I Monitor and 12-Channel Sequencer/Marginer
+
+ Prefixes: 'max34452'
+
+ Addresses scanned: -
+
+ Datasheet: -
+
* Maxim MAX34460
PMBus 12-Channel Voltage Monitor & Sequencer
@@ -94,11 +104,11 @@ Description
This driver supports multiple devices: hardware monitoring for Maxim MAX34440
PMBus 6-Channel Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply
Manager and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data
-Logger; PMBus Voltage Monitor and Sequencers for MAX34451, MAX34460, and
-MAX34461; PMBus DC/DC Power Module ADPM12160, ADPM12200, and ADPM12250. The
-MAX34451 supports monitoring voltage or current of 12 channels based on GIN
-pins. The MAX34460 supports 12 voltage channels, and the MAX34461 supports 16
-voltage channels. The ADPM12160, ADPM12200, and ADPM12250 also monitors both
+Logger; PMBus Voltage Monitor and Sequencers for MAX34451, MAX34452, MAX34460,
+and MAX34461; PMBus DC/DC Power Module ADPM12160, ADPM12200, and ADPM12250. The
+MAX34451 and MAX34452 support monitoring voltage or current of 16 channels based
+on GIN pins. The MAX34460 supports 12 voltage channels, and the MAX34461 supports
+16 voltage channels. The ADPM12160, ADPM12200, and ADPM12250 also monitor both
input and output of voltage and current.
The driver is a client driver to the core PMBus driver. Please see
@@ -171,7 +181,7 @@ curr[1-6]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT
register.
curr[1-6]_max_alarm Current high alarm. From IOUT_OC_WARNING status.
curr[1-6]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status.
-curr[1-4]_average Historical average current (MAX34446/34451 only).
+curr[1-4]_average Historical average current (MAX34446/34451/34452 only).
curr[1-6]_highest Historical maximum current.
curr[1-6]_reset_history Write any value to reset history.
======================= ========================================================
@@ -223,7 +233,7 @@ temp[1-8]_reset_history Write any value to reset history.
.. note::
- - MAX34451 supports attribute groups in[1-16] (or curr[1-16] based on
- input pins) and temp[1-5].
+ - MAX34451 and MAX34452 support attribute groups in[1-16] (or curr[1-16]
+ based on input pins) and temp[1-5].
- MAX34460 supports attribute groups in[1-12] and temp[1-5].
- MAX34461 supports attribute groups in[1-16] and temp[1-5].
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index ae003a6eac30a7b0a022c5f7f467d8f81736c3f7..91fa1c19e87c9f2de789f2908e59ac00c228eb76 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -434,8 +434,9 @@ config SENSORS_MAX34440
tristate "Maxim MAX34440 and compatibles"
help
If you say yes here you get hardware monitoring support for Maxim
- MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461.
- Other compatible are ADPM12160, and ADPM12200.
+ MAX34440, MAX34441, MAX34446, MAX34451, MAX34452, MAX34460, and
+ MAX34461. Other compatible devices are ADPM12160, ADPM12200, and
+ ADPM12250.
This driver can also be built as a module. If so, the module will
be called max34440.
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c
index 024109df26db568a4c230c9dbc45d69ba531dd8d..2e57af09f47809b0a0bddab27fc47cadfe35e0ef 100644
--- a/drivers/hwmon/pmbus/max34440.c
+++ b/drivers/hwmon/pmbus/max34440.c
@@ -23,6 +23,7 @@ enum chips {
max34441,
max34446,
max34451,
+ max34452,
max34460,
max34461,
};
@@ -116,6 +117,10 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
return -ENXIO;
ret = -ENODATA;
break;
+ case PMBUS_VOUT_OV_WARN_LIMIT:
+ if (data->id == max34452)
+ return -ENXIO;
+ return -ENODATA;
case PMBUS_VIRT_READ_VOUT_MIN:
ret = pmbus_read_word_data(client, page, phase,
MAX34440_MFR_VOUT_MIN);
@@ -126,8 +131,8 @@ static int max34440_read_word_data(struct i2c_client *client, int page,
break;
case PMBUS_VIRT_READ_IOUT_AVG:
if (data->id != max34446 && data->id != max34451 &&
- data->id != adpm12160 && data->id != adpm12200 &&
- data->id != adpm12250)
+ data->id != max34452 && data->id != adpm12160 &&
+ data->id != adpm12200 && data->id != adpm12250)
return -ENXIO;
ret = pmbus_read_word_data(client, page, phase,
MAX34446_MFR_IOUT_AVG);
@@ -192,6 +197,10 @@ static int max34440_write_word_data(struct i2c_client *client, int page,
ret = pmbus_write_word_data(client, page, data->iout_oc_warn_limit,
word);
break;
+ case PMBUS_VOUT_OV_WARN_LIMIT:
+ if (data->id == max34452)
+ return -ENXIO;
+ return -ENODATA;
case PMBUS_VIRT_RESET_POUT_HISTORY:
ret = pmbus_write_word_data(client, page,
MAX34446_MFR_POUT_PEAK, 0);
@@ -212,8 +221,8 @@ static int max34440_write_word_data(struct i2c_client *client, int page,
ret = pmbus_write_word_data(client, page,
MAX34440_MFR_IOUT_PEAK, 0);
if (!ret && (data->id == max34446 || data->id == max34451 ||
- data->id == adpm12160 || data->id == adpm12200 ||
- data->id == adpm12250))
+ data->id == max34452 || data->id == adpm12160 ||
+ data->id == adpm12200 || data->id == adpm12250))
ret = pmbus_write_word_data(client, page,
MAX34446_MFR_IOUT_AVG, 0);
@@ -281,12 +290,13 @@ static int max34451_read_byte_data(struct i2c_client *client, int page, int reg)
case PMBUS_STATUS_BYTE:
case PMBUS_STATUS_OTHER:
/*
- * MAX34451/ADPM family do not support STATUS_BYTE or
+ * MAX34451/MAX34452/ADPM family do not support STATUS_BYTE or
* STATUS_OTHER registers. Accessing them triggers CML
* error and asserts ALERT.
*/
- if (data->id == max34451 || data->id == adpm12160 ||
- data->id == adpm12200 || data->id == adpm12250)
+ if (data->id == max34451 || data->id == max34452 ||
+ data->id == adpm12160 || data->id == adpm12200 ||
+ data->id == adpm12250)
return -ENXIO;
return -ENODATA;
default:
@@ -304,12 +314,13 @@ static int max34451_write_byte_data(struct i2c_client *client, int page,
case PMBUS_STATUS_BYTE:
case PMBUS_STATUS_OTHER:
/*
- * MAX34451/ADPM family do not support STATUS_BYTE or
+ * MAX34451/MAX34452/ADPM family do not support STATUS_BYTE or
* STATUS_OTHER registers. Writing to them triggers CML
* error and asserts ALERT.
*/
- if (data->id == max34451 || data->id == adpm12160 ||
- data->id == adpm12200 || data->id == adpm12250)
+ if (data->id == max34451 || data->id == max34452 ||
+ data->id == adpm12160 || data->id == adpm12200 ||
+ data->id == adpm12250)
return -ENXIO;
return -ENODATA;
default:
@@ -340,6 +351,7 @@ static int max34451_set_supported_funcs(struct i2c_client *client,
if (rv < 0)
return rv;
+ /* MAX34452's latest MFR_REV is only at 0x0004, will skip this part */
if (rv >= MAX34451ETNA6_MFR_REV) {
max34451_na6 = true;
data->info.format[PSC_VOLTAGE_IN] = direct;
@@ -678,6 +690,32 @@ static struct pmbus_driver_info max34440_info[] = {
.write_word_data = max34440_write_word_data,
.page_change_delay = MAX34440_PAGE_CHANGE_DELAY,
},
+ [max34452] = {
+ .pages = 21,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .format[PSC_TEMPERATURE] = direct,
+ .format[PSC_CURRENT_OUT] = direct,
+ .m[PSC_VOLTAGE_OUT] = 1,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .m[PSC_CURRENT_OUT] = 1,
+ .b[PSC_CURRENT_OUT] = 0,
+ .R[PSC_CURRENT_OUT] = 2,
+ .m[PSC_TEMPERATURE] = 1,
+ .b[PSC_TEMPERATURE] = 0,
+ .R[PSC_TEMPERATURE] = 2,
+ /* func 0-15 is set dynamically before probing */
+ .func[16] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[17] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[19] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .func[20] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
+ .read_byte_data = max34451_read_byte_data,
+ .read_word_data = max34440_read_word_data,
+ .write_byte_data = max34451_write_byte_data,
+ .write_word_data = max34440_write_word_data,
+ .page_change_delay = MAX34440_PAGE_CHANGE_DELAY,
+ },
[max34460] = {
.pages = 18,
.format[PSC_VOLTAGE_OUT] = direct,
@@ -761,7 +799,7 @@ static int max34440_probe(struct i2c_client *client)
data->iout_oc_fault_limit = MAX34440_IOUT_OC_FAULT_LIMIT;
data->iout_oc_warn_limit = MAX34440_IOUT_OC_WARN_LIMIT;
- if (data->id == max34451) {
+ if (data->id == max34451 || data->id == max34452) {
rv = max34451_set_supported_funcs(client, data);
if (rv)
return rv;
@@ -782,6 +820,7 @@ static const struct i2c_device_id max34440_id[] = {
{ .name = "max34441", .driver_data = max34441 },
{ .name = "max34446", .driver_data = max34446 },
{ .name = "max34451", .driver_data = max34451 },
+ { .name = "max34452", .driver_data = max34452 },
{ .name = "max34460", .driver_data = max34460 },
{ .name = "max34461", .driver_data = max34461 },
{ }
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread