From 9c62e2282900332c8b711d9f9e37af369a8ef71b Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 18 Jul 2025 13:02:59 -0700 Subject: hwmon: (gsc-hwmon) fix fan pwm setpoint show functions The Linux hwmon sysfs API values for pwmX_auto_pointY_pwm represent an integer value between 0 (0%) to 255 (100%) and the pwmX_auto_pointY_temp represent millidegrees Celcius. Commit a6d80df47ee2 ("hwmon: (gsc-hwmon) fix fan pwm temperature scaling") properly addressed the incorrect scaling in the pwm_auto_point_temp_store implementation but erroneously scaled the pwm_auto_point_pwm_show (pwm value) instead of the pwm_auto_point_temp_show (temp value) resulting in: # cat /sys/class/hwmon/hwmon0/pwm1_auto_point6_pwm 25500 # cat /sys/class/hwmon/hwmon0/pwm1_auto_point6_temp 4500 Fix the scaling of these attributes: # cat /sys/class/hwmon/hwmon0/pwm1_auto_point6_pwm 255 # cat /sys/class/hwmon/hwmon0/pwm1_auto_point6_temp 45000 Fixes: a6d80df47ee2 ("hwmon: (gsc-hwmon) fix fan pwm temperature scaling") Cc: stable@vger.kernel.org Signed-off-by: Tim Harvey Link: https://lore.kernel.org/r/20250718200259.1840792-1-tharvey@gateworks.com Signed-off-by: Guenter Roeck --- drivers/hwmon/gsc-hwmon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index 0f9af82cebec..105b9f9dbec3 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -64,7 +64,7 @@ static ssize_t pwm_auto_point_temp_show(struct device *dev, return ret; ret = regs[0] | regs[1] << 8; - return sprintf(buf, "%d\n", ret * 10); + return sprintf(buf, "%d\n", ret * 100); } static ssize_t pwm_auto_point_temp_store(struct device *dev, @@ -99,7 +99,7 @@ static ssize_t pwm_auto_point_pwm_show(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10))); + return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)) / 100); } static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0); -- cgit v1.2.3 From e923acf15ae48a7f0a35922120fec07795123c5a Mon Sep 17 00:00:00 2001 From: Roy Seitz Date: Thu, 29 May 2025 11:01:41 +0200 Subject: hwmon: (asus-ec-sensors) add support for ROG STRIX Z490-F GAMING This adds support for the ROG STRIX Z490-F GAMING board. Signed-off-by: Roy Seitz Signed-off-by: Eugene Shalygin Link: https://lore.kernel.org/r/20250529090222.154696-1-eugene.shalygin@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/asus_ec_sensors.rst | 1 + drivers/hwmon/asus-ec-sensors.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index 816d1f9947ea..502b0faf3b31 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -29,6 +29,7 @@ Supported boards: * ROG STRIX X570-F GAMING * ROG STRIX X570-I GAMING * ROG STRIX Z390-F GAMING + * ROG STRIX Z490-F GAMING * ROG STRIX Z690-A GAMING WIFI D4 * ROG ZENITH II EXTREME * ROG ZENITH II EXTREME ALPHA diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index e0a95197c71b..c3d5bcbd63f8 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -166,6 +166,7 @@ enum board_family { family_amd_500_series, family_amd_600_series, family_intel_300_series, + family_intel_400_series, family_intel_600_series }; @@ -279,6 +280,20 @@ static const struct ec_sensor_info sensors_family_intel_300[] = { EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01), }; +static const struct ec_sensor_info sensors_family_intel_400[] = { + [ec_sensor_temp_chipset] = + EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a), + [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b), + [ec_sensor_temp_mb] = + EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c), + [ec_sensor_temp_t_sensor] = + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d), + [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e), + [ec_sensor_fan_cpu_opt] = + EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), + [ec_sensor_fan_vrm_hs] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2), +}; + static const struct ec_sensor_info sensors_family_intel_600[] = { [ec_sensor_temp_t_sensor] = EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d), @@ -498,6 +513,18 @@ static const struct ec_board_info board_info_strix_z390_f_gaming = { .family = family_intel_300_series, }; +static const struct ec_board_info board_info_strix_z490_f_gaming = { + .sensors = SENSOR_TEMP_CHIPSET | + SENSOR_TEMP_CPU | + SENSOR_TEMP_MB | + SENSOR_TEMP_T_SENSOR | + SENSOR_TEMP_VRM | + SENSOR_FAN_CPU_OPT | + SENSOR_FAN_VRM_HS, + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, + .family = family_intel_400_series, +}; + static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = { .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM, .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, @@ -586,6 +613,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_strix_x570_i_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING", &board_info_strix_z390_f_gaming), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z490-F GAMING", + &board_info_strix_z490_f_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4", &board_info_strix_z690_a_gaming_wifi_d4), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME", @@ -1061,6 +1090,9 @@ static int asus_ec_probe(struct platform_device *pdev) case family_intel_300_series: ec_data->sensors_info = sensors_family_intel_300; break; + case family_intel_400_series: + ec_data->sensors_info = sensors_family_intel_400; + break; case family_intel_600_series: ec_data->sensors_info = sensors_family_intel_600; break; -- cgit v1.2.3 From 3e538b52157b4a28b9a596210212571074d469ee Mon Sep 17 00:00:00 2001 From: Eugene Shalygin Date: Sat, 7 Jun 2025 12:26:14 +0200 Subject: hwmon: (asus-ec-sensors) add ProArt X870E-CREATOR WIFI Adds support for the ProArt X870E-CREATOR WIFI board. Signed-off-by: Eugene Shalygin Link: https://lore.kernel.org/r/20250607102626.9051-1-eugene.shalygin@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/asus_ec_sensors.rst | 1 + drivers/hwmon/asus-ec-sensors.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index 502b0faf3b31..de2f2985f06f 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -11,6 +11,7 @@ Supported boards: * Pro WS X570-ACE * ProArt X570-CREATOR WIFI * ProArt X670E-CREATOR WIFI + * ProArt X870E-CREATOR WIFI * ProArt B550-CREATOR * ROG CROSSHAIR VIII DARK HERO * ROG CROSSHAIR VIII HERO (WI-FI) diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index c3d5bcbd63f8..4ac554731e98 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -165,6 +165,7 @@ enum board_family { family_amd_400_series, family_amd_500_series, family_amd_600_series, + family_amd_800_series, family_intel_300_series, family_intel_400_series, family_intel_600_series @@ -260,6 +261,20 @@ static const struct ec_sensor_info sensors_family_amd_600[] = { EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01), }; +static const struct ec_sensor_info sensors_family_amd_800[] = { + [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x30), + [ec_sensor_temp_cpu_package] = + EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31), + [ec_sensor_temp_mb] = + EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x32), + [ec_sensor_temp_vrm] = + EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33), + [ec_sensor_temp_t_sensor] = + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x36), + [ec_sensor_fan_cpu_opt] = + EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), +}; + static const struct ec_sensor_info sensors_family_intel_300[] = { [ec_sensor_temp_chipset] = EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a), @@ -377,6 +392,14 @@ static const struct ec_board_info board_info_pro_art_x670E_creator_wifi = { .family = family_amd_600_series, }; +static const struct ec_board_info board_info_pro_art_x870E_creator_wifi = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | + SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT, + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, + .family = family_amd_800_series, +}; + static const struct ec_board_info board_info_pro_art_b550_creator = { .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR | @@ -575,6 +598,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_pro_art_x570_creator_wifi), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X670E-CREATOR WIFI", &board_info_pro_art_x670E_creator_wifi), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI", + &board_info_pro_art_x870E_creator_wifi), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR", &board_info_pro_art_b550_creator), DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE", @@ -1087,6 +1112,9 @@ static int asus_ec_probe(struct platform_device *pdev) case family_amd_600_series: ec_data->sensors_info = sensors_family_amd_600; break; + case family_amd_800_series: + ec_data->sensors_info = sensors_family_amd_800; + break; case family_intel_300_series: ec_data->sensors_info = sensors_family_intel_300; break; -- cgit v1.2.3 From 588f084a00b81ed2cea2d003fc66983a66a5ea4d Mon Sep 17 00:00:00 2001 From: Chiang Brian Date: Thu, 5 Jun 2025 12:01:33 +0800 Subject: dt-bindings: hwmon: (pmbus/isl68137) Add RAA229621 support Add device type support for raa229621 Acked-by: Krzysztof Kozlowski Signed-off-by: Chiang Brian Link: https://lore.kernel.org/r/20250605040134.4012199-2-chiang.brian@inventec.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml index bac5f8e352aa..3dc7f15484d2 100644 --- a/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml +++ b/Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml @@ -56,6 +56,7 @@ properties: - renesas,raa228228 - renesas,raa229001 - renesas,raa229004 + - renesas,raa229621 reg: maxItems: 1 -- cgit v1.2.3 From 947809f9ee86539f40bb2802c39133b918503162 Mon Sep 17 00:00:00 2001 From: Chiang Brian Date: Thu, 5 Jun 2025 12:01:34 +0800 Subject: hwmon: (pmbus/isl68137) Add support for RAA229621 The RAA229621 is a digital dual output multiphase (X+Y <= 8) PWM controller designed to be compliant with AMD SVI3 specifications, targeting VDDCR_CPU and VDDCR_SOC rails. Add support for it to the isl68137 driver. Signed-off-by: Chiang Brian Link: https://lore.kernel.org/r/20250605040134.4012199-3-chiang.brian@inventec.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/isl68137.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 2af921039309..c52c55d2e7f4 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -63,6 +63,7 @@ enum chips { raa228228, raa229001, raa229004, + raa229621, }; enum variants { @@ -465,6 +466,7 @@ static const struct i2c_device_id raa_dmpvr_id[] = { {"raa228228", raa_dmpvr2_2rail_nontc}, {"raa229001", raa_dmpvr2_2rail}, {"raa229004", raa_dmpvr2_2rail}, + {"raa229621", raa_dmpvr2_2rail}, {} }; @@ -512,6 +514,7 @@ static const struct of_device_id isl68137_of_match[] = { { .compatible = "renesas,raa228228", .data = (void *)raa_dmpvr2_2rail_nontc }, { .compatible = "renesas,raa229001", .data = (void *)raa_dmpvr2_2rail }, { .compatible = "renesas,raa229004", .data = (void *)raa_dmpvr2_2rail }, + { .compatible = "renesas,raa229621", .data = (void *)raa_dmpvr2_2rail }, { }, }; -- cgit v1.2.3 From 6e253295e9c4c1dc1cf4a5eb4c0a0d9ebb68ce4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 11 Jun 2025 17:26:13 +0100 Subject: hwmon: (ltc4282) fix copy paste on variable name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct hwmon_chip_info was named ltc2947_chip_info which is obviously a copy paste leftover. Name it accordingly. Signed-off-by: Nuno Sá Link: https://lore.kernel.org/r/20250611-fix-ltc4282-repetead-write-v1-2-fe46edd08cf1@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc4282.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c index f607fe8f7937..424fa9e3a099 100644 --- a/drivers/hwmon/ltc4282.c +++ b/drivers/hwmon/ltc4282.c @@ -1596,7 +1596,7 @@ static const struct hwmon_ops ltc4282_hwmon_ops = { .read_string = ltc4282_read_labels, }; -static const struct hwmon_chip_info ltc2947_chip_info = { +static const struct hwmon_chip_info ltc4282_chip_info = { .ops = <c4282_hwmon_ops, .info = ltc4282_info, }; @@ -1717,7 +1717,7 @@ static int ltc4282_probe(struct i2c_client *i2c) mutex_init(&st->lock); hwmon = devm_hwmon_device_register_with_info(dev, "ltc4282", st, - <c2947_chip_info, + <c4282_chip_info, ltc4282_groups); if (IS_ERR(hwmon)) return PTR_ERR(hwmon); -- cgit v1.2.3 From 36b0fef0b5437413ff3bfeba19e610d2c4fb0e5f Mon Sep 17 00:00:00 2001 From: Qiushi Wu Date: Fri, 13 Jun 2025 14:24:13 -0400 Subject: hwmon: (ibmaem) match return type of wait_for_completion_timeout Return type of wait_for_completion_timeout is unsigned long not int. Check its return value inline instead of introducing a throw-away variable. Reviewed-by: Mimi Zohar Signed-off-by: Qiushi Wu Link: https://lore.kernel.org/r/20250613182413.1426367-1-qiushi@linux.ibm.com Signed-off-by: Guenter Roeck --- drivers/hwmon/ibmaem.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index 157e232aace0..daed437d34a4 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -349,7 +349,7 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, void *buf, size_t size) { - int rs_size, res; + int rs_size; struct aem_read_sensor_req rs_req; /* Use preallocated rx buffer */ struct aem_read_sensor_resp *rs_resp = data->rs_resp; @@ -383,17 +383,12 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, aem_send_message(ipmi); - res = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!res) { - res = -ETIMEDOUT; - goto out; - } + if (!wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT)) + return -ETIMEDOUT; if (ipmi->rx_result || ipmi->rx_msg_len != rs_size || - memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) { - res = -ENOENT; - goto out; - } + memcmp(&rs_resp->id, &system_x_id, sizeof(system_x_id))) + return -ENOENT; switch (size) { case 1: { @@ -417,10 +412,8 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, break; } } - res = 0; -out: - return res; + return 0; } /* Update AEM energy registers */ @@ -491,7 +484,6 @@ static void aem_delete(struct aem_data *data) /* Retrieve version and module handle for an AEM1 instance */ static int aem_find_aem1_count(struct aem_ipmi_data *data) { - int res; struct aem_find_firmware_req ff_req; struct aem_find_firmware_resp ff_resp; @@ -508,8 +500,7 @@ static int aem_find_aem1_count(struct aem_ipmi_data *data) aem_send_message(data); - res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT); - if (!res) + if (!wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT)) return -ETIMEDOUT; if (data->rx_result || data->rx_msg_len != sizeof(ff_resp) || @@ -632,7 +623,6 @@ static int aem_find_aem2(struct aem_ipmi_data *data, struct aem_find_instance_resp *fi_resp, int instance_num) { - int res; struct aem_find_instance_req fi_req; fi_req.id = system_x_id; @@ -648,8 +638,7 @@ static int aem_find_aem2(struct aem_ipmi_data *data, aem_send_message(data); - res = wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT); - if (!res) + if (!wait_for_completion_timeout(&data->read_complete, IPMI_TIMEOUT)) return -ETIMEDOUT; if (data->rx_result || data->rx_msg_len != sizeof(*fi_resp) || -- cgit v1.2.3 From f2a32ed8691185206e080a603486730d65ffecb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Gon=C3=A7alves?= Date: Fri, 13 Jun 2025 10:42:38 -0300 Subject: dt-bindings: hwmon: amc6821: Add cooling levels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fan can be used as a cooling device, add a description of the `cooling-levels` property and restrict the maximum value to 255, which is the highest PWM duty cycle supported by the AMC6821 fan controller. Signed-off-by: João Paulo Gonçalves Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250613-b4-amc6821-cooling-device-support-v4-1-a8fc063c55de@toradex.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml b/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml index 9ca7356760a7..eb00756988be 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,amc6821.yaml @@ -32,6 +32,12 @@ properties: $ref: fan-common.yaml# unevaluatedProperties: false + properties: + cooling-levels: + description: PWM duty cycle values corresponding to thermal cooling states. + items: + maximum: 255 + "#pwm-cells": const: 2 description: | -- cgit v1.2.3 From b0078b2c9f54eac77e2562d83e70ace41f8397cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Gon=C3=A7alves?= Date: Fri, 13 Jun 2025 10:42:39 -0300 Subject: hwmon: (amc6821) Move reading fan data from OF to a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move fan property reading from OF to a separate function. This keeps OF data handling separate from the code logic and makes it easier to add features like cooling device support that use the same fan node. Signed-off-by: João Paulo Gonçalves Link: https://lore.kernel.org/r/20250613-b4-amc6821-cooling-device-support-v4-2-a8fc063c55de@toradex.com Signed-off-by: Guenter Roeck --- drivers/hwmon/amc6821.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 13a789cc85d2..612895db7d8d 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -126,6 +126,7 @@ module_param(init, int, 0444); struct amc6821_data { struct regmap *regmap; struct mutex update_lock; + enum pwm_polarity pwm_polarity; }; /* @@ -848,11 +849,11 @@ static int amc6821_detect(struct i2c_client *client, struct i2c_board_info *info return 0; } -static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client) +static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client, + struct device_node *fan_np) { enum pwm_polarity polarity = PWM_POLARITY_NORMAL; struct of_phandle_args args; - struct device_node *fan_np; /* * For backward compatibility, the pwminv module parameter takes @@ -863,10 +864,6 @@ static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client) if (pwminv > 0) return PWM_POLARITY_INVERSED; - fan_np = of_get_child_by_name(client->dev.of_node, "fan"); - if (!fan_np) - return PWM_POLARITY_NORMAL; - if (of_parse_phandle_with_args(fan_np, "pwms", "#pwm-cells", 0, &args)) goto out; of_node_put(args.np); @@ -877,10 +874,16 @@ static enum pwm_polarity amc6821_pwm_polarity(struct i2c_client *client) if (args.args[1] & PWM_POLARITY_INVERTED) polarity = PWM_POLARITY_INVERSED; out: - of_node_put(fan_np); return polarity; } +static void amc6821_of_fan_read_data(struct i2c_client *client, + struct amc6821_data *data, + struct device_node *fan_np) +{ + data->pwm_polarity = amc6821_pwm_polarity(client, fan_np); +} + static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *data) { struct regmap *regmap = data->regmap; @@ -902,7 +905,7 @@ static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *d return err; regval = AMC6821_CONF1_START; - if (amc6821_pwm_polarity(client) == PWM_POLARITY_INVERSED) + if (data->pwm_polarity == PWM_POLARITY_INVERSED) regval |= AMC6821_CONF1_PWMINV; err = regmap_update_bits(regmap, AMC6821_REG_CONF1, @@ -944,6 +947,7 @@ static int amc6821_probe(struct i2c_client *client) struct amc6821_data *data; struct device *hwmon_dev; struct regmap *regmap; + struct device_node *fan_np __free(device_node) = NULL; int err; data = devm_kzalloc(dev, sizeof(struct amc6821_data), GFP_KERNEL); @@ -956,6 +960,10 @@ static int amc6821_probe(struct i2c_client *client) "Failed to initialize regmap\n"); data->regmap = regmap; + fan_np = of_get_child_by_name(dev->of_node, "fan"); + if (fan_np) + amc6821_of_fan_read_data(client, data, fan_np); + err = amc6821_init_client(client, data); if (err) return err; -- cgit v1.2.3 From 90cf254f88d1d5a5219c8ee122ce677a3dc2f734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Gon=C3=A7alves?= Date: Fri, 13 Jun 2025 10:42:40 -0300 Subject: hwmon: (amc6821) Add cooling device support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for using the AMC6821 as a cooling device. The AMC6821 registers with the thermal framework only if the `cooling-levels` property is present in the fan device tree child node. If this property is present, the driver assumes the fan will operate in open-loop, and the kernel will control it directly. In this case, the driver will change the AMC6821 mode to manual (software DCY) and set the initial PWM duty cycle to the maximum fan cooling state level as defined in the DT. It is worth mentioning that the cooling device is registered on the child fan node, not on the fan controller node. Existing behavior is unchanged, so the AMC6821 can still be used without the thermal framework (hwmon only). Signed-off-by: João Paulo Gonçalves Link: https://lore.kernel.org/r/20250613-b4-amc6821-cooling-device-support-v4-3-a8fc063c55de@toradex.com [groeck: Reduced line length when registering thermal device] Signed-off-by: Guenter Roeck --- drivers/hwmon/amc6821.c | 113 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 612895db7d8d..d5f864b360b0 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -126,6 +127,9 @@ module_param(init, int, 0444); struct amc6821_data { struct regmap *regmap; struct mutex update_lock; + unsigned long fan_state; + unsigned long fan_max_state; + unsigned int *fan_cooling_levels; enum pwm_polarity pwm_polarity; }; @@ -805,6 +809,65 @@ static const struct hwmon_chip_info amc6821_chip_info = { .info = amc6821_info, }; +static int amc6821_set_sw_dcy(struct amc6821_data *data, u8 duty_cycle) +{ + int ret; + + ret = regmap_write(data->regmap, AMC6821_REG_DCY, duty_cycle); + if (ret) + return ret; + + return regmap_update_bits(data->regmap, AMC6821_REG_CONF1, + AMC6821_CONF1_FDRC0 | AMC6821_CONF1_FDRC1, 0); +} + +static int amc6821_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) +{ + struct amc6821_data *data = cdev->devdata; + + if (!data) + return -EINVAL; + + *state = data->fan_max_state; + + return 0; +} + +static int amc6821_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) +{ + struct amc6821_data *data = cdev->devdata; + + if (!data) + return -EINVAL; + + *state = data->fan_state; + + return 0; +} + +static int amc6821_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) +{ + struct amc6821_data *data = cdev->devdata; + int ret; + + if (!data || state > data->fan_max_state) + return -EINVAL; + + ret = amc6821_set_sw_dcy(data, data->fan_cooling_levels[state]); + if (ret) + return ret; + + data->fan_state = state; + + return 0; +} + +static const struct thermal_cooling_device_ops amc6821_cooling_ops = { + .get_max_state = amc6821_get_max_state, + .get_cur_state = amc6821_get_cur_state, + .set_cur_state = amc6821_set_cur_state, +}; + /* Return 0 if detection is successful, -ENODEV otherwise */ static int amc6821_detect(struct i2c_client *client, struct i2c_board_info *info) { @@ -877,11 +940,29 @@ out: return polarity; } -static void amc6821_of_fan_read_data(struct i2c_client *client, - struct amc6821_data *data, - struct device_node *fan_np) +static int amc6821_of_fan_read_data(struct i2c_client *client, + struct amc6821_data *data, + struct device_node *fan_np) { + int num; + data->pwm_polarity = amc6821_pwm_polarity(client, fan_np); + + num = of_property_count_u32_elems(fan_np, "cooling-levels"); + if (num <= 0) + return 0; + + data->fan_max_state = num - 1; + + data->fan_cooling_levels = devm_kcalloc(&client->dev, num, + sizeof(u32), + GFP_KERNEL); + + if (!data->fan_cooling_levels) + return -ENOMEM; + + return of_property_read_u32_array(fan_np, "cooling-levels", + data->fan_cooling_levels, num); } static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *data) @@ -914,6 +995,14 @@ static int amc6821_init_client(struct i2c_client *client, struct amc6821_data *d regval); if (err) return err; + + /* Software DCY-control mode with fan enabled when cooling-levels present */ + if (data->fan_cooling_levels) { + err = amc6821_set_sw_dcy(data, + data->fan_cooling_levels[data->fan_max_state]); + if (err) + return err; + } } return 0; } @@ -961,8 +1050,12 @@ static int amc6821_probe(struct i2c_client *client) data->regmap = regmap; fan_np = of_get_child_by_name(dev->of_node, "fan"); - if (fan_np) - amc6821_of_fan_read_data(client, data, fan_np); + if (fan_np) { + err = amc6821_of_fan_read_data(client, data, fan_np); + if (err) + return dev_err_probe(dev, err, + "Failed to read fan device tree data\n"); + } err = amc6821_init_client(client, data); if (err) @@ -978,7 +1071,15 @@ static int amc6821_probe(struct i2c_client *client) hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &amc6821_chip_info, amc6821_groups); - return PTR_ERR_OR_ZERO(hwmon_dev); + if (IS_ERR(hwmon_dev)) + return dev_err_probe(dev, PTR_ERR(hwmon_dev), + "Failed to initialize hwmon\n"); + + if (IS_ENABLED(CONFIG_THERMAL) && fan_np && data->fan_cooling_levels) + return PTR_ERR_OR_ZERO(devm_thermal_of_cooling_device_register(dev, + fan_np, client->name, data, &amc6821_cooling_ops)); + + return 0; } static const struct i2c_device_id amc6821_id[] = { -- cgit v1.2.3 From 7114b74d99a3cd588da4ecb6011858c06f8408a1 Mon Sep 17 00:00:00 2001 From: Florin Leotescu Date: Tue, 3 Jun 2025 14:31:22 +0300 Subject: hwmon: (emc2305) Add support for PWM frequency, polarity and output Add three new attributes to the driver data structures to support configuration of PWM frequency, PWM polarity and PWM output config. Signed-off-by: Florin Leotescu Link: https://lore.kernel.org/r/20250603113125.3175103-2-florin.leotescu@oss.nxp.com Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2305.c | 6 ++++++ include/linux/platform_data/emc2305.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 234c54956a4b..8fc4fcf8a063 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -89,8 +89,11 @@ struct emc2305_cdev_data { * @hwmon_dev: hwmon device * @max_state: maximum cooling state of the cooling device * @pwm_num: number of PWM channels + * @pwm_output_mask: PWM output mask + * @pwm_polarity_mask: PWM polarity mask * @pwm_separate: separate PWM settings for every channel * @pwm_min: array of minimum PWM per channel + * @pwm_freq: array of PWM frequency per channel * @cdev_data: array of cooling devices data */ struct emc2305_data { @@ -98,8 +101,11 @@ struct emc2305_data { struct device *hwmon_dev; u8 max_state; u8 pwm_num; + u8 pwm_output_mask; + u8 pwm_polarity_mask; bool pwm_separate; u8 pwm_min[EMC2305_PWM_MAX]; + u16 pwm_freq[EMC2305_PWM_MAX]; struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX]; }; diff --git a/include/linux/platform_data/emc2305.h b/include/linux/platform_data/emc2305.h index 54d672dd6f7d..76043a97f975 100644 --- a/include/linux/platform_data/emc2305.h +++ b/include/linux/platform_data/emc2305.h @@ -9,14 +9,20 @@ * struct emc2305_platform_data - EMC2305 driver platform data * @max_state: maximum cooling state of the cooling device; * @pwm_num: number of active channels; + * @pwm_output_mask: PWM output mask + * @pwm_polarity_mask: PWM polarity mask * @pwm_separate: separate PWM settings for every channel; * @pwm_min: array of minimum PWM per channel; + * @pwm_freq: array of PWM frequency per channel */ struct emc2305_platform_data { u8 max_state; u8 pwm_num; + u8 pwm_output_mask; + u8 pwm_polarity_mask; bool pwm_separate; u8 pwm_min[EMC2305_PWM_MAX]; + u16 pwm_freq[EMC2305_PWM_MAX]; }; #endif -- cgit v1.2.3 From 2ed4db7a1d07b349b50e890dee3d0f245230d254 Mon Sep 17 00:00:00 2001 From: Florin Leotescu Date: Tue, 3 Jun 2025 14:31:23 +0300 Subject: hwmon: (emc2305) Configure PWM channels based on DT properties Add support for configuring each PWM channel using Device Tree (DT) properties by parsing the 'pwms' phandle arguments. Signed-off-by: Florin Leotescu Link: https://lore.kernel.org/r/20250603113125.3175103-3-florin.leotescu@oss.nxp.com Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2305.c | 151 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 129 insertions(+), 22 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 8fc4fcf8a063..0228511f4753 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #define EMC2305_REG_DRIVE_FAIL_STATUS 0x27 #define EMC2305_REG_VENDOR 0xfe @@ -23,6 +26,8 @@ #define EMC2305_TACH_REGS_UNUSE_BITS 3 #define EMC2305_TACH_CNT_MULTIPLIER 0x02 #define EMC2305_TACH_RANGE_MIN 480 +#define EMC2305_DEFAULT_OUTPUT 0x0 +#define EMC2305_DEFAULT_POLARITY 0x0 #define EMC2305_PWM_DUTY2STATE(duty, max_state, pwm_max) \ DIV_ROUND_CLOSEST((duty) * (max_state), (pwm_max)) @@ -39,6 +44,9 @@ #define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n)) #define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n)) +/* Supported base PWM frequencies */ +static const unsigned int base_freq_table[] = { 2441, 4882, 19530, 26000 }; + enum emc230x_product_id { EMC2305 = 0x34, EMC2303 = 0x35, @@ -287,7 +295,7 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel) return 0; } -static int emc2305_set_single_tz(struct device *dev, int idx) +static int emc2305_set_single_tz(struct device *dev, struct device_node *fan_node, int idx) { struct emc2305_data *data = dev_get_drvdata(dev); long pwm; @@ -297,7 +305,7 @@ static int emc2305_set_single_tz(struct device *dev, int idx) pwm = data->pwm_min[cdev_idx]; data->cdev_data[cdev_idx].cdev = - devm_thermal_of_cooling_device_register(dev, dev->of_node, + devm_thermal_of_cooling_device_register(dev, fan_node, emc2305_fan_name[idx], data, &emc2305_cooling_ops); @@ -332,10 +340,10 @@ static int emc2305_set_tz(struct device *dev) int i, ret; if (!data->pwm_separate) - return emc2305_set_single_tz(dev, 0); + return emc2305_set_single_tz(dev, dev->of_node, 0); for (i = 0; i < data->pwm_num; i++) { - ret = emc2305_set_single_tz(dev, i + 1); + ret = emc2305_set_single_tz(dev, dev->of_node, i + 1); if (ret) return ret; } @@ -517,15 +525,85 @@ static int emc2305_identify(struct device *dev) return 0; } +static int emc2305_of_parse_pwm_child(struct device *dev, + struct device_node *child, + struct emc2305_data *data) +{ u32 ch; + int ret; + struct of_phandle_args args; + + ret = of_property_read_u32(child, "reg", &ch); + if (ret) { + dev_err(dev, "missing reg property of %pOFn\n", child); + return ret; + } + + ret = of_parse_phandle_with_args(child, "pwms", "#pwm-cells", 0, &args); + + if (ret) + return ret; + + if (args.args_count > 0) { + data->pwm_freq[ch] = find_closest(args.args[0], base_freq_table, + ARRAY_SIZE(base_freq_table)); + } else { + data->pwm_freq[ch] = base_freq_table[3]; + } + + if (args.args_count > 1) { + if (args.args[1] == PWM_POLARITY_NORMAL || args.args[1] == PWM_POLARITY_INVERSED) + data->pwm_polarity_mask |= args.args[1] << ch; + else + dev_err(dev, "Wrong PWM polarity config provided: %d\n", args.args[0]); + } else { + data->pwm_polarity_mask |= PWM_POLARITY_NORMAL << ch; + } + + if (args.args_count > 2) { + if (args.args[2] == EMC2305_PUSH_PULL || args.args[2] <= EMC2305_OPEN_DRAIN) + data->pwm_output_mask |= args.args[2] << ch; + else + dev_err(dev, "Wrong PWM output config provided: %d\n", args.args[1]); + } else { + data->pwm_output_mask |= EMC2305_OPEN_DRAIN << ch; + } + + return 0; +} + +static int emc2305_probe_childs_from_dt(struct device *dev) +{ + struct emc2305_data *data = dev_get_drvdata(dev); + struct device_node *child; + int ret, count = 0; + + data->pwm_output_mask = 0x0; + data->pwm_polarity_mask = 0x0; + + for_each_child_of_node(dev->of_node, child) { + if (of_property_present(child, "reg")) { + ret = emc2305_of_parse_pwm_child(dev, child, data); + if (ret) { + of_node_put(child); + continue; + } + count++; + } + } + return count; +} + static int emc2305_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; + struct device_node *child; struct emc2305_data *data; struct emc2305_platform_data *pdata; int vendor; int ret; int i; + int pwm_childs; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) return -ENODEV; @@ -545,22 +623,40 @@ static int emc2305_probe(struct i2c_client *client) if (ret) return ret; + pwm_childs = emc2305_probe_childs_from_dt(dev); + pdata = dev_get_platdata(&client->dev); - if (pdata) { - if (!pdata->max_state || pdata->max_state > EMC2305_FAN_MAX_STATE) - return -EINVAL; - data->max_state = pdata->max_state; - /* - * Validate a number of active PWM channels. Note that - * configured number can be less than the actual maximum - * supported by the device. - */ - if (!pdata->pwm_num || pdata->pwm_num > EMC2305_PWM_MAX) - return -EINVAL; - data->pwm_num = pdata->pwm_num; - data->pwm_separate = pdata->pwm_separate; - for (i = 0; i < EMC2305_PWM_MAX; i++) - data->pwm_min[i] = pdata->pwm_min[i]; + + if (!pwm_childs) { + if (pdata) { + if (!pdata->max_state || pdata->max_state > EMC2305_FAN_MAX_STATE) + return -EINVAL; + data->max_state = pdata->max_state; + /* + * Validate a number of active PWM channels. Note that + * configured number can be less than the actual maximum + * supported by the device. + */ + if (!pdata->pwm_num || pdata->pwm_num > EMC2305_PWM_MAX) + return -EINVAL; + data->pwm_num = pdata->pwm_num; + data->pwm_output_mask = pdata->pwm_output_mask; + data->pwm_polarity_mask = pdata->pwm_polarity_mask; + data->pwm_separate = pdata->pwm_separate; + for (i = 0; i < EMC2305_PWM_MAX; i++) { + data->pwm_min[i] = pdata->pwm_min[i]; + data->pwm_freq[i] = pdata->pwm_freq[i]; + } + } else { + data->max_state = EMC2305_FAN_MAX_STATE; + data->pwm_separate = false; + data->pwm_output_mask = EMC2305_DEFAULT_OUTPUT; + data->pwm_polarity_mask = EMC2305_DEFAULT_POLARITY; + for (i = 0; i < EMC2305_PWM_MAX; i++) { + data->pwm_min[i] = EMC2305_FAN_MIN; + data->pwm_freq[i] = base_freq_table[3]; + } + } } else { data->max_state = EMC2305_FAN_MAX_STATE; data->pwm_separate = false; @@ -574,9 +670,20 @@ static int emc2305_probe(struct i2c_client *client) return PTR_ERR(data->hwmon_dev); if (IS_REACHABLE(CONFIG_THERMAL)) { - ret = emc2305_set_tz(dev); - if (ret != 0) - return ret; + /* Parse and check for the available PWM child nodes */ + if (pwm_childs > 0) { + i = 0; + for_each_child_of_node(dev->of_node, child) { + ret = emc2305_set_single_tz(dev, child, i); + if (ret != 0) + return ret; + i++; + } + } else { + ret = emc2305_set_tz(dev); + if (ret != 0) + return ret; + } } for (i = 0; i < data->pwm_num; i++) { -- cgit v1.2.3 From ef8b1b4eb702cdd56807c0430b511f94b2af8e66 Mon Sep 17 00:00:00 2001 From: Florin Leotescu Date: Tue, 3 Jun 2025 14:31:24 +0300 Subject: hwmon: (emc2305) Enable PWM polarity and output configuration Enable configuration of PWM polarity and PWM output config based Device Tree properties. Signed-off-by: Florin Leotescu Link: https://lore.kernel.org/r/20250603113125.3175103-4-florin.leotescu@oss.nxp.com Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2305.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 0228511f4753..db65c3177f29 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -28,6 +28,10 @@ #define EMC2305_TACH_RANGE_MIN 480 #define EMC2305_DEFAULT_OUTPUT 0x0 #define EMC2305_DEFAULT_POLARITY 0x0 +#define EMC2305_REG_POLARITY 0x2a +#define EMC2305_REG_DRIVE_PWM_OUT 0x2b +#define EMC2305_OPEN_DRAIN 0x0 +#define EMC2305_PUSH_PULL 0x1 #define EMC2305_PWM_DUTY2STATE(duty, max_state, pwm_max) \ DIV_ROUND_CLOSEST((duty) * (max_state), (pwm_max)) @@ -686,6 +690,16 @@ static int emc2305_probe(struct i2c_client *client) } } + ret = i2c_smbus_write_byte_data(client, EMC2305_REG_DRIVE_PWM_OUT, + data->pwm_output_mask); + if (ret < 0) + dev_err(dev, "Failed to configure pwm output, using default\n"); + + ret = i2c_smbus_write_byte_data(client, EMC2305_REG_POLARITY, + data->pwm_polarity_mask); + if (ret < 0) + dev_err(dev, "Failed to configure pwm polarity, using default\n"); + for (i = 0; i < data->pwm_num; i++) { ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_MIN_DRIVE(i), data->pwm_min[i]); -- cgit v1.2.3 From 0429415a084a15466e87d504e8c2a502488184a5 Mon Sep 17 00:00:00 2001 From: Florin Leotescu Date: Tue, 3 Jun 2025 14:31:25 +0300 Subject: hwmon: (emc2305) Set initial PWM minimum value during probe based on thermal state Prevent the PWM value from being set to minimum when thermal zone temperature exceeds any trip point during driver probe. Otherwise, the PWM fan speed will remains at minimum speed and not respond to temperature changes. Signed-off-by: Florin Leotescu Link: https://lore.kernel.org/r/20250603113125.3175103-5-florin.leotescu@oss.nxp.com Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2305.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index db65c3177f29..60809289f816 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -317,6 +317,12 @@ static int emc2305_set_single_tz(struct device *dev, struct device_node *fan_nod dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]); return PTR_ERR(data->cdev_data[cdev_idx].cdev); } + + if (data->cdev_data[cdev_idx].cur_state > 0) + /* Update pwm when temperature is above trips */ + pwm = EMC2305_PWM_STATE2DUTY(data->cdev_data[cdev_idx].cur_state, + data->max_state, EMC2305_FAN_MAX); + /* Set minimal PWM speed. */ if (data->pwm_separate) { ret = emc2305_set_pwm(dev, pwm, cdev_idx); @@ -330,10 +336,10 @@ static int emc2305_set_single_tz(struct device *dev, struct device_node *fan_nod } } data->cdev_data[cdev_idx].cur_state = - EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state, + EMC2305_PWM_DUTY2STATE(pwm, data->max_state, EMC2305_FAN_MAX); data->cdev_data[cdev_idx].last_hwmon_state = - EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state, + EMC2305_PWM_DUTY2STATE(pwm, data->max_state, EMC2305_FAN_MAX); return 0; } -- cgit v1.2.3 From bb4eb5739deda3c84801397f5fa9b067a9fc4746 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 14 Jul 2025 16:55:05 +0100 Subject: hwmon: (w83627ehf) make the read-only arrays 'bit' static const Don't populate the read-only arrays 'bit' on the stack at run time, instead make them static const. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20250714155505.1234012-1-colin.i.king@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/w83627ehf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 7d7d70afde65..a23edd35c19f 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1448,7 +1448,8 @@ w83627ehf_do_read_temp(struct w83627ehf_data *data, u32 attr, return 0; case hwmon_temp_alarm: if (channel < 3) { - int bit[] = { 4, 5, 13 }; + static const int bit[] = { 4, 5, 13 }; + *val = (data->alarms >> bit[channel]) & 1; return 0; } @@ -1479,7 +1480,8 @@ w83627ehf_do_read_in(struct w83627ehf_data *data, u32 attr, return 0; case hwmon_in_alarm: if (channel < 10) { - int bit[] = { 0, 1, 2, 3, 8, 21, 20, 16, 17, 19 }; + static const int bit[] = { 0, 1, 2, 3, 8, 21, 20, 16, 17, 19 }; + *val = (data->alarms >> bit[channel]) & 1; return 0; } @@ -1507,7 +1509,8 @@ w83627ehf_do_read_fan(struct w83627ehf_data *data, u32 attr, return 0; case hwmon_fan_alarm: if (channel < 5) { - int bit[] = { 6, 7, 11, 10, 23 }; + static const int bit[] = { 6, 7, 11, 10, 23 }; + *val = (data->alarms >> bit[channel]) & 1; return 0; } -- cgit v1.2.3 From 3e72912e6a8a6a2edfa3c6fd03ab6998c3086e9b Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 1 Jul 2025 16:00:40 -0500 Subject: dt-bindings: hwmon: national,lm90: Add missing Dallas max6654 and onsemi nct72, nct214, and nct218 The onsemi nct72, nct214, and nct218 and Dallas/Analog max6654 temperature sensors are already supported, but not documented. Add them to the LM90 binding. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250701-dt-hwmon-compatibles-v1-1-ad99e65cf11b@kernel.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/national,lm90.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/national,lm90.yaml b/Documentation/devicetree/bindings/hwmon/national,lm90.yaml index 4feb76919404..1b871f166e79 100644 --- a/Documentation/devicetree/bindings/hwmon/national,lm90.yaml +++ b/Documentation/devicetree/bindings/hwmon/national,lm90.yaml @@ -20,6 +20,7 @@ properties: - dallas,max6646 - dallas,max6647 - dallas,max6649 + - dallas,max6654 - dallas,max6657 - dallas,max6658 - dallas,max6659 @@ -36,6 +37,9 @@ properties: - nuvoton,nct7717 - nuvoton,nct7718 - nxp,sa56004 + - onnn,nct72 + - onnn,nct214 + - onnn,nct218 - onnn,nct1008 - ti,tmp451 - ti,tmp461 @@ -118,6 +122,7 @@ allOf: - dallas,max6646 - dallas,max6647 - dallas,max6649 + - dallas,max6654 - dallas,max6657 - dallas,max6658 - dallas,max6659 @@ -139,6 +144,9 @@ allOf: - adi,adt7461 - adi,adt7461a - adi,adt7481 + - onnn,nct72 + - onnn,nct214 + - onnn,nct218 - onnn,nct1008 then: patternProperties: -- cgit v1.2.3 From a735074da1859cd7cc1486587f7713e33df68bc5 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 1 Jul 2025 16:00:41 -0500 Subject: dt-bindings: hwmon: ti,lm87: Add adi,adm1024 compatible The adi,adm1024 compatible is already in use. Add it to the lm87 binding as the device appears to be compatible. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250701-dt-hwmon-compatibles-v1-2-ad99e65cf11b@kernel.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ti,lm87.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/hwmon/ti,lm87.yaml b/Documentation/devicetree/bindings/hwmon/ti,lm87.yaml index 63d8cf467806..5c0cdc0091b5 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,lm87.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,lm87.yaml @@ -18,7 +18,9 @@ description: | properties: compatible: - const: ti,lm87 + enum: + - adi,adm1024 + - ti,lm87 reg: maxItems: 1 -- cgit v1.2.3 From ed3f35ca5f8385a3441b7c9a44b3c3df6cb90090 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 1 Jul 2025 16:00:42 -0500 Subject: dt-bindings: hwmon: lltc,ltc2978: Add lltc,ltc713 compatible The lltc,ltc713 compatible is already in use. Add it to the lltc,ltc2978 binding as the device appears to be similar. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250701-dt-hwmon-compatibles-v1-3-ad99e65cf11b@kernel.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml index aa801ef1640b..ea8b1553a3e9 100644 --- a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml +++ b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml @@ -28,6 +28,7 @@ properties: - lltc,ltc3886 - lltc,ltc3887 - lltc,ltc3889 + - lltc,ltc7132 - lltc,ltc7841 - lltc,ltc7880 - lltc,ltm2987 @@ -55,6 +56,7 @@ properties: * ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1 + * ltc7132 : vout0 - vout1 * ltc7841 : vout0 * ltc7880 : vout0 - vout1 * ltc3883 : vout0 -- cgit v1.2.3 From 887088fabb4de70838910907f7270183d509148f Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 1 Jul 2025 16:00:43 -0500 Subject: dt-bindings: hwmon: maxim,max20730: Add maxim,max20710 compatible The maxim,max20710 compatible is already in use. Add it to the maxim,max20730 binding as the device appears to be similar. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250701-dt-hwmon-compatibles-v1-4-ad99e65cf11b@kernel.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml b/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml index 8af0d7458e62..8588d97ba6ec 100644 --- a/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml +++ b/Documentation/devicetree/bindings/hwmon/maxim,max20730.yaml @@ -25,6 +25,7 @@ description: | properties: compatible: enum: + - maxim,max20710 - maxim,max20730 - maxim,max20734 - maxim,max20743 -- cgit v1.2.3 From 535ac9ae4138e632f56621d0d70b34c54f01aced Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Tue, 1 Jul 2025 16:00:44 -0500 Subject: dt-bindings: hwmon: pmbus: ti,ucd90320: Add missing compatibles Add several compatibles already in use to the ti,ucd90320 binding. Signed-off-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250701-dt-hwmon-compatibles-v1-5-ad99e65cf11b@kernel.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml index f8bea1c0e94a..8f9ce00079df 100644 --- a/Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml +++ b/Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml @@ -23,7 +23,13 @@ description: | properties: compatible: enum: + - ti,ucd9000 + - ti,ucd9090 + - ti,ucd90120 + - ti,ucd90124 + - ti,ucd90160 - ti,ucd90320 + - ti,ucd90910 reg: maxItems: 1 -- cgit v1.2.3 From 6082bfe47795c9ffc250df245d94e7057489466f Mon Sep 17 00:00:00 2001 From: Shantanu Tushar Date: Mon, 30 Jun 2025 22:14:44 +0200 Subject: hwmon: (corsair-psu) add support for HX1200i Series 2025 Add the USB ID of the Corsair HXi Series 2025 HX1200i PSU (CP-9020307). Update the documentation to mention this. Signed-off-by: Shantanu Tushar Reviewed-by: Wilken Gottwalt Link: https://lore.kernel.org/r/20250630201444.210420-1-shantanu@kde.org Signed-off-by: Guenter Roeck --- Documentation/hwmon/corsair-psu.rst | 2 +- drivers/hwmon/corsair-psu.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index 7ed794087f84..2e99cfd556a0 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -17,7 +17,7 @@ Supported devices: Corsair HX1000i (Legacy and Series 2023) - Corsair HX1200i (Legacy and Series 2023) + Corsair HX1200i (Legacy, Series 2023 and Series 2025) Corsair HX1500i (Legacy and Series 2023) diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index f8f22b8a67cd..6b5c8f200780 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -885,6 +885,7 @@ static const struct hid_device_id corsairpsu_idtable[] = { { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */ { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Legacy and Series 2023 */ { HID_USB_DEVICE(0x1b1c, 0x1c23) }, /* Corsair HX1200i Series 2023 */ + { HID_USB_DEVICE(0x1b1c, 0x1c27) }, /* Corsair HX1200i Series 2025 */ { }, }; MODULE_DEVICE_TABLE(hid, corsairpsu_idtable); -- cgit v1.2.3 From 9f4401ad3740ecc7ea46ff8406b35cd29ddadd9b Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 Jul 2025 14:10:41 -0400 Subject: hwmon: (ltc4282) convert from round_rate() to determine_rate() The round_rate() clk ops is deprecated, so migrate this driver from round_rate() to determine_rate() using the Coccinelle semantic patch appended to the "under-the-cut" portion of the patch. Signed-off-by: Brian Masney Link: https://lore.kernel.org/r/20250710-hwmon-round-rate-v1-1-64fbe4bf3d05@redhat.com Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc4282.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c index 424fa9e3a099..dbb30abcd343 100644 --- a/drivers/hwmon/ltc4282.c +++ b/drivers/hwmon/ltc4282.c @@ -177,13 +177,15 @@ static const unsigned int ltc4282_out_rates[] = { LTC4282_CLKOUT_CNV, LTC4282_CLKOUT_SYSTEM }; -static long ltc4282_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ltc4282_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - int idx = find_closest(rate, ltc4282_out_rates, + int idx = find_closest(req->rate, ltc4282_out_rates, ARRAY_SIZE(ltc4282_out_rates)); - return ltc4282_out_rates[idx]; + req->rate = ltc4282_out_rates[idx]; + + return 0; } static unsigned long ltc4282_recalc_rate(struct clk_hw *hw, @@ -1124,7 +1126,7 @@ static ssize_t ltc4282_energy_show(struct device *dev, static const struct clk_ops ltc4282_ops = { .recalc_rate = ltc4282_recalc_rate, - .round_rate = ltc4282_round_rate, + .determine_rate = ltc4282_determine_rate, .set_rate = ltc4282_set_rate, .disable = ltc4282_disable, }; -- cgit v1.2.3 From d1eb9fe14e73dc2ca47fd3c2f9f3c8753e33b774 Mon Sep 17 00:00:00 2001 From: Khaled Elnaggar Date: Sat, 12 Jul 2025 16:14:46 +0300 Subject: hwmon: (max31827) use sysfs_emit() in temp1_resolution_show() Replace scnprintf() with sysfs_emit() in temp1_resolution_show(), as recommended in Documentation/filesystems/sysfs.rst: show() callbacks should use sysfs_emit() or sysfs_emit_at() to format values returned to userspace. Signed-off-by: Khaled Elnaggar Link: https://lore.kernel.org/r/20250712131447.326995-1-khaledelnaggarlinux@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/max31827.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c index 48e8f8ba4d05..a31c7b655da1 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -445,7 +445,7 @@ static ssize_t temp1_resolution_show(struct device *dev, val = FIELD_GET(MAX31827_CONFIGURATION_RESOLUTION_MASK, val); - return scnprintf(buf, PAGE_SIZE, "%u\n", max31827_resolutions[val]); + return sysfs_emit(buf, "%u\n", max31827_resolutions[val]); } static ssize_t temp1_resolution_store(struct device *dev, -- cgit v1.2.3 From 409d2add31070fb79184acfb73b132b2a7146668 Mon Sep 17 00:00:00 2001 From: Cedric Encarnacion Date: Wed, 9 Jul 2025 13:43:25 +0800 Subject: dt-bindings: hwmon: pmbus/adp1050: Add adp1051, adp1055 and ltp8800 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for adp1051, adp1055, and ltp8800. ADP1051: 6 PWM for I/O Voltage, I/O Current, Temperature ADP1055: 6 PWM for I/O Voltage, I/O Current, Power, Temperature LTP8800-1A/-2/-4A: 150A/135A/200A DC/DC µModule Regulator Co-developed-by: Alexis Czezar Torreno Signed-off-by: Alexis Czezar Torreno Signed-off-by: Cedric Encarnacion Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20250709-adp1051-v5-1-539254692252@analog.com Signed-off-by: Guenter Roeck --- .../devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml index 10c2204bc3df..af7530093942 100644 --- a/Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml +++ b/Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml @@ -10,16 +10,27 @@ maintainers: - Radu Sabau description: | - The ADP1050 is used to monitor system voltages, currents and temperatures. + The ADP1050 and similar devices are used to monitor system voltages, + currents, power, and temperatures. + Through the PMBus interface, the ADP1050 targets isolated power supplies and has four individual monitors for input/output voltage, input current and temperature. Datasheet: https://www.analog.com/en/products/adp1050.html + https://www.analog.com/en/products/adp1051.html + https://www.analog.com/en/products/adp1055.html + https://www.analog.com/en/products/ltp8800-1a.html + https://www.analog.com/en/products/ltp8800-2.html + https://www.analog.com/en/products/ltp8800-4a.html properties: compatible: - const: adi,adp1050 + enum: + - adi,adp1050 + - adi,adp1051 + - adi,adp1055 + - adi,ltp8800 reg: maxItems: 1 -- cgit v1.2.3 From 3e5f73a0620dff64a22aae1cd62334a6706dc307 Mon Sep 17 00:00:00 2001 From: Cedric Encarnacion Date: Wed, 9 Jul 2025 13:43:26 +0800 Subject: hwmon: (pmbus/adp1050) Add support for adp1051, adp1055 and ltp8800 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce hardware monitoring support for the following devices: ADP1051: 6 PWM for I/O Voltage, I/O Current, Temperature ADP1055: 6 PWM for I/O Voltage, I/O Current, Power, Temperature LTP8800-1A/-2/-4A: 150A/135A/200A DC/DC µModule Regulator The ADP1051 and ADP1055 are similar digital controllers for high efficiency DC-DC power conversion while the LTP8800 is a family of step-down μModule regulators that provides microprocessor core voltage from 54V power distribution architecture. All of the above components features telemetry monitoring of input/output voltage, input current, output power, and temperature over PMBus. Reviewed-by: Andy Shevchenko Co-developed-by: Alexis Czezar Torreno Signed-off-by: Alexis Czezar Torreno Signed-off-by: Cedric Encarnacion Link: https://lore.kernel.org/r/20250709-adp1051-v5-2-539254692252@analog.com [groeck: Dropped unnecessaary spaces after type casts] Signed-off-by: Guenter Roeck --- Documentation/hwmon/adp1050.rst | 71 +++++++++++++++++++++++++++++++++++++---- drivers/hwmon/pmbus/adp1050.c | 62 +++++++++++++++++++++++++++++++++-- 2 files changed, 124 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/adp1050.rst b/Documentation/hwmon/adp1050.rst index 8fa937064886..32514084fbdc 100644 --- a/Documentation/hwmon/adp1050.rst +++ b/Documentation/hwmon/adp1050.rst @@ -13,6 +13,32 @@ Supported chips: Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1050.pdf + * Analog Devices ADP1051 + + Prefix: 'adp1051' + + Addresses scanned: I2C 0x70 - 0x77 + + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1051.pdf + + * Analog Devices ADP1055 + + Prefix: 'adp1055' + + Addresses scanned: I2C 0x4B - 0x77 + + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1055.pdf + + * Analog Devices LTP8800-1A/-2/-4A + + Prefix: 'ltp8800' + + Addresses scanned: - + + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/LTP8800-1A.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/LTP8800-2.pdf + https://www.analog.com/media/en/technical-documentation/data-sheets/LTP8800-4A.pdf + Authors: - Radu Sabau @@ -21,14 +47,17 @@ Authors: Description ----------- -This driver supprts hardware monitoring for Analog Devices ADP1050 Digital -Controller for Isolated Power Supply with PMBus interface. +This driver supports hardware monitoring for Analog Devices ADP1050, ADP1051, +and ADP1055 Digital Controller for Isolated Power Supply with PMBus interface, +and the LTP8800 step-down μModule regulators. -The ADP1050 is an advanced digital controller with a PMBus™ +The ADP1050, ADP1051, and ADP1055 are advanced digital controllers with PMBus™ interface targeting high density, high efficiency dc-to-dc power -conversion used to monitor system temperatures, voltages and currents. -Through the PMBus interface, the device can monitor input/output voltages, -input current and temperature. +conversion used to monitor system temperatures, voltages and currents. The +LTP8800 is a family of step-down μModule regulators that provides microprocessor +core voltage from 54V power distribution architecture. Through the PMBus +interface, the device can monitor input/output voltages, input current and +temperature. Usage Notes ----------- @@ -49,16 +78,46 @@ Sysfs Attributes in1_label "vin" in1_input Measured input voltage in1_alarm Input voltage alarm +in1_crit Critical maximum input voltage +in1_crit_alarm Input voltage high alarm +in1_lcrit Critical minimum input voltage +in1_lcrit_alarm Input voltage critical low alarm in2_label "vout1" in2_input Measured output voltage in2_crit Critical maximum output voltage in2_crit_alarm Output voltage high alarm in2_lcrit Critical minimum output voltage in2_lcrit_alarm Output voltage critical low alarm +in2_max Critical maximum output voltage +in2_max_alarm Output voltage critical max alarm +in2_min Critical minimum output voltage +in2_min_alarm Output voltage critical min alarm curr1_label "iin" curr1_input Measured input current. curr1_alarm Input current alarm +curr1_crit Critical maximum input current +curr1_crit_alarm Input current high alarm +curr2_label "iout1" +curr2_input Measured output current +curr2_alarm Output current alarm +curr2_crit Critical maximum output current +curr2_crit_alarm Output current high alarm +curr2_lcrit Critical minimum output current +curr2_lcrit_alarm Output current critical low alarm +curr2_max Critical maximum output current +curr2_max_alarm Output current critical max alarm +power1_label "pout1" +power1_input Measured output power +power1_crit Critical maximum output power +power1_crit_alarm Output power high alarm temp1_input Measured temperature temp1_crit Critical high temperature temp1_crit_alarm Chip temperature critical high alarm +temp1_max Critical maximum temperature +temp1_max_alarm Temperature critical max alarm +temp2_input Measured temperature +temp2_crit Critical high temperature +temp2_crit_alarm Chip temperature critical high alarm +temp2_max Critical maximum temperature +temp2_max_alarm Temperature critical max alarm ================= ======================================== diff --git a/drivers/hwmon/pmbus/adp1050.c b/drivers/hwmon/pmbus/adp1050.c index ef46c880b168..1ffb189f4b6f 100644 --- a/drivers/hwmon/pmbus/adp1050.c +++ b/drivers/hwmon/pmbus/adp1050.c @@ -23,19 +23,75 @@ static struct pmbus_driver_info adp1050_info = { | PMBUS_HAVE_STATUS_TEMP, }; +static struct pmbus_driver_info adp1051_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_TEMPERATURE] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_TEMP + | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_STATUS_TEMP, +}; + +static struct pmbus_driver_info adp1055_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_TEMPERATURE] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 + | PMBUS_HAVE_POUT + | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_STATUS_TEMP, +}; + +static struct pmbus_driver_info ltp8800_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_TEMPERATURE] = linear, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT + | PMBUS_HAVE_TEMP + | PMBUS_HAVE_POUT + | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_STATUS_TEMP, +}; + static int adp1050_probe(struct i2c_client *client) { - return pmbus_do_probe(client, &adp1050_info); + struct pmbus_driver_info *info; + + info = (struct pmbus_driver_info *)i2c_get_match_data(client); + if (!info) + return -ENODEV; + + return pmbus_do_probe(client, info); } static const struct i2c_device_id adp1050_id[] = { - {"adp1050"}, + { .name = "adp1050", .driver_data = (kernel_ulong_t)&adp1050_info }, + { .name = "adp1051", .driver_data = (kernel_ulong_t)&adp1051_info }, + { .name = "adp1055", .driver_data = (kernel_ulong_t)&adp1055_info }, + { .name = "ltp8800", .driver_data = (kernel_ulong_t)<p8800_info }, {} }; MODULE_DEVICE_TABLE(i2c, adp1050_id); static const struct of_device_id adp1050_of_match[] = { - { .compatible = "adi,adp1050"}, + { .compatible = "adi,adp1050", .data = &adp1050_info }, + { .compatible = "adi,adp1051", .data = &adp1051_info }, + { .compatible = "adi,adp1055", .data = &adp1055_info }, + { .compatible = "adi,ltp8800", .data = <p8800_info }, {} }; MODULE_DEVICE_TABLE(of, adp1050_of_match); -- cgit v1.2.3 From e09ef2fe4ae61e35037d290696fec8236c5ae9ad Mon Sep 17 00:00:00 2001 From: Cedric Encarnacion Date: Wed, 9 Jul 2025 13:43:27 +0800 Subject: hwmon: (pmbus/adp1050) Add regulator support for ltp8800 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add regulator support for the single-channel LTP8800-1A/-2/-4A 150A/135A/200A DC/DC µModule Regulator. Reviewed-by: Andy Shevchenko Signed-off-by: Cedric Encarnacion Link: https://lore.kernel.org/r/20250709-adp1051-v5-3-539254692252@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/Kconfig | 9 +++++++++ drivers/hwmon/pmbus/adp1050.c | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 441f984a859d..55e492452ce8 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -67,6 +67,15 @@ config SENSORS_ADP1050 This driver can also be built as a module. If so, the module will be called adp1050. +config SENSORS_ADP1050_REGULATOR + bool "Regulator support for ADP1050 and compatibles" + depends on SENSORS_ADP1050 && REGULATOR + help + If you say yes here you get regulator support for Analog Devices + LTP8800-1A, LTP8800-4A, and LTP8800-2. LTP8800 is a family of DC/DC + µModule regulators that can provide microprocessor power from 54V + power distribution architecture. + config SENSORS_BEL_PFE tristate "Bel PFE Compatible Power Supplies" help diff --git a/drivers/hwmon/pmbus/adp1050.c b/drivers/hwmon/pmbus/adp1050.c index 1ffb189f4b6f..a73774f8da2d 100644 --- a/drivers/hwmon/pmbus/adp1050.c +++ b/drivers/hwmon/pmbus/adp1050.c @@ -11,6 +11,12 @@ #include "pmbus.h" +#if IS_ENABLED(CONFIG_SENSORS_ADP1050_REGULATOR) +static const struct regulator_desc adp1050_reg_desc[] = { + PMBUS_REGULATOR_ONE("vout"), +}; +#endif /* CONFIG_SENSORS_ADP1050_REGULATOR */ + static struct pmbus_driver_info adp1050_info = { .pages = 1, .format[PSC_VOLTAGE_IN] = linear, @@ -65,6 +71,10 @@ static struct pmbus_driver_info ltp8800_info = { | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, +#if IS_ENABLED(CONFIG_SENSORS_ADP1050_REGULATOR) + .num_regulators = 1, + .reg_desc = adp1050_reg_desc, +#endif }; static int adp1050_probe(struct i2c_client *client) -- cgit v1.2.3 From a6945f39d9fe6ed301bd037de8eb1b0d6fb18aeb Mon Sep 17 00:00:00 2001 From: Chiang Brian Date: Thu, 19 Jun 2025 14:42:22 +0800 Subject: dt-bindings: trivial: Add tps53685 support Add device type support for tps53685 Acked-by: Krzysztof Kozlowski Signed-off-by: Chiang Brian Link: https://lore.kernel.org/r/20250619064223.3165523-2-chiang.brian@inventec.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 27930708ccd5..a613b9c3f6ea 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -396,6 +396,8 @@ properties: - ti,tps53679 # TI Dual channel DCAP+ multiphase controller TPS53681 - ti,tps53681 + # TI Dual channel DCAP+ multiphase controller TPS53685 with AMD-SVI3 + - ti,tps53685 # TI Dual channel DCAP+ multiphase controller TPS53688 - ti,tps53688 # TI DC-DC converters on PMBus -- cgit v1.2.3 From 75ca1e5875fe3f0b9d0e8615c69f49bc2c7fb65d Mon Sep 17 00:00:00 2001 From: Chiang Brian Date: Thu, 19 Jun 2025 14:42:23 +0800 Subject: hwmon: (pmbus/tps53679) Add support for TPS53685 The TPS53685 is a fully AMD SVI3 compliant step down controller with trans-inductor voltage regulator(TLVR) topology support, dual channels, built-in non-volatile memory (NVM), PMBus interface, and full compatible with TI NexFET smart power stages. Add support for it to the tps53679 driver. Signed-off-by: Chiang Brian Link: https://lore.kernel.org/r/20250619064223.3165523-3-chiang.brian@inventec.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/tps53679.rst | 8 ++++++++ drivers/hwmon/pmbus/tps53679.c | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/Documentation/hwmon/tps53679.rst b/Documentation/hwmon/tps53679.rst index 3b9561648c24..dd5e4a37375d 100644 --- a/Documentation/hwmon/tps53679.rst +++ b/Documentation/hwmon/tps53679.rst @@ -43,6 +43,14 @@ Supported chips: Datasheet: https://www.ti.com/lit/gpn/TPS53681 + * Texas Instruments TPS53685 + + Prefix: 'tps53685' + + Addresses scanned: - + + Datasheet: https://www.ti.com/lit/gpn/TPS53685 + * Texas Instruments TPS53688 Prefix: 'tps53688' diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 63524dff5e75..ca2bfa25eb04 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -16,7 +16,7 @@ #include "pmbus.h" enum chips { - tps53647, tps53667, tps53676, tps53679, tps53681, tps53688 + tps53647, tps53667, tps53676, tps53679, tps53681, tps53685, tps53688 }; #define TPS53647_PAGE_NUM 1 @@ -31,7 +31,8 @@ enum chips { #define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */ #define TPS53679_PAGE_NUM 2 -#define TPS53681_DEVICE_ID 0x81 +#define TPS53681_DEVICE_ID "\x81" +#define TPS53685_DEVICE_ID "TIShP" #define TPS53681_PMBUS_REVISION 0x33 @@ -86,10 +87,12 @@ static int tps53679_identify_phases(struct i2c_client *client, } static int tps53679_identify_chip(struct i2c_client *client, - u8 revision, u16 id) + u8 revision, char *id) { u8 buf[I2C_SMBUS_BLOCK_MAX]; int ret; + int buf_len; + int id_len; ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION); if (ret < 0) @@ -102,8 +105,14 @@ static int tps53679_identify_chip(struct i2c_client *client, ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); if (ret < 0) return ret; - if (ret != 1 || buf[0] != id) { - dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]); + + /* Adjust length if null terminator if present */ + buf_len = (buf[ret - 1] != '\x00' ? ret : ret - 1); + + id_len = strlen(id); + + if (buf_len != id_len || strncmp(id, buf, id_len)) { + dev_err(&client->dev, "Unexpected device ID: %*ph\n", ret, buf); return -ENODEV; } return 0; @@ -117,7 +126,7 @@ static int tps53679_identify_chip(struct i2c_client *client, */ static int tps53679_identify_multiphase(struct i2c_client *client, struct pmbus_driver_info *info, - int pmbus_rev, int device_id) + int pmbus_rev, char *device_id) { int ret; @@ -138,6 +147,16 @@ static int tps53679_identify(struct i2c_client *client, return tps53679_identify_mode(client, info); } +static int tps53685_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + info->func[1] |= PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | + PMBUS_HAVE_STATUS_INPUT; + info->format[PSC_VOLTAGE_OUT] = linear; + return tps53679_identify_chip(client, TPS53681_PMBUS_REVISION, + TPS53685_DEVICE_ID); +} + static int tps53681_identify(struct i2c_client *client, struct pmbus_driver_info *info) { @@ -263,6 +282,10 @@ static int tps53679_probe(struct i2c_client *client) info->identify = tps53681_identify; info->read_word_data = tps53681_read_word_data; break; + case tps53685: + info->pages = TPS53679_PAGE_NUM; + info->identify = tps53685_identify; + break; default: return -ENODEV; } @@ -277,6 +300,7 @@ static const struct i2c_device_id tps53679_id[] = { {"tps53676", tps53676}, {"tps53679", tps53679}, {"tps53681", tps53681}, + {"tps53685", tps53685}, {"tps53688", tps53688}, {} }; @@ -289,6 +313,7 @@ static const struct of_device_id __maybe_unused tps53679_of_match[] = { {.compatible = "ti,tps53676", .data = (void *)tps53676}, {.compatible = "ti,tps53679", .data = (void *)tps53679}, {.compatible = "ti,tps53681", .data = (void *)tps53681}, + {.compatible = "ti,tps53685", .data = (void *)tps53685}, {.compatible = "ti,tps53688", .data = (void *)tps53688}, {} }; -- cgit v1.2.3 From 50f16073d175670f41f3f64ae64ab66a745fd58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 19 Jun 2025 21:37:45 +0200 Subject: hwmon: (adt7475) Implement support for #pwm-cells = <3> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The adt7475 driver and binding are outliers requiring 4 pwm-cells. The typical value is 3, there are a few devices that use a lesser value for historical reasons, no other uses a value bigger than 3. Implement support for 3 cells to make the adt7475 binding match the usual PWM binding. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/b5cc994cbe74095e39468fd694c721d7c879db78.1750361514.git.u.kleine-koenig@baylibre.com Signed-off-by: Guenter Roeck --- drivers/hwmon/adt7475.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 5f2541c11fe9..8cefa14e1633 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1704,12 +1704,15 @@ static int adt7475_pwm_properties_parse_reference_args(struct fwnode_handle *fwn if (ret) return ret; - if (rargs.nargs != 4) { + if (rargs.nargs != 3 && rargs.nargs != 4) { fwnode_handle_put(rargs.fwnode); return -EINVAL; } - for (i = 0; i < 4; i++) + /* Let duty_cycle default to period */ + args[3] = rargs.args[1]; + + for (i = 0; i < rargs.nargs; i++) args[i] = rargs.args[i]; ret = _adt7475_pwm_properties_parse_args(args, cfg); @@ -1724,11 +1727,22 @@ static int adt7475_pwm_properties_parse_args(struct fwnode_handle *fwnode, { int ret; u32 args[4] = {}; + size_t n_vals = fwnode_property_count_u32(fwnode, "pwms"); + + if (n_vals != 3 && n_vals != 4) + return -EOVERFLOW; - ret = fwnode_property_read_u32_array(fwnode, "pwms", args, ARRAY_SIZE(args)); + ret = fwnode_property_read_u32_array(fwnode, "pwms", args, n_vals); if (ret) return ret; + /* + * If there are no item to define the duty_cycle, default it to the + * period. + */ + if (n_vals == 3) + args[3] = args[1]; + return _adt7475_pwm_properties_parse_args(args, cfg); } -- cgit v1.2.3 From 05a0ffe37c44f4dea0433a8c753fc0259650cb3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 19 Jun 2025 21:37:46 +0200 Subject: dt-bindings: hwmon: adt7475: Allow and recommend #pwm-cells = <3> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make this binding match what is usally used for PWMs, deprecate 4 cells and allow 3 instead. Signed-off-by: Uwe Kleine-König Reviewed-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/77895aec937b6217f513d3b12e7945f1707fd906.1750361514.git.u.kleine-koenig@baylibre.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/adt7475.yaml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/adt7475.yaml b/Documentation/devicetree/bindings/hwmon/adt7475.yaml index 79e8d62fa3b3..43e9fe225870 100644 --- a/Documentation/devicetree/bindings/hwmon/adt7475.yaml +++ b/Documentation/devicetree/bindings/hwmon/adt7475.yaml @@ -53,7 +53,10 @@ properties: default: 1 "#pwm-cells": - const: 4 + oneOf: + - const: 3 + - const: 4 + deprecated: true description: | Number of cells in a PWM specifier. - 0: The PWM channel @@ -68,7 +71,7 @@ properties: - 11363636 (88 Hz) - 44444 (22 kHz) - 2: PWM flags 0 or PWM_POLARITY_INVERTED - - 3: The default PWM duty cycle in nanoseconds + - 3: The default PWM duty cycle in nanoseconds, defaults to period. patternProperties: "^adi,bypass-attenuator-in[0-4]$": @@ -124,15 +127,15 @@ examples: adi,bypass-attenuator-in1 = <0>; adi,pin10-function = "smbalert#"; adi,pin14-function = "tach4"; - #pwm-cells = <4>; + #pwm-cells = <3>; - /* PWMs at 22.5 kHz frequency, 50% duty*/ + /* PWMs at 22.5 kHz frequency */ fan-0 { - pwms = <&pwm 0 44444 0 22222>; + pwms = <&pwm 0 44444 0>; }; fan-1 { - pwms = <&pwm 2 44444 0 22222>; + pwms = <&pwm 2 44444 0>; }; }; }; -- cgit v1.2.3 From cde1cc6b6079fa24c236bff3d58f7f8b4b1fc1bb Mon Sep 17 00:00:00 2001 From: Jonas Rebmann Date: Fri, 18 Jul 2025 16:12:48 +0200 Subject: hwmon: (ina238) Fix inconsistent whitespace Some purely cosmetic changes in ina238.c: - When aligning definitions, do so consistently with tab stop of 8. - Use spaces instead of tabs around operators. - Align wrapped lines. Signed-off-by: Jonas Rebmann Link: https://lore.kernel.org/r/20250718-ina228-v2-1-227feb62f709@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ina238.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 9a5fd16a4ec2..5e43bbe8817d 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -41,7 +41,7 @@ #define INA238_CONFIG_ADCRANGE BIT(4) #define SQ52206_CONFIG_ADCRANGE_HIGH BIT(4) -#define SQ52206_CONFIG_ADCRANGE_LOW BIT(3) +#define SQ52206_CONFIG_ADCRANGE_LOW BIT(3) #define INA238_DIAG_ALERT_TMPOL BIT(7) #define INA238_DIAG_ALERT_SHNTOL BIT(6) @@ -104,7 +104,7 @@ #define INA238_SHUNT_VOLTAGE_LSB 5 /* 5 uV/lsb */ #define INA238_BUS_VOLTAGE_LSB 3125 /* 3.125 mV/lsb */ -#define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */ +#define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */ #define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */ #define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ @@ -118,12 +118,12 @@ enum ina238_ids { ina238, ina237, sq52206 }; struct ina238_config { bool has_power_highest; /* chip detection power peak */ - bool has_energy; /* chip detection energy */ - u8 temp_shift; /* fixed parameters for temp calculate */ + bool has_energy; /* chip detection energy */ + u8 temp_shift; /* fixed parameters for temp calculate */ u32 power_calculate_factor; /* fixed parameters for power calculate */ - u16 config_default; /* Power-on default state */ + u16 config_default; /* Power-on default state */ int bus_voltage_lsb; /* use for temperature calculate, uV/lsb */ - int temp_lsb; /* use for temperature calculate */ + int temp_lsb; /* use for temperature calculate */ }; struct ina238_data { @@ -271,7 +271,7 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel, if (channel == 0) /* gain of 1 -> LSB / 4 */ *val = (regval * INA238_SHUNT_VOLTAGE_LSB) * - data->gain / (1000 * 4); + data->gain / (1000 * 4); else *val = (regval * data->config->bus_voltage_lsb) / 1000; break; @@ -370,7 +370,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val) return err; /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */ - power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * + power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * data->config->power_calculate_factor, 4 * 100 * data->rshunt); /* Clamp value to maximum value of long */ *val = clamp_val(power, 0, LONG_MAX); @@ -381,7 +381,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val) return err; /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */ - power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * + power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * data->config->power_calculate_factor, 4 * 100 * data->rshunt); /* Clamp value to maximum value of long */ *val = clamp_val(power, 0, LONG_MAX); @@ -395,7 +395,7 @@ static int ina238_read_power(struct device *dev, u32 attr, long *val) * Truncated 24-bit compare register, lower 8-bits are * truncated. Same conversion to/from uW as POWER register. */ - power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT * data->gain * + power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT * data->gain * data->config->power_calculate_factor, 4 * 100 * data->rshunt); /* Clamp value to maximum value of long */ *val = clamp_val(power, 0, LONG_MAX); @@ -448,7 +448,7 @@ static int ina238_read_temp(struct device *dev, u32 attr, long *val) return err; /* Signed, result in mC */ *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * - (s64)data->config->temp_lsb, 10000); + (s64)data->config->temp_lsb, 10000); break; case hwmon_temp_max: err = regmap_read(data->regmap, INA238_TEMP_LIMIT, ®val); @@ -456,7 +456,7 @@ static int ina238_read_temp(struct device *dev, u32 attr, long *val) return err; /* Signed, result in mC */ *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * - (s64)data->config->temp_lsb, 10000); + (s64)data->config->temp_lsb, 10000); break; case hwmon_temp_max_alarm: err = regmap_read(data->regmap, INA238_DIAG_ALERT, ®val); @@ -501,8 +501,8 @@ static ssize_t energy1_input_show(struct device *dev, return ret; /* result in uJ */ - energy = div_u64(regval * INA238_FIXED_SHUNT * data->gain * 16 * 10 * - data->config->power_calculate_factor, 4 * data->rshunt); + energy = div_u64(regval * INA238_FIXED_SHUNT * data->gain * 16 * 10 * + data->config->power_calculate_factor, 4 * data->rshunt); return sysfs_emit(buf, "%llu\n", energy); } -- cgit v1.2.3 From 8aee29f743954d8fc91ecc83fbfd283a0d8f7cfd Mon Sep 17 00:00:00 2001 From: Jonas Rebmann Date: Fri, 18 Jul 2025 16:12:49 +0200 Subject: dt-bindings: Add INA228 to ina2xx devicetree bindings Add the ina228 to ina2xx bindings. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Jonas Rebmann Link: https://lore.kernel.org/r/20250718-ina228-v2-2-227feb62f709@pengutronix.de Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml index d1fb7b9abda0..fa68b99ef2e2 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml @@ -25,6 +25,7 @@ properties: - ti,ina219 - ti,ina220 - ti,ina226 + - ti,ina228 - ti,ina230 - ti,ina231 - ti,ina233 @@ -107,6 +108,7 @@ allOf: - ti,ina219 - ti,ina220 - ti,ina226 + - ti,ina228 - ti,ina230 - ti,ina231 - ti,ina237 -- cgit v1.2.3 From fd470f4ed80ce0807943b8d6802ca41044c73521 Mon Sep 17 00:00:00 2001 From: Jonas Rebmann Date: Fri, 18 Jul 2025 16:12:50 +0200 Subject: hwmon: (ina238) Add support for INA228 Add support for the Texas Instruments INA228 Ultra-Precise Power/Energy/Charge Monitor. The INA228 is very similar to the INA238 but offers four bits of extra precision in the temperature, voltage and current measurement fields. It also supports energy and charge monitoring, the latter of which is not supported through this patch. While it seems in the datasheet that some constants such as LSB values differ between the 228 and the 238, they differ only for those registers where four bits of precision have been added and they differ by a factor of 16 (VBUS, VSHUNT, DIETEMP, CURRENT). Therefore, the INA238 constants are still applicable with regard to the bit of the same significance. Signed-off-by: Jonas Rebmann Link: https://lore.kernel.org/r/20250718-ina228-v2-3-227feb62f709@pengutronix.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ina238.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 5e43bbe8817d..5a394eeff676 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -6,6 +6,7 @@ * Copyright (C) 2021 Nathan Rossi */ +#include #include #include #include @@ -107,6 +108,7 @@ #define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */ #define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */ #define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ +#define INA228_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ static const struct regmap_config ina238_regmap_config = { .max_register = INA238_REGISTERS, @@ -114,9 +116,10 @@ static const struct regmap_config ina238_regmap_config = { .val_bits = 16, }; -enum ina238_ids { ina238, ina237, sq52206 }; +enum ina238_ids { ina238, ina237, sq52206, ina228 }; struct ina238_config { + bool has_20bit_voltage_current; /* vshunt, vbus and current are 20-bit fields */ bool has_power_highest; /* chip detection power peak */ bool has_energy; /* chip detection energy */ u8 temp_shift; /* fixed parameters for temp calculate */ @@ -137,6 +140,7 @@ struct ina238_data { static const struct ina238_config ina238_config[] = { [ina238] = { + .has_20bit_voltage_current = false, .has_energy = false, .has_power_highest = false, .temp_shift = 4, @@ -146,6 +150,7 @@ static const struct ina238_config ina238_config[] = { .temp_lsb = INA238_DIE_TEMP_LSB, }, [ina237] = { + .has_20bit_voltage_current = false, .has_energy = false, .has_power_highest = false, .temp_shift = 4, @@ -155,6 +160,7 @@ static const struct ina238_config ina238_config[] = { .temp_lsb = INA238_DIE_TEMP_LSB, }, [sq52206] = { + .has_20bit_voltage_current = false, .has_energy = true, .has_power_highest = true, .temp_shift = 0, @@ -163,6 +169,16 @@ static const struct ina238_config ina238_config[] = { .bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB, .temp_lsb = SQ52206_DIE_TEMP_LSB, }, + [ina228] = { + .has_20bit_voltage_current = true, + .has_energy = true, + .has_power_highest = false, + .temp_shift = 0, + .power_calculate_factor = 20, + .config_default = INA238_CONFIG_DEFAULT, + .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, + .temp_lsb = INA228_DIE_TEMP_LSB, + }, }; static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val) @@ -199,6 +215,65 @@ static int ina238_read_reg40(const struct i2c_client *client, u8 reg, u64 *val) return 0; } +static int ina238_read_field_s20(const struct i2c_client *client, u8 reg, s32 *val) +{ + u32 regval; + int err; + + err = ina238_read_reg24(client, reg, ®val); + if (err) + return err; + + /* bits 3-0 Reserved, always zero */ + regval >>= 4; + + *val = sign_extend32(regval, 19); + + return 0; +} + +static int ina228_read_shunt_voltage(struct device *dev, u32 attr, int channel, + long *val) +{ + struct ina238_data *data = dev_get_drvdata(dev); + int regval; + int err; + + err = ina238_read_field_s20(data->client, INA238_SHUNT_VOLTAGE, ®val); + if (err) + return err; + + /* + * gain of 1 -> LSB / 4 + * This field has 16 bit on ina238. ina228 adds another 4 bits of + * precision. ina238 conversion factors can still be applied when + * dividing by 16. + */ + *val = (regval * INA238_SHUNT_VOLTAGE_LSB) * data->gain / (1000 * 4) / 16; + return 0; +} + +static int ina228_read_bus_voltage(struct device *dev, u32 attr, int channel, + long *val) +{ + struct ina238_data *data = dev_get_drvdata(dev); + int regval; + int err; + + err = ina238_read_field_s20(data->client, INA238_BUS_VOLTAGE, ®val); + if (err) + return err; + + /* + * gain of 1 -> LSB / 4 + * This field has 16 bit on ina238. ina228 adds another 4 bits of + * precision. ina238 conversion factors can still be applied when + * dividing by 16. + */ + *val = (regval * data->config->bus_voltage_lsb) / 1000 / 16; + return 0; +} + static int ina238_read_in(struct device *dev, u32 attr, int channel, long *val) { @@ -211,6 +286,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel, case 0: switch (attr) { case hwmon_in_input: + if (data->config->has_20bit_voltage_current) + return ina228_read_shunt_voltage(dev, attr, channel, val); reg = INA238_SHUNT_VOLTAGE; break; case hwmon_in_max: @@ -234,6 +311,8 @@ static int ina238_read_in(struct device *dev, u32 attr, int channel, case 1: switch (attr) { case hwmon_in_input: + if (data->config->has_20bit_voltage_current) + return ina228_read_bus_voltage(dev, attr, channel, val); reg = INA238_BUS_VOLTAGE; break; case hwmon_in_max: @@ -341,13 +420,25 @@ static int ina238_read_current(struct device *dev, u32 attr, long *val) switch (attr) { case hwmon_curr_input: - err = regmap_read(data->regmap, INA238_CURRENT, ®val); - if (err < 0) - return err; + if (data->config->has_20bit_voltage_current) { + err = ina238_read_field_s20(data->client, INA238_CURRENT, ®val); + if (err) + return err; + } else { + err = regmap_read(data->regmap, INA238_CURRENT, ®val); + if (err < 0) + return err; + /* sign-extend */ + regval = (s16)regval; + } /* Signed register, fixed 1mA current lsb. result in mA */ - *val = div_s64((s16)regval * INA238_FIXED_SHUNT * data->gain, + *val = div_s64((s64)regval * INA238_FIXED_SHUNT * data->gain, data->rshunt * 4); + + /* Account for 4 bit offset */ + if (data->config->has_20bit_voltage_current) + *val /= 16; break; default: return -EOPNOTSUPP; @@ -750,6 +841,7 @@ static int ina238_probe(struct i2c_client *client) } static const struct i2c_device_id ina238_id[] = { + { "ina228", ina228 }, { "ina237", ina237 }, { "ina238", ina238 }, { "sq52206", sq52206 }, @@ -758,6 +850,10 @@ static const struct i2c_device_id ina238_id[] = { MODULE_DEVICE_TABLE(i2c, ina238_id); static const struct of_device_id __maybe_unused ina238_of_match[] = { + { + .compatible = "ti,ina228", + .data = (void *)ina228 + }, { .compatible = "ti,ina237", .data = (void *)ina237 -- cgit v1.2.3 From de1fffd88600c5ee1c095c84b86484cd0329a9e8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 24 Jul 2025 13:37:36 +0200 Subject: dt-bindings: hwmon: Replace bouncing Alexandru Tachici emails Emails to alexandru.tachici@analog.com bounce permanently: Remote Server returned '550 5.1.10 RESOLVER.ADR.RecipientNotFound; Recipient not found by SMTP address lookup' so replace him with Cedric Encarnacion from Analog. Signed-off-by: Krzysztof Kozlowski Acked-by: Rob Herring (Arm) Link: https://lore.kernel.org/r/20250724113735.59148-2-krzysztof.kozlowski@linaro.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml | 2 +- Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml index 4f8e11bd5142..fe87a592de45 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml @@ -8,7 +8,7 @@ title: Analog Devices ADM1266 Cascadable Super Sequencer with Margin Control and Fault Recording maintainers: - - Alexandru Tachici + - Cedric Encarnacion description: | Analog Devices ADM1266 Cascadable Super Sequencer with Margin diff --git a/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml b/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml index 0ad12d245656..38a8f3a14c02 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Linear Technology 2992 Power Monitor maintainers: - - Alexandru Tachici + - Cedric Encarnacion description: | Linear Technology 2992 Dual Wide Range Power Monitor -- cgit v1.2.3