From 895cbbc122589925ab7082c0a83285db74c32ff8 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 20 Nov 2024 09:33:50 +0100 Subject: [PATCH 01/44] hwmon: (isl28022) use proper path for DT bindings Vendor is "Renesas" not "ISL". Signed-off-by: Wolfram Sang Signed-off-by: Guenter Roeck --- Documentation/hwmon/isl28022.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/hwmon/isl28022.rst b/Documentation/hwmon/isl28022.rst index 8d4422a2dacd9..a7920a884b9f7 100644 --- a/Documentation/hwmon/isl28022.rst +++ b/Documentation/hwmon/isl28022.rst @@ -33,7 +33,7 @@ details. The shunt value in micro-ohms, shunt voltage range and averaging can be set with device properties. -Please refer to the Documentation/devicetree/bindings/hwmon/isl,isl28022.yaml +Please refer to the Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml for bindings if the device tree is used. The driver supports only shunt and bus continuous ADC mode at 15bit resolution. From 262a3f6ea8f11aaf27571712a0f983cbea874278 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 20 Nov 2024 09:33:51 +0100 Subject: [PATCH 02/44] hwmon: (isl28022) document shunt voltage channel During the upstreaming process, the driver has been extended to report the shunt voltage as well. Document that. Signed-off-by: Wolfram Sang Signed-off-by: Guenter Roeck --- Documentation/hwmon/isl28022.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/hwmon/isl28022.rst b/Documentation/hwmon/isl28022.rst index a7920a884b9f7..273ce54601357 100644 --- a/Documentation/hwmon/isl28022.rst +++ b/Documentation/hwmon/isl28022.rst @@ -48,6 +48,7 @@ The following attributes are supported. All attributes are read-only. ======================= ======================================================= in0_input bus voltage (milli Volt) +in1_input shunt voltage (milli Volt) curr1_input current (milli Ampere) power1_input power (micro Watt) From 10208399dbe0967880ed32ec43f663f644fde36e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 20 Nov 2024 09:33:52 +0100 Subject: [PATCH 03/44] hwmon: (isl28022) apply coding style to module init/exit Function declarations can be in one line. module_init|exit macros should be tied to the function. Signed-off-by: Wolfram Sang Signed-off-by: Guenter Roeck --- drivers/hwmon/isl28022.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/isl28022.c b/drivers/hwmon/isl28022.c index f9edcfd164c20..7748f6b8a5341 100644 --- a/drivers/hwmon/isl28022.c +++ b/drivers/hwmon/isl28022.c @@ -506,8 +506,7 @@ static struct i2c_driver isl28022_driver = { .id_table = isl28022_ids, }; -static int __init -isl28022_init(void) +static int __init isl28022_init(void) { int err; @@ -519,15 +518,13 @@ isl28022_init(void) debugfs_remove_recursive(isl28022_debugfs_root); return err; } +module_init(isl28022_init); -static void __exit -isl28022_exit(void) +static void __exit isl28022_exit(void) { i2c_del_driver(&isl28022_driver); debugfs_remove_recursive(isl28022_debugfs_root); } - -module_init(isl28022_init); module_exit(isl28022_exit); MODULE_AUTHOR("Carsten Spieß "); From f6477c85db0c34c8ed98c899d698251b4847d387 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Thu, 21 Nov 2024 22:44:55 +0100 Subject: [PATCH 04/44] MAINTAINERS: Drop IIO from the title of the Chipcap 2 hwmon driver The Chipcap 2 driver belongs to hwmon, and not to iio. When at it, drop the sensor type description, as that is documented elsewhere. Signed-off-by: Javier Carrasco Signed-off-by: Guenter Roeck --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 17daa9ee93845..74f8353c629f1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1226,7 +1226,7 @@ S: Maintained F: Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml F: drivers/rtc/rtc-amlogic-a4.c -AMPHENOL CHIPCAP 2 HUMIDITY-TEMPERATURE IIO DRIVER +AMPHENOL CHIPCAP 2 DRIVER M: Javier Carrasco L: linux-hwmon@vger.kernel.org S: Maintained From 232ba88182083b4410df41cf310c9a16b84e547e Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Thu, 21 Nov 2024 22:44:56 +0100 Subject: [PATCH 05/44] hwmon: (chipcap2) Switch to guard() for mutext handling Switch to guard() for mutex handling to simplify the code, getting rid of the 'ret = x, break; return ret;' construct and return the result of the operation instead. Signed-off-by: Javier Carrasco Signed-off-by: Guenter Roeck --- drivers/hwmon/chipcap2.c | 63 ++++++++++++---------------------------- 1 file changed, 18 insertions(+), 45 deletions(-) diff --git a/drivers/hwmon/chipcap2.c b/drivers/hwmon/chipcap2.c index edf454474f11c..9d071f7ca9d2e 100644 --- a/drivers/hwmon/chipcap2.c +++ b/drivers/hwmon/chipcap2.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -556,55 +557,40 @@ static int cc2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { struct cc2_data *data = dev_get_drvdata(dev); - int ret = 0; - mutex_lock(&data->dev_access_lock); + guard(mutex)(&data->dev_access_lock); switch (type) { case hwmon_temp: - ret = cc2_measurement(data, type, val); - break; + return cc2_measurement(data, type, val); case hwmon_humidity: switch (attr) { case hwmon_humidity_input: - ret = cc2_measurement(data, type, val); - break; + return cc2_measurement(data, type, val); case hwmon_humidity_min: - ret = cc2_get_reg_val(data, CC2_R_ALARM_L_ON, val); - break; + return cc2_get_reg_val(data, CC2_R_ALARM_L_ON, val); case hwmon_humidity_min_hyst: - ret = cc2_get_reg_val(data, CC2_R_ALARM_L_OFF, val); - break; + return cc2_get_reg_val(data, CC2_R_ALARM_L_OFF, val); case hwmon_humidity_max: - ret = cc2_get_reg_val(data, CC2_R_ALARM_H_ON, val); - break; + return cc2_get_reg_val(data, CC2_R_ALARM_H_ON, val); case hwmon_humidity_max_hyst: - ret = cc2_get_reg_val(data, CC2_R_ALARM_H_OFF, val); - break; + return cc2_get_reg_val(data, CC2_R_ALARM_H_OFF, val); case hwmon_humidity_min_alarm: - ret = cc2_humidity_min_alarm_status(data, val); - break; + return cc2_humidity_min_alarm_status(data, val); case hwmon_humidity_max_alarm: - ret = cc2_humidity_max_alarm_status(data, val); - break; + return cc2_humidity_max_alarm_status(data, val); default: - ret = -EOPNOTSUPP; + return -EOPNOTSUPP; } - break; default: - ret = -EOPNOTSUPP; + return -EOPNOTSUPP; } - - mutex_unlock(&data->dev_access_lock); - - return ret; } static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { struct cc2_data *data = dev_get_drvdata(dev); - int ret; u16 arg; u8 cmd; @@ -614,41 +600,28 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, if (val < 0 || val > CC2_RH_MAX) return -EINVAL; - mutex_lock(&data->dev_access_lock); + guard(mutex)(&data->dev_access_lock); switch (attr) { case hwmon_humidity_min: cmd = CC2_W_ALARM_L_ON; arg = cc2_rh_to_reg(val); - ret = cc2_write_reg(data, cmd, arg); - break; - + return cc2_write_reg(data, cmd, arg); case hwmon_humidity_min_hyst: cmd = CC2_W_ALARM_L_OFF; arg = cc2_rh_to_reg(val); - ret = cc2_write_reg(data, cmd, arg); - break; - + return cc2_write_reg(data, cmd, arg); case hwmon_humidity_max: cmd = CC2_W_ALARM_H_ON; arg = cc2_rh_to_reg(val); - ret = cc2_write_reg(data, cmd, arg); - break; - + return cc2_write_reg(data, cmd, arg); case hwmon_humidity_max_hyst: cmd = CC2_W_ALARM_H_OFF; arg = cc2_rh_to_reg(val); - ret = cc2_write_reg(data, cmd, arg); - break; - + return cc2_write_reg(data, cmd, arg); default: - ret = -EOPNOTSUPP; - break; + return -EOPNOTSUPP; } - - mutex_unlock(&data->dev_access_lock); - - return ret; } static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev) From 868dc3cd1105bd328be864bf2c409891438df44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 18 Nov 2024 07:15:58 +0100 Subject: [PATCH 06/44] thermal: core: Add stub for thermal_zone_device_update() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To simplify the !CONFIG_THERMAL case in the hwmon core, add a !CONFIG_THERMAL stub for thermal_zone_device_update(). Signed-off-by: Thomas Weißschuh Reviewed-by: Guenter Roeck Acked-by: Rafael J. Wysocki Signed-off-by: Guenter Roeck --- include/linux/thermal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 754802478b96a..69f9bedd0ee88 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -295,6 +295,10 @@ static inline struct thermal_zone_device *thermal_tripless_zone_device_register( static inline void thermal_zone_device_unregister(struct thermal_zone_device *tz) { } +static inline void thermal_zone_device_update(struct thermal_zone_device *tz, + enum thermal_notify_event event) +{ } + static inline struct thermal_cooling_device * thermal_cooling_device_register(const char *type, void *devdata, const struct thermal_cooling_device_ops *ops) From 4d2ffc42f78c429b7d42a635351a654c6f0b01b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Mon, 18 Nov 2024 07:15:59 +0100 Subject: [PATCH 07/44] hwmon: (core) Avoid ifdef CONFIG_THERMAL in C source file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using an #ifdef in a C source files to have different definitions of the same symbol makes the code harder to read and understand. Furthermore it makes it harder to test compilation of the different branches. Replace the ifdeffery with IS_ENABLED() which is just a normal conditional. The resulting binary is still the same as before as the compiler optimizes away all the unused code and definitions. Signed-off-by: Thomas Weißschuh Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/hwmon/hwmon.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index bbb9cc44e29fb..9ed750d4c4f51 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -158,11 +158,6 @@ static umode_t hwmon_is_visible(const struct hwmon_ops *ops, /* Thermal zone handling */ -/* - * The complex conditional is necessary to avoid a cyclic dependency - * between hwmon and thermal_sys modules. - */ -#ifdef CONFIG_THERMAL_OF static int hwmon_thermal_get_temp(struct thermal_zone_device *tz, int *temp) { struct hwmon_thermal_data *tdata = thermal_zone_device_priv(tz); @@ -268,6 +263,9 @@ static int hwmon_thermal_register_sensors(struct device *dev) void *drvdata = dev_get_drvdata(dev); int i; + if (!IS_ENABLED(CONFIG_THERMAL_OF)) + return 0; + for (i = 1; info[i]; i++) { int j; @@ -296,6 +294,9 @@ static void hwmon_thermal_notify(struct device *dev, int index) struct hwmon_device *hwdev = to_hwmon_device(dev); struct hwmon_thermal_data *tzdata; + if (!IS_ENABLED(CONFIG_THERMAL_OF)) + return; + list_for_each_entry(tzdata, &hwdev->tzdata, node) { if (tzdata->index == index) { thermal_zone_device_update(tzdata->tzd, @@ -304,16 +305,6 @@ static void hwmon_thermal_notify(struct device *dev, int index) } } -#else -static int hwmon_thermal_register_sensors(struct device *dev) -{ - return 0; -} - -static void hwmon_thermal_notify(struct device *dev, int index) { } - -#endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */ - static int hwmon_attr_base(enum hwmon_sensor_types type) { if (type == hwmon_in || type == hwmon_intrusion) From c26eef895794b31be8a2714b8a1b5d0b8b605bc4 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 2 Dec 2024 12:58:32 +0100 Subject: [PATCH 08/44] hwmon: (raspberrypi) Add PM suspend/resume support Add suspend/resume handler in order to stop firmware polling during s2idle. This was just waking-up the system without a real benefit. Signed-off-by: Stefan Wahren Signed-off-by: Guenter Roeck --- drivers/hwmon/raspberrypi-hwmon.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c index 10ef1e1f9458e..a2938881ccd2f 100644 --- a/drivers/hwmon/raspberrypi-hwmon.c +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -128,10 +128,32 @@ static int rpi_hwmon_probe(struct platform_device *pdev) return 0; } +static int rpi_hwmon_suspend(struct device *dev) +{ + struct rpi_hwmon_data *data = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&data->get_values_poll_work); + + return 0; +} + +static int rpi_hwmon_resume(struct device *dev) +{ + struct rpi_hwmon_data *data = dev_get_drvdata(dev); + + get_values_poll(&data->get_values_poll_work.work); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(rpi_hwmon_pm_ops, rpi_hwmon_suspend, + rpi_hwmon_resume); + static struct platform_driver rpi_hwmon_driver = { .probe = rpi_hwmon_probe, .driver = { .name = "raspberrypi-hwmon", + .pm = pm_ptr(&rpi_hwmon_pm_ops), }, }; module_platform_driver(rpi_hwmon_driver); From f40452577557caf0e5d0ff182da8479c3d492ac5 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 2 Dec 2024 11:28:00 +0100 Subject: [PATCH 09/44] hwmon: (pmbus/core) improve handling of write protected regulators Writing PMBus protected registers does succeed from the smbus perspective, even if the write is ignored by the device and a communication fault is raised. This fault will silently be caught and cleared by pmbus irq if one has been registered. This means that the regulator call may return succeed although the operation was ignored. With this change, the operation which are not supported will be properly flagged as such and the regulator framework won't even try to execute them. Signed-off-by: Jerome Brunet [groeck: Adjust to EXPORT_SYMBOL_NS_GPL API change] Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus-core.rst | 14 ++++++++ drivers/hwmon/pmbus/pmbus.h | 4 +++ drivers/hwmon/pmbus/pmbus_core.c | 52 ++++++++++++++++++++++++++---- include/linux/pmbus.h | 14 ++++++++ 4 files changed, 78 insertions(+), 6 deletions(-) diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 686a00265bf71..0a251960f8910 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -312,6 +312,10 @@ currently provides a flags field with four bits used:: #define PMBUS_USE_COEFFICIENTS_CMD BIT(5) + #define PMBUS_OP_PROTECTED BIT(6) + + #define PMBUS_VOUT_PROTECTED BIT(7) + struct pmbus_platform_data { u32 flags; /* Device specific flags */ @@ -373,3 +377,13 @@ PMBUS_USE_COEFFICIENTS_CMD When this flag is set the PMBus core driver will use the COEFFICIENTS register to initialize the coefficients for the direct mode format. + +PMBUS_OP_PROTECTED + +Set if the chip OPERATION command is protected and protection is not +determined by the standard WRITE_PROTECT command. + +PMBUS_VOUT_PROTECTED + +Set if the chip VOUT_COMMAND command is protected and protection is not +determined by the standard WRITE_PROTECT command. diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index d605412a3173b..ddb19c9726d62 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -487,6 +487,8 @@ struct pmbus_driver_info { /* Regulator ops */ extern const struct regulator_ops pmbus_regulator_ops; +int pmbus_regulator_init_cb(struct regulator_dev *rdev, + struct regulator_config *config); /* Macros for filling in array of struct regulator_desc */ #define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step, _min_uV) \ @@ -501,6 +503,7 @@ extern const struct regulator_ops pmbus_regulator_ops; .n_voltages = _voltages, \ .uV_step = _step, \ .min_uV = _min_uV, \ + .init_cb = pmbus_regulator_init_cb, \ } #define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0) @@ -516,6 +519,7 @@ extern const struct regulator_ops pmbus_regulator_ops; .n_voltages = _voltages, \ .uV_step = _step, \ .min_uV = _min_uV, \ + .init_cb = pmbus_regulator_init_cb, \ } #define PMBUS_REGULATOR_ONE(_name) PMBUS_REGULATOR_STEP_ONE(_name, 0, 0, 0) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index a1375cb6b648c..5976dd819b3c6 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2665,6 +2665,30 @@ static void pmbus_remove_pec(void *dev) device_remove_file(dev, &dev_attr_pec); } +static void pmbus_init_wp(struct i2c_client *client, struct pmbus_data *data) +{ + int ret; + + ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT); + if (ret < 0) + return; + + switch (ret & PB_WP_ANY) { + case PB_WP_ALL: + data->flags |= PMBUS_OP_PROTECTED; + fallthrough; + case PB_WP_OP: + data->flags |= PMBUS_VOUT_PROTECTED; + fallthrough; + case PB_WP_VOUT: + data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; + break; + + default: + break; + } +} + static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, struct pmbus_driver_info *info) { @@ -2718,12 +2742,8 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, * faults, and we should not try it. Also, in that case, writes into * limit registers need to be disabled. */ - if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) { - ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT); - - if (ret > 0 && (ret & PB_WP_ANY)) - data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; - } + if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) + pmbus_init_wp(client, data); ret = i2c_smbus_read_byte_data(client, PMBUS_REVISION); if (ret >= 0) @@ -3183,8 +3203,12 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, { struct device *dev = rdev_get_dev(rdev); struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_data *data = i2c_get_clientdata(client); int val, low, high; + if (data->flags & PMBUS_VOUT_PROTECTED) + return 0; + if (selector >= rdev->desc->n_voltages || selector < rdev->desc->linear_min_sel) return -EINVAL; @@ -3219,6 +3243,22 @@ const struct regulator_ops pmbus_regulator_ops = { }; EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, "PMBUS"); +int pmbus_regulator_init_cb(struct regulator_dev *rdev, + struct regulator_config *config) +{ + struct pmbus_data *data = config->driver_data; + struct regulation_constraints *constraints = rdev->constraints; + + if (data->flags & PMBUS_OP_PROTECTED) + constraints->valid_ops_mask &= ~REGULATOR_CHANGE_STATUS; + + if (data->flags & PMBUS_VOUT_PROTECTED) + constraints->valid_ops_mask &= ~REGULATOR_CHANGE_VOLTAGE; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(pmbus_regulator_init_cb, "PMBUS"); + static int pmbus_regulator_register(struct pmbus_data *data) { struct device *dev = data->dev; diff --git a/include/linux/pmbus.h b/include/linux/pmbus.h index fa9f08164c365..884040e1383bf 100644 --- a/include/linux/pmbus.h +++ b/include/linux/pmbus.h @@ -73,6 +73,20 @@ */ #define PMBUS_USE_COEFFICIENTS_CMD BIT(5) +/* + * PMBUS_OP_PROTECTED + * Set if the chip OPERATION command is protected and protection is not + * determined by the standard WRITE_PROTECT command. + */ +#define PMBUS_OP_PROTECTED BIT(6) + +/* + * PMBUS_VOUT_PROTECTED + * Set if the chip VOUT_COMMAND command is protected and protection is not + * determined by the standard WRITE_PROTECT command. + */ +#define PMBUS_VOUT_PROTECTED BIT(7) + struct pmbus_platform_data { u32 flags; /* Device specific flags */ From 83bed3c159f44bf2e205875feb8d932bbcf1b656 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 2 Dec 2024 11:28:01 +0100 Subject: [PATCH 10/44] hwmon: (pmbus/core) add wp module param Add a module parameter to force the write protection mode of pmbus chips. 4 protections modes are provided to start with: * 0: Remove the write protection * 1: Disable all writes except to the WRITE_PROTECT, OPERATION, PAGE, ON_OFF_CONFIG and VOUT_COMMAND commands * 2: Disable all writes except to the WRITE_PROTECT, OPERATION and PAGE commands * 3: Disable all writes except to the WRITE_PROTECT command Of course, if the parameter is not provided, the default write protection status of the pmbus chips is left untouched. Suggested-by: Guenter Roeck Signed-off-by: Jerome Brunet Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus-core.rst | 21 +++++++++++++++++++++ drivers/hwmon/pmbus/pmbus_core.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 0a251960f8910..fdfb237731486 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -387,3 +387,24 @@ PMBUS_VOUT_PROTECTED Set if the chip VOUT_COMMAND command is protected and protection is not determined by the standard WRITE_PROTECT command. + +Module parameter +---------------- + +pmbus_core.wp: PMBus write protect forced mode + +PMBus may come up with a variety of write protection configuration. +'pmbus_core.wp' may be used if a particular write protection is necessary. +The ability to actually alter the protection may also depend on the chip +so the actual runtime write protection configuration may differ from +the requested one. pmbus_core currently support the following value: + +* 0: write protection removed. +* 1: Disable all writes except to the WRITE_PROTECT, OPERATION, + PAGE, ON_OFF_CONFIG and VOUT_COMMAND commands. +* 2: Disable all writes except to the WRITE_PROTECT, OPERATION and + PAGE commands. +* 3: Disable all writes except to the WRITE_PROTECT command. Note that + protection should include the PAGE register. This may be problematic + for multi-page chips, if the chips strictly follows the PMBus + specification, preventing the chip from changing the active page. diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 5976dd819b3c6..a7000314e5add 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -31,6 +31,9 @@ #define PMBUS_ATTR_ALLOC_SIZE 32 #define PMBUS_NAME_SIZE 24 +static int wp = -1; +module_param(wp, int, 0444); + struct pmbus_sensor { struct pmbus_sensor *next; char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */ @@ -2669,6 +2672,32 @@ static void pmbus_init_wp(struct i2c_client *client, struct pmbus_data *data) { int ret; + switch (wp) { + case 0: + _pmbus_write_byte_data(client, -1, + PMBUS_WRITE_PROTECT, 0); + break; + + case 1: + _pmbus_write_byte_data(client, -1, + PMBUS_WRITE_PROTECT, PB_WP_VOUT); + break; + + case 2: + _pmbus_write_byte_data(client, -1, + PMBUS_WRITE_PROTECT, PB_WP_OP); + break; + + case 3: + _pmbus_write_byte_data(client, -1, + PMBUS_WRITE_PROTECT, PB_WP_ALL); + break; + + default: + /* Ignore the other values */ + break; + } + ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT); if (ret < 0) return; From 339bca4ffdaa7267b1597e634ac6002a133ad7b8 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 2 Dec 2024 11:28:02 +0100 Subject: [PATCH 11/44] hwmon: (pmbus/tps25990) Add initial support Add initial support for the Texas Instruments TPS25990 eFuse. This adds the basic PMBUS telemetry support for the device. From Karol Przybylski: The tps25990_read_word_data function contains a block of unreachable code caused by the syntactic structure in the PMBUS_VIRT_READ_IIN_MAX case. Specifically, the return TPS25990_READ_IIN_PEAK; statement immediately exits the function, making the next lines unreachable. This patch removes the return statement, leaving the expected handling. Discovered in coverity: CID 1602227 Tested-by: Vaishnav Achath Signed-off-by: Jerome Brunet [groeck: Adjust to MODULE_IMPORT_NS API change] [karprzy7@gmail.com: Fix unreachable code in tps25990_read_word_data] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/tps25990.rst | 147 +++++++++++ MAINTAINERS | 2 + drivers/hwmon/pmbus/Kconfig | 17 ++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/tps25990.c | 436 +++++++++++++++++++++++++++++++ 6 files changed, 604 insertions(+) create mode 100644 Documentation/hwmon/tps25990.rst create mode 100644 drivers/hwmon/pmbus/tps25990.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 55f1111594b2e..1a3cb0a59f721 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -236,6 +236,7 @@ Hardware Monitoring Kernel Drivers tmp464 tmp513 tps23861 + tps25990 tps40422 tps53679 tps546d24 diff --git a/Documentation/hwmon/tps25990.rst b/Documentation/hwmon/tps25990.rst new file mode 100644 index 0000000000000..04faec780d262 --- /dev/null +++ b/Documentation/hwmon/tps25990.rst @@ -0,0 +1,147 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver tps25990 +====================== + +Supported chips: + + * TI TPS25990 + + Prefix: 'tps25990' + + * Datasheet + + Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps25990 + +Author: + + Jerome Brunet + +Description +----------- + +This driver implements support for TI TPS25990 eFuse. +This is an integrated, high-current circuit protection and power +management device with PMBUS interface + +Device compliant with: + +- PMBus rev 1.3 interface. + +Device supports direct format for reading input voltages, +output voltage, input current, input power and temperature. + +Due to the specificities of the chip, all history reset attributes +are tied together. Resetting the history of a sensor, resets the +history of all the sensors. + +The driver exports the following attributes via the 'sysfs' files +for input current: + +**curr1_average** + +**curr1_crit** + +**curr1_crit_alarm** + +**curr1_highest** + +**curr1_input** + +**curr1_label** + +**curr1_max** + +**curr1_max_alarm** + +**curr1_reset_history** + +The driver provides the following attributes for main input voltage: + +**in1_average** + +**in1_crit** + +**in1_crit_alarm** + +**in1_highest** + +**in1_input** + +**in1_label** + +**in1_lcrit** + +**in1_lcrit_alarm** + +**in1_lowest** + +**in1_max** + +**in1_max_alarm** + +**in1_min** + +**in1_min_alarm** + +**in1_reset_history** + +The driver provides the following attributes for auxiliary input voltage: + +**in2_input** + +**in2_label** + +The driver provides the following attributes for output voltage: + +**in3_average** + +**in3_input** + +**in3_label** + +**in3_lowest** + +**in3_min** + +**in3_min_alarm** + +**in3_reset_history** + +The driver provides the following attributes for input power: + +**power1_alarm** + +**power1_average** + +**power1_input** + +**power1_input_highest** + +**power1_label** + +**power1_max** + +**power1_reset_history** + +The driver provides the following attributes for temperature: + +**temp1_average** + +**temp1_crit** + +**temp1_crit_alarm** + +**temp1_highest** + +**temp1_input** + +**temp1_max** + +**temp1_max_alarm** + +**temp1_reset_history** + +The driver provides the following attributes for sampling: + +**samples** diff --git a/MAINTAINERS b/MAINTAINERS index 74f8353c629f1..114d4f4960e95 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23218,6 +23218,8 @@ M: Jerome Brunet L: linux-hwmon@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml +F: Documentation/hwmon/tps25990.rst +F: drivers/hwmon/pmbus/tps25990.c TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER M: Robert Marko diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index f6d3528419536..22418a05ced0c 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -510,6 +510,23 @@ config SENSORS_TDA38640_REGULATOR If you say yes here you get regulator support for Infineon TDA38640 as regulator. +config SENSORS_TPS25990 + tristate "TI TPS25990" + help + If you say yes here you get hardware monitoring support for TI + TPS25990. + + This driver can also be built as a module. If so, the module will + be called tps25990. + +config SENSORS_TPS25990_REGULATOR + bool "Regulator support for TPS25990 and compatibles" + depends on SENSORS_TPS25990 && REGULATOR + default SENSORS_TPS25990 + help + If you say yes here you get regulator support for Texas Instruments + TPS25990. + config SENSORS_TPS40422 tristate "TI TPS40422" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index d00bcc758b972..3d3183f8d2a70 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o obj-$(CONFIG_SENSORS_TDA38640) += tda38640.o +obj-$(CONFIG_SENSORS_TPS25990) += tps25990.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o diff --git a/drivers/hwmon/pmbus/tps25990.c b/drivers/hwmon/pmbus/tps25990.c new file mode 100644 index 0000000000000..0d2655e69549f --- /dev/null +++ b/drivers/hwmon/pmbus/tps25990.c @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2024 BayLibre, SAS. +// Author: Jerome Brunet + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmbus.h" + +#define TPS25990_READ_VAUX 0xd0 +#define TPS25990_READ_VIN_MIN 0xd1 +#define TPS25990_READ_VIN_PEAK 0xd2 +#define TPS25990_READ_IIN_PEAK 0xd4 +#define TPS25990_READ_PIN_PEAK 0xd5 +#define TPS25990_READ_TEMP_AVG 0xd6 +#define TPS25990_READ_TEMP_PEAK 0xd7 +#define TPS25990_READ_VOUT_MIN 0xda +#define TPS25990_READ_VIN_AVG 0xdc +#define TPS25990_READ_VOUT_AVG 0xdd +#define TPS25990_READ_IIN_AVG 0xde +#define TPS25990_READ_PIN_AVG 0xdf +#define TPS25990_VIREF 0xe0 +#define TPS25990_PK_MIN_AVG 0xea +#define PK_MIN_AVG_RST_PEAK BIT(7) +#define PK_MIN_AVG_RST_AVG BIT(6) +#define PK_MIN_AVG_RST_MIN BIT(5) +#define PK_MIN_AVG_AVG_CNT GENMASK(2, 0) +#define TPS25990_MFR_WRITE_PROTECT 0xf8 +#define TPS25990_UNLOCKED BIT(7) + +#define TPS25990_8B_SHIFT 2 +#define TPS25990_VIN_OVF_NUM 525100 +#define TPS25990_VIN_OVF_DIV 10163 +#define TPS25990_VIN_OVF_OFF 155 +#define TPS25990_IIN_OCF_NUM 953800 +#define TPS25990_IIN_OCF_DIV 129278 +#define TPS25990_IIN_OCF_OFF 157 + +#define PK_MIN_AVG_RST_MASK (PK_MIN_AVG_RST_PEAK | \ + PK_MIN_AVG_RST_AVG | \ + PK_MIN_AVG_RST_MIN) + +/* + * Arbitrary default Rimon value: 1kOhm + * This correspond to an overcurrent limit of 55A, close to the specified limit + * of un-stacked TPS25990 and makes further calculation easier to setup in + * sensor.conf, if necessary + */ +#define TPS25990_DEFAULT_RIMON 1000000000 + +static void tps25990_set_m(int *m, u32 rimon) +{ + u64 val = ((u64)*m) * rimon; + + /* Make sure m fits the s32 type */ + *m = DIV_ROUND_CLOSEST_ULL(val, 1000000); +} + +static int tps25990_mfr_write_protect_set(struct i2c_client *client, + u8 protect) +{ + u8 val; + + switch (protect) { + case 0: + val = 0xa2; + break; + case PB_WP_ALL: + val = 0x0; + break; + default: + return -EINVAL; + } + + return pmbus_write_byte_data(client, -1, TPS25990_MFR_WRITE_PROTECT, + val); +} + +static int tps25990_mfr_write_protect_get(struct i2c_client *client) +{ + int ret = pmbus_read_byte_data(client, -1, TPS25990_MFR_WRITE_PROTECT); + + if (ret < 0) + return ret; + + return (ret & TPS25990_UNLOCKED) ? 0 : PB_WP_ALL; +} + +static int tps25990_read_word_data(struct i2c_client *client, + int page, int phase, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_VIRT_READ_VIN_MAX: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_VIN_PEAK); + break; + + case PMBUS_VIRT_READ_VIN_MIN: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_VIN_MIN); + break; + + case PMBUS_VIRT_READ_VIN_AVG: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_VIN_AVG); + break; + + case PMBUS_VIRT_READ_VOUT_MIN: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_VOUT_MIN); + break; + + case PMBUS_VIRT_READ_VOUT_AVG: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_VOUT_AVG); + break; + + case PMBUS_VIRT_READ_IIN_AVG: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_IIN_AVG); + break; + + case PMBUS_VIRT_READ_IIN_MAX: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_IIN_PEAK); + break; + + case PMBUS_VIRT_READ_TEMP_AVG: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_TEMP_AVG); + break; + + case PMBUS_VIRT_READ_TEMP_MAX: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_TEMP_PEAK); + break; + + case PMBUS_VIRT_READ_PIN_AVG: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_PIN_AVG); + break; + + case PMBUS_VIRT_READ_PIN_MAX: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_PIN_PEAK); + break; + + case PMBUS_VIRT_READ_VMON: + ret = pmbus_read_word_data(client, page, phase, + TPS25990_READ_VAUX); + break; + + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_VOUT_UV_WARN_LIMIT: + case PMBUS_IIN_OC_WARN_LIMIT: + case PMBUS_OT_WARN_LIMIT: + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_PIN_OP_WARN_LIMIT: + /* + * These registers provide an 8 bits value instead of a + * 10bits one. Just shifting twice the register value is + * enough to make the sensor type conversion work, even + * if the datasheet provides different m, b and R for + * those. + */ + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + break; + ret <<= TPS25990_8B_SHIFT; + break; + + case PMBUS_VIN_OV_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + break; + ret = DIV_ROUND_CLOSEST(ret * TPS25990_VIN_OVF_NUM, + TPS25990_VIN_OVF_DIV); + ret += TPS25990_VIN_OVF_OFF; + break; + + case PMBUS_IIN_OC_FAULT_LIMIT: + /* + * VIREF directly sets the over-current limit at which the eFuse + * will turn the FET off and trigger a fault. Expose it through + * this generic property instead of a manufacturer specific one. + */ + ret = pmbus_read_byte_data(client, page, TPS25990_VIREF); + if (ret < 0) + break; + ret = DIV_ROUND_CLOSEST(ret * TPS25990_IIN_OCF_NUM, + TPS25990_IIN_OCF_DIV); + ret += TPS25990_IIN_OCF_OFF; + break; + + case PMBUS_VIRT_SAMPLES: + ret = pmbus_read_byte_data(client, page, TPS25990_PK_MIN_AVG); + if (ret < 0) + break; + ret = 1 << FIELD_GET(PK_MIN_AVG_AVG_CNT, ret); + break; + + case PMBUS_VIRT_RESET_TEMP_HISTORY: + case PMBUS_VIRT_RESET_VIN_HISTORY: + case PMBUS_VIRT_RESET_IIN_HISTORY: + case PMBUS_VIRT_RESET_PIN_HISTORY: + case PMBUS_VIRT_RESET_VOUT_HISTORY: + ret = 0; + break; + + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int tps25990_write_word_data(struct i2c_client *client, + int page, int reg, u16 value) +{ + int ret; + + switch (reg) { + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_VOUT_UV_WARN_LIMIT: + case PMBUS_IIN_OC_WARN_LIMIT: + case PMBUS_OT_WARN_LIMIT: + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_PIN_OP_WARN_LIMIT: + value >>= TPS25990_8B_SHIFT; + value = clamp_val(value, 0, 0xff); + ret = pmbus_write_word_data(client, page, reg, value); + break; + + case PMBUS_VIN_OV_FAULT_LIMIT: + value -= TPS25990_VIN_OVF_OFF; + value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_VIN_OVF_DIV, + TPS25990_VIN_OVF_NUM); + value = clamp_val(value, 0, 0xf); + ret = pmbus_write_word_data(client, page, reg, value); + break; + + case PMBUS_IIN_OC_FAULT_LIMIT: + value -= TPS25990_IIN_OCF_OFF; + value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_IIN_OCF_DIV, + TPS25990_IIN_OCF_NUM); + value = clamp_val(value, 0, 0x3f); + ret = pmbus_write_byte_data(client, page, TPS25990_VIREF, value); + break; + + case PMBUS_VIRT_SAMPLES: + value = clamp_val(value, 1, 1 << PK_MIN_AVG_AVG_CNT); + value = ilog2(value); + ret = pmbus_update_byte_data(client, page, TPS25990_PK_MIN_AVG, + PK_MIN_AVG_AVG_CNT, + FIELD_PREP(PK_MIN_AVG_AVG_CNT, value)); + break; + + case PMBUS_VIRT_RESET_TEMP_HISTORY: + case PMBUS_VIRT_RESET_VIN_HISTORY: + case PMBUS_VIRT_RESET_IIN_HISTORY: + case PMBUS_VIRT_RESET_PIN_HISTORY: + case PMBUS_VIRT_RESET_VOUT_HISTORY: + /* + * TPS25990 has history resets based on MIN/AVG/PEAK instead of per + * sensor type. Exposing this quirk in hwmon is not desirable so + * reset MIN, AVG and PEAK together. Even is there effectively only + * one reset, which resets everything, expose the 5 entries so + * userspace is not required map a sensor type to another to trigger + * a reset + */ + ret = pmbus_update_byte_data(client, 0, TPS25990_PK_MIN_AVG, + PK_MIN_AVG_RST_MASK, + PK_MIN_AVG_RST_MASK); + break; + + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int tps25990_read_byte_data(struct i2c_client *client, + int page, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_WRITE_PROTECT: + ret = tps25990_mfr_write_protect_get(client); + break; + + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int tps25990_write_byte_data(struct i2c_client *client, + int page, int reg, u8 byte) +{ + int ret; + + switch (reg) { + case PMBUS_WRITE_PROTECT: + ret = tps25990_mfr_write_protect_set(client, byte); + break; + + default: + ret = -ENODATA; + break; + } + + return ret; +} + +#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR) +static const struct regulator_desc tps25990_reg_desc[] = { + PMBUS_REGULATOR_ONE("vout"), +}; +#endif + +static const struct pmbus_driver_info tps25990_base_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = direct, + .m[PSC_VOLTAGE_IN] = 5251, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = -2, + .format[PSC_VOLTAGE_OUT] = direct, + .m[PSC_VOLTAGE_OUT] = 5251, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = -2, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_TEMPERATURE] = 140, + .b[PSC_TEMPERATURE] = 32100, + .R[PSC_TEMPERATURE] = -2, + /* + * Current and Power measurement depends on the ohm value + * of Rimon. m is multiplied by 1000 below to have an integer + * and -3 is added to R to compensate. + */ + .format[PSC_CURRENT_IN] = direct, + .m[PSC_CURRENT_IN] = 9538, + .b[PSC_CURRENT_IN] = 0, + .R[PSC_CURRENT_IN] = -6, + .format[PSC_POWER] = direct, + .m[PSC_POWER] = 4901, + .b[PSC_POWER] = 0, + .R[PSC_POWER] = -7, + .func[0] = (PMBUS_HAVE_VIN | + PMBUS_HAVE_VOUT | + PMBUS_HAVE_VMON | + PMBUS_HAVE_IIN | + PMBUS_HAVE_PIN | + PMBUS_HAVE_TEMP | + PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_SAMPLES), + .read_word_data = tps25990_read_word_data, + .write_word_data = tps25990_write_word_data, + .read_byte_data = tps25990_read_byte_data, + .write_byte_data = tps25990_write_byte_data, + +#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR) + .reg_desc = tps25990_reg_desc, + .num_regulators = ARRAY_SIZE(tps25990_reg_desc), +#endif +}; + +static const struct i2c_device_id tps25990_i2c_id[] = { + { "tps25990" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, tps25990_i2c_id); + +static const struct of_device_id tps25990_of_match[] = { + { .compatible = "ti,tps25990" }, + {} +}; +MODULE_DEVICE_TABLE(of, tps25990_of_match); + +static int tps25990_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct pmbus_driver_info *info; + u32 rimon = TPS25990_DEFAULT_RIMON; + int ret; + + ret = device_property_read_u32(dev, "ti,rimon-micro-ohms", &rimon); + if (ret < 0 && ret != -EINVAL) + return dev_err_probe(dev, ret, "failed to get rimon\n"); + + info = devm_kmemdup(dev, &tps25990_base_info, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + /* Adapt the current and power scale for each instance */ + tps25990_set_m(&info->m[PSC_CURRENT_IN], rimon); + tps25990_set_m(&info->m[PSC_POWER], rimon); + + return pmbus_do_probe(client, info); +} + +static struct i2c_driver tps25990_driver = { + .driver = { + .name = "tps25990", + .of_match_table = tps25990_of_match, + }, + .probe = tps25990_probe, + .id_table = tps25990_i2c_id, +}; +module_i2c_driver(tps25990_driver); + +MODULE_AUTHOR("Jerome Brunet "); +MODULE_DESCRIPTION("PMBUS driver for TPS25990 eFuse"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); From 2505f87eb3af55f3dd7f57d7cb7783b94b52a2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 3 Dec 2024 18:31:49 +0100 Subject: [PATCH 12/44] hwmon: (nct6775): Actually make use of the HWMON_NCT6775 symbol namespace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DEFAULT_SYMBOL_NAMESPACE must already be defined when is included. So move the define above the include block. Fixes: c3963bc0a0cf ("hwmon: (nct6775) Split core and platform driver") Signed-off-by: Uwe Kleine-König Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index c243b51837d2f..fa3351351825b 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -42,6 +42,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#undef DEFAULT_SYMBOL_NAMESPACE +#define DEFAULT_SYMBOL_NAMESPACE "HWMON_NCT6775" + #include #include #include @@ -56,9 +59,6 @@ #include "lm75.h" #include "nct6775.h" -#undef DEFAULT_SYMBOL_NAMESPACE -#define DEFAULT_SYMBOL_NAMESPACE "HWMON_NCT6775" - #define USE_ALTERNATE /* used to set data->name = nct6775_device_names[data->sio_kind] */ From 7582b7ae896e3b63fbadbe08af28ba59c95a4d91 Mon Sep 17 00:00:00 2001 From: Li XingYang Date: Sun, 1 Dec 2024 11:47:44 +0800 Subject: [PATCH 13/44] hwmon: (asus-ec-sensors) Add support for fan cpu opt on AMD 600 motherboards According to the LibreHardwareMonitor project, LibreHardwareMonitorLib/ Hardware/Motherboard/Lpc/EC/EmbeddedController.cs file, fan cpu opt is supported by the AMD600 EC. Registers are described as follows. BoardFamily.Amd600, new Dictionary { { ECSensor.FanCPUOpt, new EmbeddedControllerSource ("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) }, } Add FanCPUOpt support for AMD600. Signed-off-by: Li XingYang [groeck: Massaged subject and description] Signed-off-by: Guenter Roeck --- drivers/hwmon/asus-ec-sensors.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index 9555366aeaf0d..381bf117104fa 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -250,6 +250,8 @@ static const struct ec_sensor_info sensors_family_amd_600[] = { EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00), [ec_sensor_temp_water_out] = EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01), + [ec_sensor_fan_cpu_opt] = + EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), }; static const struct ec_sensor_info sensors_family_intel_300[] = { From fd8caceaaeb4c74d7f3917209cc653f70e73f007 Mon Sep 17 00:00:00 2001 From: Li XingYang Date: Sun, 1 Dec 2024 11:47:45 +0800 Subject: [PATCH 14/44] hwmon: (asus-ec-sensors) Add TUF GAMING X670E PLUS Add support for TUF GAMING X670E PLUS. Signed-off-by: Li XingYang [groeck: Massaged description] Signed-off-by: Guenter Roeck --- Documentation/hwmon/asus_ec_sensors.rst | 1 + drivers/hwmon/asus-ec-sensors.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index ca38922f4ec56..739636cf79945 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -29,6 +29,7 @@ Supported boards: * ROG STRIX Z690-A GAMING WIFI D4 * ROG ZENITH II EXTREME * ROG ZENITH II EXTREME ALPHA + * TUF GAMING X670E PLUS Authors: - Eugene Shalygin diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index 381bf117104fa..43e54dc513daa 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -479,6 +479,15 @@ static const struct ec_board_info board_info_zenith_ii_extreme = { .family = family_amd_500_series, }; +static const struct ec_board_info board_info_tuf_gaming_x670e_plus = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | + SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT | + SENSOR_FAN_CPU_OPT, + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, + .family = family_amd_600_series, +}; + #define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, board_info) \ { \ .matches = { \ @@ -540,6 +549,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_zenith_ii_extreme), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA", &board_info_zenith_ii_extreme), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("TUF GAMING X670E-PLUS", + &board_info_tuf_gaming_x670e_plus), {}, }; From bddbb9cff4ab97ad367692201a0abe680a59d44d Mon Sep 17 00:00:00 2001 From: Stanislav Jakubek Date: Tue, 26 Nov 2024 09:40:35 +0100 Subject: [PATCH 15/44] hwmon: (tmp108) Add basic regulator support TMP108/P3T1085 are powered by the V+/VCC regulator, add support for it. Signed-off-by: Stanislav Jakubek Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp108.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index fbe6730091261..cd631e481d80c 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define DRIVER_NAME "tmp108" @@ -331,6 +332,10 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char * u32 config; int err; + err = devm_regulator_get_enable(dev, "vcc"); + if (err) + return dev_err_probe(dev, err, "Failed to enable regulator\n"); + tmp108 = devm_kzalloc(dev, sizeof(*tmp108), GFP_KERNEL); if (!tmp108) return -ENOMEM; From 27cad221a4dddc27b281fabcf500fd307a196bac Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 4 Dec 2024 06:17:54 -0800 Subject: [PATCH 16/44] hwmon: (tmp108) Drop of_match_ptr() protection Limiting the scope of devicetree support to CONFIG_OF prevents use of this driver with ACPI via PRP0001. Drop the dependency. While at it, - Switch of.h for mod_devicetable.h include given the use of struct of_device_id which is defined in that header - Add I2C device ID for p3t1085 - Drop the unnecessary include of hwmon-sysfs.h. Cc: Frank Li Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20241204141754.4051186-1-linux@roeck-us.net Reviewed-by: Frank Li Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp108.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index cd631e481d80c..a971ff628435b 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -8,10 +8,9 @@ #include #include #include -#include +#include #include #include -#include #include #include #include @@ -422,25 +421,24 @@ static int tmp108_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume); static const struct i2c_device_id tmp108_i2c_ids[] = { + { "p3t1085" }, { "tmp108" }, { } }; MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids); -#ifdef CONFIG_OF static const struct of_device_id tmp108_of_ids[] = { { .compatible = "nxp,p3t1085", }, { .compatible = "ti,tmp108", }, {} }; MODULE_DEVICE_TABLE(of, tmp108_of_ids); -#endif static struct i2c_driver tmp108_driver = { .driver = { .name = DRIVER_NAME, .pm = pm_sleep_ptr(&tmp108_dev_pm_ops), - .of_match_table = of_match_ptr(tmp108_of_ids), + .of_match_table = tmp108_of_ids, }, .probe = tmp108_probe, .id_table = tmp108_i2c_ids, From a4ea3e41befd012c967edfacacea1594b80f762e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 4 Dec 2024 15:08:57 +0100 Subject: [PATCH 17/44] hwmon: (isl28022) Drop explicit initialization of struct i2c_device_id::driver_data to 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This driver doesn't use the driver_data member of struct i2c_device_id, so don't explicitly initialize it. This prepares putting driver_data in an anonymous union which requires either no initialization or named designators. But it's also a nice cleanup on its own. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20241204140857.1691402-2-u.kleine-koenig@baylibre.com Signed-off-by: Guenter Roeck --- drivers/hwmon/isl28022.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/isl28022.c b/drivers/hwmon/isl28022.c index 7748f6b8a5341..3f9b4520b53ef 100644 --- a/drivers/hwmon/isl28022.c +++ b/drivers/hwmon/isl28022.c @@ -486,7 +486,7 @@ static int isl28022_probe(struct i2c_client *client) } static const struct i2c_device_id isl28022_ids[] = { - { "isl28022", 0}, + { "isl28022" }, { /* LIST END */ } }; MODULE_DEVICE_TABLE(i2c, isl28022_ids); From cf85760f6a0a656d06d9e2851fc82baf1240262a Mon Sep 17 00:00:00 2001 From: Max Ammann Date: Sat, 14 Dec 2024 11:22:01 +0100 Subject: [PATCH 18/44] hwmon: (nct6683) Add customer ID for ASRock B650 Steel Legend WiFi This value was found on an ASRock B650 Steel Legend WiFi with an NCT6686D chip. Signed-off-by: Max Ammann Link: https://lore.kernel.org/r/20241214102201.122851-1-max@maxammann.org [groeck: htmldocs fix] Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct6683.rst | 23 ++++++++++++----------- drivers/hwmon/nct6683.c | 3 +++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Documentation/hwmon/nct6683.rst b/Documentation/hwmon/nct6683.rst index 2a7a78eb1b468..1707844f6d660 100644 --- a/Documentation/hwmon/nct6683.rst +++ b/Documentation/hwmon/nct6683.rst @@ -55,14 +55,15 @@ Tested Boards and Firmware Versions The driver has been reported to work with the following boards and firmware versions. -=============== =============================================== -Board Firmware version -=============== =============================================== -Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13 -Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13 -Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13 -ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19 -ASRock X670E NCT6686D EC firmware version 1.0 build 05/19/22 -MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20 -MSI X670-P NCT6687D EC firmware version 0.0 build 09/27/22 -=============== =============================================== +=============================== =============================================== +Board Firmware version +=============================== =============================================== +Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13 +Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13 +Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13 +ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19 +ASRock X670E NCT6686D EC firmware version 1.0 build 05/19/22 +ASRock B650 Steel Legend WiFi NCT6686D EC firmware version 1.0 build 11/09/23 +MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20 +MSI X670-P NCT6687D EC firmware version 0.0 build 09/27/22 +=============================== =============================================== diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index f71615e06a8fb..3d31b8e2c8353 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -178,6 +178,7 @@ superio_exit(int ioreg) #define NCT6683_CUSTOMER_ID_ASROCK 0xe2c #define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b #define NCT6683_CUSTOMER_ID_ASROCK3 0x1631 +#define NCT6683_CUSTOMER_ID_ASROCK4 0x163e #define NCT6683_REG_BUILD_YEAR 0x604 #define NCT6683_REG_BUILD_MONTH 0x605 @@ -1233,6 +1234,8 @@ static int nct6683_probe(struct platform_device *pdev) break; case NCT6683_CUSTOMER_ID_ASROCK3: break; + case NCT6683_CUSTOMER_ID_ASROCK4: + break; default: if (!force) return -ENODEV; From 0f049da5b0568cafd39706cc87a1b689dcdae8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 15 Dec 2024 16:19:04 +0100 Subject: [PATCH 19/44] hwmon: (occ/p9_sbe) Constify 'struct bin_attribute' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sysfs core now allows instances of 'struct bin_attribute' to be moved into read-only memory. Make use of that to protect them against accidental or malicious modifications. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20241215-sysfs-const-bin_attr-hwmon-v1-1-ea72a6a46c36@weissschuh.net Signed-off-by: Guenter Roeck --- drivers/hwmon/occ/p9_sbe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c index 89761a9c8892f..1e3749dfa598c 100644 --- a/drivers/hwmon/occ/p9_sbe.c +++ b/drivers/hwmon/occ/p9_sbe.c @@ -30,7 +30,7 @@ struct p9_sbe_occ { #define to_p9_sbe_occ(x) container_of((x), struct p9_sbe_occ, occ) static ssize_t ffdc_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *battr, char *buf, loff_t pos, + const struct bin_attribute *battr, char *buf, loff_t pos, size_t count) { ssize_t rc = 0; @@ -48,7 +48,7 @@ static ssize_t ffdc_read(struct file *filp, struct kobject *kobj, return rc; } -static BIN_ATTR_RO(ffdc, OCC_MAX_RESP_WORDS * 4); +static const BIN_ATTR_RO(ffdc, OCC_MAX_RESP_WORDS * 4); static bool p9_sbe_occ_save_ffdc(struct p9_sbe_occ *ctx, const void *resp, size_t resp_len) From 30062044a1a652ad1722a19604b816e363af7089 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Mon, 16 Dec 2024 11:50:39 -0600 Subject: [PATCH 20/44] hwmon: (pmbus/core) Add PMBUS_REVISION in debugfs Add debugfs file for the PMBUS_REVISION command. This command provides information about PMBus protocol revision number. Signed-off-by: Ninad Palsule Link: https://lore.kernel.org/r/20241216175044.4144442-2-ninad@linux.ibm.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index a7000314e5add..787683e83db6c 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -3534,11 +3534,11 @@ static int pmbus_init_debugfs(struct i2c_client *client, /* * Allocate the max possible entries we need. - * 6 entries device-specific + * 7 entries device-specific * 10 entries page-specific */ entries = devm_kcalloc(data->dev, - 6 + data->info->pages * 10, sizeof(*entries), + 7 + data->info->pages * 10, sizeof(*entries), GFP_KERNEL); if (!entries) return -ENOMEM; @@ -3551,6 +3551,15 @@ static int pmbus_init_debugfs(struct i2c_client *client, * assume that values of the following registers are the same for all * pages and report values only for page 0. */ + if (pmbus_check_byte_register(client, 0, PMBUS_REVISION)) { + entries[idx].client = client; + entries[idx].page = 0; + entries[idx].reg = PMBUS_REVISION; + debugfs_create_file("revision", 0444, data->debugfs, + &entries[idx++], + &pmbus_debugfs_ops); + } + if (pmbus_check_block_register(client, 0, PMBUS_MFR_ID)) { entries[idx].client = client; entries[idx].page = 0; From 844029c59d44c590871b93fdc9720245a71f63c4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 18 Dec 2024 08:41:32 +0100 Subject: [PATCH 21/44] dt-bindings: hwmon: lm75: Add NXP P3T1755 Add this LM75 compatible sensor which needs a separate entry because of its default sampling time and SMBusAlert handling. Signed-off-by: Wolfram Sang Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20241218074131.4351-6-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lm75.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/hwmon/lm75.yaml b/Documentation/devicetree/bindings/hwmon/lm75.yaml index 29bd7460cc268..c38255243f572 100644 --- a/Documentation/devicetree/bindings/hwmon/lm75.yaml +++ b/Documentation/devicetree/bindings/hwmon/lm75.yaml @@ -28,6 +28,7 @@ properties: - maxim,max31725 - maxim,max31726 - maxim,mcp980x + - nxp,p3t1755 - nxp,pct2075 - st,stds75 - st,stlm75 From d3506653d01c0df1f1c86cd49fe70c98f00f1aef Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 18 Dec 2024 08:41:33 +0100 Subject: [PATCH 22/44] hwmon: (lm75) Add NXP P3T1755 support Add this LM75 compatible sensor which needs a separate entry because of its default sampling time and SMBusAlert handling. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20241218074131.4351-7-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm75.rst | 6 ++++-- drivers/hwmon/lm75.c | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Documentation/hwmon/lm75.rst b/Documentation/hwmon/lm75.rst index 6adab608dd05c..9877ddbbf7c87 100644 --- a/Documentation/hwmon/lm75.rst +++ b/Documentation/hwmon/lm75.rst @@ -121,9 +121,9 @@ Supported chips: https://www.ti.com/product/TMP1075 - * NXP LM75B, PCT2075 + * NXP LM75B, P3T1755, PCT2075 - Prefix: 'lm75b', 'pct2075' + Prefix: 'lm75b', 'p3t1755', 'pct2075' Addresses scanned: none @@ -131,6 +131,8 @@ Supported chips: https://www.nxp.com/documents/data_sheet/LM75B.pdf + https://www.nxp.com/docs/en/data-sheet/P3T1755.pdf + https://www.nxp.com/docs/en/data-sheet/PCT2075.pdf * AMS OSRAM AS6200 diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 2c2205aec7d40..a8f95bef68cbc 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -38,6 +38,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ max6626, max31725, mcp980x, + p3t1755, pct2075, stds75, stlm75, @@ -222,6 +223,13 @@ static const struct lm75_params device_params[] = { .default_resolution = 9, .default_sample_time = MSEC_PER_SEC / 18, }, + [p3t1755] = { + .clr_mask = 1 << 1 | 1 << 7, /* disable SMBAlert and one-shot */ + .default_resolution = 12, + .default_sample_time = 55, + .num_sample_times = 4, + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, + }, [pct2075] = { .default_resolution = 11, .default_sample_time = MSEC_PER_SEC / 10, @@ -734,6 +742,7 @@ static const struct i2c_device_id lm75_ids[] = { { "max31725", max31725, }, { "max31726", max31725, }, { "mcp980x", mcp980x, }, + { "p3t1755", p3t1755, }, { "pct2075", pct2075, }, { "stds75", stds75, }, { "stlm75", stlm75, }, @@ -813,6 +822,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = { .compatible = "maxim,mcp980x", .data = (void *)mcp980x }, + { + .compatible = "nxp,p3t1755", + .data = (void *)p3t1755 + }, { .compatible = "nxp,pct2075", .data = (void *)pct2075 From 409e29df6d149c37009c9547647cbb85f82d77e1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 18 Dec 2024 08:41:34 +0100 Subject: [PATCH 23/44] hwmon: (lm75) Fix LM75B document link NXP reorganized their website. Update the link for the LM75B datasheet. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20241218074131.4351-8-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/lm75.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/hwmon/lm75.rst b/Documentation/hwmon/lm75.rst index 9877ddbbf7c87..c6a54bbca3c51 100644 --- a/Documentation/hwmon/lm75.rst +++ b/Documentation/hwmon/lm75.rst @@ -129,7 +129,7 @@ Supported chips: Datasheet: Publicly available at the NXP website - https://www.nxp.com/documents/data_sheet/LM75B.pdf + https://www.nxp.com/docs/en/data-sheet/LM75B.pdf https://www.nxp.com/docs/en/data-sheet/P3T1755.pdf From 18e930f9813345abecbee994ede58ebac274e9f4 Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Tue, 17 Dec 2024 11:35:34 -0600 Subject: [PATCH 24/44] dt-bindings: hwmon: intel,crps185: Add to trivial Add INTEL Common Redundant Power Supply Versions crps185 bindings as trivial. The hardware does not have any resources like clocks which are required to be included in the device tree. Acked-by: Krzysztof Kozlowski Signed-off-by: Ninad Palsule Link: https://lore.kernel.org/r/20241217173537.192331-4-ninad@linux.ibm.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 88abb5c174f3b..6bdcd055e7639 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -149,6 +149,8 @@ properties: - injoinic,ip5209 # Inspur Power System power supply unit version 1 - inspur,ipsps1 + # Intel common redudant power supply crps185 + - intel,crps185 # Intersil ISL29028 Ambient Light and Proximity Sensor - isil,isl29028 # Intersil ISL29030 Ambient Light and Proximity Sensor From de076198d1e4934c5fc17aa52d5f1884f469ce1a Mon Sep 17 00:00:00 2001 From: Ninad Palsule Date: Tue, 17 Dec 2024 11:35:33 -0600 Subject: [PATCH 25/44] hwmon: (pmbus/crps) Add Intel CRPS185 power supply Add the driver to monitor Intel common redundant power supply (crps185) with hwmon over pmbus. Signed-off-by: Ninad Palsule Link: https://lore.kernel.org/r/20241217173537.192331-3-ninad@linux.ibm.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/crps.rst | 97 +++++++++++++++++++++++++++++++++++ Documentation/hwmon/index.rst | 1 + MAINTAINERS | 7 +++ drivers/hwmon/pmbus/Kconfig | 9 ++++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/crps.c | 74 ++++++++++++++++++++++++++ 6 files changed, 189 insertions(+) create mode 100644 Documentation/hwmon/crps.rst create mode 100644 drivers/hwmon/pmbus/crps.c diff --git a/Documentation/hwmon/crps.rst b/Documentation/hwmon/crps.rst new file mode 100644 index 0000000000000..87380b4965580 --- /dev/null +++ b/Documentation/hwmon/crps.rst @@ -0,0 +1,97 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver crps +================== + +Supported chips: + + * Intel CRPS185 + + Prefix: 'crps185' + + Addresses scanned: - + + Datasheet: Only available under NDA. + +Authors: + Ninad Palsule + + +Description +----------- + +This driver implements support for Intel Common Redundant Power supply with +PMBus support. + +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_label "iin" +curr1_input Measured input current +curr1_max Maximum input current +curr1_max_alarm Input maximum current high alarm +curr1_crit Critial high input current +curr1_crit_alarm Input critical current high alarm +curr1_rated_max Maximum rated input current + +curr2_label "iout1" +curr2_input Measured output current +curr2_max Maximum output current +curr2_max_alarm Output maximum current high alarm +curr2_crit Critial high output current +curr2_crit_alarm Output critical current high alarm +curr2_rated_max Maximum rated output current + +in1_label "vin" +in1_input Measured input voltage +in1_crit Critical input over voltage +in1_crit_alarm Critical input over voltage alarm +in1_max Maximum input over voltage +in1_max_alarm Maximum input over voltage alarm +in1_rated_min Minimum rated input voltage +in1_rated_max Maximum rated input voltage + +in2_label "vout1" +in2_input Measured input voltage +in2_crit Critical input over voltage +in2_crit_alarm Critical input over voltage alarm +in2_lcrit Critical input under voltage fault +in2_lcrit_alarm Critical input under voltage fault alarm +in2_max Maximum input over voltage +in2_max_alarm Maximum input over voltage alarm +in2_min Minimum input under voltage warning +in2_min_alarm Minimum input under voltage warning alarm +in2_rated_min Minimum rated input voltage +in2_rated_max Maximum rated input voltage + +power1_label "pin" +power1_input Measured input power +power1_alarm Input power high alarm +power1_max Maximum input power +power1_rated_max Maximum rated input power + +temp[1-2]_input Measured temperature +temp[1-2]_crit Critical temperature +temp[1-2]_crit_alarm Critical temperature alarm +temp[1-2]_max Maximum temperature +temp[1-2]_max_alarm Maximum temperature alarm +temp[1-2]_rated_max Maximum rated temperature + +fan1_alarm Fan 1 warning. +fan1_fault Fan 1 fault. +fan1_input Fan 1 speed in RPM. +fan1_target Fan 1 target. +======================= ====================================================== diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 1a3cb0a59f721..b1ea445479b0c 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -58,6 +58,7 @@ Hardware Monitoring Kernel Drivers corsair-cpro corsair-psu cros_ec_hwmon + crps da9052 da9055 dell-smm-hwmon diff --git a/MAINTAINERS b/MAINTAINERS index 114d4f4960e95..3792893695050 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6064,6 +6064,13 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/hid/hid-creative-sb0540.c +INTEL CRPS COMMON REDUNDANT PSU DRIVER +M: Ninad Palsule +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/crps.rst +F: drivers/hwmon/pmbus/crps.c + CRYPTO API M: Herbert Xu M: "David S. Miller" diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 22418a05ced0c..43b6df04e0f9c 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -85,6 +85,15 @@ config SENSORS_BPA_RS600 This driver can also be built as a module. If so, the module will be called bpa-rs600. +config SENSORS_CRPS + tristate "Intel Common Redundant Power Supply" + help + If you say yes here you get hardware monitoring support for the Intel + Common Redundant Power Supply. + + This driver can also be built as a module. If so, the module will + be called crps. + config SENSORS_DELTA_AHE50DC_FAN tristate "Delta AHE-50DC fan control module" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 3d3183f8d2a70..c7eb7739b7f86 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -62,3 +62,4 @@ obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o obj-$(CONFIG_SENSORS_XDPE152) += xdpe152c4.o obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o obj-$(CONFIG_SENSORS_PIM4328) += pim4328.o +obj-$(CONFIG_SENSORS_CRPS) += crps.o diff --git a/drivers/hwmon/pmbus/crps.c b/drivers/hwmon/pmbus/crps.c new file mode 100644 index 0000000000000..164b33fed312f --- /dev/null +++ b/drivers/hwmon/pmbus/crps.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2024 IBM Corp. + */ + +#include +#include +#include + +#include "pmbus.h" + +static const struct i2c_device_id crps_id[] = { + { "intel_crps185" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, crps_id); + +static struct pmbus_driver_info crps_info = { + .pages = 1, + /* PSU uses default linear data format. */ + .func[0] = PMBUS_HAVE_PIN | PMBUS_HAVE_IOUT | + PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_IIN | + PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | + PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12, +}; + +static int crps_probe(struct i2c_client *client) +{ + int rc; + struct device *dev = &client->dev; + char buf[I2C_SMBUS_BLOCK_MAX + 2] = { 0 }; + + rc = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (rc < 0) + return dev_err_probe(dev, rc, "Failed to read PMBUS_MFR_MODEL\n"); + + if (rc != 7 || strncmp(buf, "03NK260", 7)) { + buf[rc] = '\0'; + return dev_err_probe(dev, -ENODEV, "Model '%s' not supported\n", buf); + } + + rc = pmbus_do_probe(client, &crps_info); + if (rc) + return dev_err_probe(dev, rc, "Failed to probe\n"); + + return 0; +} + +static const struct of_device_id crps_of_match[] = { + { + .compatible = "intel,crps185", + }, + {} +}; +MODULE_DEVICE_TABLE(of, crps_of_match); + +static struct i2c_driver crps_driver = { + .driver = { + .name = "crps", + .of_match_table = crps_of_match, + }, + .probe = crps_probe, + .id_table = crps_id, +}; + +module_i2c_driver(crps_driver); + +MODULE_AUTHOR("Ninad Palsule"); +MODULE_DESCRIPTION("PMBus driver for Intel Common Redundant power supplies"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); From 6da24a25f766e02fbfc07570b5560154818ba59d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 17 Dec 2024 09:29:10 -0800 Subject: [PATCH 26/44] hwmon: (lm75) Hide register size differences in regmap access functions Hide register size differences in regmap access functions to simplify runtime code and to simplify adding support for I3C devices. Also use regmap API functions for bit operations where possible. For this to work, the 16-bit and 8-bit configuration register has to be mapped to a 16-bit value. Unlike other registers, this register is a low-byte-first register, presumably for compatibility with chips with 8-bit wide configuration registers. Hide the differences in the regmap access code. While at it, enable alarm attribute support for TMP112. Cc: Wolfram Sang Reviewed-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 131 ++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 69 deletions(-) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index a8f95bef68cbc..b8889392d5daa 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -111,7 +111,6 @@ struct lm75_data { struct regmap *regmap; struct regulator *vs; u16 orig_conf; - u16 current_conf; u8 resolution; /* In bits, 9 to 16 */ unsigned int sample_time; /* In ms */ enum lm75_type kind; @@ -284,6 +283,7 @@ static const struct lm75_params device_params[] = { .default_sample_time = 125, .num_sample_times = 4, .sample_times = (unsigned int []){ 125, 250, 1000, 4000 }, + .alarm = true, }, [tmp175] = { .set_mask = 3 << 5, /* 12-bit mode */ @@ -343,40 +343,16 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution) static int lm75_write_config(struct lm75_data *data, u16 set_mask, u16 clr_mask) { - unsigned int value; + int err; - clr_mask |= LM75_SHUTDOWN << (8 * data->params->config_reg_16bits); - value = data->current_conf & ~clr_mask; - value |= set_mask; + err = regmap_update_bits(data->regmap, LM75_REG_CONF, + clr_mask | LM75_SHUTDOWN, set_mask); + if (err) + return err; - if (data->current_conf != value) { - s32 err; - if (data->params->config_reg_16bits) - err = regmap_write(data->regmap, LM75_REG_CONF, value); - else - err = i2c_smbus_write_byte_data(data->client, - LM75_REG_CONF, - value); - if (err) - return err; - data->current_conf = value; - } return 0; } -static int lm75_read_config(struct lm75_data *data) -{ - int ret; - unsigned int status; - - if (data->params->config_reg_16bits) { - ret = regmap_read(data->regmap, LM75_REG_CONF, &status); - return ret ? ret : status; - } - - return i2c_smbus_read_byte_data(data->client, LM75_REG_CONF); -} - static irqreturn_t lm75_alarm_handler(int irq, void *private) { struct device *hwmon_dev = private; @@ -426,7 +402,8 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type, if (attr == hwmon_temp_alarm) { switch (data->kind) { case as6200: - *val = (regval >> 5) & 0x1; + case tmp112: + *val = (regval >> 13) & 0x1; break; default: return -EINVAL; @@ -477,7 +454,6 @@ static int lm75_write_temp(struct device *dev, u32 attr, long temp) static int lm75_update_interval(struct device *dev, long val) { struct lm75_data *data = dev_get_drvdata(dev); - unsigned int reg; u8 index; s32 err; @@ -497,19 +473,14 @@ static int lm75_update_interval(struct device *dev, long val) break; case tmp112: case as6200: - err = regmap_read(data->regmap, LM75_REG_CONF, ®); - if (err < 0) - return err; - reg &= ~0x00c0; - reg |= (3 - index) << 6; - err = regmap_write(data->regmap, LM75_REG_CONF, reg); + err = regmap_update_bits(data->regmap, LM75_REG_CONF, + 0xc000, (3 - index) << 14); if (err < 0) return err; data->sample_time = data->params->sample_times[index]; break; case pct2075: - err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE, - index + 1); + err = regmap_write(data->regmap, PCT2075_REG_IDLE, index + 1); if (err) return err; data->sample_time = data->params->sample_times[index]; @@ -606,6 +577,39 @@ static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) return reg == LM75_REG_TEMP || reg == LM75_REG_CONF; } +static int lm75_i2c_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct lm75_data *data = context; + struct i2c_client *client = data->client; + int ret; + + if (reg == LM75_REG_CONF) { + if (!data->params->config_reg_16bits) + ret = i2c_smbus_read_byte_data(client, LM75_REG_CONF); + else + ret = i2c_smbus_read_word_data(client, LM75_REG_CONF); + } else { + ret = i2c_smbus_read_word_swapped(client, reg); + } + if (ret < 0) + return ret; + *val = ret; + return 0; +} + +static int lm75_i2c_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct lm75_data *data = context; + struct i2c_client *client = data->client; + + if (reg == PCT2075_REG_IDLE || + (reg == LM75_REG_CONF && !data->params->config_reg_16bits)) + return i2c_smbus_write_byte_data(client, reg, val); + else if (reg == LM75_REG_CONF) + return i2c_smbus_write_word_data(client, reg, val); + return i2c_smbus_write_word_swapped(client, reg, val); +} + static const struct regmap_config lm75_regmap_config = { .reg_bits = 8, .val_bits = 16, @@ -618,6 +622,11 @@ static const struct regmap_config lm75_regmap_config = { .use_single_write = true, }; +static const struct regmap_bus lm75_i2c_regmap_bus = { + .reg_read = lm75_i2c_reg_read, + .reg_write = lm75_i2c_reg_write, +}; + static void lm75_disable_regulator(void *data) { struct lm75_data *lm75 = data; @@ -628,9 +637,8 @@ static void lm75_disable_regulator(void *data) static void lm75_remove(void *data) { struct lm75_data *lm75 = data; - struct i2c_client *client = lm75->client; - i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf); + regmap_write(lm75->regmap, LM75_REG_CONF, lm75->orig_conf); } static int lm75_probe(struct i2c_client *client) @@ -648,6 +656,9 @@ static int lm75_probe(struct i2c_client *client) if (!data) return -ENOMEM; + /* needed by custom regmap callbacks */ + dev_set_drvdata(dev, data); + data->client = client; data->kind = (uintptr_t)i2c_get_match_data(client); @@ -655,7 +666,8 @@ static int lm75_probe(struct i2c_client *client) if (IS_ERR(data->vs)) return PTR_ERR(data->vs); - data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config); + data->regmap = devm_regmap_init(dev, &lm75_i2c_regmap_bus, data, + &lm75_regmap_config); if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); @@ -681,13 +693,10 @@ static int lm75_probe(struct i2c_client *client) return err; /* Cache original configuration */ - status = lm75_read_config(data); - if (status < 0) { - dev_dbg(dev, "Can't read config? %d\n", status); - return status; - } + err = regmap_read(data->regmap, LM75_REG_CONF, &status); + if (err) + return err; data->orig_conf = status; - data->current_conf = status; err = lm75_write_config(data, data->params->set_mask, data->params->clr_mask); @@ -985,32 +994,16 @@ static int lm75_detect(struct i2c_client *new_client, #ifdef CONFIG_PM static int lm75_suspend(struct device *dev) { - int status; - struct i2c_client *client = to_i2c_client(dev); + struct lm75_data *data = dev_get_drvdata(dev); - status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); - if (status < 0) { - dev_dbg(&client->dev, "Can't read config? %d\n", status); - return status; - } - status = status | LM75_SHUTDOWN; - i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); - return 0; + return regmap_update_bits(data->regmap, LM75_REG_CONF, LM75_SHUTDOWN, LM75_SHUTDOWN); } static int lm75_resume(struct device *dev) { - int status; - struct i2c_client *client = to_i2c_client(dev); + struct lm75_data *data = dev_get_drvdata(dev); - status = i2c_smbus_read_byte_data(client, LM75_REG_CONF); - if (status < 0) { - dev_dbg(&client->dev, "Can't read config? %d\n", status); - return status; - } - status = status & ~LM75_SHUTDOWN; - i2c_smbus_write_byte_data(client, LM75_REG_CONF, status); - return 0; + return regmap_update_bits(data->regmap, LM75_REG_CONF, LM75_SHUTDOWN, 0); } static const struct dev_pm_ops lm75_dev_pm_ops = { From c4d08cf8a03eb9b14858a9b8cf8f4d71a639da57 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Dec 2024 23:55:23 +0100 Subject: [PATCH 27/44] hwmon: (lm75) simplify lm75_write_config() After previous refactoring, it is now possible to make lm75_write_config() a simple inline function. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20241219225522.3490-8-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index b8889392d5daa..b03e760cf3a1c 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -340,17 +340,11 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution) return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8); } -static int lm75_write_config(struct lm75_data *data, u16 set_mask, - u16 clr_mask) +static inline int lm75_write_config(struct lm75_data *data, u16 set_mask, + u16 clr_mask) { - int err; - - err = regmap_update_bits(data->regmap, LM75_REG_CONF, - clr_mask | LM75_SHUTDOWN, set_mask); - if (err) - return err; - - return 0; + return regmap_update_bits(data->regmap, LM75_REG_CONF, + clr_mask | LM75_SHUTDOWN, set_mask); } static irqreturn_t lm75_alarm_handler(int irq, void *private) From 2b64c6f652b0f5435b293d33f7d231132e987fb2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Dec 2024 23:55:24 +0100 Subject: [PATCH 28/44] hwmon: (lm75) simplify regulator handling devm_regulator_get_enable() was introduced exactly to avoid open coding regulator handling like in this driver. Make use of this helper. Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20241219225522.3490-9-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index b03e760cf3a1c..4d0fd1c93c630 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -109,7 +109,6 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, struct lm75_data { struct i2c_client *client; struct regmap *regmap; - struct regulator *vs; u16 orig_conf; u8 resolution; /* In bits, 9 to 16 */ unsigned int sample_time; /* In ms */ @@ -621,13 +620,6 @@ static const struct regmap_bus lm75_i2c_regmap_bus = { .reg_write = lm75_i2c_reg_write, }; -static void lm75_disable_regulator(void *data) -{ - struct lm75_data *lm75 = data; - - regulator_disable(lm75->vs); -} - static void lm75_remove(void *data) { struct lm75_data *lm75 = data; @@ -656,9 +648,9 @@ static int lm75_probe(struct i2c_client *client) data->client = client; data->kind = (uintptr_t)i2c_get_match_data(client); - data->vs = devm_regulator_get(dev, "vs"); - if (IS_ERR(data->vs)) - return PTR_ERR(data->vs); + err = devm_regulator_get_enable(dev, "vs"); + if (err) + return err; data->regmap = devm_regmap_init(dev, &lm75_i2c_regmap_bus, data, &lm75_regmap_config); @@ -675,17 +667,6 @@ static int lm75_probe(struct i2c_client *client) data->sample_time = data->params->default_sample_time; data->resolution = data->params->default_resolution; - /* Enable the power */ - err = regulator_enable(data->vs); - if (err) { - dev_err(dev, "failed to enable regulator: %d\n", err); - return err; - } - - err = devm_add_action_or_reset(dev, lm75_disable_regulator, data); - if (err) - return err; - /* Cache original configuration */ err = regmap_read(data->regmap, LM75_REG_CONF, &status); if (err) From 7a5c24da4b3c96949a6d93c3c7fa4133c6f2b88e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Dec 2024 23:55:25 +0100 Subject: [PATCH 29/44] hwmon: (lm75) Remove superfluous 'client' member from private struct The regmap-only conversion allows us to store the client-pointer as the 'context' parameter for regmap. This not only makes the private struct smaller, but also allows proper separation of I2C and I3C in the future. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20241219225522.3490-10-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 4d0fd1c93c630..0f034110daed3 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -105,9 +105,7 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, #define LM75_REG_MAX 0x03 #define PCT2075_REG_IDLE 0x04 -/* Each client has this additional data */ struct lm75_data { - struct i2c_client *client; struct regmap *regmap; u16 orig_conf; u8 resolution; /* In bits, 9 to 16 */ @@ -572,8 +570,8 @@ static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg) static int lm75_i2c_reg_read(void *context, unsigned int reg, unsigned int *val) { - struct lm75_data *data = context; - struct i2c_client *client = data->client; + struct i2c_client *client = context; + struct lm75_data *data = i2c_get_clientdata(client); int ret; if (reg == LM75_REG_CONF) { @@ -592,8 +590,8 @@ static int lm75_i2c_reg_read(void *context, unsigned int reg, unsigned int *val) static int lm75_i2c_reg_write(void *context, unsigned int reg, unsigned int val) { - struct lm75_data *data = context; - struct i2c_client *client = data->client; + struct i2c_client *client = context; + struct lm75_data *data = i2c_get_clientdata(client); if (reg == PCT2075_REG_IDLE || (reg == LM75_REG_CONF && !data->params->config_reg_16bits)) @@ -645,14 +643,13 @@ static int lm75_probe(struct i2c_client *client) /* needed by custom regmap callbacks */ dev_set_drvdata(dev, data); - data->client = client; data->kind = (uintptr_t)i2c_get_match_data(client); err = devm_regulator_get_enable(dev, "vs"); if (err) return err; - data->regmap = devm_regmap_init(dev, &lm75_i2c_regmap_bus, data, + data->regmap = devm_regmap_init(dev, &lm75_i2c_regmap_bus, client, &lm75_regmap_config); if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); From bc96dc1a1cdad999ccd84a7ea6d5e0926c26d8ce Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Dec 2024 23:55:26 +0100 Subject: [PATCH 30/44] hwmon: (lm75) separate probe into common and I2C parts Put generic probe functionality into a separate function and let the I2C driver call it. This is a preparation for adding I3C support which will also use the generic probe function. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20241219225522.3490-11-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 68 +++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 0f034110daed3..8b4f324524dae 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -601,6 +601,11 @@ static int lm75_i2c_reg_write(void *context, unsigned int reg, unsigned int val) return i2c_smbus_write_word_swapped(client, reg, val); } +static const struct regmap_bus lm75_i2c_regmap_bus = { + .reg_read = lm75_i2c_reg_read, + .reg_write = lm75_i2c_reg_write, +}; + static const struct regmap_config lm75_regmap_config = { .reg_bits = 8, .val_bits = 16, @@ -613,11 +618,6 @@ static const struct regmap_config lm75_regmap_config = { .use_single_write = true, }; -static const struct regmap_bus lm75_i2c_regmap_bus = { - .reg_read = lm75_i2c_reg_read, - .reg_write = lm75_i2c_reg_write, -}; - static void lm75_remove(void *data) { struct lm75_data *lm75 = data; @@ -625,17 +625,13 @@ static void lm75_remove(void *data) regmap_write(lm75->regmap, LM75_REG_CONF, lm75->orig_conf); } -static int lm75_probe(struct i2c_client *client) +static int lm75_generic_probe(struct device *dev, const char *name, + const void *kind_ptr, int irq, struct regmap *regmap) { - struct device *dev = &client->dev; struct device *hwmon_dev; struct lm75_data *data; int status, err; - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) - return -EIO; - data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -643,17 +639,13 @@ static int lm75_probe(struct i2c_client *client) /* needed by custom regmap callbacks */ dev_set_drvdata(dev, data); - data->kind = (uintptr_t)i2c_get_match_data(client); + data->kind = (uintptr_t)kind_ptr; + data->regmap = regmap; err = devm_regulator_get_enable(dev, "vs"); if (err) return err; - data->regmap = devm_regmap_init(dev, &lm75_i2c_regmap_bus, client, - &lm75_regmap_config); - if (IS_ERR(data->regmap)) - return PTR_ERR(data->regmap); - /* Set to LM75 resolution (9 bits, 1/2 degree C) and range. * Then tweak to be more precise when appropriate. */ @@ -679,20 +671,19 @@ static int lm75_probe(struct i2c_client *client) if (err) return err; - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, - data, &lm75_chip_info, - NULL); + hwmon_dev = devm_hwmon_device_register_with_info(dev, name, data, + &lm75_chip_info, NULL); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); - if (client->irq) { + if (irq) { if (data->params->alarm) { err = devm_request_threaded_irq(dev, - client->irq, + irq, NULL, &lm75_alarm_handler, IRQF_ONESHOT, - client->name, + name, hwmon_dev); if (err) return err; @@ -702,12 +693,29 @@ static int lm75_probe(struct i2c_client *client) } } - dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name); + dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), name); return 0; } -static const struct i2c_device_id lm75_ids[] = { +static int lm75_i2c_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) + return -EOPNOTSUPP; + + regmap = devm_regmap_init(dev, &lm75_i2c_regmap_bus, client, &lm75_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return lm75_generic_probe(dev, client->name, i2c_get_match_data(client), + client->irq, regmap); +} + +static const struct i2c_device_id lm75_i2c_ids[] = { { "adt75", adt75, }, { "as6200", as6200, }, { "at30ts74", at30ts74, }, @@ -740,7 +748,7 @@ static const struct i2c_device_id lm75_ids[] = { { "tmp1075", tmp1075, }, { /* LIST END */ } }; -MODULE_DEVICE_TABLE(i2c, lm75_ids); +MODULE_DEVICE_TABLE(i2c, lm75_i2c_ids); static const struct of_device_id __maybe_unused lm75_of_match[] = { { @@ -987,20 +995,20 @@ static const struct dev_pm_ops lm75_dev_pm_ops = { #define LM75_DEV_PM_OPS NULL #endif /* CONFIG_PM */ -static struct i2c_driver lm75_driver = { +static struct i2c_driver lm75_i2c_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "lm75", .of_match_table = of_match_ptr(lm75_of_match), .pm = LM75_DEV_PM_OPS, }, - .probe = lm75_probe, - .id_table = lm75_ids, + .probe = lm75_i2c_probe, + .id_table = lm75_i2c_ids, .detect = lm75_detect, .address_list = normal_i2c, }; -module_i2c_driver(lm75_driver); +module_i2c_driver(lm75_i2c_driver); MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("LM75 driver"); From 6071d10413ff8489c3e842b19b1e0d539700068d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 20 Dec 2024 10:36:34 +0100 Subject: [PATCH 31/44] hwmon: (lm75) add I3C support for P3T1755 Introduce I3C support by defining I3C accessors for regmap and implementing an I3C driver. Enable I3C for the NXP P3T1755. Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20241220093635.11218-1-wsa+renesas@sang-engineering.com Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 2 + drivers/hwmon/lm75.c | 121 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 119 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index dd376602f3f19..86897b4d105f6 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1412,7 +1412,9 @@ config SENSORS_LM73 config SENSORS_LM75 tristate "National Semiconductor LM75 and compatibles" depends on I2C + depends on I3C || !I3C select REGMAP_I2C + select REGMAP_I3C if I3C help If you say yes here you get support for one common type of temperature sensor chip, with models including: diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 8b4f324524dae..d95a3c6c245c5 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,8 @@ struct lm75_data { unsigned int sample_time; /* In ms */ enum lm75_type kind; const struct lm75_params *params; + u8 reg_buf[1]; + u8 val_buf[3]; }; /*-----------------------------------------------------------------------*/ @@ -606,6 +609,77 @@ static const struct regmap_bus lm75_i2c_regmap_bus = { .reg_write = lm75_i2c_reg_write, }; +static int lm75_i3c_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct i3c_device *i3cdev = context; + struct lm75_data *data = i3cdev_get_drvdata(i3cdev); + struct i3c_priv_xfer xfers[] = { + { + .rnw = false, + .len = 1, + .data.out = data->reg_buf, + }, + { + .rnw = true, + .len = 2, + .data.out = data->val_buf, + }, + }; + int ret; + + data->reg_buf[0] = reg; + + if (reg == LM75_REG_CONF && !data->params->config_reg_16bits) + xfers[1].len--; + + ret = i3c_device_do_priv_xfers(i3cdev, xfers, 2); + if (ret < 0) + return ret; + + if (reg == LM75_REG_CONF && !data->params->config_reg_16bits) + *val = data->val_buf[0]; + else if (reg == LM75_REG_CONF) + *val = data->val_buf[0] | (data->val_buf[1] << 8); + else + *val = data->val_buf[1] | (data->val_buf[0] << 8); + + return 0; +} + +static int lm75_i3c_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct i3c_device *i3cdev = context; + struct lm75_data *data = i3cdev_get_drvdata(i3cdev); + struct i3c_priv_xfer xfers[] = { + { + .rnw = false, + .len = 3, + .data.out = data->val_buf, + }, + }; + + data->val_buf[0] = reg; + + if (reg == PCT2075_REG_IDLE || + (reg == LM75_REG_CONF && !data->params->config_reg_16bits)) { + xfers[0].len--; + data->val_buf[1] = val & 0xff; + } else if (reg == LM75_REG_CONF) { + data->val_buf[1] = val & 0xff; + data->val_buf[2] = (val >> 8) & 0xff; + } else { + data->val_buf[1] = (val >> 8) & 0xff; + data->val_buf[2] = val & 0xff; + } + + return i3c_device_do_priv_xfers(i3cdev, xfers, 1); +} + +static const struct regmap_bus lm75_i3c_regmap_bus = { + .reg_read = lm75_i3c_reg_read, + .reg_write = lm75_i3c_reg_write, +}; + static const struct regmap_config lm75_regmap_config = { .reg_bits = 8, .val_bits = 16, @@ -626,7 +700,7 @@ static void lm75_remove(void *data) } static int lm75_generic_probe(struct device *dev, const char *name, - const void *kind_ptr, int irq, struct regmap *regmap) + enum lm75_type kind, int irq, struct regmap *regmap) { struct device *hwmon_dev; struct lm75_data *data; @@ -639,7 +713,7 @@ static int lm75_generic_probe(struct device *dev, const char *name, /* needed by custom regmap callbacks */ dev_set_drvdata(dev, data); - data->kind = (uintptr_t)kind_ptr; + data->kind = kind; data->regmap = regmap; err = devm_regulator_get_enable(dev, "vs"); @@ -711,7 +785,7 @@ static int lm75_i2c_probe(struct i2c_client *client) if (IS_ERR(regmap)) return PTR_ERR(regmap); - return lm75_generic_probe(dev, client->name, i2c_get_match_data(client), + return lm75_generic_probe(dev, client->name, (uintptr_t)i2c_get_match_data(client), client->irq, regmap); } @@ -750,6 +824,37 @@ static const struct i2c_device_id lm75_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, lm75_i2c_ids); +struct lm75_i3c_device { + enum lm75_type type; + const char *name; +}; + +static const struct lm75_i3c_device lm75_i3c_p3t1755 = { + .name = "p3t1755", + .type = p3t1755, +}; + +static const struct i3c_device_id lm75_i3c_ids[] = { + I3C_DEVICE(0x011b, 0x152a, &lm75_i3c_p3t1755), + { /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i3c, lm75_i3c_ids); + +static int lm75_i3c_probe(struct i3c_device *i3cdev) +{ + struct device *dev = i3cdev_to_dev(i3cdev); + const struct lm75_i3c_device *id_data; + struct regmap *regmap; + + regmap = devm_regmap_init(dev, &lm75_i3c_regmap_bus, i3cdev, &lm75_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + id_data = i3c_device_match_id(i3cdev, lm75_i3c_ids)->data; + + return lm75_generic_probe(dev, id_data->name, id_data->type, 0, regmap); +} + static const struct of_device_id __maybe_unused lm75_of_match[] = { { .compatible = "adi,adt75", @@ -1008,7 +1113,15 @@ static struct i2c_driver lm75_i2c_driver = { .address_list = normal_i2c, }; -module_i2c_driver(lm75_i2c_driver); +static struct i3c_driver lm75_i3c_driver = { + .driver = { + .name = "lm75_i3c", + }, + .probe = lm75_i3c_probe, + .id_table = lm75_i3c_ids, +}; + +module_i3c_i2c_driver(lm75_i3c_driver, &lm75_i2c_driver) MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("LM75 driver"); From 4b0447261b21efcb888e84ec1b37cf6436981874 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 2 Jan 2025 18:04:29 +0100 Subject: [PATCH 32/44] hwmon: (pwm-fan): Make use of device properties everywhere Commit 255ab27a0743 ("hwmon: (pwm-fan) Introduce start from stopped state handling") added two of_property_read_u32() calls after the driver was reworked to use device_property_* in commit dfd977d85b15 ("hwmon: (pwm-fan) Make use of device properties"), so convert those as well. Signed-off-by: Peter Korsgaard Reviewed-by: Marek Vasut Link: https://lore.kernel.org/r/20250102170429.791912-1-peter@korsgaard.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 53a1a968d00d4..231b3b348263d 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -638,16 +638,16 @@ static int pwm_fan_probe(struct platform_device *pdev) channels[1] = &ctx->fan_channel; } - ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-percent", - &pwm_min_from_stopped); + ret = device_property_read_u32(dev, "fan-stop-to-start-percent", + &pwm_min_from_stopped); if (!ret && pwm_min_from_stopped) { ctx->pwm_duty_cycle_from_stopped = DIV_ROUND_UP_ULL(pwm_min_from_stopped * (ctx->pwm_state.period - 1), 100); } - ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-us", - &ctx->pwm_usec_from_stopped); + ret = device_property_read_u32(dev, "fan-stop-to-start-us", + &ctx->pwm_usec_from_stopped); if (ret) ctx->pwm_usec_from_stopped = 250000; From a045a189f425e073ea5d6427ee66252eb990ed92 Mon Sep 17 00:00:00 2001 From: John Audia Date: Wed, 1 Jan 2025 08:27:59 -0500 Subject: [PATCH 33/44] hwmon: (nct6683) Add another customer ID for MSI The new customer ID was found on a MPG X870E CARBON WIFI (MS-7E49) with a NCT6687D chip. Signed-off-by: John Audia [groeck: Resolved conflicts in Documentation/hwmon/nct6683.rst] Signed-off-by: Guenter Roeck --- Documentation/hwmon/nct6683.rst | 1 + drivers/hwmon/nct6683.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Documentation/hwmon/nct6683.rst b/Documentation/hwmon/nct6683.rst index 1707844f6d660..8d4a20d99e598 100644 --- a/Documentation/hwmon/nct6683.rst +++ b/Documentation/hwmon/nct6683.rst @@ -66,4 +66,5 @@ ASRock X670E NCT6686D EC firmware version 1.0 build 05/19/22 ASRock B650 Steel Legend WiFi NCT6686D EC firmware version 1.0 build 11/09/23 MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20 MSI X670-P NCT6687D EC firmware version 0.0 build 09/27/22 +MSI X870E NCT6687D EC firmware version 0.0 build 11/13/24 =============================== =============================================== diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index 3d31b8e2c8353..416ac02e9f746 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -175,6 +175,7 @@ superio_exit(int ioreg) #define NCT6683_CUSTOMER_ID_MSI 0x201 #define NCT6683_CUSTOMER_ID_MSI2 0x200 #define NCT6683_CUSTOMER_ID_MSI3 0x207 +#define NCT6683_CUSTOMER_ID_MSI4 0x20d #define NCT6683_CUSTOMER_ID_ASROCK 0xe2c #define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b #define NCT6683_CUSTOMER_ID_ASROCK3 0x1631 @@ -1228,6 +1229,8 @@ static int nct6683_probe(struct platform_device *pdev) break; case NCT6683_CUSTOMER_ID_MSI3: break; + case NCT6683_CUSTOMER_ID_MSI4: + break; case NCT6683_CUSTOMER_ID_ASROCK: break; case NCT6683_CUSTOMER_ID_ASROCK2: From 2b2b62a91196d32fa488c719cf9d1f5001b92c1e Mon Sep 17 00:00:00 2001 From: John Erasmus Mari Geronimo Date: Mon, 6 Jan 2025 21:17:39 +0800 Subject: [PATCH 34/44] dt-bindings: hwmon: adm1275: add adm1273 Add support for the adm1273 Hot-Swap Controller and Digital Power and Energy Monitor Signed-off-by: John Erasmus Mari Geronimo Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250106131740.305988-2-johnerasmusmari.geronimo@analog.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml index 5b076d677395f..fd79bf2e0d168 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml @@ -24,6 +24,7 @@ properties: enum: - adi,adm1075 - adi,adm1272 + - adi,adm1273 - adi,adm1275 - adi,adm1276 - adi,adm1278 @@ -79,6 +80,7 @@ allOf: contains: enum: - adi,adm1272 + - adi,adm1273 then: properties: adi,volt-curr-sample-average: From adc52dd4078067fabf1431036ba180eafd8a7eee Mon Sep 17 00:00:00 2001 From: John Erasmus Mari Geronimo Date: Mon, 6 Jan 2025 21:17:40 +0800 Subject: [PATCH 35/44] hwmon: (pmbus/adm1275) add adm1273 support Add support for adm1273 which is similar to adm1275 and other chips of the series. Signed-off-by: John Erasmus Mari Geronimo Link: https://lore.kernel.org/r/20250106131740.305988-3-johnerasmusmari.geronimo@analog.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/adm1275.rst | 28 ++++++++++++++++++---------- drivers/hwmon/pmbus/Kconfig | 2 +- drivers/hwmon/pmbus/adm1275.c | 10 ++++++---- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Documentation/hwmon/adm1275.rst b/Documentation/hwmon/adm1275.rst index 467daf8ce3c5b..57bd7a8505589 100644 --- a/Documentation/hwmon/adm1275.rst +++ b/Documentation/hwmon/adm1275.rst @@ -19,6 +19,14 @@ Supported chips: Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1272.pdf + * Analog Devices ADM1273 + + Prefix: 'adm1273' + + Addresses scanned: - + + Datasheet: Not yet publicly available + * Analog Devices ADM1275 Prefix: 'adm1275' @@ -66,14 +74,14 @@ Description ----------- This driver supports hardware monitoring for Analog Devices ADM1075, ADM1272, -ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 Hot-Swap Controller and -Digital Power Monitors. +ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 Hot-Swap +Controller and Digital Power Monitors. -ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 are hot-swap -controllers that allow a circuit board to be removed from or inserted into -a live backplane. They also feature current and voltage readback via an -integrated 12 bit analog-to-digital converter (ADC), accessed using a -PMBus interface. +ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and +ADM1294 are hot-swap controllers that allow a circuit board to be removed from +or inserted into a live backplane. They also feature current and voltage +readback via an integrated 12 bit analog-to-digital converter (ADC), accessed +using a PMBus interface. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers. @@ -141,7 +149,7 @@ power1_input_highest Highest observed input power. power1_reset_history Write any value to reset history. Power attributes are supported on ADM1075, ADM1272, - ADM1276, ADM1293, and ADM1294. + ADM1273, ADM1276, ADM1293, and ADM1294. temp1_input Chip temperature. temp1_max Maximum chip temperature. @@ -151,6 +159,6 @@ temp1_crit_alarm Critical temperature high alarm. temp1_highest Highest observed temperature. temp1_reset_history Write any value to reset history. - Temperature attributes are supported on ADM1272 and - ADM1278, and ADM1281. + Temperature attributes are supported on ADM1272, + ADM1273, ADM1278, and ADM1281. ======================= ======================================================= diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 43b6df04e0f9c..233533e28f767 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -51,7 +51,7 @@ config SENSORS_ADM1275 tristate "Analog Devices ADM1275 and compatibles" help If you say yes here you get hardware monitoring support for Analog - Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1281, + Devices ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors. This driver can also be built as a module. If so, the module will diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 127593e10a03f..7d175baa5de2f 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -18,7 +18,7 @@ #include #include "pmbus.h" -enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1281, adm1293, adm1294 }; +enum chips { adm1075, adm1272, adm1273, adm1275, adm1276, adm1278, adm1281, adm1293, adm1294 }; #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) @@ -479,6 +479,7 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) static const struct i2c_device_id adm1275_id[] = { { "adm1075", adm1075 }, { "adm1272", adm1272 }, + { "adm1273", adm1273 }, { "adm1275", adm1275 }, { "adm1276", adm1276 }, { "adm1278", adm1278 }, @@ -555,9 +556,9 @@ static int adm1275_probe(struct i2c_client *client) "Device mismatch: Configured %s, detected %s\n", client->name, mid->name); - if (mid->driver_data == adm1272 || mid->driver_data == adm1278 || - mid->driver_data == adm1281 || mid->driver_data == adm1293 || - mid->driver_data == adm1294) + if (mid->driver_data == adm1272 || mid->driver_data == adm1273 || + mid->driver_data == adm1278 || mid->driver_data == adm1281 || + mid->driver_data == adm1293 || mid->driver_data == adm1294) config_read_fn = i2c_smbus_read_word_data; else config_read_fn = i2c_smbus_read_byte_data; @@ -630,6 +631,7 @@ static int adm1275_probe(struct i2c_client *client) PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; case adm1272: + case adm1273: data->have_vout = true; data->have_pin_max = true; data->have_temp_max = true; From 788bd792c74a3d1ddd0e49f5ddd68102dbbbe351 Mon Sep 17 00:00:00 2001 From: Nuno Sa Date: Wed, 8 Jan 2025 16:44:23 +0000 Subject: [PATCH 36/44] hwmon: (pmbus/max15301) Add support for MAX15303 The MAX15303 is a full-featured, flexible, efficient, 6A digital point-of-load (PoL) controller with integrated switching MOSFETs. It contains advanced power management and telemetry features. Tested-by: Robin Getz Signed-off-by: Nuno Sa Link: https://lore.kernel.org/r/20250108-dev-max15303-v1-1-9154eb2c9d9e@analog.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/max15301.rst | 8 ++++++++ drivers/hwmon/pmbus/Kconfig | 2 +- drivers/hwmon/pmbus/max15301.c | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/max15301.rst b/Documentation/hwmon/max15301.rst index e3dc22fe1c6d0..e2222e98304fd 100644 --- a/Documentation/hwmon/max15301.rst +++ b/Documentation/hwmon/max15301.rst @@ -13,6 +13,14 @@ Supported chips: Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX15301.pdf + * Maxim MAX15303 + + Prefix: 'max15303' + + Addresses scanned: - + + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max15303.pdf + Author: Erik Rosen diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 233533e28f767..419469f40ba02 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -260,7 +260,7 @@ config SENSORS_MAX15301 tristate "Maxim MAX15301" help If you say yes here you get hardware monitoring support for Maxim - MAX15301, as well as for Flex BMR461. + MAX15301, MAX15303, as well as for Flex BMR461. This driver can also be built as a module. If so, the module will be called max15301. diff --git a/drivers/hwmon/pmbus/max15301.c b/drivers/hwmon/pmbus/max15301.c index 50dfd477772ff..d5810b88ea8d8 100644 --- a/drivers/hwmon/pmbus/max15301.c +++ b/drivers/hwmon/pmbus/max15301.c @@ -25,6 +25,7 @@ static const struct i2c_device_id max15301_id[] = { { "bmr461" }, { "max15301" }, + { "max15303" }, {} }; MODULE_DEVICE_TABLE(i2c, max15301_id); From c909e68f81279cb5147c6f4a7ecf80e4c6c19b04 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 9 Jan 2025 20:53:55 +0100 Subject: [PATCH 37/44] hwmon: (core) Use device name as a fallback in devm_hwmon_device_register_with_info A number of network PHY drivers use the following code: name = devm_hwmon_sanitize_name(dev, dev_name(dev)); if (IS_ERR(name)) return PTR_ERR(name); devm_hwmon_device_register_with_info(dev, name, ..); Make this a generic fallback option and use the device name if no name is provided to devm_hwmon_device_register_with_info(). This would allow to simplify the affected drivers. Signed-off-by: Heiner Kallweit Link: https://lore.kernel.org/r/1ebe6961-6445-4408-bfb4-b56173af9db5@gmail.com [groeck: Update API document] Signed-off-by: Guenter Roeck --- Documentation/hwmon/hwmon-kernel-api.rst | 3 ++- drivers/hwmon/hwmon.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst index 8297acfa3a2d8..e47fc757e63ed 100644 --- a/Documentation/hwmon/hwmon-kernel-api.rst +++ b/Documentation/hwmon/hwmon-kernel-api.rst @@ -64,7 +64,8 @@ hwmon_device_register_with_info. All supported hwmon device registration functions only accept valid device names. Device names including invalid characters (whitespace, '*', or '-') -will be rejected. The 'name' parameter is mandatory. +will be rejected. If NULL is passed as name parameter, the hardware monitoring +device name will be derived from the parent device name. If the driver doesn't use a static device name (for example it uses dev_name()), and therefore cannot make sure the name only contains valid diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 9ed750d4c4f51..b7c0b1e3c23b8 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -1170,6 +1170,12 @@ devm_hwmon_device_register_with_info(struct device *dev, const char *name, if (!dev) return ERR_PTR(-EINVAL); + if (!name) { + name = devm_hwmon_sanitize_name(dev, dev_name(dev)); + if (IS_ERR(name)) + return ERR_CAST(name); + } + ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) return ERR_PTR(-ENOMEM); From 7532e68f5d8f05353765d7585a791a14985d68b7 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Thu, 9 Jan 2025 16:17:07 +0800 Subject: [PATCH 38/44] hwmon: (acpi_power_meter) Fix uninitialized variables The 'power1_alarm' attribute uses the 'power' and 'cap' in the acpi_power_meter_resource structure. Currently, these two fields are just updated when user query 'power' and 'cap' attribute. If user directly query the 'power1_alarm' attribute without queryng above two attributes, driver will use uninitialized variables to judge. So this patch adds the setting of alarm state and update 'cap' in the notification callback and update 'power' and 'cap' if needed to show the real alarm state. Signed-off-by: Huisong Li Link: https://lore.kernel.org/r/20250109081708.27366-2-lihuisong@huawei.com Signed-off-by: Guenter Roeck --- drivers/hwmon/acpi_power_meter.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 2f1c9d97ad211..dcf86794485fe 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -84,6 +84,7 @@ struct acpi_power_meter_resource { u64 power; u64 cap; u64 avg_interval; + bool power_alarm; int sensors_valid; unsigned long sensors_last_updated; struct sensor_device_attribute sensors[NUM_SENSORS]; @@ -396,6 +397,9 @@ static ssize_t show_val(struct device *dev, struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_power_meter_resource *resource = acpi_dev->driver_data; u64 val = 0; + int ret; + + guard(mutex)(&resource->lock); switch (attr->index) { case 0: @@ -423,10 +427,17 @@ static ssize_t show_val(struct device *dev, val = 0; break; case 6: - if (resource->power > resource->cap) - val = 1; - else - val = 0; + ret = update_meter(resource); + if (ret) + return ret; + /* need to update cap if not to support the notification. */ + if (!(resource->caps.flags & POWER_METER_CAN_NOTIFY)) { + ret = update_cap(resource); + if (ret) + return ret; + } + val = resource->power_alarm || resource->power > resource->cap; + resource->power_alarm = resource->power > resource->cap; break; case 7: case 8: @@ -847,12 +858,20 @@ static void acpi_power_meter_notify(struct acpi_device *device, u32 event) sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME); break; case METER_NOTIFY_CAP: + mutex_lock(&resource->lock); + res = update_cap(resource); + if (res) + dev_err_once(&device->dev, "update cap failed when capping value is changed.\n"); + mutex_unlock(&resource->lock); sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME); break; case METER_NOTIFY_INTERVAL: sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME); break; case METER_NOTIFY_CAPPING: + mutex_lock(&resource->lock); + resource->power_alarm = true; + mutex_unlock(&resource->lock); sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME); dev_info(&device->dev, "Capping in progress.\n"); break; From 02f1a5911550bd6b39526d18282b10d441e04ed1 Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Thu, 9 Jan 2025 16:17:08 +0800 Subject: [PATCH 39/44] hwmon: (acpi_power_meter) Fix update the power trip points on failure The power trip points maintained in local should not be updated when '_PTP' method fails to evaluate. Signed-off-by: Huisong Li Link: https://lore.kernel.org/r/20250109081708.27366-3-lihuisong@huawei.com Signed-off-by: Guenter Roeck --- drivers/hwmon/acpi_power_meter.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index dcf86794485fe..65de2cadfc60e 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -293,8 +293,8 @@ static ssize_t set_trip(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_power_meter_resource *resource = acpi_dev->driver_data; + unsigned long temp, trip_bk; int res; - unsigned long temp; res = kstrtoul(buf, 10, &temp); if (res) @@ -302,13 +302,15 @@ static ssize_t set_trip(struct device *dev, struct device_attribute *devattr, temp = DIV_ROUND_CLOSEST(temp, 1000); - mutex_lock(&resource->lock); + guard(mutex)(&resource->lock); + + trip_bk = resource->trip[attr->index - 7]; resource->trip[attr->index - 7] = temp; res = set_acpi_trip(resource); - mutex_unlock(&resource->lock); - - if (res) + if (res) { + resource->trip[attr->index - 7] = trip_bk; return res; + } return count; } From 516b0138003647181654a5c8022399bba5a0136a Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Thu, 9 Jan 2025 23:07:00 +0200 Subject: [PATCH 40/44] hwmon: (dell-smm) Add Dell XPS 9370 to fan control whitelist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the Dell XPS 9370 to the fan control whitelist to allow for manual fan control. Signed-off-by: Povilas Kanapickas Reviewed-by: Armin Wolf Acked-by: Pali Rohár Link: https://lore.kernel.org/r/6e6b7a47-d0e3-4c5a-8be2-dfc58852da8e@radix.lt Signed-off-by: Guenter Roeck --- drivers/hwmon/dell-smm-hwmon.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index f5bdf842040e6..cd00adaad1b41 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -1544,6 +1544,14 @@ static const struct dmi_system_id i8k_whitelist_fan_control[] __initconst = { }, .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], }, + { + .ident = "Dell XPS 13 9370", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 13 9370"), + }, + .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_30A3_31A3], + }, { .ident = "Dell Optiplex 7000", .matches = { From c8571eab11131cce6dcce76b3345c1524e074071 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Fri, 10 Jan 2025 22:17:36 +1030 Subject: [PATCH 41/44] hwmon: Fix help text for aspeed-g6-pwm-tach The help text has the wrong module name mentioned, and the capitalisation of the title is inconsistent. Fixes: 7e1449cd15d1 ("hwmon: (aspeed-g6-pwm-tacho): Support for ASPEED g6 PWM/Fan tach") Signed-off-by: Joel Stanley Link: https://lore.kernel.org/r/20250110114737.64035-1-joel@jms.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 86897b4d105f6..760c1a1cf30cd 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -413,7 +413,7 @@ config SENSORS_ASPEED will be called aspeed_pwm_tacho. config SENSORS_ASPEED_G6 - tristate "ASPEED g6 PWM and Fan tach driver" + tristate "ASPEED G6 PWM and Fan tach driver" depends on ARCH_ASPEED || COMPILE_TEST depends on PWM help @@ -421,7 +421,7 @@ config SENSORS_ASPEED_G6 controllers. This driver can also be built as a module. If so, the module - will be called aspeed_pwm_tacho. + will be called aspeed_g6_pwm_tach. config SENSORS_ATXP1 tristate "Attansic ATXP1 VID controller" From 74a2594a2767e890348ef4cfe64b7908d00d5353 Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Sun, 12 Jan 2025 11:51:28 +0100 Subject: [PATCH 42/44] hwmon: (asus_atk0110) Use str_enabled_disabled() and str_enable_disable() helpers Remove hard-coded strings by using the str_enabled_disabled() and str_enable_disable() helper functions. Signed-off-by: Thorsten Blum Link: https://lore.kernel.org/r/20250112105128.86653-2-thorsten.blum@linux.dev [groeck: Fixed subject and continuation line alignments] Signed-off-by: Guenter Roeck --- drivers/hwmon/asus_atk0110.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 1dc7e24fe4c5e..c80350e499e97 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -17,6 +17,7 @@ #include #include #include +#include #define ATK_HID "ATK0110" @@ -441,7 +442,7 @@ static void atk_print_sensor(struct atk_data *data, union acpi_object *obj) flags->integer.value, name->string.pointer, limit1->integer.value, limit2->integer.value, - enable->integer.value ? "enabled" : "disabled"); + str_enabled_disabled(enable->integer.value)); #endif } @@ -1074,8 +1075,7 @@ static int atk_ec_enabled(struct atk_data *data) err = -EIO; } else { err = (buf->value != 0); - dev_dbg(dev, "EC is %sabled\n", - err ? "en" : "dis"); + dev_dbg(dev, "EC is %s\n", str_enabled_disabled(err)); } ACPI_FREE(obj); @@ -1096,18 +1096,15 @@ static int atk_ec_ctl(struct atk_data *data, int enable) obj = atk_sitm(data, &sitm); if (IS_ERR(obj)) { - dev_err(dev, "Failed to %sable the EC\n", - enable ? "en" : "dis"); + dev_err(dev, "Failed to %s the EC\n", str_enable_disable(enable)); return PTR_ERR(obj); } ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; if (ec_ret->flags == 0) { - dev_err(dev, "Failed to %sable the EC\n", - enable ? "en" : "dis"); + dev_err(dev, "Failed to %s the EC\n", str_enable_disable(enable)); err = -EIO; } else { - dev_info(dev, "EC %sabled\n", - enable ? "en" : "dis"); + dev_info(dev, "EC %s\n", str_enabled_disabled(enable)); } ACPI_FREE(obj); From ecf1cf1c58c17a2eda046787b73baba2ac547c16 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Mon, 13 Jan 2025 14:51:18 +0100 Subject: [PATCH 43/44] hwmon: (pwm-fan) Default to the Maximum cooling level if provided The pwm-fan driver uses full PWM (255) duty cycle at startup, which may not always be desirable because of noise or power consumption peaks. The driver optionally accept a list of "cooling-levels" for the thermal subsystem. If provided, use the PWM value corresponding to the maximum cooling level rather than the full level as the initial PWM setting. Signed-off-by: Peter Korsgaard Link: https://lore.kernel.org/r/20250113135118.3994998-1-peter@korsgaard.com [groeck: Dropped double empty line] Signed-off-by: Guenter Roeck --- drivers/hwmon/pwm-fan.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 231b3b348263d..579d31bb9ac78 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -497,7 +497,7 @@ static int pwm_fan_probe(struct platform_device *pdev) struct device *hwmon; int ret; const struct hwmon_channel_info **channels; - u32 pwm_min_from_stopped = 0; + u32 initial_pwm, pwm_min_from_stopped = 0; u32 *fan_channel_config; int channel_count = 1; /* We always have a PWM channel. */ int i; @@ -545,11 +545,21 @@ static int pwm_fan_probe(struct platform_device *pdev) ctx->enable_mode = pwm_disable_reg_enable; + ret = pwm_fan_get_cooling_data(dev, ctx); + if (ret) + return ret; + + /* use maximum cooling level if provided */ + if (ctx->pwm_fan_cooling_levels) + initial_pwm = ctx->pwm_fan_cooling_levels[ctx->pwm_fan_max_state]; + else + initial_pwm = MAX_PWM; + /* * Set duty cycle to maximum allowed and enable PWM output as well as * the regulator. In case of error nothing is changed */ - ret = set_pwm(ctx, MAX_PWM); + ret = set_pwm(ctx, initial_pwm); if (ret) { dev_err(dev, "Failed to configure PWM: %d\n", ret); return ret; @@ -661,10 +671,6 @@ static int pwm_fan_probe(struct platform_device *pdev) return PTR_ERR(hwmon); } - ret = pwm_fan_get_cooling_data(dev, ctx); - if (ret) - return ret; - ctx->pwm_fan_state = ctx->pwm_fan_max_state; if (IS_ENABLED(CONFIG_THERMAL)) { cdev = devm_thermal_of_cooling_device_register(dev, From a76539b293677c5c163b9285b0cd8dd420d33989 Mon Sep 17 00:00:00 2001 From: Denis Kirjanov Date: Mon, 13 Jan 2025 12:28:46 +0300 Subject: [PATCH 44/44] hwmon: pmbus: dps920ab: Add ability to instantiate through i2c Add support for instantiating the Delta DPS920AB PSU through I2C on systems without devicetree support. Signed-off-by: Denis Kirjanov Link: https://lore.kernel.org/r/20250113092846.10786-1-kirjanov@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/dps920ab.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c index cc5aac9dfdb3c..325111a955e61 100644 --- a/drivers/hwmon/pmbus/dps920ab.c +++ b/drivers/hwmon/pmbus/dps920ab.c @@ -190,12 +190,19 @@ static const struct of_device_id __maybe_unused dps920ab_of_match[] = { MODULE_DEVICE_TABLE(of, dps920ab_of_match); +static const struct i2c_device_id dps920ab_device_id[] = { + { "dps920ab" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, dps920ab_device_id); + static struct i2c_driver dps920ab_driver = { .driver = { .name = "dps920ab", .of_match_table = of_match_ptr(dps920ab_of_match), }, .probe = dps920ab_probe, + .id_table = dps920ab_device_id, }; module_i2c_driver(dps920ab_driver);