From: Brian Chiang Date: Tue, 28 Apr 2026 12:19:29 +0000 (+0000) Subject: hwmon: (pmbus/lx1308) Add support for LX1308 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=d71d17d347deeb674115bf2f883a26c1920e7af6;p=thirdparty%2Flinux.git hwmon: (pmbus/lx1308) Add support for LX1308 Add support for the Luxshare LX1308, a high-efficiency 12V 860W DC/DC power module. The module operates from 40-60V input voltage. Signed-off-by: Brian Chiang Link: https://lore.kernel.org/r/20260428-add-support-lx1308-v2-2-90f115954143@inventec.com Signed-off-by: Guenter Roeck --- diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 96612a16f93ac..2ae3316c46659 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -146,6 +146,7 @@ Hardware Monitoring Kernel Drivers ltc4261 ltc4282 ltc4286 + lx1308 macsmc-hwmon max127 max15301 diff --git a/Documentation/hwmon/lx1308.rst b/Documentation/hwmon/lx1308.rst new file mode 100644 index 0000000000000..c1b72e1647c52 --- /dev/null +++ b/Documentation/hwmon/lx1308.rst @@ -0,0 +1,90 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver lx1308 +==================== + +Supported chips: + + * Luxshare LX1308 + + Prefixes: 'lx1308' + + Addresses scanned: - + + Datasheet: Datasheet is not publicly available. + +Author: Brian Chiang + + +Description +----------- + +The LX1308 is a high-efficiency, non-isolated, regulated 12V, 860W, +digital DC/DC power module. The module operates from a 40V to 60V DC +primary bus and provides a 12V regulated output voltage. It can deliver +up to 860W continuous and 1300W in transient. + +The module has slow OCP and fast OCP. If the module output current is higher +than slow OCP set point and the lasting time is also longer than the delay, +the module will shut down and retry 3 time, if the fault still exists then +module enter latch mode. + +If the module output current is higher than fast OCP set point then it shut +down and enter latch mode. + +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. + + +Sysfs entries +------------- + +======================= ====================================================== +curr1_alarm Input current alarm +curr1_input Input current (IIN) +curr1_label "iin" +curr2_crit Output over current fault threshold (slow OCP, 60ms delay) +curr2_crit_alarm Output over current fault alarm +curr2_input Output current (IOUT) +curr2_label "iout1" +curr2_max Output over current warning threshold (slow OCP, 60ms delay) +curr2_max_alarm Output over current warning alarm +in1_crit Input over voltage fault threshold +in1_crit_alarm Input over voltage fault alarm +in1_input Input voltage (VIN) +in1_label "vin" +in1_lcrit Input under voltage fault threshold +in1_lcrit_alarm Input under voltage fault alarm +in1_max Input over voltage warning threshold +in1_max_alarm Input over voltage warning alarm +in1_min Input under voltage warning threshold +in1_min_alarm Input under voltage warning alarm +in2_crit Output over voltage fault threshold +in2_crit_alarm Output over voltage fault alarm +in2_input Output voltage (VOUT) +in2_label "vout1" +in2_lcrit Output under voltage fault threshold +in2_lcrit_alarm Output under voltage fault alarm +in2_max Output over voltage warning threshold +in2_max_alarm Output over voltage warning alarm +in2_min Output under voltage warning threshold +in2_min_alarm Output under voltage warning alarm +power1_alarm Input power alarm +power1_input Input power (PIN) +power1_label "pin" +power2_input Output power (POUT) +power2_label "pout1" +temp1_crit Over temperature fault threshold +temp1_crit_alarm Over temperature fault alarm +temp1_input Module hot spot temperature +temp1_max Over temperature warning threshold +temp1_max_alarm Over temperature warning alarm +======================= ====================================================== diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 8a2c3ea50c8d8..1f99a333abc75 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -311,6 +311,16 @@ config SENSORS_LTC4286 If you say yes here you get hardware monitoring support for Analog Devices LTC4286. +config SENSORS_LX1308 + tristate "Luxshare LX1308 DC/DC Power Module" + help + If you say yes here you get hardware monitoring support for + Luxshare LX1308, a high-efficiency 12V 860W DC/DC power module + with PMBus interface. + + This driver can also be built as a module. If so, the module will + be called lx1308. + config SENSORS_MAX15301 tristate "Maxim MAX15301" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 6022614722bd1..039848ecee7f5 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_SENSORS_LT7182S) += lt7182s.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o obj-$(CONFIG_SENSORS_LTC4286) += ltc4286.o +obj-$(CONFIG_SENSORS_LX1308) += lx1308.o obj-$(CONFIG_SENSORS_MAX15301) += max15301.o obj-$(CONFIG_SENSORS_MAX16064) += max16064.o obj-$(CONFIG_SENSORS_MAX16601) += max16601.o diff --git a/drivers/hwmon/pmbus/lx1308.c b/drivers/hwmon/pmbus/lx1308.c new file mode 100644 index 0000000000000..0c453393796bf --- /dev/null +++ b/drivers/hwmon/pmbus/lx1308.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include "pmbus.h" + +#define LX1308_MFR_IOUT_OCP3_FAULT 0xBE +#define LX1308_MFR_IOUT_OCP3_WARN 0xBF + +/* + * Decode a Linear11-encoded word to an integer value. + * Linear11 format: bits[15:11] = signed 5-bit exponent, + * bits[10:0] = signed 11-bit mantissa. Result = mant * 2^exp. + */ +static inline int linear11_to_int(u16 word) +{ + s16 exp = ((s16)word) >> 11; + s16 mant = ((s16)((word & 0x7ff) << 5)) >> 5; + + return (exp >= 0) ? (int)((u32)mant << exp) : (mant >> -exp); +} + +static int lx1308_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + int ret; + + if (page > 0) + return -ENXIO; + + switch (reg) { + /* + * The LX1308 OCP3 registers (slow OCP, 60ms delay) use a + * manufacturer-specific U8.0 format. Read the byte value N and present + * it as a Linear11 word with exponent 0. + */ + case PMBUS_IOUT_OC_FAULT_LIMIT: + ret = i2c_smbus_read_byte_data(client, LX1308_MFR_IOUT_OCP3_FAULT); + if (ret < 0) + break; + ret &= 0x7FF; + break; + + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = i2c_smbus_read_byte_data(client, LX1308_MFR_IOUT_OCP3_WARN); + if (ret < 0) + break; + ret &= 0x7FF; + break; + + /* + * The following registers are not implemented by the LX1308. Return + * -ENXIO to suppress the corresponding sysfs attributes. + */ + case PMBUS_IIN_OC_WARN_LIMIT: + case PMBUS_IIN_OC_FAULT_LIMIT: + case PMBUS_IOUT_UC_FAULT_LIMIT: + case PMBUS_PIN_OP_WARN_LIMIT: + case PMBUS_POUT_OP_WARN_LIMIT: + case PMBUS_UT_WARN_LIMIT: + case PMBUS_UT_FAULT_LIMIT: + case PMBUS_MFR_IIN_MAX: + case PMBUS_MFR_IOUT_MAX: + case PMBUS_MFR_VIN_MIN: + case PMBUS_MFR_VIN_MAX: + case PMBUS_MFR_VOUT_MIN: + case PMBUS_MFR_VOUT_MAX: + case PMBUS_MFR_PIN_MAX: + case PMBUS_MFR_POUT_MAX: + case PMBUS_MFR_MAX_TEMP_1: + ret = -ENXIO; + break; + + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int lx1308_write_word_data(struct i2c_client *client, int page, + int reg, u16 word) +{ + int ret; + + if (page > 0) + return -ENXIO; + + switch (reg) { + case PMBUS_IOUT_OC_FAULT_LIMIT: + /* + * Decode Linear11 word from pmbus_core back to a plain integer + * and write as the U8.0 byte the device expects. + */ + ret = i2c_smbus_write_byte_data(client, LX1308_MFR_IOUT_OCP3_FAULT, + clamp_val(linear11_to_int(word), 0, 255)); + break; + + case PMBUS_IOUT_OC_WARN_LIMIT: + ret = i2c_smbus_write_byte_data(client, LX1308_MFR_IOUT_OCP3_WARN, + clamp_val(linear11_to_int(word), 0, 255)); + break; + + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static struct pmbus_driver_info lx1308_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_STATUS_INPUT, + + .read_word_data = lx1308_read_word_data, + .write_word_data = lx1308_write_word_data, +}; + +static const struct of_device_id lx1308_of_match[] = { + { .compatible = "luxshare,lx1308" }, + { } +}; + +MODULE_DEVICE_TABLE(of, lx1308_of_match); + +static const struct i2c_device_id lx1308_id[] = { + { "lx1308" }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, lx1308_id); + +static int lx1308_probe(struct i2c_client *client) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; + const struct i2c_device_id *mid; + int ret; + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read manufacturer id\n"); + buf[ret] = '\0'; + + if (ret != 12 || strncmp(buf, "LUXSHARE", 8)) + return dev_err_probe(&client->dev, -ENODEV, + "Unsupported Manufacturer ID '%s'\n", buf); + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read Manufacturer Model\n"); + buf[ret] = '\0'; + + for (mid = lx1308_id; mid->name[0]; mid++) { + if (!strncasecmp(mid->name, buf, strlen(mid->name))) + break; + } + if (!mid->name[0]) + return dev_err_probe(&client->dev, -ENODEV, + "Unsupported Manufacturer Model '%s'\n", buf); + + ret = i2c_smbus_read_block_data(client, PMBUS_MFR_REVISION, buf); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read Manufacturer Revision\n"); + buf[ret] = '\0'; + + if (ret != 12 || buf[0] != 'V') + return dev_err_probe(&client->dev, -ENODEV, + "Unsupported Manufacturer Revision '%s'\n", buf); + return pmbus_do_probe(client, &lx1308_info); +} + +static struct i2c_driver lx1308_driver = { + .driver = { + .name = "lx1308", + .of_match_table = lx1308_of_match, + }, + .probe = lx1308_probe, + .id_table = lx1308_id, +}; + +module_i2c_driver(lx1308_driver); + +MODULE_AUTHOR("Brian Chiang "); +MODULE_DESCRIPTION("PMBus driver for Luxshare LX1308"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS");