From 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 2 Sep 2026 15:31:14 -0700 Subject: treewide: refresh kmalloc_obj() conversions This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook --- drivers/hwmon/pmbus/max20830.c | 158 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 drivers/hwmon/pmbus/max20830.c (limited to 'drivers/hwmon/pmbus/max20830.c') diff --git a/drivers/hwmon/pmbus/max20830.c b/drivers/hwmon/pmbus/max20830.c new file mode 100644 index 000000000..4d25a084a --- /dev/null +++ b/drivers/hwmon/pmbus/max20830.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hardware monitoring driver for Analog Devices MAX20830 + * + * Copyright (C) 2026 Analog Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include "pmbus.h" + +#define MAX20830_IC_DEVICE_ID_LENGTH 9 + +struct max20830_data { + struct pmbus_driver_info info; + u32 vout_rfb1; + u32 vout_rfb2; +}; + +static const char * const supported_chip_ids[] = { + "MAX20830", + "MAX20830C", + "MAX20840C", +}; + +/* + * MAX20830 only supports READ_VOUT for VOUT monitoring. + * + * Limit registers (VOUT_OV_WARN_LIMIT, VOUT_OV_FAULT_LIMIT, etc.) are not + * supported by this driver and return -ENODATA. This means sysfs attributes + * like in1_max, in1_crit, etc. will not be available. Only in1_input (the + * scaled output voltage) is supported. + * + * MAX20830 uses an external resistor divider for voltage sensing: + * - VOUT_COMMAND and VOUT_MAX set the reference voltage at the feedback pin + * - READ_VOUT reports the feedback voltage, which needs to be scaled for actual + * output voltage + * + * Scaling formula: vout_actual = vout_fb × (1 + RFB1 / RFB2) + * + * If regulator support is added in the future, some adjustments are needed to + * ensure correct feedback voltages are set. + */ +static int max20830_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + const struct max20830_data *data = container_of(info, struct max20830_data, info); + int ret; + u64 temp; + + switch (reg) { + case PMBUS_READ_VOUT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + /* Apply voltage divider scaling if resistors are non-zero */ + if (data->vout_rfb1 && data->vout_rfb2) { + temp = (u64)data->vout_rfb1 + (u64)data->vout_rfb2; + temp = DIV_ROUND_CLOSEST_ULL((u64)ret * temp, data->vout_rfb2); + ret = clamp_val(temp, 0, 0xFFFF); + } + return ret; + default: + return -ENODATA; + } +} + +static struct pmbus_driver_info max20830_info = { + .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_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_TEMP | + PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, + .read_word_data = max20830_read_word_data, + .have_pmbus_revision = true, + .pmbus_revision = PMBUS_REV_13, +}; + +static int max20830_probe(struct i2c_client *client) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX + 1] = {}; + struct max20830_data *data; + int i, ret; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->info = max20830_info; + + /* Read optional voltage divider resistor values */ + device_property_read_u32(&client->dev, "adi,vout-rfb1-ohms", &data->vout_rfb1); + device_property_read_u32(&client->dev, "adi,vout-rfb2-ohms", &data->vout_rfb2); + + ret = pmbus_read_smbus_i2c_block_data(client, PMBUS_IC_DEVICE_ID, buf); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read IC_DEVICE_ID\n"); + + /* Verify we read the expected number of bytes */ + if (ret < MAX20830_IC_DEVICE_ID_LENGTH) + return dev_err_probe(&client->dev, -ENODEV, + "IC_DEVICE_ID too short: expected %d bytes, got %d\n", + MAX20830_IC_DEVICE_ID_LENGTH, ret); + + /* Null-terminate the string */ + buf[ret] = '\0'; + + /* Verify the device ID matches what we expect */ + for (i = 0; i < ARRAY_SIZE(supported_chip_ids); i++) { + if (!strcmp(buf, supported_chip_ids[i])) + break; + } + + /* No match found - unsupported device */ + if (i == ARRAY_SIZE(supported_chip_ids)) + return dev_err_probe(&client->dev, -ENODEV, + "Unsupported device: '%*pE'\n", ret, buf); + + return pmbus_do_probe(client, &data->info); +} + +static const struct i2c_device_id max20830_id[] = { + {"max20830"}, + { } +}; +MODULE_DEVICE_TABLE(i2c, max20830_id); + +static const struct of_device_id max20830_of_match[] = { + { .compatible = "adi,max20830" }, + { } +}; +MODULE_DEVICE_TABLE(of, max20830_of_match); + +static struct i2c_driver max20830_driver = { + .driver = { + .name = "max20830", + .of_match_table = max20830_of_match, + }, + .probe = max20830_probe, + .id_table = max20830_id, +}; + +module_i2c_driver(max20830_driver); + +MODULE_AUTHOR("Alexis Czezar Torreno "); +MODULE_DESCRIPTION("PMBus driver for Analog Devices MAX20830"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); -- cgit v1.3.1