]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
hwmon: (pmbus/lx1308) Add support for LX1308
authorBrian Chiang <chiang.brian@inventec.com>
Tue, 28 Apr 2026 12:19:29 +0000 (12:19 +0000)
committerGuenter Roeck <linux@roeck-us.net>
Tue, 9 Jun 2026 15:22:52 +0000 (08:22 -0700)
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 <chiang.brian@inventec.com>
Link: https://lore.kernel.org/r/20260428-add-support-lx1308-v2-2-90f115954143@inventec.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Documentation/hwmon/index.rst
Documentation/hwmon/lx1308.rst [new file with mode: 0644]
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/lx1308.c [new file with mode: 0644]

index 96612a16f93ac1767a121b97c4afdf8dbb765f3e..2ae3316c46659a02ac08fac0f5dc55f9cc34a9c7 100644 (file)
@@ -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 (file)
index 0000000..c1b72e1
--- /dev/null
@@ -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 <chiang.brian@inventec.com>
+
+
+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
+======================= ======================================================
index 8a2c3ea50c8d8a2272662a224b5ab625cdf3b237..1f99a333abc75098d2c73b149d156634d08500e5 100644 (file)
@@ -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
index 6022614722bd18741a64bda4fcd9b7c07f35b65a..039848ecee7f53815d70741c8fee372237142151 100644 (file)
@@ -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 (file)
index 0000000..0c45339
--- /dev/null
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#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 <chiang.brian@inventec.com>");
+MODULE_DESCRIPTION("PMBus driver for Luxshare LX1308");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("PMBUS");