From 0babf89c9cca7e074d6e59893e462e4886f481cc Mon Sep 17 00:00:00 2001 From: Nikita Zhandarovich Date: Wed, 10 May 2023 07:35:37 -0700 Subject: [PATCH 01/54] hwmon: (f71882fg) prevent possible division by zero In the unlikely event that something goes wrong with the device and its registers, the fan_from_reg() function may return 0. This value will cause a division-by-zero error in the show_pwm() function. To prevent this, test the value of fan_from_reg(data->fan_full_speed[nr]) against 0 before performing the division. If the division-by-zero error is avoided, assign 0 to the val variable. Found by Linux Verification Center (linuxtesting.org) with static analysis tool SVACE. Fixes: df9ec2dae094 ("hwmon: (f71882fg) Reorder symbols to get rid of a few forward declarations") Signed-off-by: Nikita Zhandarovich Link: https://lore.kernel.org/r/20230510143537.145060-1-n.zhandarovich@fintech.ru Signed-off-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 70121482a617..27207ec6f7fe 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -1096,8 +1096,11 @@ static ssize_t show_pwm(struct device *dev, val = data->pwm[nr]; else { /* RPM mode */ - val = 255 * fan_from_reg(data->fan_target[nr]) - / fan_from_reg(data->fan_full_speed[nr]); + if (fan_from_reg(data->fan_full_speed[nr])) + val = 255 * fan_from_reg(data->fan_target[nr]) + / fan_from_reg(data->fan_full_speed[nr]); + else + val = 0; } mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", val); From a6d80df47ee2c69db99e4f2f8871aa4db154620b Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 6 Jun 2023 08:30:04 -0700 Subject: [PATCH 02/54] hwmon: (gsc-hwmon) fix fan pwm temperature scaling The GSC fan pwm temperature register is in centidegrees celcius but the Linux hwmon convention is to use milidegrees celcius. Fix the scaling. Fixes: 3bce5377ef66 ("hwmon: Add Gateworks System Controller support") Signed-off-by: Tim Harvey Link: https://lore.kernel.org/r/20230606153004.1448086-1-tharvey@gateworks.com Signed-off-by: Guenter Roeck --- drivers/hwmon/gsc-hwmon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index 73e5d92b200b..1501ceb551e7 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -82,8 +82,8 @@ static ssize_t pwm_auto_point_temp_store(struct device *dev, if (kstrtol(buf, 10, &temp)) return -EINVAL; - temp = clamp_val(temp, 0, 10000); - temp = DIV_ROUND_CLOSEST(temp, 10); + temp = clamp_val(temp, 0, 100000); + temp = DIV_ROUND_CLOSEST(temp, 100); regs[0] = temp & 0xff; regs[1] = (temp >> 8) & 0xff; @@ -100,7 +100,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)) / 100); + return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10))); } static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0); From b153a0bb4199566abd337119207f82b59a8cd1ca Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 2 Jun 2023 14:34:47 -0700 Subject: [PATCH 03/54] hwmon: (pmbus/adm1275) Fix problems with temperature monitoring on ADM1272 The PMON_CONFIG register on ADM1272 is a 16 bit register. Writing a 8 bit value into it clears the upper 8 bits of the register, resulting in unexpected side effects. Fix by writing the 16 bit register value. Also, it has been reported that temperature readings are sometimes widely inaccurate, to the point where readings may result in device shutdown due to errant overtemperature faults. Improve by enabling temperature sampling. While at it, move the common code for ADM1272 and ADM1278 into a separate function, and clarify in the error message that an attempt was made to enable both VOUT and temperature monitoring. Last but not least, return the error code reported by the underlying I2C controller and not -ENODEV if updating the PMON_CONFIG register fails. After all, this does not indicate that the chip is not present, but an error in the communication with the chip. Fixes: 4ff0ce227a1e ("hwmon: (pmbus/adm1275) Add support for ADM1272") Fixes: 9da9c2dc57b2 ("hwmon: (adm1275) enable adm1272 temperature reporting") Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230602213447.3557346-1-linux@roeck-us.net Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 3b07bfb43e93..b8543c06d022 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -37,10 +37,13 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 }; #define ADM1272_IRANGE BIT(0) +#define ADM1278_TSFILT BIT(15) #define ADM1278_TEMP1_EN BIT(3) #define ADM1278_VIN_EN BIT(2) #define ADM1278_VOUT_EN BIT(1) +#define ADM1278_PMON_DEFCONFIG (ADM1278_VOUT_EN | ADM1278_TEMP1_EN | ADM1278_TSFILT) + #define ADM1293_IRANGE_25 0 #define ADM1293_IRANGE_50 BIT(6) #define ADM1293_IRANGE_100 BIT(7) @@ -462,6 +465,22 @@ static const struct i2c_device_id adm1275_id[] = { }; MODULE_DEVICE_TABLE(i2c, adm1275_id); +/* Enable VOUT & TEMP1 if not enabled (disabled by default) */ +static int adm1275_enable_vout_temp(struct i2c_client *client, int config) +{ + int ret; + + if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) { + config |= ADM1278_PMON_DEFCONFIG; + ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, config); + if (ret < 0) { + dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n"); + return ret; + } + } + return 0; +} + static int adm1275_probe(struct i2c_client *client) { s32 (*config_read_fn)(const struct i2c_client *client, u8 reg); @@ -615,19 +634,10 @@ static int adm1275_probe(struct i2c_client *client) PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ - if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) != - (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) { - config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN; - ret = i2c_smbus_write_byte_data(client, - ADM1275_PMON_CONFIG, - config); - if (ret < 0) { - dev_err(&client->dev, - "Failed to enable VOUT monitoring\n"); - return -ENODEV; - } - } + ret = adm1275_enable_vout_temp(client, config); + if (ret) + return ret; + if (config & ADM1278_VIN_EN) info->func[0] |= PMBUS_HAVE_VIN; break; @@ -684,19 +694,9 @@ static int adm1275_probe(struct i2c_client *client) PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ - if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) != - (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) { - config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN; - ret = i2c_smbus_write_word_data(client, - ADM1275_PMON_CONFIG, - config); - if (ret < 0) { - dev_err(&client->dev, - "Failed to enable VOUT monitoring\n"); - return -ENODEV; - } - } + ret = adm1275_enable_vout_temp(client, config); + if (ret) + return ret; if (config & ADM1278_VIN_EN) info->func[0] |= PMBUS_HAVE_VIN; From f415cb6c0ffece69eb60eca9750a2877c7985c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Wed, 26 Apr 2023 15:44:20 -0300 Subject: [PATCH 04/54] hwmon: (oxp-sensors) Add AYANEO 2 and Geek models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for handhelds with same EC registers - AYANEO 2 - AYANEO GEEK All functionality tests succeed on AYANEO 2 by "pastaq" user on Discord and AYANEO GEEK tested by "oneoc" Discord user. Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230426184420.99945-1-samsagax@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/oxp-sensors.rst | 2 ++ drivers/hwmon/oxp-sensors.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst index 566a8d5bde08..4ab442301415 100644 --- a/Documentation/hwmon/oxp-sensors.rst +++ b/Documentation/hwmon/oxp-sensors.rst @@ -25,8 +25,10 @@ Supported devices Currently the driver supports the following handhelds: - AOK ZOE A1 + - Aya Neo 2 - Aya Neo AIR - Aya Neo AIR Pro + - Aya Neo Geek - OneXPlayer AMD - OneXPlayer mini AMD - OneXPlayer mini AMD PRO diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index ae67207030e8..9093c608dee0 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -42,8 +42,10 @@ static bool unlock_global_acpi_lock(void) enum oxp_board { aok_zoe_a1 = 1, + aya_neo_2, aya_neo_air, aya_neo_air_pro, + aya_neo_geek, oxp_mini_amd, oxp_mini_amd_pro, }; @@ -62,6 +64,13 @@ static const struct dmi_system_id dmi_table[] = { }, .driver_data = (void *) &(enum oxp_board) {aok_zoe_a1}, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 2"), + }, + .driver_data = (void *) &(enum oxp_board) {aya_neo_2}, + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), @@ -76,6 +85,13 @@ static const struct dmi_system_id dmi_table[] = { }, .driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro}, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "GEEK"), + }, + .driver_data = (void *) &(enum oxp_board) {aya_neo_geek}, + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), @@ -178,8 +194,10 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, if (ret) return ret; switch (board) { + case aya_neo_2: case aya_neo_air: case aya_neo_air_pro: + case aya_neo_geek: case oxp_mini_amd: *val = (*val * 255) / 100; break; @@ -217,8 +235,10 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, if (val < 0 || val > 255) return -EINVAL; switch (board) { + case aya_neo_2: case aya_neo_air: case aya_neo_air_pro: + case aya_neo_geek: case oxp_mini_amd: val = (val * 100) / 255; break; From 790dec13c0128dfec5b6bf28bef433661875e634 Mon Sep 17 00:00:00 2001 From: Michael Carns Date: Wed, 26 Apr 2023 22:03:44 +0200 Subject: [PATCH 05/54] hwmon: (asus-ec-sensors) add ROG Crosshair X670E Hero. Only the temp sensors that I can verify are present. HWINFO in Windows shows other accumulated data and statistics (time since installed, total power used, etc) that I have not attempted to find. Signed-off-by: Michael Carns Signed-off-by: Eugene Shalygin Link: https://lore.kernel.org/r/20230426200345.65765-1-eugene.shalygin@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/asus_ec_sensors.rst | 1 + drivers/hwmon/asus-ec-sensors.c | 30 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index c92c1d3839e4..7e3cd5b6686f 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -14,6 +14,7 @@ Supported boards: * ROG CROSSHAIR VIII FORMULA * ROG CROSSHAIR VIII HERO * ROG CROSSHAIR VIII IMPACT + * ROG CROSSHAIR X670E HERO * ROG MAXIMUS XI HERO * ROG MAXIMUS XI HERO (WI-FI) * ROG STRIX B550-E GAMING diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index e5be0cf472fc..f52a539eb33e 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -101,6 +101,8 @@ enum ec_sensors { ec_sensor_temp_chipset, /* CPU temperature [℃] */ ec_sensor_temp_cpu, + /* CPU package temperature [℃] */ + ec_sensor_temp_cpu_package, /* motherboard temperature [℃] */ ec_sensor_temp_mb, /* "T_Sensor" temperature sensor reading [℃] */ @@ -139,6 +141,7 @@ enum ec_sensors { #define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset) #define SENSOR_TEMP_CPU BIT(ec_sensor_temp_cpu) +#define SENSOR_TEMP_CPU_PACKAGE BIT(ec_sensor_temp_cpu_package) #define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb) #define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor) #define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm) @@ -161,6 +164,7 @@ enum board_family { family_unknown, family_amd_400_series, family_amd_500_series, + family_amd_600_series, family_intel_300_series, family_intel_600_series }; @@ -233,6 +237,19 @@ static const struct ec_sensor_info sensors_family_amd_500[] = { EC_SENSOR("Extra_3", hwmon_temp, 1, 0x01, 0x0c), }; +static const struct ec_sensor_info sensors_family_amd_600[] = { + [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_water_in] = + EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00), + [ec_sensor_temp_water_out] = + EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01), +}; + static const struct ec_sensor_info sensors_family_intel_300[] = { [ec_sensor_temp_chipset] = EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a), @@ -319,6 +336,14 @@ static const struct ec_board_info board_info_pro_ws_x570_ace = { .family = family_amd_500_series, }; +static const struct ec_board_info board_info_crosshair_x670e_hero = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | + SENSOR_SET_TEMP_WATER, + .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, + .family = family_amd_600_series, +}; + static const struct ec_board_info board_info_crosshair_viii_dark_hero = { .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR | @@ -463,6 +488,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_crosshair_viii_hero), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO (WI-FI)", &board_info_crosshair_viii_hero), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO", + &board_info_crosshair_x670e_hero), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO", &board_info_maximus_xi_hero), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)", @@ -946,6 +973,9 @@ static int asus_ec_probe(struct platform_device *pdev) case family_amd_500_series: ec_data->sensors_info = sensors_family_amd_500; break; + case family_amd_600_series: + ec_data->sensors_info = sensors_family_amd_600; + break; case family_intel_300_series: ec_data->sensors_info = sensors_family_intel_300; break; From 5d06ec4279a8605b0fa53dd649d7feda3f06d0c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Sat, 29 Apr 2023 11:25:48 -0300 Subject: [PATCH 06/54] hwmon: (oxp-sensors) Use less convoluted enum cast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change .driver_data = (void *) &(enum type) {enum_literal}; to more readable form: .driver_data = (void *) enum_literal; and corresponding cast usage as board type flag. Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230429142547.328125-1-samsagax@gmail.com [groeck: Use double cast for assignment from driver_data to fix clang build warning] Signed-off-by: Guenter Roeck --- drivers/hwmon/oxp-sensors.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index 9093c608dee0..4d09a63af64a 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -62,49 +62,49 @@ static const struct dmi_system_id dmi_table[] = { DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"), }, - .driver_data = (void *) &(enum oxp_board) {aok_zoe_a1}, + .driver_data = (void *)aok_zoe_a1, }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 2"), }, - .driver_data = (void *) &(enum oxp_board) {aya_neo_2}, + .driver_data = (void *)aya_neo_2, }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), }, - .driver_data = (void *) &(enum oxp_board) {aya_neo_air}, + .driver_data = (void *)aya_neo_air, }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), }, - .driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro}, + .driver_data = (void *)aya_neo_air_pro, }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "GEEK"), }, - .driver_data = (void *) &(enum oxp_board) {aya_neo_geek}, + .driver_data = (void *)aya_neo_geek, }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"), }, - .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd}, + .driver_data = (void *)oxp_mini_amd, }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"), }, - .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro}, + .driver_data = (void *)oxp_mini_amd_pro, }, {}, }; @@ -296,7 +296,7 @@ static int oxp_platform_probe(struct platform_device *pdev) if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD) return -ENODEV; - board = *((enum oxp_board *) dmi_entry->driver_data); + board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, &oxp_ec_chip_info, NULL); From 5a4417bc67cd2cb24667f226667dba66d284de8b Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 29 Apr 2023 21:52:03 +1000 Subject: [PATCH 07/54] hwmon: (it87) Add controls for chips with only 4 fans Add feature and support for chips with only 4 fans. Reorder macro definitions to bring all fan definitions together. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230429115205.1547251-2-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index eb38f54ebeb6..bd9a24942e70 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -317,6 +317,7 @@ struct it87_devices { * chips to avoid the problem. */ #define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */ +#define FEAT_FOUR_FANS BIT(20) /* Supports four fans */ static const struct it87_devices it87_devices[] = { [it87] = { @@ -508,11 +509,14 @@ static const struct it87_devices it87_devices[] = { (((data)->features & FEAT_TEMP_OLD_PECI) && \ ((data)->old_peci_mask & BIT(nr))) #define has_fan16_config(data) ((data)->features & FEAT_FAN16_CONFIG) +#define has_four_fans(data) ((data)->features & (FEAT_FOUR_FANS | \ + FEAT_FIVE_FANS | \ + FEAT_SIX_FANS)) #define has_five_fans(data) ((data)->features & (FEAT_FIVE_FANS | \ FEAT_SIX_FANS)) +#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS) #define has_vid(data) ((data)->features & FEAT_VID) #define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL) -#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS) #define has_avcc3(data) ((data)->features & FEAT_AVCC3) #define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM \ | FEAT_SIX_PWM)) @@ -3169,16 +3173,14 @@ static void it87_init_device(struct platform_device *pdev) it87_check_tachometers_16bit_mode(pdev); /* Check for additional fans */ - if (has_five_fans(data)) { - tmp = it87_read_value(data, IT87_REG_FAN_16BIT); + tmp = it87_read_value(data, IT87_REG_FAN_16BIT); - if (tmp & BIT(4)) - data->has_fan |= BIT(3); /* fan4 enabled */ - if (tmp & BIT(5)) - data->has_fan |= BIT(4); /* fan5 enabled */ - if (has_six_fans(data) && (tmp & BIT(2))) - data->has_fan |= BIT(5); /* fan6 enabled */ - } + if (has_four_fans(data) && (tmp & BIT(4))) + data->has_fan |= BIT(3); /* fan4 enabled */ + if (has_five_fans(data) && (tmp & BIT(5))) + data->has_fan |= BIT(4); /* fan5 enabled */ + if (has_six_fans(data) && (tmp & BIT(2))) + data->has_fan |= BIT(5); /* fan6 enabled */ /* Fan input pins may be used for alternative functions */ data->has_fan &= ~sio_data->skip_fan; From 39a6dcf640a5fc0aa880a8cf8871755fdbd42a5e Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 29 Apr 2023 21:52:04 +1000 Subject: [PATCH 08/54] hwmon: (it87) Add controls for chips with only 4 PWMs Add feature and support for chips with only 4 PWMs. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230429115205.1547251-3-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index bd9a24942e70..d5482c6ed18f 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -318,6 +318,7 @@ struct it87_devices { */ #define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */ #define FEAT_FOUR_FANS BIT(20) /* Supports four fans */ +#define FEAT_FOUR_PWM BIT(21) /* Supports four fan controls */ static const struct it87_devices it87_devices[] = { [it87] = { @@ -518,8 +519,11 @@ static const struct it87_devices it87_devices[] = { #define has_vid(data) ((data)->features & FEAT_VID) #define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL) #define has_avcc3(data) ((data)->features & FEAT_AVCC3) -#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM \ - | FEAT_SIX_PWM)) +#define has_four_pwm(data) ((data)->features & (FEAT_FOUR_PWM | \ + FEAT_FIVE_PWM | \ + FEAT_SIX_PWM)) +#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM | \ + FEAT_SIX_PWM)) #define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM) #define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2) #define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP) @@ -2734,8 +2738,10 @@ static int __init it87_find(int sioaddr, unsigned short *address, else sio_data->skip_in |= BIT(9); - if (!has_five_pwm(config)) + if (!has_four_pwm(config)) sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5); + else if (!has_five_pwm(config)) + sio_data->skip_pwm |= BIT(4) | BIT(5); else if (!has_six_pwm(config)) sio_data->skip_pwm |= BIT(5); From bd5940221b7d49addfa5e80f3cf8fcd7cedd4dc5 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 29 Apr 2023 21:52:05 +1000 Subject: [PATCH 09/54] hwmon: (it87) Update IT8732F chip for 4 fans and PWMs Add support for 4 fans and 4 PWMs to chipset IT8732F. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230429115205.1547251-4-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index d5482c6ed18f..96c17660ff0f 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -377,7 +377,8 @@ static const struct it87_devices it87_devices[] = { .model = "IT8732F", .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI - | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS + | FEAT_FOUR_PWM, .peci_mask = 0x07, .old_peci_mask = 0x02, /* Actually reports PCH */ }, @@ -2932,6 +2933,34 @@ static int __init it87_find(int sioaddr, unsigned short *address, if (!(reg & BIT(0))) sio_data->skip_in |= BIT(9); + sio_data->beep_pin = superio_inb(sioaddr, + IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8732) { + int reg; + + superio_select(sioaddr, GPIO); + + /* Check for pwm2, fan2 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); + if (reg & BIT(1)) + sio_data->skip_pwm |= BIT(1); + if (reg & BIT(2)) + sio_data->skip_fan |= BIT(1); + + /* Check for pwm3, fan3, fan4 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); + if (reg & BIT(6)) + sio_data->skip_pwm |= BIT(2); + if (reg & BIT(7)) + sio_data->skip_fan |= BIT(2); + if (reg & BIT(5)) + sio_data->skip_fan |= BIT(3); + + /* Check if AVCC is on VIN3 */ + reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); + if (reg & BIT(0)) + sio_data->internal |= BIT(0); + sio_data->beep_pin = superio_inb(sioaddr, IT87_SIO_BEEP_PIN_REG) & 0x3f; } else { From 6a01a12d7e1609defa9a025e22e8730008a62104 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 19 Apr 2023 11:36:56 +1200 Subject: [PATCH 10/54] hwmon: (adt7475) Convert to use device_property APIs Instead of of_property_read_*() use the equivalent device_property_read_*() API. This will allow these properties to be used on DT unaware platforms. For DT aware platforms this will be a noop. Signed-off-by: Chris Packham Link: https://lore.kernel.org/r/20230418233656.869055-3-chris.packham@alliedtelesis.co.nz Signed-off-by: Guenter Roeck --- drivers/hwmon/adt7475.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 6a6ebcc896b1..3b9289bc5997 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1468,7 +1468,7 @@ static int load_config3(const struct i2c_client *client, const char *propname) u8 config3; int ret; - ret = of_property_read_string(client->dev.of_node, propname, &function); + ret = device_property_read_string(&client->dev, propname, &function); if (!ret) { ret = adt7475_read(REG_CONFIG3); if (ret < 0) @@ -1494,7 +1494,7 @@ static int load_config4(const struct i2c_client *client, const char *propname) u8 config4; int ret; - ret = of_property_read_string(client->dev.of_node, propname, &function); + ret = device_property_read_string(&client->dev, propname, &function); if (!ret) { ret = adt7475_read(REG_CONFIG4); if (ret < 0) @@ -1556,8 +1556,8 @@ static int set_property_bit(const struct i2c_client *client, char *property, u8 *config, u8 bit_index) { u32 prop_value = 0; - int ret = of_property_read_u32(client->dev.of_node, property, - &prop_value); + int ret = device_property_read_u32(&client->dev, property, + &prop_value); if (!ret) { if (prop_value) From 339c8f2484a110fd94af4d045e2be9bf25800381 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sun, 30 Apr 2023 14:50:32 +1000 Subject: [PATCH 11/54] hwmon: (it87) Allow for chips with only 4 temp sensors Some chips are known to only have 4 temperature sensors and there is no requirement to test for more. Currently only the IT8622E fits this category. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230430045032.1723288-1-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 96c17660ff0f..4c3641d28a6a 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -319,6 +319,7 @@ struct it87_devices { #define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */ #define FEAT_FOUR_FANS BIT(20) /* Supports four fans */ #define FEAT_FOUR_PWM BIT(21) /* Supports four fan controls */ +#define FEAT_FOUR_TEMP BIT(22) static const struct it87_devices it87_devices[] = { [it87] = { @@ -475,7 +476,7 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 - | FEAT_AVCC3 | FEAT_VIN3_5V, + | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP, .peci_mask = 0x07, .smbus_bitmap = BIT(1) | BIT(2), }, @@ -527,6 +528,7 @@ static const struct it87_devices it87_devices[] = { FEAT_SIX_PWM)) #define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM) #define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2) +#define has_four_temp(data) ((data)->features & FEAT_FOUR_TEMP) #define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP) #define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V) #define has_conf_noexit(data) ((data)->features & FEAT_CONF_NOEXIT) @@ -3393,7 +3395,9 @@ static int it87_probe(struct platform_device *pdev) data->need_in7_reroute = sio_data->need_in7_reroute; data->has_in = 0x3ff & ~sio_data->skip_in; - if (has_six_temp(data)) { + if (has_four_temp(data)) { + data->has_temp |= BIT(3); + } else if (has_six_temp(data)) { u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE); /* Check for additional temperature sensors */ From 1975d167869ef03102771d6267582623d6e07058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 5 May 2023 15:17:18 +0200 Subject: [PATCH 12/54] hwmon: Switch i2c drivers back to use .probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After commit b8a1a4cd5a98 ("i2c: Provide a temporary .probe_new() call-back type"), all drivers being converted to .probe_new() and then 03c835f498b5 ("i2c: Switch .probe() to not take an id parameter") convert back to (the new) .probe() to be able to eventually drop .probe_new() from struct i2c_driver. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230505131718.1210071-1-u.kleine-koenig@pengutronix.de [groeck: Added missing change in pmbus/acbel-fsg032.c] Signed-off-by: Guenter Roeck --- drivers/hwmon/ad7414.c | 2 +- drivers/hwmon/ad7418.c | 2 +- drivers/hwmon/adc128d818.c | 2 +- drivers/hwmon/adm1021.c | 2 +- drivers/hwmon/adm1025.c | 2 +- drivers/hwmon/adm1026.c | 2 +- drivers/hwmon/adm1029.c | 2 +- drivers/hwmon/adm1031.c | 2 +- drivers/hwmon/adm1177.c | 2 +- drivers/hwmon/adm9240.c | 2 +- drivers/hwmon/ads7828.c | 2 +- drivers/hwmon/adt7410.c | 2 +- drivers/hwmon/adt7411.c | 2 +- drivers/hwmon/adt7462.c | 2 +- drivers/hwmon/adt7470.c | 2 +- drivers/hwmon/adt7475.c | 2 +- drivers/hwmon/aht10.c | 2 +- drivers/hwmon/amc6821.c | 2 +- drivers/hwmon/asb100.c | 2 +- drivers/hwmon/asc7621.c | 2 +- drivers/hwmon/atxp1.c | 2 +- drivers/hwmon/dme1737.c | 2 +- drivers/hwmon/ds1621.c | 2 +- drivers/hwmon/ds620.c | 2 +- drivers/hwmon/emc1403.c | 2 +- drivers/hwmon/emc2103.c | 2 +- drivers/hwmon/emc2305.c | 2 +- drivers/hwmon/emc6w201.c | 2 +- drivers/hwmon/f75375s.c | 2 +- drivers/hwmon/fschmd.c | 2 +- drivers/hwmon/ftsteutates.c | 2 +- drivers/hwmon/g760a.c | 2 +- drivers/hwmon/g762.c | 2 +- drivers/hwmon/gl518sm.c | 2 +- drivers/hwmon/gl520sm.c | 2 +- drivers/hwmon/hih6130.c | 2 +- drivers/hwmon/ina209.c | 2 +- drivers/hwmon/ina238.c | 2 +- drivers/hwmon/ina2xx.c | 2 +- drivers/hwmon/ina3221.c | 2 +- drivers/hwmon/jc42.c | 2 +- drivers/hwmon/lineage-pem.c | 2 +- drivers/hwmon/lm63.c | 2 +- drivers/hwmon/lm73.c | 2 +- drivers/hwmon/lm75.c | 2 +- drivers/hwmon/lm77.c | 2 +- drivers/hwmon/lm78.c | 2 +- drivers/hwmon/lm80.c | 2 +- drivers/hwmon/lm83.c | 2 +- drivers/hwmon/lm85.c | 2 +- drivers/hwmon/lm87.c | 2 +- drivers/hwmon/lm90.c | 2 +- drivers/hwmon/lm92.c | 2 +- drivers/hwmon/lm93.c | 2 +- drivers/hwmon/lm95234.c | 2 +- drivers/hwmon/lm95241.c | 2 +- drivers/hwmon/lm95245.c | 2 +- drivers/hwmon/ltc2945.c | 2 +- drivers/hwmon/ltc2947-i2c.c | 2 +- drivers/hwmon/ltc2990.c | 2 +- drivers/hwmon/ltc2992.c | 2 +- drivers/hwmon/ltc4151.c | 2 +- drivers/hwmon/ltc4215.c | 2 +- drivers/hwmon/ltc4222.c | 2 +- drivers/hwmon/ltc4245.c | 2 +- drivers/hwmon/ltc4260.c | 2 +- drivers/hwmon/ltc4261.c | 2 +- drivers/hwmon/max127.c | 2 +- drivers/hwmon/max16065.c | 2 +- drivers/hwmon/max1619.c | 2 +- drivers/hwmon/max1668.c | 2 +- drivers/hwmon/max31730.c | 2 +- drivers/hwmon/max31760.c | 2 +- drivers/hwmon/max31790.c | 2 +- drivers/hwmon/max6620.c | 2 +- drivers/hwmon/max6621.c | 2 +- drivers/hwmon/max6639.c | 2 +- drivers/hwmon/max6642.c | 2 +- drivers/hwmon/max6650.c | 2 +- drivers/hwmon/max6697.c | 2 +- drivers/hwmon/mc34vr500.c | 2 +- drivers/hwmon/mcp3021.c | 2 +- drivers/hwmon/nct6775-i2c.c | 2 +- drivers/hwmon/nct7802.c | 2 +- drivers/hwmon/nct7904.c | 2 +- drivers/hwmon/occ/p8_i2c.c | 2 +- drivers/hwmon/pcf8591.c | 2 +- drivers/hwmon/pmbus/acbel-fsg032.c | 2 +- drivers/hwmon/pmbus/adm1266.c | 2 +- drivers/hwmon/pmbus/adm1275.c | 2 +- drivers/hwmon/pmbus/bel-pfe.c | 2 +- drivers/hwmon/pmbus/bpa-rs600.c | 2 +- drivers/hwmon/pmbus/delta-ahe50dc-fan.c | 2 +- drivers/hwmon/pmbus/dps920ab.c | 2 +- drivers/hwmon/pmbus/fsp-3y.c | 2 +- drivers/hwmon/pmbus/ibm-cffps.c | 2 +- drivers/hwmon/pmbus/inspur-ipsps.c | 2 +- drivers/hwmon/pmbus/ir35221.c | 2 +- drivers/hwmon/pmbus/ir36021.c | 2 +- drivers/hwmon/pmbus/ir38064.c | 2 +- drivers/hwmon/pmbus/irps5401.c | 2 +- drivers/hwmon/pmbus/isl68137.c | 2 +- drivers/hwmon/pmbus/lm25066.c | 2 +- drivers/hwmon/pmbus/lt7182s.c | 2 +- drivers/hwmon/pmbus/ltc2978.c | 2 +- drivers/hwmon/pmbus/ltc3815.c | 2 +- drivers/hwmon/pmbus/max15301.c | 2 +- drivers/hwmon/pmbus/max16064.c | 2 +- drivers/hwmon/pmbus/max16601.c | 2 +- drivers/hwmon/pmbus/max20730.c | 2 +- drivers/hwmon/pmbus/max20751.c | 2 +- drivers/hwmon/pmbus/max31785.c | 2 +- drivers/hwmon/pmbus/max34440.c | 2 +- drivers/hwmon/pmbus/max8688.c | 2 +- drivers/hwmon/pmbus/mp2888.c | 2 +- drivers/hwmon/pmbus/mp2975.c | 2 +- drivers/hwmon/pmbus/mp5023.c | 2 +- drivers/hwmon/pmbus/mpq7932.c | 2 +- drivers/hwmon/pmbus/pim4328.c | 2 +- drivers/hwmon/pmbus/pli1209bc.c | 2 +- drivers/hwmon/pmbus/pm6764tr.c | 2 +- drivers/hwmon/pmbus/pmbus.c | 2 +- drivers/hwmon/pmbus/pxe1610.c | 2 +- drivers/hwmon/pmbus/q54sj108a2.c | 2 +- drivers/hwmon/pmbus/stpddc60.c | 2 +- drivers/hwmon/pmbus/tda38640.c | 2 +- drivers/hwmon/pmbus/tps40422.c | 2 +- drivers/hwmon/pmbus/tps53679.c | 2 +- drivers/hwmon/pmbus/tps546d24.c | 2 +- drivers/hwmon/pmbus/ucd9000.c | 2 +- drivers/hwmon/pmbus/ucd9200.c | 2 +- drivers/hwmon/pmbus/xdpe12284.c | 2 +- drivers/hwmon/pmbus/xdpe152c4.c | 2 +- drivers/hwmon/pmbus/zl6100.c | 2 +- drivers/hwmon/powr1220.c | 2 +- drivers/hwmon/sbrmi.c | 2 +- drivers/hwmon/sbtsi_temp.c | 2 +- drivers/hwmon/sht21.c | 2 +- drivers/hwmon/sht3x.c | 2 +- drivers/hwmon/sht4x.c | 2 +- drivers/hwmon/shtc1.c | 2 +- drivers/hwmon/smm665.c | 2 +- drivers/hwmon/smsc47m192.c | 2 +- drivers/hwmon/stts751.c | 2 +- drivers/hwmon/tc654.c | 2 +- drivers/hwmon/tc74.c | 2 +- drivers/hwmon/thmc50.c | 2 +- drivers/hwmon/tmp102.c | 2 +- drivers/hwmon/tmp103.c | 2 +- drivers/hwmon/tmp108.c | 2 +- drivers/hwmon/tmp401.c | 2 +- drivers/hwmon/tmp421.c | 2 +- drivers/hwmon/tmp464.c | 2 +- drivers/hwmon/tmp513.c | 2 +- drivers/hwmon/tps23861.c | 2 +- drivers/hwmon/w83773g.c | 2 +- drivers/hwmon/w83781d.c | 2 +- drivers/hwmon/w83791d.c | 2 +- drivers/hwmon/w83792d.c | 2 +- drivers/hwmon/w83793.c | 2 +- drivers/hwmon/w83795.c | 2 +- drivers/hwmon/w83l785ts.c | 2 +- drivers/hwmon/w83l786ng.c | 2 +- 163 files changed, 163 insertions(+), 163 deletions(-) diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index 0afb89c4629d..7f1bef59046f 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -221,7 +221,7 @@ static struct i2c_driver ad7414_driver = { .name = "ad7414", .of_match_table = of_match_ptr(ad7414_of_match), }, - .probe_new = ad7414_probe, + .probe = ad7414_probe, .id_table = ad7414_id, }; diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index 22bdb7e5b9e0..ffe81e445010 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -306,7 +306,7 @@ static struct i2c_driver ad7418_driver = { .name = "ad7418", .of_match_table = ad7418_dt_ids, }, - .probe_new = ad7418_probe, + .probe = ad7418_probe, .id_table = ad7418_id, }; diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index 97b330b6c165..46e3c8c50765 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -521,7 +521,7 @@ static struct i2c_driver adc128_driver = { .name = "adc128d818", .of_match_table = of_match_ptr(adc128_of_match), }, - .probe_new = adc128_probe, + .probe = adc128_probe, .remove = adc128_remove, .id_table = adc128_id, .detect = adc128_detect, diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 2dc45e958730..7c15398ebb37 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -488,7 +488,7 @@ static struct i2c_driver adm1021_driver = { .driver = { .name = "adm1021", }, - .probe_new = adm1021_probe, + .probe = adm1021_probe, .id_table = adm1021_id, .detect = adm1021_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 2984c4f98496..389382d54752 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -559,7 +559,7 @@ static struct i2c_driver adm1025_driver = { .driver = { .name = "adm1025", }, - .probe_new = adm1025_probe, + .probe = adm1025_probe, .id_table = adm1025_id, .detect = adm1025_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 1f084f708743..581d8edf70ea 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -1859,7 +1859,7 @@ static struct i2c_driver adm1026_driver = { .driver = { .name = "adm1026", }, - .probe_new = adm1026_probe, + .probe = adm1026_probe, .id_table = adm1026_id, .detect = adm1026_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index eaf6e5e04aac..9a465f3f71c8 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -389,7 +389,7 @@ static struct i2c_driver adm1029_driver = { .driver = { .name = "adm1029", }, - .probe_new = adm1029_probe, + .probe = adm1029_probe, .id_table = adm1029_id, .detect = adm1029_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index b42797bcb5b4..88c7e0d62d08 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -1068,7 +1068,7 @@ static struct i2c_driver adm1031_driver = { .driver = { .name = "adm1031", }, - .probe_new = adm1031_probe, + .probe = adm1031_probe, .id_table = adm1031_id, .detect = adm1031_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c index bfe070a1b501..60a893f27159 100644 --- a/drivers/hwmon/adm1177.c +++ b/drivers/hwmon/adm1177.c @@ -255,7 +255,7 @@ static struct i2c_driver adm1177_driver = { .name = "adm1177", .of_match_table = adm1177_dt_ids, }, - .probe_new = adm1177_probe, + .probe = adm1177_probe, .id_table = adm1177_id, }; module_i2c_driver(adm1177_driver); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 9eb973a38e4b..6dfbeb6acf00 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -819,7 +819,7 @@ static struct i2c_driver adm9240_driver = { .driver = { .name = "adm9240", }, - .probe_new = adm9240_probe, + .probe = adm9240_probe, .id_table = adm9240_id, .detect = adm9240_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index 7246198f0901..1932613ec095 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -208,7 +208,7 @@ static struct i2c_driver ads7828_driver = { }, .id_table = ads7828_device_ids, - .probe_new = ads7828_probe, + .probe = ads7828_probe, }; module_i2c_driver(ads7828_driver); diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 0cebf6777239..952506779336 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -100,7 +100,7 @@ static struct i2c_driver adt7410_driver = { .name = "adt7410", .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops), }, - .probe_new = adt7410_i2c_probe, + .probe = adt7410_i2c_probe, .id_table = adt7410_ids, .address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b), }; diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 6ba84921614f..45fe4e8aae4e 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -706,7 +706,7 @@ static struct i2c_driver adt7411_driver = { .driver = { .name = "adt7411", }, - .probe_new = adt7411_probe, + .probe = adt7411_probe, .id_table = adt7411_id, .detect = adt7411_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 9c0235849d4b..429566c4245d 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -1819,7 +1819,7 @@ static struct i2c_driver adt7462_driver = { .driver = { .name = "adt7462", }, - .probe_new = adt7462_probe, + .probe = adt7462_probe, .id_table = adt7462_id, .detect = adt7462_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 64f801b859ff..c4b3a4a18670 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -1314,7 +1314,7 @@ static struct i2c_driver adt7470_driver = { .driver = { .name = "adt7470", }, - .probe_new = adt7470_probe, + .probe = adt7470_probe, .remove = adt7470_remove, .id_table = adt7470_id, .detect = adt7470_detect, diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 3b9289bc5997..c0ce88324ea6 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1821,7 +1821,7 @@ static struct i2c_driver adt7475_driver = { .name = "adt7475", .of_match_table = of_match_ptr(adt7475_of_match), }, - .probe_new = adt7475_probe, + .probe = adt7475_probe, .id_table = adt7475_id, .detect = adt7475_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index b8fe3f7248ba..4ecc02315f8f 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -334,7 +334,7 @@ static struct i2c_driver aht10_driver = { .driver = { .name = "aht10", }, - .probe_new = aht10_probe, + .probe = aht10_probe, .id_table = aht10_id, }; diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 3bfd12ff4b3c..2a7a4b6b0094 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -939,7 +939,7 @@ static struct i2c_driver amc6821_driver = { .driver = { .name = "amc6821", }, - .probe_new = amc6821_probe, + .probe = amc6821_probe, .id_table = amc6821_id, .detect = amc6821_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index ce4da836765c..974521e9b6b4 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -223,7 +223,7 @@ static struct i2c_driver asb100_driver = { .driver = { .name = "asb100", }, - .probe_new = asb100_probe, + .probe = asb100_probe, .remove = asb100_remove, .id_table = asb100_id, .detect = asb100_detect, diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 54595454537b..87e186700849 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -1191,7 +1191,7 @@ static struct i2c_driver asc7621_driver = { .driver = { .name = "asc7621", }, - .probe_new = asc7621_probe, + .probe = asc7621_probe, .remove = asc7621_remove, .id_table = asc7621_id, .detect = asc7621_detect, diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 118297ea1dcf..d1de020abec6 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -288,7 +288,7 @@ static struct i2c_driver atxp1_driver = { .driver = { .name = "atxp1", }, - .probe_new = atxp1_probe, + .probe = atxp1_probe, .id_table = atxp1_id, }; diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 66c48f70fae7..cdbf3dff9172 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2528,7 +2528,7 @@ static struct i2c_driver dme1737_i2c_driver = { .driver = { .name = "dme1737", }, - .probe_new = dme1737_i2c_probe, + .probe = dme1737_i2c_probe, .remove = dme1737_i2c_remove, .id_table = dme1737_id, .detect = dme1737_i2c_detect, diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index e803d6393b9e..21b635046521 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -384,7 +384,7 @@ static struct i2c_driver ds1621_driver = { .driver = { .name = "ds1621", }, - .probe_new = ds1621_probe, + .probe = ds1621_probe, .id_table = ds1621_id, }; diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 82d7c3d58f49..2b09536630cb 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -245,7 +245,7 @@ static struct i2c_driver ds620_driver = { .driver = { .name = "ds620", }, - .probe_new = ds620_probe, + .probe = ds620_probe, .id_table = ds620_id, }; diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 61d59189a6d1..bb7c859e799d 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -454,7 +454,7 @@ static struct i2c_driver sensor_emc1403 = { .name = "emc1403", }, .detect = emc1403_detect, - .probe_new = emc1403_probe, + .probe = emc1403_probe, .id_table = emc1403_idtable, .address_list = emc1403_address_list, }; diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 361cf9292456..b59472bbe5bf 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -653,7 +653,7 @@ static struct i2c_driver emc2103_driver = { .driver = { .name = "emc2103", }, - .probe_new = emc2103_probe, + .probe = emc2103_probe, .id_table = emc2103_ids, .detect = emc2103_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 723f57518c9a..29f0e4945f19 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -615,7 +615,7 @@ static struct i2c_driver emc2305_driver = { .driver = { .name = "emc2305", }, - .probe_new = emc2305_probe, + .probe = emc2305_probe, .remove = emc2305_remove, .id_table = emc2305_ids, .address_list = emc2305_normal_i2c, diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index bcd93f0fe982..9a4f868bf1e6 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -474,7 +474,7 @@ static struct i2c_driver emc6w201_driver = { .driver = { .name = "emc6w201", }, - .probe_new = emc6w201_probe, + .probe = emc6w201_probe, .id_table = emc6w201_id, .detect = emc6w201_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 64fbb8cf687c..8c572bb64f5d 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -129,7 +129,7 @@ static struct i2c_driver f75375_driver = { .driver = { .name = "f75375", }, - .probe_new = f75375_probe, + .probe = f75375_probe, .remove = f75375_remove, .id_table = f75375_id, .detect = f75375_detect, diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index e1f426e86f36..b30512a705a7 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -241,7 +241,7 @@ static struct i2c_driver fschmd_driver = { .driver = { .name = "fschmd", }, - .probe_new = fschmd_probe, + .probe = fschmd_probe, .remove = fschmd_remove, .id_table = fschmd_id, .detect = fschmd_detect, diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index f5a4d91a7e90..b74a2665e733 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -678,7 +678,7 @@ static struct i2c_driver fts_driver = { .name = "ftsteutates", }, .id_table = fts_id, - .probe_new = fts_probe, + .probe = fts_probe, .detect = fts_detect, .address_list = normal_i2c, }; diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 36717b524dbd..b5edee00267b 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -206,7 +206,7 @@ static struct i2c_driver g760a_driver = { .driver = { .name = "g760a", }, - .probe_new = g760a_probe, + .probe = g760a_probe, .id_table = g760a_id, }; diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index e2c3c34f06e8..1b6ff4712138 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -1084,7 +1084,7 @@ static struct i2c_driver g762_driver = { .name = DRVNAME, .of_match_table = of_match_ptr(g762_dt_match), }, - .probe_new = g762_probe, + .probe = g762_probe, .id_table = g762_id, }; diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 95286c40f55a..03db6158b13a 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -652,7 +652,7 @@ static struct i2c_driver gl518_driver = { .driver = { .name = "gl518sm", }, - .probe_new = gl518_probe, + .probe = gl518_probe, .id_table = gl518_id, .detect = gl518_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 394da4ac977c..8bbc6a4f2928 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -895,7 +895,7 @@ static struct i2c_driver gl520_driver = { .driver = { .name = "gl520sm", }, - .probe_new = gl520_probe, + .probe = gl520_probe, .id_table = gl520_id, .detect = gl520_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index 3a7582824f94..a9726b5370fb 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -249,7 +249,7 @@ static struct i2c_driver hih6130_driver = { .name = "hih6130", .of_match_table = of_match_ptr(hih6130_of_match), }, - .probe_new = hih6130_probe, + .probe = hih6130_probe, .id_table = hih6130_id, }; diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c index 9b58655d2de4..c558143e5285 100644 --- a/drivers/hwmon/ina209.c +++ b/drivers/hwmon/ina209.c @@ -594,7 +594,7 @@ static struct i2c_driver ina209_driver = { .name = "ina209", .of_match_table = of_match_ptr(ina209_of_match), }, - .probe_new = ina209_probe, + .probe = ina209_probe, .remove = ina209_remove, .id_table = ina209_id, }; diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 8af07bc0c50e..f519c22d3907 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -633,7 +633,7 @@ static struct i2c_driver ina238_driver = { .name = "ina238", .of_match_table = of_match_ptr(ina238_of_match), }, - .probe_new = ina238_probe, + .probe = ina238_probe, .id_table = ina238_id, }; diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index fd50d9785ccb..cfd7efef5cdf 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -721,7 +721,7 @@ static struct i2c_driver ina2xx_driver = { .name = "ina2xx", .of_match_table = of_match_ptr(ina2xx_of_match), }, - .probe_new = ina2xx_probe, + .probe = ina2xx_probe, .id_table = ina2xx_id, }; diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 2735e3782ffb..5ab944056ec0 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -1010,7 +1010,7 @@ static const struct i2c_device_id ina3221_ids[] = { MODULE_DEVICE_TABLE(i2c, ina3221_ids); static struct i2c_driver ina3221_i2c_driver = { - .probe_new = ina3221_probe, + .probe = ina3221_probe, .remove = ina3221_remove, .driver = { .name = INA3221_DRIVER_NAME, diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 4c60dc520b12..f958e830b23c 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -629,7 +629,7 @@ static struct i2c_driver jc42_driver = { .pm = JC42_DEV_PM_OPS, .of_match_table = of_match_ptr(jc42_of_ids), }, - .probe_new = jc42_probe, + .probe = jc42_probe, .remove = jc42_remove, .id_table = jc42_id, .detect = jc42_detect, diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c index ef5a49cd9149..df69c380cde7 100644 --- a/drivers/hwmon/lineage-pem.c +++ b/drivers/hwmon/lineage-pem.c @@ -511,7 +511,7 @@ static struct i2c_driver pem_driver = { .driver = { .name = "lineage_pem", }, - .probe_new = pem_probe, + .probe = pem_probe, .id_table = pem_id, }; diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 9ab2cab4c710..6972454eb4e0 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -1164,7 +1164,7 @@ static struct i2c_driver lm63_driver = { .name = "lm63", .of_match_table = of_match_ptr(lm63_of_match), }, - .probe_new = lm63_probe, + .probe = lm63_probe, .id_table = lm63_id, .detect = lm63_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index b6433ae2d75c..637d35c5ae23 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -277,7 +277,7 @@ static struct i2c_driver lm73_driver = { .name = "lm73", .of_match_table = lm73_of_match, }, - .probe_new = lm73_probe, + .probe = lm73_probe, .id_table = lm73_ids, .detect = lm73_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index dbb99ea4a0ec..182aeb388523 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -945,7 +945,7 @@ static struct i2c_driver lm75_driver = { .of_match_table = of_match_ptr(lm75_of_match), .pm = LM75_DEV_PM_OPS, }, - .probe_new = lm75_probe, + .probe = lm75_probe, .id_table = lm75_ids, .detect = lm75_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 645cb2191abe..8b9862519178 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -348,7 +348,7 @@ static struct i2c_driver lm77_driver = { .driver = { .name = "lm77", }, - .probe_new = lm77_probe, + .probe = lm77_probe, .id_table = lm77_id, .detect = lm77_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 694e171cab7f..b739c354311b 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -662,7 +662,7 @@ static struct i2c_driver lm78_driver = { .driver = { .name = "lm78", }, - .probe_new = lm78_i2c_probe, + .probe = lm78_i2c_probe, .id_table = lm78_i2c_id, .detect = lm78_i2c_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 35db0b97f912..63c7831bd3e1 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -633,7 +633,7 @@ static struct i2c_driver lm80_driver = { .driver = { .name = "lm80", }, - .probe_new = lm80_probe, + .probe = lm80_probe, .id_table = lm80_id, .detect = lm80_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index bcaf31ec176e..5befedca6abb 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -454,7 +454,7 @@ static struct i2c_driver lm83_driver = { .driver = { .name = "lm83", }, - .probe_new = lm83_probe, + .probe = lm83_probe, .id_table = lm83_id, .detect = lm83_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 8d33c2484755..8540178f5b74 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1698,7 +1698,7 @@ static struct i2c_driver lm85_driver = { .name = "lm85", .of_match_table = of_match_ptr(lm85_of_match), }, - .probe_new = lm85_probe, + .probe = lm85_probe, .id_table = lm85_id, .detect = lm85_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 818fb6195245..2195a735d28e 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -994,7 +994,7 @@ static struct i2c_driver lm87_driver = { .name = "lm87", .of_match_table = lm87_of_match, }, - .probe_new = lm87_probe, + .probe = lm87_probe, .id_table = lm87_id, .detect = lm87_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 6498d5acf705..90101c236f35 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -2972,7 +2972,7 @@ static struct i2c_driver lm90_driver = { .of_match_table = of_match_ptr(lm90_of_match), .pm = pm_sleep_ptr(&lm90_pm_ops), }, - .probe_new = lm90_probe, + .probe = lm90_probe, .alert = lm90_alert, .id_table = lm90_id, .detect = lm90_detect, diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 2ff3044a677d..46579a3e1715 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -330,7 +330,7 @@ static struct i2c_driver lm92_driver = { .driver = { .name = "lm92", }, - .probe_new = lm92_probe, + .probe = lm92_probe, .id_table = lm92_id, .detect = lm92_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 4cf50d5f4f59..75bca805720e 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2635,7 +2635,7 @@ static struct i2c_driver lm93_driver = { .driver = { .name = "lm93", }, - .probe_new = lm93_probe, + .probe = lm93_probe, .id_table = lm93_id, .detect = lm93_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index b4a9d0c223c4..67b9d7636ee4 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -720,7 +720,7 @@ static struct i2c_driver lm95234_driver = { .driver = { .name = DRVNAME, }, - .probe_new = lm95234_probe, + .probe = lm95234_probe, .id_table = lm95234_id, .detect = lm95234_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 647a90570bc6..475551f5024b 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -468,7 +468,7 @@ static struct i2c_driver lm95241_driver = { .driver = { .name = DEVNAME, }, - .probe_new = lm95241_probe, + .probe = lm95241_probe, .id_table = lm95241_id, .detect = lm95241_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 4236d1e0544d..7f13b6b712fb 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -597,7 +597,7 @@ static struct i2c_driver lm95245_driver = { .name = "lm95245", .of_match_table = of_match_ptr(lm95245_of_match), }, - .probe_new = lm95245_probe, + .probe = lm95245_probe, .id_table = lm95245_id, .detect = lm95245_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index 3494f7261ebf..45b87a863cae 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -519,7 +519,7 @@ static struct i2c_driver ltc2945_driver = { .name = "ltc2945", .of_match_table = of_match_ptr(ltc2945_of_match), }, - .probe_new = ltc2945_probe, + .probe = ltc2945_probe, .id_table = ltc2945_id, }; diff --git a/drivers/hwmon/ltc2947-i2c.c b/drivers/hwmon/ltc2947-i2c.c index 96852bc8a964..33f574bf2ce7 100644 --- a/drivers/hwmon/ltc2947-i2c.c +++ b/drivers/hwmon/ltc2947-i2c.c @@ -38,7 +38,7 @@ static struct i2c_driver ltc2947_driver = { .of_match_table = ltc2947_of_match, .pm = pm_sleep_ptr(<c2947_pm_ops), }, - .probe_new = ltc2947_probe, + .probe = ltc2947_probe, .id_table = ltc2947_id, }; module_i2c_driver(ltc2947_driver); diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 689f788b8563..1ad362c0fd2c 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -268,7 +268,7 @@ static struct i2c_driver ltc2990_i2c_driver = { .driver = { .name = "ltc2990", }, - .probe_new = ltc2990_i2c_probe, + .probe = ltc2990_i2c_probe, .id_table = ltc2990_i2c_id, }; diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c index 429a7f5837f0..589bcd07ce7f 100644 --- a/drivers/hwmon/ltc2992.c +++ b/drivers/hwmon/ltc2992.c @@ -928,7 +928,7 @@ static struct i2c_driver ltc2992_i2c_driver = { .name = "ltc2992", .of_match_table = ltc2992_of_match, }, - .probe_new = ltc2992_i2c_probe, + .probe = ltc2992_i2c_probe, .id_table = ltc2992_i2c_id, }; diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index e3ac004c1ed1..f42ac3c9475e 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -205,7 +205,7 @@ static struct i2c_driver ltc4151_driver = { .name = "ltc4151", .of_match_table = of_match_ptr(ltc4151_match), }, - .probe_new = ltc4151_probe, + .probe = ltc4151_probe, .id_table = ltc4151_id, }; diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index fa43d26ddd4f..66fd28f713ab 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -255,7 +255,7 @@ static struct i2c_driver ltc4215_driver = { .driver = { .name = "ltc4215", }, - .probe_new = ltc4215_probe, + .probe = ltc4215_probe, .id_table = ltc4215_id, }; diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c index d2027ca5c925..9098ef521739 100644 --- a/drivers/hwmon/ltc4222.c +++ b/drivers/hwmon/ltc4222.c @@ -210,7 +210,7 @@ static struct i2c_driver ltc4222_driver = { .driver = { .name = "ltc4222", }, - .probe_new = ltc4222_probe, + .probe = ltc4222_probe, .id_table = ltc4222_id, }; diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index fb9bc8dbe99b..b90184a3e0ec 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -479,7 +479,7 @@ static struct i2c_driver ltc4245_driver = { .driver = { .name = "ltc4245", }, - .probe_new = ltc4245_probe, + .probe = ltc4245_probe, .id_table = ltc4245_id, }; diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c index 75e89cec381e..52f7a809b27b 100644 --- a/drivers/hwmon/ltc4260.c +++ b/drivers/hwmon/ltc4260.c @@ -173,7 +173,7 @@ static struct i2c_driver ltc4260_driver = { .driver = { .name = "ltc4260", }, - .probe_new = ltc4260_probe, + .probe = ltc4260_probe, .id_table = ltc4260_id, }; diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c index b91cc4fe84e5..509e68176c7a 100644 --- a/drivers/hwmon/ltc4261.c +++ b/drivers/hwmon/ltc4261.c @@ -233,7 +233,7 @@ static struct i2c_driver ltc4261_driver = { .driver = { .name = "ltc4261", }, - .probe_new = ltc4261_probe, + .probe = ltc4261_probe, .id_table = ltc4261_id, }; diff --git a/drivers/hwmon/max127.c b/drivers/hwmon/max127.c index 49de1d2be294..ee5ead06d612 100644 --- a/drivers/hwmon/max127.c +++ b/drivers/hwmon/max127.c @@ -339,7 +339,7 @@ static struct i2c_driver max127_driver = { .driver = { .name = "max127", }, - .probe_new = max127_probe, + .probe = max127_probe, .id_table = max127_id, }; diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index daa5d8af1e69..aa38c45adc09 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -600,7 +600,7 @@ static struct i2c_driver max16065_driver = { .driver = { .name = "max16065", }, - .probe_new = max16065_probe, + .probe = max16065_probe, .id_table = max16065_id, }; diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 445c77197f69..500dc926a7a7 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -305,7 +305,7 @@ static struct i2c_driver max1619_driver = { .name = "max1619", .of_match_table = of_match_ptr(max1619_of_match), }, - .probe_new = max1619_probe, + .probe = max1619_probe, .id_table = max1619_id, .detect = max1619_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index 9f748973d6a3..c4a02edefbee 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -435,7 +435,7 @@ static struct i2c_driver max1668_driver = { .driver = { .name = "max1668", }, - .probe_new = max1668_probe, + .probe = max1668_probe, .id_table = max1668_id, .detect = max1668_detect, .address_list = max1668_addr_list, diff --git a/drivers/hwmon/max31730.c b/drivers/hwmon/max31730.c index 924333d89ce4..b1300ca9db1f 100644 --- a/drivers/hwmon/max31730.c +++ b/drivers/hwmon/max31730.c @@ -427,7 +427,7 @@ static struct i2c_driver max31730_driver = { .of_match_table = of_match_ptr(max31730_of_match), .pm = pm_sleep_ptr(&max31730_pm_ops), }, - .probe_new = max31730_probe, + .probe = max31730_probe, .id_table = max31730_ids, .detect = max31730_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max31760.c b/drivers/hwmon/max31760.c index 4489110f109c..79945eb466ae 100644 --- a/drivers/hwmon/max31760.c +++ b/drivers/hwmon/max31760.c @@ -584,7 +584,7 @@ static struct i2c_driver max31760_driver = { .of_match_table = max31760_of_match, .pm = pm_ptr(&max31760_pm_ops) }, - .probe_new = max31760_probe, + .probe = max31760_probe, .id_table = max31760_id }; module_i2c_driver(max31760_driver); diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 6caba6e8ee8f..0cd44c1e998a 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -544,7 +544,7 @@ MODULE_DEVICE_TABLE(i2c, max31790_id); static struct i2c_driver max31790_driver = { .class = I2C_CLASS_HWMON, - .probe_new = max31790_probe, + .probe = max31790_probe, .driver = { .name = "max31790", }, diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c index 0f277d945ea2..5d12fb9c9786 100644 --- a/drivers/hwmon/max6620.c +++ b/drivers/hwmon/max6620.c @@ -503,7 +503,7 @@ static struct i2c_driver max6620_driver = { .driver = { .name = "max6620", }, - .probe_new = max6620_probe, + .probe = max6620_probe, .id_table = max6620_id, }; diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c index 0656eb1e7959..7f709fd1af89 100644 --- a/drivers/hwmon/max6621.c +++ b/drivers/hwmon/max6621.c @@ -554,7 +554,7 @@ static struct i2c_driver max6621_driver = { .name = MAX6621_DRV_NAME, .of_match_table = of_match_ptr(max6621_of_match), }, - .probe_new = max6621_probe, + .probe = max6621_probe, .id_table = max6621_id, }; diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 9b895402c80d..caf527154fca 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -624,7 +624,7 @@ static struct i2c_driver max6639_driver = { .name = "max6639", .pm = pm_sleep_ptr(&max6639_pm_ops), }, - .probe_new = max6639_probe, + .probe = max6639_probe, .id_table = max6639_id, .detect = max6639_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 47ea34ff78f3..8b2e4d6101a2 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -301,7 +301,7 @@ static struct i2c_driver max6642_driver = { .driver = { .name = "max6642", }, - .probe_new = max6642_probe, + .probe = max6642_probe, .id_table = max6642_id, .detect = max6642_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 19e2c762ed2d..cc8428a3045d 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -819,7 +819,7 @@ static struct i2c_driver max6650_driver = { .name = "max6650", .of_match_table = of_match_ptr(max6650_dt_match), }, - .probe_new = max6650_probe, + .probe = max6650_probe, .id_table = max6650_id, }; diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 2895cea54193..3a67778f111c 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -786,7 +786,7 @@ static struct i2c_driver max6697_driver = { .name = "max6697", .of_match_table = of_match_ptr(max6697_of_match), }, - .probe_new = max6697_probe, + .probe = max6697_probe, .id_table = max6697_id, }; diff --git a/drivers/hwmon/mc34vr500.c b/drivers/hwmon/mc34vr500.c index 6a7a950a9332..0c8fd3fce83e 100644 --- a/drivers/hwmon/mc34vr500.c +++ b/drivers/hwmon/mc34vr500.c @@ -251,7 +251,7 @@ static struct i2c_driver mc34vr500_driver = { .name = "mc34vr500", .of_match_table = of_match_ptr(mc34vr500_of_match), }, - .probe_new = mc34vr500_probe, + .probe = mc34vr500_probe, .id_table = mc34vr500_id, }; diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index a5f7a294f33d..127e15ff3e76 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -198,7 +198,7 @@ static struct i2c_driver mcp3021_driver = { .name = "mcp3021", .of_match_table = of_match_ptr(of_mcp3021_match), }, - .probe_new = mcp3021_probe, + .probe = mcp3021_probe, .id_table = mcp3021_id, }; diff --git a/drivers/hwmon/nct6775-i2c.c b/drivers/hwmon/nct6775-i2c.c index e1bcd1146191..8acd83e1e009 100644 --- a/drivers/hwmon/nct6775-i2c.c +++ b/drivers/hwmon/nct6775-i2c.c @@ -183,7 +183,7 @@ static struct i2c_driver nct6775_i2c_driver = { .name = "nct6775-i2c", .of_match_table = of_match_ptr(nct6775_i2c_of_match), }, - .probe_new = nct6775_i2c_probe, + .probe = nct6775_i2c_probe, .id_table = nct6775_i2c_id, }; diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index a175f8283695..9339bfc02a3e 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -1223,7 +1223,7 @@ static struct i2c_driver nct7802_driver = { .name = DRVNAME, }, .detect = nct7802_detect, - .probe_new = nct7802_probe, + .probe = nct7802_probe, .id_table = nct7802_idtable, .address_list = nct7802_address_list, }; diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index 007bae4c7028..8f867d4570e1 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -1171,7 +1171,7 @@ static struct i2c_driver nct7904_driver = { .driver = { .name = "nct7904", }, - .probe_new = nct7904_probe, + .probe = nct7904_probe, .id_table = nct7904_id, .detect = nct7904_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/occ/p8_i2c.c b/drivers/hwmon/occ/p8_i2c.c index 9e1744fccb35..06095975f5c8 100644 --- a/drivers/hwmon/occ/p8_i2c.c +++ b/drivers/hwmon/occ/p8_i2c.c @@ -246,7 +246,7 @@ static struct i2c_driver p8_i2c_occ_driver = { .name = "occ-hwmon", .of_match_table = p8_i2c_occ_of_match, }, - .probe_new = p8_i2c_occ_probe, + .probe = p8_i2c_occ_probe, .remove = p8_i2c_occ_remove, }; diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index 1dbe209ae13f..66c76b28c9e0 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -294,7 +294,7 @@ static struct i2c_driver pcf8591_driver = { .driver = { .name = "pcf8591", }, - .probe_new = pcf8591_probe, + .probe = pcf8591_probe, .remove = pcf8591_remove, .id_table = pcf8591_id, }; diff --git a/drivers/hwmon/pmbus/acbel-fsg032.c b/drivers/hwmon/pmbus/acbel-fsg032.c index 28a25f30e2cf..0a0ef4ce3493 100644 --- a/drivers/hwmon/pmbus/acbel-fsg032.c +++ b/drivers/hwmon/pmbus/acbel-fsg032.c @@ -73,7 +73,7 @@ static struct i2c_driver acbel_fsg032_driver = { .name = "acbel-fsg032", .of_match_table = acbel_fsg032_of_match, }, - .probe_new = acbel_fsg032_probe, + .probe = acbel_fsg032_probe, .id_table = acbel_fsg032_id, }; diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index 1ac2b2f4c570..aba70330b319 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -502,7 +502,7 @@ static struct i2c_driver adm1266_driver = { .name = "adm1266", .of_match_table = adm1266_of_match, }, - .probe_new = adm1266_probe, + .probe = adm1266_probe, .id_table = adm1266_id, }; diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index b8543c06d022..49d59b745afe 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -832,7 +832,7 @@ static struct i2c_driver adm1275_driver = { .driver = { .name = "adm1275", }, - .probe_new = adm1275_probe, + .probe = adm1275_probe, .id_table = adm1275_id, }; diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index 4100eefb7ac3..fa5070ae26bc 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -120,7 +120,7 @@ static struct i2c_driver pfe_pmbus_driver = { .driver = { .name = "bel-pfe", }, - .probe_new = pfe_pmbus_probe, + .probe = pfe_pmbus_probe, .id_table = pfe_device_id, }; diff --git a/drivers/hwmon/pmbus/bpa-rs600.c b/drivers/hwmon/pmbus/bpa-rs600.c index f2d4e378a775..0dce26c35556 100644 --- a/drivers/hwmon/pmbus/bpa-rs600.c +++ b/drivers/hwmon/pmbus/bpa-rs600.c @@ -196,7 +196,7 @@ static struct i2c_driver bpa_rs600_driver = { .name = "bpa-rs600", .of_match_table = of_match_ptr(bpa_rs600_of_match), }, - .probe_new = bpa_rs600_probe, + .probe = bpa_rs600_probe, .id_table = bpa_rs600_id, }; diff --git a/drivers/hwmon/pmbus/delta-ahe50dc-fan.c b/drivers/hwmon/pmbus/delta-ahe50dc-fan.c index f546f0c12497..4dd3b6686d6a 100644 --- a/drivers/hwmon/pmbus/delta-ahe50dc-fan.c +++ b/drivers/hwmon/pmbus/delta-ahe50dc-fan.c @@ -119,7 +119,7 @@ static struct i2c_driver ahe50dc_fan_driver = { .name = "ahe50dc_fan", .of_match_table = of_match_ptr(ahe50dc_fan_of_match), }, - .probe_new = ahe50dc_fan_probe, + .probe = ahe50dc_fan_probe, .id_table = ahe50dc_fan_id, }; module_i2c_driver(ahe50dc_fan_driver); diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c index d3941f6eb29a..f7ff3e4650b7 100644 --- a/drivers/hwmon/pmbus/dps920ab.c +++ b/drivers/hwmon/pmbus/dps920ab.c @@ -195,7 +195,7 @@ static struct i2c_driver dps920ab_driver = { .name = "dps920ab", .of_match_table = of_match_ptr(dps920ab_of_match), }, - .probe_new = dps920ab_probe, + .probe = dps920ab_probe, }; module_i2c_driver(dps920ab_driver); diff --git a/drivers/hwmon/pmbus/fsp-3y.c b/drivers/hwmon/pmbus/fsp-3y.c index c7469d2cdedc..72a7c261ef06 100644 --- a/drivers/hwmon/pmbus/fsp-3y.c +++ b/drivers/hwmon/pmbus/fsp-3y.c @@ -282,7 +282,7 @@ static struct i2c_driver fsp3y_driver = { .driver = { .name = "fsp3y", }, - .probe_new = fsp3y_probe, + .probe = fsp3y_probe, .id_table = fsp3y_id }; diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 76e72e9acda7..c791925b8907 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -605,7 +605,7 @@ static struct i2c_driver ibm_cffps_driver = { .name = "ibm-cffps", .of_match_table = ibm_cffps_of_match, }, - .probe_new = ibm_cffps_probe, + .probe = ibm_cffps_probe, .id_table = ibm_cffps_id, }; diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c index 0f614e8d95f6..dfeae68b5e52 100644 --- a/drivers/hwmon/pmbus/inspur-ipsps.c +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -215,7 +215,7 @@ static struct i2c_driver ipsps_driver = { .name = "inspur-ipsps", .of_match_table = of_match_ptr(ipsps_of_match), }, - .probe_new = ipsps_probe, + .probe = ipsps_probe, .id_table = ipsps_id, }; diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index a6cf98e49666..e3ee5c1bd967 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -136,7 +136,7 @@ static struct i2c_driver ir35221_driver = { .driver = { .name = "ir35221", }, - .probe_new = ir35221_probe, + .probe = ir35221_probe, .id_table = ir35221_id, }; diff --git a/drivers/hwmon/pmbus/ir36021.c b/drivers/hwmon/pmbus/ir36021.c index 4dca4767f571..382ba6b6031a 100644 --- a/drivers/hwmon/pmbus/ir36021.c +++ b/drivers/hwmon/pmbus/ir36021.c @@ -68,7 +68,7 @@ static struct i2c_driver ir36021_driver = { .name = "ir36021", .of_match_table = of_match_ptr(ir36021_of_id), }, - .probe_new = ir36021_probe, + .probe = ir36021_probe, .id_table = ir36021_id, }; diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c index 09276e397194..871c322d3d51 100644 --- a/drivers/hwmon/pmbus/ir38064.c +++ b/drivers/hwmon/pmbus/ir38064.c @@ -78,7 +78,7 @@ static struct i2c_driver ir38064_driver = { .name = "ir38064", .of_match_table = of_match_ptr(ir38064_of_match), }, - .probe_new = ir38064_probe, + .probe = ir38064_probe, .id_table = ir38064_id, }; diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c index de3449e4d77a..146d32a35a7c 100644 --- a/drivers/hwmon/pmbus/irps5401.c +++ b/drivers/hwmon/pmbus/irps5401.c @@ -54,7 +54,7 @@ static struct i2c_driver irps5401_driver = { .driver = { .name = "irps5401", }, - .probe_new = irps5401_probe, + .probe = irps5401_probe, .id_table = irps5401_id, }; diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 1a8caff1ac5f..7e53fb1d5ea3 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -323,7 +323,7 @@ static struct i2c_driver isl68137_driver = { .driver = { .name = "isl68137", }, - .probe_new = isl68137_probe, + .probe = isl68137_probe, .id_table = raa_dmpvr_id, }; diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 09792cd03d9f..929fa6d34efd 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -568,7 +568,7 @@ static struct i2c_driver lm25066_driver = { .name = "lm25066", .of_match_table = of_match_ptr(lm25066_of_match), }, - .probe_new = lm25066_probe, + .probe = lm25066_probe, .id_table = lm25066_id, }; diff --git a/drivers/hwmon/pmbus/lt7182s.c b/drivers/hwmon/pmbus/lt7182s.c index 4cfe476fc92d..28afc5f15ae8 100644 --- a/drivers/hwmon/pmbus/lt7182s.c +++ b/drivers/hwmon/pmbus/lt7182s.c @@ -183,7 +183,7 @@ static struct i2c_driver lt7182s_driver = { .name = "lt7182s", .of_match_table = of_match_ptr(lt7182s_of_match), }, - .probe_new = lt7182s_probe, + .probe = lt7182s_probe, .id_table = lt7182s_id, }; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 91df8e895147..73a86f4d6472 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -927,7 +927,7 @@ static struct i2c_driver ltc2978_driver = { .name = "ltc2978", .of_match_table = of_match_ptr(ltc2978_of_match), }, - .probe_new = ltc2978_probe, + .probe = ltc2978_probe, .id_table = ltc2978_id, }; diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index 8e13a7ddcb42..f2023b17aa8d 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -199,7 +199,7 @@ static struct i2c_driver ltc3815_driver = { .driver = { .name = "ltc3815", }, - .probe_new = ltc3815_probe, + .probe = ltc3815_probe, .id_table = ltc3815_id, }; diff --git a/drivers/hwmon/pmbus/max15301.c b/drivers/hwmon/pmbus/max15301.c index 0b6f88428ea8..2cfaa62aedd6 100644 --- a/drivers/hwmon/pmbus/max15301.c +++ b/drivers/hwmon/pmbus/max15301.c @@ -178,7 +178,7 @@ static struct i2c_driver max15301_driver = { .driver = { .name = "max15301", }, - .probe_new = max15301_probe, + .probe = max15301_probe, .id_table = max15301_id, }; diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 94f869039071..a573a0ab9e48 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -102,7 +102,7 @@ static struct i2c_driver max16064_driver = { .driver = { .name = "max16064", }, - .probe_new = max16064_probe, + .probe = max16064_probe, .id_table = max16064_id, }; diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 6724f723f74c..9b0177409109 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -357,7 +357,7 @@ static struct i2c_driver max16601_driver = { .driver = { .name = "max16601", }, - .probe_new = max16601_probe, + .probe = max16601_probe, .id_table = max16601_id, }; diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index ba39f03c6374..7bcf27995033 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -776,7 +776,7 @@ static struct i2c_driver max20730_driver = { .name = "max20730", .of_match_table = max20730_of_match, }, - .probe_new = max20730_probe, + .probe = max20730_probe, .id_table = max20730_id, }; diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index 2272dc8c2e38..6ebd71cd081b 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -42,7 +42,7 @@ static struct i2c_driver max20751_driver = { .driver = { .name = "max20751", }, - .probe_new = max20751_probe, + .probe = max20751_probe, .id_table = max20751_id, }; diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index 95d79a64b483..f9aa576495a5 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -394,7 +394,7 @@ static struct i2c_driver max31785_driver = { .name = "max31785", .of_match_table = max31785_of_match, }, - .probe_new = max31785_probe, + .probe = max31785_probe, .id_table = max31785_id, }; diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index ea7609058a12..fe7f6b1b0985 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -520,7 +520,7 @@ static struct i2c_driver max34440_driver = { .driver = { .name = "max34440", }, - .probe_new = max34440_probe, + .probe = max34440_probe, .id_table = max34440_id, }; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 5e66c28c0b71..ae8573fdf5ba 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -182,7 +182,7 @@ static struct i2c_driver max8688_driver = { .driver = { .name = "max8688", }, - .probe_new = max8688_probe, + .probe = max8688_probe, .id_table = max8688_id, }; diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c index 24e5194706cf..50662ed8e3d5 100644 --- a/drivers/hwmon/pmbus/mp2888.c +++ b/drivers/hwmon/pmbus/mp2888.c @@ -395,7 +395,7 @@ static struct i2c_driver mp2888_driver = { .name = "mp2888", .of_match_table = of_match_ptr(mp2888_of_match), }, - .probe_new = mp2888_probe, + .probe = mp2888_probe, .id_table = mp2888_id, }; diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c index 51986adfbf47..2109b0458a8b 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -757,7 +757,7 @@ static struct i2c_driver mp2975_driver = { .name = "mp2975", .of_match_table = of_match_ptr(mp2975_of_match), }, - .probe_new = mp2975_probe, + .probe = mp2975_probe, .id_table = mp2975_id, }; diff --git a/drivers/hwmon/pmbus/mp5023.c b/drivers/hwmon/pmbus/mp5023.c index 791a06c3c54a..c4c4324d2b74 100644 --- a/drivers/hwmon/pmbus/mp5023.c +++ b/drivers/hwmon/pmbus/mp5023.c @@ -56,7 +56,7 @@ static struct i2c_driver mp5023_driver = { .name = "mp5023", .of_match_table = of_match_ptr(mp5023_of_match), }, - .probe_new = mp5023_probe, + .probe = mp5023_probe, }; module_i2c_driver(mp5023_driver); diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c index ff939881dc3b..865d42edda1a 100644 --- a/drivers/hwmon/pmbus/mpq7932.c +++ b/drivers/hwmon/pmbus/mpq7932.c @@ -145,7 +145,7 @@ static struct i2c_driver mpq7932_regulator_driver = { .name = "mpq7932", .of_match_table = mpq7932_of_match, }, - .probe_new = mpq7932_probe, + .probe = mpq7932_probe, .id_table = mpq7932_id, }; module_i2c_driver(mpq7932_regulator_driver); diff --git a/drivers/hwmon/pmbus/pim4328.c b/drivers/hwmon/pmbus/pim4328.c index 273ff6e57654..31d9ae06379a 100644 --- a/drivers/hwmon/pmbus/pim4328.c +++ b/drivers/hwmon/pmbus/pim4328.c @@ -221,7 +221,7 @@ static struct i2c_driver pim4328_driver = { .driver = { .name = "pim4328", }, - .probe_new = pim4328_probe, + .probe = pim4328_probe, .id_table = pim4328_id, }; diff --git a/drivers/hwmon/pmbus/pli1209bc.c b/drivers/hwmon/pmbus/pli1209bc.c index 05b4ee35ba27..7d8bd3167b21 100644 --- a/drivers/hwmon/pmbus/pli1209bc.c +++ b/drivers/hwmon/pmbus/pli1209bc.c @@ -134,7 +134,7 @@ static struct i2c_driver pli1209bc_driver = { .name = "pli1209bc", .of_match_table = of_match_ptr(pli1209bc_of_match), }, - .probe_new = pli1209bc_probe, + .probe = pli1209bc_probe, .id_table = pli1209bc_id, }; diff --git a/drivers/hwmon/pmbus/pm6764tr.c b/drivers/hwmon/pmbus/pm6764tr.c index e0bbc8a30d21..2a16504c85b7 100644 --- a/drivers/hwmon/pmbus/pm6764tr.c +++ b/drivers/hwmon/pmbus/pm6764tr.c @@ -64,7 +64,7 @@ static struct i2c_driver pm6764tr_driver = { .name = "pm6764tr", .of_match_table = of_match_ptr(pm6764tr_of_match), }, - .probe_new = pm6764tr_probe, + .probe = pm6764tr_probe, .id_table = pm6764tr_id, }; diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index d0d386990af5..ec40c5c59954 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -252,7 +252,7 @@ static struct i2c_driver pmbus_driver = { .driver = { .name = "pmbus", }, - .probe_new = pmbus_probe, + .probe = pmbus_probe, .id_table = pmbus_id, }; diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index 52bee5de2988..e2790a682dc8 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -139,7 +139,7 @@ static struct i2c_driver pxe1610_driver = { .driver = { .name = "pxe1610", }, - .probe_new = pxe1610_probe, + .probe = pxe1610_probe, .id_table = pxe1610_id, }; diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c index d3ba12951324..b830f3b02bcc 100644 --- a/drivers/hwmon/pmbus/q54sj108a2.c +++ b/drivers/hwmon/pmbus/q54sj108a2.c @@ -412,7 +412,7 @@ static struct i2c_driver q54sj108a2_driver = { .name = "q54sj108a2", .of_match_table = q54sj108a2_of_match, }, - .probe_new = q54sj108a2_probe, + .probe = q54sj108a2_probe, .id_table = q54sj108a2_id, }; diff --git a/drivers/hwmon/pmbus/stpddc60.c b/drivers/hwmon/pmbus/stpddc60.c index 357b9d9d896b..be9076dcc2db 100644 --- a/drivers/hwmon/pmbus/stpddc60.c +++ b/drivers/hwmon/pmbus/stpddc60.c @@ -237,7 +237,7 @@ static struct i2c_driver stpddc60_driver = { .driver = { .name = "stpddc60", }, - .probe_new = stpddc60_probe, + .probe = stpddc60_probe, .id_table = stpddc60_id, }; diff --git a/drivers/hwmon/pmbus/tda38640.c b/drivers/hwmon/pmbus/tda38640.c index c3e781319cd1..450b0273fb59 100644 --- a/drivers/hwmon/pmbus/tda38640.c +++ b/drivers/hwmon/pmbus/tda38640.c @@ -62,7 +62,7 @@ static struct i2c_driver tda38640_driver = { .name = "tda38640", .of_match_table = of_match_ptr(tda38640_of_match), }, - .probe_new = tda38640_probe, + .probe = tda38640_probe, .id_table = tda38640_id, }; diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index 31bb83c0ef3e..ea0074a6b9fc 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -42,7 +42,7 @@ static struct i2c_driver tps40422_driver = { .driver = { .name = "tps40422", }, - .probe_new = tps40422_probe, + .probe = tps40422_probe, .id_table = tps40422_id, }; diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 81b9d813655a..ef99005a3af5 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -299,7 +299,7 @@ static struct i2c_driver tps53679_driver = { .name = "tps53679", .of_match_table = of_match_ptr(tps53679_of_match), }, - .probe_new = tps53679_probe, + .probe = tps53679_probe, .id_table = tps53679_id, }; diff --git a/drivers/hwmon/pmbus/tps546d24.c b/drivers/hwmon/pmbus/tps546d24.c index 435f94304ad8..69bbdb6c680b 100644 --- a/drivers/hwmon/pmbus/tps546d24.c +++ b/drivers/hwmon/pmbus/tps546d24.c @@ -59,7 +59,7 @@ static struct i2c_driver tps546d24_driver = { .name = "tps546d24", .of_match_table = of_match_ptr(tps546d24_of_match), }, - .probe_new = tps546d24_probe, + .probe = tps546d24_probe, .id_table = tps546d24_id, }; diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 3daaf2237832..ba712ff7666f 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -695,7 +695,7 @@ static struct i2c_driver ucd9000_driver = { .name = "ucd9000", .of_match_table = of_match_ptr(ucd9000_of_match), }, - .probe_new = ucd9000_probe, + .probe = ucd9000_probe, .id_table = ucd9000_id, }; diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 3ad375a76f3e..a82847945508 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -200,7 +200,7 @@ static struct i2c_driver ucd9200_driver = { .name = "ucd9200", .of_match_table = of_match_ptr(ucd9200_of_match), }, - .probe_new = ucd9200_probe, + .probe = ucd9200_probe, .id_table = ucd9200_id, }; diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index 32bc7736d609..37d08dd427d5 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -185,7 +185,7 @@ static struct i2c_driver xdpe122_driver = { .name = "xdpe12284", .of_match_table = of_match_ptr(xdpe122_of_match), }, - .probe_new = xdpe122_probe, + .probe = xdpe122_probe, .id_table = xdpe122_id, }; diff --git a/drivers/hwmon/pmbus/xdpe152c4.c b/drivers/hwmon/pmbus/xdpe152c4.c index b8a36ef73e45..235e6b41ae4c 100644 --- a/drivers/hwmon/pmbus/xdpe152c4.c +++ b/drivers/hwmon/pmbus/xdpe152c4.c @@ -63,7 +63,7 @@ static struct i2c_driver xdpe152_driver = { .name = "xdpe152c4", .of_match_table = of_match_ptr(xdpe152_of_match), }, - .probe_new = xdpe152_probe, + .probe = xdpe152_probe, .id_table = xdpe152_id, }; diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index e9df0c56d91e..83458df0d0cf 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -461,7 +461,7 @@ static struct i2c_driver zl6100_driver = { .driver = { .name = "zl6100", }, - .probe_new = zl6100_probe, + .probe = zl6100_probe, .id_table = zl6100_id, }; diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index 9cb0c2de5219..4120cadb00ae 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c @@ -327,7 +327,7 @@ static struct i2c_driver powr1220_driver = { .driver = { .name = "powr1220", }, - .probe_new = powr1220_probe, + .probe = powr1220_probe, .id_table = powr1220_ids, }; diff --git a/drivers/hwmon/sbrmi.c b/drivers/hwmon/sbrmi.c index 529f0e766319..484703f0ea5f 100644 --- a/drivers/hwmon/sbrmi.c +++ b/drivers/hwmon/sbrmi.c @@ -347,7 +347,7 @@ static struct i2c_driver sbrmi_driver = { .name = "sbrmi", .of_match_table = of_match_ptr(sbrmi_of_match), }, - .probe_new = sbrmi_probe, + .probe = sbrmi_probe, .id_table = sbrmi_id, }; diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c index 7049d9464ac6..b79cece4ac9a 100644 --- a/drivers/hwmon/sbtsi_temp.c +++ b/drivers/hwmon/sbtsi_temp.c @@ -238,7 +238,7 @@ static struct i2c_driver sbtsi_driver = { .name = "sbtsi", .of_match_table = of_match_ptr(sbtsi_of_match), }, - .probe_new = sbtsi_probe, + .probe = sbtsi_probe, .id_table = sbtsi_id, }; diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index f50b90198f23..55c179475208 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -285,7 +285,7 @@ MODULE_DEVICE_TABLE(i2c, sht21_id); static struct i2c_driver sht21_driver = { .driver.name = "sht21", - .probe_new = sht21_probe, + .probe = sht21_probe, .id_table = sht21_id, }; diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 8305e44d9ab2..1dab3002728b 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -743,7 +743,7 @@ MODULE_DEVICE_TABLE(i2c, sht3x_ids); static struct i2c_driver sht3x_i2c_driver = { .driver.name = "sht3x", - .probe_new = sht3x_probe, + .probe = sht3x_probe, .id_table = sht3x_ids, }; diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 5bbe09135ab9..7ee797410458 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -291,7 +291,7 @@ static struct i2c_driver sht4x_driver = { .name = "sht4x", .of_match_table = sht4x_of_match, }, - .probe_new = sht4x_probe, + .probe = sht4x_probe, .id_table = sht4x_id, }; diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index 18546ebc8e9f..1f96e94967ee 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -279,7 +279,7 @@ static struct i2c_driver shtc1_i2c_driver = { .name = "shtc1", .of_match_table = shtc1_of_match, }, - .probe_new = shtc1_probe, + .probe = shtc1_probe, .id_table = shtc1_id, }; diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index c36bdbe423de..026c76f8c22e 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -694,7 +694,7 @@ static struct i2c_driver smm665_driver = { .driver = { .name = "smm665", }, - .probe_new = smm665_probe, + .probe = smm665_probe, .remove = smm665_remove, .id_table = smm665_id, }; diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 70d2152234e2..d20800a1f02b 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -628,7 +628,7 @@ static struct i2c_driver smsc47m192_driver = { .driver = { .name = "smsc47m192", }, - .probe_new = smsc47m192_probe, + .probe = smsc47m192_probe, .id_table = smsc47m192_id, .detect = smsc47m192_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c index 2f67c6747ead..847c99376930 100644 --- a/drivers/hwmon/stts751.c +++ b/drivers/hwmon/stts751.c @@ -821,7 +821,7 @@ static struct i2c_driver stts751_driver = { .name = DEVNAME, .of_match_table = of_match_ptr(stts751_of_match), }, - .probe_new = stts751_probe, + .probe = stts751_probe, .id_table = stts751_id, .detect = stts751_detect, .alert = stts751_alert, diff --git a/drivers/hwmon/tc654.c b/drivers/hwmon/tc654.c index 54cd33d09688..42a9658f1bc2 100644 --- a/drivers/hwmon/tc654.c +++ b/drivers/hwmon/tc654.c @@ -561,7 +561,7 @@ static struct i2c_driver tc654_driver = { .driver = { .name = "tc654", }, - .probe_new = tc654_probe, + .probe = tc654_probe, .id_table = tc654_id, }; diff --git a/drivers/hwmon/tc74.c b/drivers/hwmon/tc74.c index ace55da97fc2..03950670bd78 100644 --- a/drivers/hwmon/tc74.c +++ b/drivers/hwmon/tc74.c @@ -160,7 +160,7 @@ static struct i2c_driver tc74_driver = { .driver = { .name = "tc74", }, - .probe_new = tc74_probe, + .probe = tc74_probe, .id_table = tc74_id, }; diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 81cdb012993c..68ba26bc9014 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -420,7 +420,7 @@ static struct i2c_driver thmc50_driver = { .driver = { .name = "thmc50", }, - .probe_new = thmc50_probe, + .probe = thmc50_probe, .id_table = thmc50_id, .detect = thmc50_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index e271556efe0b..6359d12b2420 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -301,7 +301,7 @@ static struct i2c_driver tmp102_driver = { .driver.name = DRIVER_NAME, .driver.of_match_table = of_match_ptr(tmp102_of_match), .driver.pm = pm_sleep_ptr(&tmp102_dev_pm_ops), - .probe_new = tmp102_probe, + .probe = tmp102_probe, .id_table = tmp102_id, }; diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c index d257bb91fc69..a84c29a3a765 100644 --- a/drivers/hwmon/tmp103.c +++ b/drivers/hwmon/tmp103.c @@ -214,7 +214,7 @@ static struct i2c_driver tmp103_driver = { .of_match_table = of_match_ptr(tmp103_of_match), .pm = pm_sleep_ptr(&tmp103_dev_pm_ops), }, - .probe_new = tmp103_probe, + .probe = tmp103_probe, .id_table = tmp103_id, }; diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 43784c289a9e..300b24d5586b 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -432,7 +432,7 @@ static struct i2c_driver tmp108_driver = { .pm = pm_sleep_ptr(&tmp108_dev_pm_ops), .of_match_table = of_match_ptr(tmp108_of_ids), }, - .probe_new = tmp108_probe, + .probe = tmp108_probe, .id_table = tmp108_i2c_ids, }; diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index f358ba679626..91f2314568cf 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -766,7 +766,7 @@ static struct i2c_driver tmp401_driver = { .name = "tmp401", .of_match_table = of_match_ptr(tmp4xx_of_match), }, - .probe_new = tmp401_probe, + .probe = tmp401_probe, .id_table = tmp401_id, .detect = tmp401_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 45fd7fb5ee01..3cde3916ab6d 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -487,7 +487,7 @@ static struct i2c_driver tmp421_driver = { .name = "tmp421", .of_match_table = of_match_ptr(tmp421_of_match), }, - .probe_new = tmp421_probe, + .probe = tmp421_probe, .id_table = tmp421_id, .detect = tmp421_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c index 9213a493a590..8a88032d8e9d 100644 --- a/drivers/hwmon/tmp464.c +++ b/drivers/hwmon/tmp464.c @@ -699,7 +699,7 @@ static struct i2c_driver tmp464_driver = { .name = "tmp464", .of_match_table = of_match_ptr(tmp464_of_match), }, - .probe_new = tmp464_probe, + .probe = tmp464_probe, .id_table = tmp464_id, .detect = tmp464_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 0693eaee054f..bff10f4b56e1 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -760,7 +760,7 @@ static struct i2c_driver tmp51x_driver = { .name = "tmp51x", .of_match_table = tmp51x_of_match, }, - .probe_new = tmp51x_probe, + .probe = tmp51x_probe, .id_table = tmp51x_id, }; diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c index 85a75f551148..8fbbb29ae11d 100644 --- a/drivers/hwmon/tps23861.c +++ b/drivers/hwmon/tps23861.c @@ -581,7 +581,7 @@ static const struct of_device_id __maybe_unused tps23861_of_match[] = { MODULE_DEVICE_TABLE(of, tps23861_of_match); static struct i2c_driver tps23861_driver = { - .probe_new = tps23861_probe, + .probe = tps23861_probe, .remove = tps23861_remove, .driver = { .name = "tps23861", diff --git a/drivers/hwmon/w83773g.c b/drivers/hwmon/w83773g.c index 8dbcd05abd9a..7f3615f5587c 100644 --- a/drivers/hwmon/w83773g.c +++ b/drivers/hwmon/w83773g.c @@ -295,7 +295,7 @@ static struct i2c_driver w83773_driver = { .name = "w83773g", .of_match_table = of_match_ptr(w83773_of_match), }, - .probe_new = w83773_probe, + .probe = w83773_probe, .id_table = w83773_id, }; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index dacabf25e83f..b33f382f238d 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1585,7 +1585,7 @@ static struct i2c_driver w83781d_driver = { .name = "w83781d", .of_match_table = w83781d_of_match, }, - .probe_new = w83781d_probe, + .probe = w83781d_probe, .remove = w83781d_remove, .id_table = w83781d_ids, .detect = w83781d_detect, diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index eaf691365023..9681eaa06c8e 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -338,7 +338,7 @@ static struct i2c_driver w83791d_driver = { .driver = { .name = "w83791d", }, - .probe_new = w83791d_probe, + .probe = w83791d_probe, .remove = w83791d_remove, .id_table = w83791d_id, .detect = w83791d_detect, diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 6d160eee1446..69ce379a9e13 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -306,7 +306,7 @@ static struct i2c_driver w83792d_driver = { .driver = { .name = "w83792d", }, - .probe_new = w83792d_probe, + .probe = w83792d_probe, .remove = w83792d_remove, .id_table = w83792d_id, .detect = w83792d_detect, diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index a4926d907198..96bab94ba899 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -301,7 +301,7 @@ static struct i2c_driver w83793_driver = { .driver = { .name = "w83793", }, - .probe_new = w83793_probe, + .probe = w83793_probe, .remove = w83793_remove, .id_table = w83793_id, .detect = w83793_detect, diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 84ff5c57e98c..c446e00db658 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -2255,7 +2255,7 @@ static struct i2c_driver w83795_driver = { .driver = { .name = "w83795", }, - .probe_new = w83795_probe, + .probe = w83795_probe, .remove = w83795_remove, .id_table = w83795_id, diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index f3622de0d96f..9c11ed69c055 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -84,7 +84,7 @@ static struct i2c_driver w83l785ts_driver = { .driver = { .name = "w83l785ts", }, - .probe_new = w83l785ts_probe, + .probe = w83l785ts_probe, .remove = w83l785ts_remove, .id_table = w83l785ts_id, .detect = w83l785ts_detect, diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 5597e1c2d95c..75874cf7851c 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -751,7 +751,7 @@ static struct i2c_driver w83l786ng_driver = { .driver = { .name = "w83l786ng", }, - .probe_new = w83l786ng_probe, + .probe = w83l786ng_probe, .id_table = w83l786ng_id, .detect = w83l786ng_detect, .address_list = normal_i2c, From 6d3b8bc508784f62acd2d25acb253244bbcc3f69 Mon Sep 17 00:00:00 2001 From: James Seo Date: Thu, 4 May 2023 00:57:42 -0700 Subject: [PATCH 13/54] Documentation/hwmon: Move misplaced entry in hwmon docs index Move the entry for the inspur-ipsps1 driver so that it no longer appears in the hwmon docs TOC as a document relating to the hwmon subsystem itself. Signed-off-by: James Seo Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20230504075752.1320967-2-james@equiv.tech Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index fa1208c62855..03b30a94a9e6 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -9,7 +9,6 @@ Hardware Monitoring hwmon-kernel-api pmbus-core - inspur-ipsps1 submitting-patches sysfs-interface userspace-tools @@ -85,6 +84,7 @@ Hardware Monitoring Kernel Drivers ina2xx ina238 ina3221 + inspur-ipsps1 intel-m10-bmc-hwmon ir35221 ir38064 From 7c415ed8673470fbe18ce4a3694e5776d4db2456 Mon Sep 17 00:00:00 2001 From: Gopal Prasad Date: Wed, 17 May 2023 09:50:25 +0530 Subject: [PATCH 14/54] hwmon: (nct6683) Add another customer ID for NCT6687D sensor chip on some MSI boards. This value was found on a MSI Z690-A PRO DDR5 with NCT6687D. Signed-off-by: Gopal Prasad Link: https://lore.kernel.org/r/20230517042025.16942-1-llyyr.public@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6683.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index a872f783e9cc..f673f7d07941 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -173,6 +173,7 @@ superio_exit(int ioreg) #define NCT6683_CUSTOMER_ID_INTEL 0x805 #define NCT6683_CUSTOMER_ID_MITAC 0xa0e #define NCT6683_CUSTOMER_ID_MSI 0x201 +#define NCT6683_CUSTOMER_ID_MSI2 0x200 #define NCT6683_CUSTOMER_ID_ASROCK 0xe2c #define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b @@ -1220,6 +1221,8 @@ static int nct6683_probe(struct platform_device *pdev) break; case NCT6683_CUSTOMER_ID_MSI: break; + case NCT6683_CUSTOMER_ID_MSI2: + break; case NCT6683_CUSTOMER_ID_ASROCK: break; case NCT6683_CUSTOMER_ID_ASROCK2: From fe6ac23777ef70c17aa7333400ede88e364fbd36 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 7 May 2023 08:22:17 -0700 Subject: [PATCH 15/54] hwmon: (core) Add missing beep-related standard attributes beep_enable, inX_beep, currX_beep, fanX_beep, and tempX_beep are standard attributes mentioned in the sysfs interface specification but not implemented in the hwmon core. Since these are not deprecated, implement them. Adding beep_mask is not necessary, as it is deprecated and the drivers already using it are manually defining it. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230507152216.1862653-1-james@equiv.tech Signed-off-by: Guenter Roeck --- drivers/hwmon/hwmon.c | 5 +++++ include/linux/hwmon.h | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 573b83b6c08c..5fab82dc9464 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -456,6 +456,7 @@ static const char * const hwmon_chip_attrs[] = { [hwmon_chip_in_samples] = "in_samples", [hwmon_chip_power_samples] = "power_samples", [hwmon_chip_temp_samples] = "temp_samples", + [hwmon_chip_beep_enable] = "beep_enable", }; static const char * const hwmon_temp_attr_templates[] = { @@ -486,6 +487,7 @@ static const char * const hwmon_temp_attr_templates[] = { [hwmon_temp_reset_history] = "temp%d_reset_history", [hwmon_temp_rated_min] = "temp%d_rated_min", [hwmon_temp_rated_max] = "temp%d_rated_max", + [hwmon_temp_beep] = "temp%d_beep", }; static const char * const hwmon_in_attr_templates[] = { @@ -507,6 +509,7 @@ static const char * const hwmon_in_attr_templates[] = { [hwmon_in_crit_alarm] = "in%d_crit_alarm", [hwmon_in_rated_min] = "in%d_rated_min", [hwmon_in_rated_max] = "in%d_rated_max", + [hwmon_in_beep] = "in%d_beep", }; static const char * const hwmon_curr_attr_templates[] = { @@ -528,6 +531,7 @@ static const char * const hwmon_curr_attr_templates[] = { [hwmon_curr_crit_alarm] = "curr%d_crit_alarm", [hwmon_curr_rated_min] = "curr%d_rated_min", [hwmon_curr_rated_max] = "curr%d_rated_max", + [hwmon_curr_beep] = "curr%d_beep", }; static const char * const hwmon_power_attr_templates[] = { @@ -597,6 +601,7 @@ static const char * const hwmon_fan_attr_templates[] = { [hwmon_fan_min_alarm] = "fan%d_min_alarm", [hwmon_fan_max_alarm] = "fan%d_max_alarm", [hwmon_fan_fault] = "fan%d_fault", + [hwmon_fan_beep] = "fan%d_beep", }; static const char * const hwmon_pwm_attr_templates[] = { diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 492dd27a5dd8..8cd6a6b33593 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -44,6 +44,7 @@ enum hwmon_chip_attributes { hwmon_chip_in_samples, hwmon_chip_power_samples, hwmon_chip_temp_samples, + hwmon_chip_beep_enable, }; #define HWMON_C_TEMP_RESET_HISTORY BIT(hwmon_chip_temp_reset_history) @@ -58,6 +59,7 @@ enum hwmon_chip_attributes { #define HWMON_C_IN_SAMPLES BIT(hwmon_chip_in_samples) #define HWMON_C_POWER_SAMPLES BIT(hwmon_chip_power_samples) #define HWMON_C_TEMP_SAMPLES BIT(hwmon_chip_temp_samples) +#define HWMON_C_BEEP_ENABLE BIT(hwmon_chip_beep_enable) enum hwmon_temp_attributes { hwmon_temp_enable, @@ -87,6 +89,7 @@ enum hwmon_temp_attributes { hwmon_temp_reset_history, hwmon_temp_rated_min, hwmon_temp_rated_max, + hwmon_temp_beep, }; #define HWMON_T_ENABLE BIT(hwmon_temp_enable) @@ -116,6 +119,7 @@ enum hwmon_temp_attributes { #define HWMON_T_RESET_HISTORY BIT(hwmon_temp_reset_history) #define HWMON_T_RATED_MIN BIT(hwmon_temp_rated_min) #define HWMON_T_RATED_MAX BIT(hwmon_temp_rated_max) +#define HWMON_T_BEEP BIT(hwmon_temp_beep) enum hwmon_in_attributes { hwmon_in_enable, @@ -136,6 +140,7 @@ enum hwmon_in_attributes { hwmon_in_crit_alarm, hwmon_in_rated_min, hwmon_in_rated_max, + hwmon_in_beep, }; #define HWMON_I_ENABLE BIT(hwmon_in_enable) @@ -156,6 +161,7 @@ enum hwmon_in_attributes { #define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm) #define HWMON_I_RATED_MIN BIT(hwmon_in_rated_min) #define HWMON_I_RATED_MAX BIT(hwmon_in_rated_max) +#define HWMON_I_BEEP BIT(hwmon_in_beep) enum hwmon_curr_attributes { hwmon_curr_enable, @@ -176,6 +182,7 @@ enum hwmon_curr_attributes { hwmon_curr_crit_alarm, hwmon_curr_rated_min, hwmon_curr_rated_max, + hwmon_curr_beep, }; #define HWMON_C_ENABLE BIT(hwmon_curr_enable) @@ -196,6 +203,7 @@ enum hwmon_curr_attributes { #define HWMON_C_CRIT_ALARM BIT(hwmon_curr_crit_alarm) #define HWMON_C_RATED_MIN BIT(hwmon_curr_rated_min) #define HWMON_C_RATED_MAX BIT(hwmon_curr_rated_max) +#define HWMON_C_BEEP BIT(hwmon_curr_beep) enum hwmon_power_attributes { hwmon_power_enable, @@ -312,6 +320,7 @@ enum hwmon_fan_attributes { hwmon_fan_min_alarm, hwmon_fan_max_alarm, hwmon_fan_fault, + hwmon_fan_beep, }; #define HWMON_F_ENABLE BIT(hwmon_fan_enable) @@ -326,6 +335,7 @@ enum hwmon_fan_attributes { #define HWMON_F_MIN_ALARM BIT(hwmon_fan_min_alarm) #define HWMON_F_MAX_ALARM BIT(hwmon_fan_max_alarm) #define HWMON_F_FAULT BIT(hwmon_fan_fault) +#define HWMON_F_BEEP BIT(hwmon_fan_beep) enum hwmon_pwm_attributes { hwmon_pwm_input, From 3b9da0422a7b597cfde3d9d7dfec0b5b065c4824 Mon Sep 17 00:00:00 2001 From: James Seo Date: Sun, 7 May 2023 08:10:53 -0700 Subject: [PATCH 16/54] hwmon: (core) Finish renaming groups parameter in API to extra_groups Commit 848ba0a2f20d ("hwmon: (core) Rename groups parameter in API to extra_groups") renames the 'groups' parameter of devm_hwmon_device_register_with_info() to 'extra_groups' in hwmon-kernel-api.txt (later .rst) and hwmon.h, but this change was not propagated to the function code itself in hwmon.c. Finish the job. Note that hwmon_device_register_with_info() has the same parameter, and the name of that parameter was changed in all three files. Harmonizing the name between these related functions also removes a potential source of confusion. Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230507151051.1861929-1-james@equiv.tech [groeck: Fixed up SHA reference in description] Signed-off-by: Guenter Roeck --- drivers/hwmon/hwmon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 5fab82dc9464..c7dd3f5b2bd5 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -1034,7 +1034,7 @@ EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); * @name: hwmon name attribute * @drvdata: driver data to attach to created device * @chip: pointer to hwmon chip information - * @groups: pointer to list of driver specific attribute groups + * @extra_groups: pointer to list of driver specific attribute groups * * Returns the pointer to the new device. The new device is automatically * unregistered with the parent device. @@ -1043,7 +1043,7 @@ struct device * devm_hwmon_device_register_with_info(struct device *dev, const char *name, void *drvdata, const struct hwmon_chip_info *chip, - const struct attribute_group **groups) + const struct attribute_group **extra_groups) { struct device **ptr, *hwdev; @@ -1055,7 +1055,7 @@ devm_hwmon_device_register_with_info(struct device *dev, const char *name, return ERR_PTR(-ENOMEM); hwdev = hwmon_device_register_with_info(dev, name, drvdata, chip, - groups); + extra_groups); if (IS_ERR(hwdev)) goto error; From 0cb01ec31529096b6460290963bf78c9146d83b7 Mon Sep 17 00:00:00 2001 From: Kirill Yatsenko Date: Thu, 11 May 2023 22:26:31 +0200 Subject: [PATCH 17/54] hwmon: (aht10) Fix typos in comments Fix typos in the description of the return value section of the functions. The word 'succesfull' is incorrect, it should be 'successful'. Signed-off-by: Kirill Yatsenko Link: https://lore.kernel.org/r/20230511202633.299174-1-kiriyatsenko@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aht10.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index 4ecc02315f8f..4ccf49c7cc8c 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -80,7 +80,7 @@ struct aht10_data { /** * aht10_init() - Initialize an AHT10 chip * @data: the data associated with this AHT10 chip - * Return: 0 if succesfull, 1 if not + * Return: 0 if successful, 1 if not */ static int aht10_init(struct aht10_data *data) { @@ -124,7 +124,7 @@ static int aht10_polltime_expired(struct aht10_data *data) /** * aht10_read_values() - read and parse the raw data from the AHT10 * @data: the struct aht10_data to use for the lock - * Return: 0 if succesfull, 1 if not + * Return: 0 if successful, 1 if not */ static int aht10_read_values(struct aht10_data *data) { From 014714b8a62107d22bd2a089801bbfb4bb6412ae Mon Sep 17 00:00:00 2001 From: Kirill Yatsenko Date: Thu, 11 May 2023 22:26:32 +0200 Subject: [PATCH 18/54] hwmon: (aht10) Refactor aht10_read_values function Exit from the function immediately if the poll time hasn't yet expired. Therefore the code after the check can be moved one tab to the left which improves readability. Signed-off-by: Kirill Yatsenko Link: https://lore.kernel.org/r/20230511202633.299174-2-kiriyatsenko@gmail.com [groeck: Dropped else after return] Signed-off-by: Guenter Roeck --- drivers/hwmon/aht10.c | 68 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index 4ccf49c7cc8c..ec7459575c58 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -135,40 +135,42 @@ static int aht10_read_values(struct aht10_data *data) struct i2c_client *client = data->client; mutex_lock(&data->lock); - if (aht10_polltime_expired(data)) { - res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas)); - if (res < 0) { - mutex_unlock(&data->lock); - return res; - } - - usleep_range(AHT10_MEAS_DELAY, - AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA); - - res = i2c_master_recv(client, raw_data, AHT10_MEAS_SIZE); - if (res != AHT10_MEAS_SIZE) { - mutex_unlock(&data->lock); - if (res >= 0) - return -ENODATA; - else - return res; - } - - hum = ((u32)raw_data[1] << 12u) | - ((u32)raw_data[2] << 4u) | - ((raw_data[3] & 0xF0u) >> 4u); - - temp = ((u32)(raw_data[3] & 0x0Fu) << 16u) | - ((u32)raw_data[4] << 8u) | - raw_data[5]; - - temp = ((temp * 625) >> 15u) * 10; - hum = ((hum * 625) >> 16u) * 10; - - data->temperature = (int)temp - 50000; - data->humidity = hum; - data->previous_poll_time = ktime_get_boottime(); + if (!aht10_polltime_expired(data)) { + mutex_unlock(&data->lock); + return 0; } + + res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas)); + if (res < 0) { + mutex_unlock(&data->lock); + return res; + } + + usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA); + + res = i2c_master_recv(client, raw_data, AHT10_MEAS_SIZE); + if (res != AHT10_MEAS_SIZE) { + mutex_unlock(&data->lock); + if (res >= 0) + return -ENODATA; + return res; + } + + hum = ((u32)raw_data[1] << 12u) | + ((u32)raw_data[2] << 4u) | + ((raw_data[3] & 0xF0u) >> 4u); + + temp = ((u32)(raw_data[3] & 0x0Fu) << 16u) | + ((u32)raw_data[4] << 8u) | + raw_data[5]; + + temp = ((temp * 625) >> 15u) * 10; + hum = ((hum * 625) >> 16u) * 10; + + data->temperature = (int)temp - 50000; + data->humidity = hum; + data->previous_poll_time = ktime_get_boottime(); + mutex_unlock(&data->lock); return 0; } From fdbfd330c43034e539692c3798bc38736dd1f1c7 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Sat, 20 May 2023 11:54:46 +0200 Subject: [PATCH 19/54] hwmon: (aquacomputer_d5next) Rename AQC_TEMP_SENSOR_DISCONNECTED Rename the macro in question to AQC_SENSOR_NA because more than just temperature sensors use this value to indicate that they don't have a reading. Implemented by Noah Bergbauer [1]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/41 Originally-from: Noah Bergbauer Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20230520095447.509287-2-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index a4fcd4ebf76c..834d011e220f 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -93,7 +93,7 @@ static u8 aquaero_secondary_ctrl_report[] = { #define AQC_FIRMWARE_VERSION 0xD #define AQC_SENSOR_SIZE 0x02 -#define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF +#define AQC_SENSOR_NA 0x7FFF #define AQC_FAN_PERCENT_OFFSET 0x00 #define AQC_FAN_VOLTAGE_OFFSET 0x02 #define AQC_FAN_CURRENT_OFFSET 0x04 @@ -1224,7 +1224,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 sensor_value = get_unaligned_be16(data + priv->temp_sensor_start_offset + i * AQC_SENSOR_SIZE); - if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED) + if (sensor_value == AQC_SENSOR_NA) priv->temp_input[i] = -ENODATA; else priv->temp_input[i] = sensor_value * 10; @@ -1235,7 +1235,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 sensor_value = get_unaligned_be16(data + priv->virtual_temp_sensor_start_offset + j * AQC_SENSOR_SIZE); - if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED) + if (sensor_value == AQC_SENSOR_NA) priv->temp_input[i] = -ENODATA; else priv->temp_input[i] = sensor_value * 10; @@ -1277,7 +1277,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 sensor_value = get_unaligned_be16(data + priv->calc_virt_temp_sensor_start_offset + j * AQC_SENSOR_SIZE); - if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED) + if (sensor_value == AQC_SENSOR_NA) priv->temp_input[i] = -ENODATA; else priv->temp_input[i] = sensor_value * 10; From b3d3be6c4cd1908b9ffdb3d347de232a6c34a0a9 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Sat, 20 May 2023 11:54:47 +0200 Subject: [PATCH 20/54] hwmon: (aquacomputer_d5next) Add support for Aquacomputer Leakshield Extend aquacomputer_d5next driver to expose various hardware sensors of the Aquacomputer Leakshield leak prevention system, which communicates through a proprietary USB HID protocol. Implemented by Noah Bergbauer [1]. Two temperature sensors are exposed, along with pressure (current, min, max and target), reservoir volume (total and filled), pump speed and flow. Pump speed and flow values are user provided and allow the Leakshield to optimize its operation. Writing them to the device is subject of future patches. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/41 Originally-from: Noah Bergbauer Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20230520095447.509287-3-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 9 ++ drivers/hwmon/aquacomputer_d5next.c | 109 +++++++++++++++++++- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 14b37851af0c..94dc2d93d180 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -12,6 +12,7 @@ Supported devices: * Aquacomputer Octo fan controller * Aquacomputer Quadro fan controller * Aquacomputer High Flow Next sensor +* Aquacomputer Leakshield leak prevention system * Aquacomputer Aquastream XT watercooling pump * Aquacomputer Aquastream Ultimate watercooling pump * Aquacomputer Poweradjust 3 fan controller @@ -57,6 +58,11 @@ The High Flow Next exposes +5V voltages, water quality, conductivity and flow re A temperature sensor can be connected to it, in which case it provides its reading and an estimation of the dissipated/absorbed power in the liquid cooling loop. +The Leakshield exposes two temperature sensors and coolant pressure (current, min, max and +target readings). It also exposes the estimated reservoir volume and how much of it is +filled with coolant. Pump RPM and flow can be set to enhance on-device calculations, +but this is not yet implemented here. + The Aquastream XT pump exposes temperature readings for the coolant, external sensor and fan IC. It also exposes pump and fan speeds (in RPM), voltages, as well as pump current. @@ -83,6 +89,9 @@ Sysfs entries temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius) temp[1-8]_offset Temperature sensor correction offset (in millidegrees Celsius) fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h) +fan1_min Minimal fan speed (in RPM) +fan1_max Maximal fan speed (in RPM) +fan1_target Target fan speed (in RPM) fan5_pulses Quadro flow sensor pulses power[1-8]_input Pump/fan power (in micro Watts) in[0-7]_input Pump/fan voltage (in milli Volts) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 834d011e220f..a981f7086114 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo, - * Quadro, High Flow Next, Aquaero, Aquastream Ultimate) + * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield) * * Aquacomputer devices send HID reports (with ID 0x01) every second to report * sensor values, except for devices that communicate through the @@ -29,6 +29,7 @@ #define USB_PRODUCT_ID_FARBWERK360 0xf010 #define USB_PRODUCT_ID_OCTO 0xf011 #define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012 +#define USB_PRODUCT_ID_LEAKSHIELD 0xf014 #define USB_PRODUCT_ID_AQUASTREAMXT 0xf0b6 #define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b #define USB_PRODUCT_ID_POWERADJUST3 0xf0bd @@ -36,7 +37,7 @@ enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero, poweradjust3, aquastreamult, - aquastreamxt + aquastreamxt, leakshield }; static const char *const aqc_device_names[] = { @@ -46,6 +47,7 @@ static const char *const aqc_device_names[] = { [octo] = "octo", [quadro] = "quadro", [highflownext] = "highflownext", + [leakshield] = "leakshield", [aquastreamxt] = "aquastreamxt", [aquaero] = "aquaero", [aquastreamult] = "aquastreamultimate", @@ -236,6 +238,21 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed #define HIGHFLOWNEXT_5V_VOLTAGE 97 #define HIGHFLOWNEXT_5V_VOLTAGE_USB 99 +/* Specs of the Leakshield */ +#define LEAKSHIELD_NUM_SENSORS 2 + +/* Sensor report offsets for Leakshield */ +#define LEAKSHIELD_PRESSURE_ADJUSTED 285 +#define LEAKSHIELD_TEMPERATURE_1 265 +#define LEAKSHIELD_TEMPERATURE_2 287 +#define LEAKSHIELD_PRESSURE_MIN 291 +#define LEAKSHIELD_PRESSURE_TARGET 293 +#define LEAKSHIELD_PRESSURE_MAX 295 +#define LEAKSHIELD_PUMP_RPM_IN 101 +#define LEAKSHIELD_FLOW_IN 111 +#define LEAKSHIELD_RESERVOIR_VOLUME 313 +#define LEAKSHIELD_RESERVOIR_FILLED 311 + /* Specs of the Aquastream XT pump */ #define AQUASTREAMXT_SERIAL_START 0x3a #define AQUASTREAMXT_FIRMWARE_VERSION 0x32 @@ -411,6 +428,20 @@ static const char *const label_highflownext_voltage[] = { "+5V USB voltage" }; +/* Labels for Leakshield */ +static const char *const label_leakshield_temp_sensors[] = { + "Temperature 1", + "Temperature 2" +}; + +static const char *const label_leakshield_fan_speed[] = { + "Pressure [ubar]", + "User-Provided Pump Speed", + "User-Provided Flow [dL/h]", + "Reservoir Volume [ml]", + "Reservoir Filled [ml]", +}; + /* Labels for Aquastream XT */ static const char *const label_aquastreamxt_temp_sensors[] = { "Fan IC temp", @@ -529,7 +560,10 @@ struct aqc_data { /* Sensor values */ s32 temp_input[20]; /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */ - u16 speed_input[8]; + s32 speed_input[8]; + u32 speed_input_min[1]; + u32 speed_input_target[1]; + u32 speed_input_max[1]; u32 power_input[8]; u16 voltage_input[8]; u16 current_input[8]; @@ -747,6 +781,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 if (channel < 3) return 0444; break; + case leakshield: + /* Special case for Leakshield sensors */ + if (channel < 5) + return 0444; + break; case aquaero: case quadro: /* Special case to support flow sensors */ @@ -764,6 +803,13 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 if (priv->kind == quadro && channel == priv->num_fans) return 0644; break; + case hwmon_fan_min: + case hwmon_fan_max: + case hwmon_fan_target: + /* Special case for Leakshield pressure sensor */ + if (priv->kind == leakshield && channel == 0) + return 0444; + break; default: break; } @@ -938,8 +984,20 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_fan: switch (attr) { case hwmon_fan_input: + if (priv->speed_input[channel] == -ENODATA) + return -ENODATA; + *val = priv->speed_input[channel]; break; + case hwmon_fan_min: + *val = priv->speed_input_min[channel]; + break; + case hwmon_fan_max: + *val = priv->speed_input_max[channel]; + break; + case hwmon_fan_target: + *val = priv->speed_input_target[channel]; + break; case hwmon_fan_pulses: ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val, AQC_BE16); @@ -1151,7 +1209,8 @@ static const struct hwmon_channel_info * const aqc_info[] = { HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(fan, - HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX | + HWMON_F_TARGET, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, @@ -1314,6 +1373,28 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY); priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY); break; + case leakshield: + priv->speed_input[0] = + ((s16)get_unaligned_be16(data + LEAKSHIELD_PRESSURE_ADJUSTED)) * 100; + priv->speed_input_min[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MIN) * 100; + priv->speed_input_target[0] = + get_unaligned_be16(data + LEAKSHIELD_PRESSURE_TARGET) * 100; + priv->speed_input_max[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MAX) * 100; + + priv->speed_input[1] = get_unaligned_be16(data + LEAKSHIELD_PUMP_RPM_IN); + if (priv->speed_input[1] == AQC_SENSOR_NA) + priv->speed_input[1] = -ENODATA; + + priv->speed_input[2] = get_unaligned_be16(data + LEAKSHIELD_FLOW_IN); + if (priv->speed_input[2] == AQC_SENSOR_NA) + priv->speed_input[2] = -ENODATA; + + priv->speed_input[3] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_VOLUME); + priv->speed_input[4] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_FILLED); + + /* Second temp sensor is not positioned after the first one, read it here */ + priv->temp_input[1] = get_unaligned_be16(data + LEAKSHIELD_TEMPERATURE_2) * 10; + break; default: break; } @@ -1571,6 +1652,25 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->power_label = label_highflownext_power; priv->voltage_label = label_highflownext_voltage; break; + case USB_PRODUCT_ID_LEAKSHIELD: + /* + * Choose the right Leakshield device, because + * the other one acts as a keyboard + */ + if (hdev->type != 2) { + ret = -ENODEV; + goto fail_and_close; + } + + priv->kind = leakshield; + + priv->num_fans = 0; + priv->num_temp_sensors = LEAKSHIELD_NUM_SENSORS; + priv->temp_sensor_start_offset = LEAKSHIELD_TEMPERATURE_1; + + priv->temp_label = label_leakshield_temp_sensors; + priv->speed_label = label_leakshield_fan_speed; + break; case USB_PRODUCT_ID_AQUASTREAMXT: priv->kind = aquastreamxt; @@ -1707,6 +1807,7 @@ static const struct hid_device_id aqc_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_LEAKSHIELD) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) }, From 7d0c2c61b1a4d1cf5641b35b491fe58ffafe26bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Wed, 17 May 2023 15:35:41 -0300 Subject: [PATCH 21/54] hwmon: (oxp-sensors) Add new DMI match for OXP Mini MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A newer BIOS version for the OneXPlayer Mini AMD modified vendor and board name strings. Add those to the match table and set the same board model as older OXP Mini AMD. Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230517183540.187383-1-samsagax@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/oxp-sensors.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index 4d09a63af64a..a4ee757f879f 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -99,6 +99,13 @@ static const struct dmi_system_id dmi_table[] = { }, .driver_data = (void *)oxp_mini_amd, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), + }, + .driver_data = (void *)oxp_mini_amd, + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), From d2abcb5cc88577f996ab505c8102254aba7062d8 Mon Sep 17 00:00:00 2001 From: Kirill Yatsenko Date: Wed, 24 May 2023 22:19:12 +0200 Subject: [PATCH 22/54] hwmon: (aht10) Add support for compatible aht20 Add support for compatible AHT20 temperature/humidity sensor. The only difference between the two is that AHT20 has additional crc8 byte. It seems like AHT15 is also supported by the driver but it wasn't verified and tested yet. Tested on Beaglebone black rev C. Signed-off-by: Kirill Yatsenko Link: https://lore.kernel.org/r/20230524201912.815993-1-kiriyatsenko@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aht10.rst | 20 ++++++--- drivers/hwmon/Kconfig | 5 ++- drivers/hwmon/aht10.c | 84 +++++++++++++++++++++++++++-------- 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/Documentation/hwmon/aht10.rst b/Documentation/hwmon/aht10.rst index 4e198c5eb683..213644b4ecba 100644 --- a/Documentation/hwmon/aht10.rst +++ b/Documentation/hwmon/aht10.rst @@ -5,32 +5,42 @@ Kernel driver aht10 Supported chips: - * Aosong AHT10 + * Aosong AHT10/AHT20 Prefix: 'aht10' Addresses scanned: None - Datasheet: + Datasheet(AHT10): Chinese: http://www.aosong.com/userfiles/files/media/AHT10%E4%BA%A7%E5%93%81%E6%89%8B%E5%86%8C%20A3%2020201210.pdf English: https://server4.eca.ir/eshop/AHT10/Aosong_AHT10_en_draft_0c.pdf + Datasheet(AHT20): + + English: http://www.aosong.com/userfiles/files/media/Data%20Sheet%20AHT20.pdf + Author: Johannes Cornelis Draaijer Description ----------- -The AHT10 is a Temperature and Humidity sensor +The AHT10/AHT20 is a Temperature and Humidity sensor The address of this i2c device may only be 0x38 +Special Features +---------------- + +AHT20 has additional CRC8 support which is sent as the last byte of the sensor +values. + Usage Notes ----------- -This driver does not probe for AHT10 devices, as there is no reliable -way to determine if an i2c chip is or isn't an AHT10. The device has +This driver does not probe for AHT10/ATH20 devices, as there is no reliable +way to determine if an i2c chip is or isn't an AHT10/AHT20. The device has to be instantiated explicitly with the address 0x38. See Documentation/i2c/instantiating-devices.rst for details. diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index fc640201a2de..bf73934a6eee 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -255,10 +255,11 @@ config SENSORS_ADT7475 will be called adt7475. config SENSORS_AHT10 - tristate "Aosong AHT10" + tristate "Aosong AHT10, AHT20" depends on I2C + select CRC8 help - If you say yes here, you get support for the Aosong AHT10 + If you say yes here, you get support for the Aosong AHT10 and AHT20 temperature and humidity sensors This driver can also be built as a module. If so, the module diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index ec7459575c58..f136bf3ff40a 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * aht10.c - Linux hwmon driver for AHT10 Temperature and Humidity sensor + * aht10.c - Linux hwmon driver for AHT10/AHT20 Temperature and Humidity sensors * Copyright (C) 2020 Johannes Cornelis Draaijer */ @@ -10,9 +10,13 @@ #include #include #include +#include #define AHT10_MEAS_SIZE 6 +#define AHT20_MEAS_SIZE 7 +#define AHT20_CRC8_POLY 0x31 + /* * Poll intervals (in milliseconds) */ @@ -44,9 +48,18 @@ #define AHT10_MAX_POLL_INTERVAL_LEN 30 +enum aht10_variant { aht10, aht20 }; + +static const struct i2c_device_id aht10_id[] = { + { "aht10", aht10 }, + { "aht20", aht20 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, aht10_id); + /** - * struct aht10_data - All the data required to operate an AHT10 chip - * @client: the i2c client associated with the AHT10 + * struct aht10_data - All the data required to operate an AHT10/AHT20 chip + * @client: the i2c client associated with the AHT10/AHT20 * @lock: a mutex that is used to prevent parallel access to the * i2c client * @min_poll_interval: the minimum poll interval @@ -56,12 +69,14 @@ * the chip from warming up due to the heat it generates. * If it's unwanted, it can be ignored setting it to * it to 0. Default value is 2000 ms - * @previous_poll_time: the previous time that the AHT10 + * @previous_poll_time: the previous time that the AHT10/AHT20 * was polled * @temperature: the latest temperature value received from - * the AHT10 + * the AHT10/AHT20 * @humidity: the latest humidity value received from the - * AHT10 + * AHT10/AHT20 + * @crc8: crc8 support flag + * @meas_size: measurements data size */ struct aht10_data { @@ -75,11 +90,13 @@ struct aht10_data { ktime_t previous_poll_time; int temperature; int humidity; + bool crc8; + unsigned int meas_size; }; /** - * aht10_init() - Initialize an AHT10 chip - * @data: the data associated with this AHT10 chip + * aht10_init() - Initialize an AHT10/AHT20 chip + * @data: the data associated with this AHT10/AHT20 chip * Return: 0 if successful, 1 if not */ static int aht10_init(struct aht10_data *data) @@ -121,8 +138,25 @@ static int aht10_polltime_expired(struct aht10_data *data) return ktime_after(difference, data->min_poll_interval); } +DECLARE_CRC8_TABLE(crc8_table); + /** - * aht10_read_values() - read and parse the raw data from the AHT10 + * crc8_check() - check crc of the sensor's measurements + * @raw_data: data frame received from sensor(including crc as the last byte) + * @count: size of the data frame + * Return: 0 if successful, 1 if not + */ +static int crc8_check(u8 *raw_data, int count) +{ + /* + * crc calculated on the whole frame(including crc byte) should yield + * zero in case of correctly received bytes + */ + return crc8(crc8_table, raw_data, count, CRC8_INIT_VALUE); +} + +/** + * aht10_read_values() - read and parse the raw data from the AHT10/AHT20 * @data: the struct aht10_data to use for the lock * Return: 0 if successful, 1 if not */ @@ -131,7 +165,7 @@ static int aht10_read_values(struct aht10_data *data) const u8 cmd_meas[] = {AHT10_CMD_MEAS, 0x33, 0x00}; u32 temp, hum; int res; - u8 raw_data[AHT10_MEAS_SIZE]; + u8 raw_data[AHT20_MEAS_SIZE]; struct i2c_client *client = data->client; mutex_lock(&data->lock); @@ -148,14 +182,19 @@ static int aht10_read_values(struct aht10_data *data) usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA); - res = i2c_master_recv(client, raw_data, AHT10_MEAS_SIZE); - if (res != AHT10_MEAS_SIZE) { + res = i2c_master_recv(client, raw_data, data->meas_size); + if (res != data->meas_size) { mutex_unlock(&data->lock); if (res >= 0) return -ENODATA; return res; } + if (data->crc8 && crc8_check(raw_data, data->meas_size)) { + mutex_unlock(&data->lock); + return -EIO; + } + hum = ((u32)raw_data[1] << 12u) | ((u32)raw_data[2] << 4u) | ((raw_data[3] & 0xF0u) >> 4u); @@ -292,6 +331,8 @@ static const struct hwmon_chip_info aht10_chip_info = { static int aht10_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_match_id(aht10_id, client); + enum aht10_variant variant = id->driver_data; struct device *device = &client->dev; struct device *hwmon_dev; struct aht10_data *data; @@ -307,6 +348,17 @@ static int aht10_probe(struct i2c_client *client) data->min_poll_interval = ms_to_ktime(AHT10_DEFAULT_MIN_POLL_INTERVAL); data->client = client; + switch (variant) { + case aht20: + data->meas_size = AHT20_MEAS_SIZE; + data->crc8 = true; + crc8_populate_msb(crc8_table, AHT20_CRC8_POLY); + break; + default: + data->meas_size = AHT10_MEAS_SIZE; + break; + } + mutex_init(&data->lock); res = aht10_init(data); @@ -326,12 +378,6 @@ static int aht10_probe(struct i2c_client *client) return PTR_ERR_OR_ZERO(hwmon_dev); } -static const struct i2c_device_id aht10_id[] = { - { "aht10", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, aht10_id); - static struct i2c_driver aht10_driver = { .driver = { .name = "aht10", @@ -343,6 +389,6 @@ static struct i2c_driver aht10_driver = { module_i2c_driver(aht10_driver); MODULE_AUTHOR("Johannes Cornelis Draaijer "); -MODULE_DESCRIPTION("AHT10 Temperature and Humidity sensor driver"); +MODULE_DESCRIPTION("AHT10/AHT20 Temperature and Humidity sensor driver"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL v2"); From 9702fc8768ee7262aa2f672d77c1062eba761cf9 Mon Sep 17 00:00:00 2001 From: Daniel Matyas Date: Wed, 24 May 2023 19:01:29 +0300 Subject: [PATCH 23/54] dt-bindings: hwmon: add MAX31827 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MAX31827 is a low-power temperature switch with I2C interface. The device is a ±1°C accuracy from -40°C to +125°C (12 bits) local temperature switch and sensor with I2C/SM- Bus interface. The combination of small 6-bump wafer-lev- el package (WLP) and high accuracy makes this temper- ature sensor/switch ideal for a wide range of applications. Signed-off-by: Daniel Matyas Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230524160131.14081-1-daniel.matyas@analog.com Signed-off-by: Guenter Roeck --- .../bindings/hwmon/adi,max31827.yaml | 54 +++++++++++++++++++ MAINTAINERS | 7 +++ 2 files changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/adi,max31827.yaml diff --git a/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml new file mode 100644 index 000000000000..2dc8b07b4d3b --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/adi,max31827.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch + +maintainers: + - Daniel Matyas + +description: | + Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch with + I2C Interface + https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf + +properties: + compatible: + oneOf: + - const: adi,max31827 + - items: + - enum: + - adi,max31828 + - adi,max31829 + - const: adi,max31827 + + reg: + maxItems: 1 + + vref-supply: + description: + Must have values in the interval (1.6V; 3.6V) in order for the device to + function correctly. + +required: + - compatible + - reg + - vref-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + temperature-sensor@42 { + compatible = "adi,max31827"; + reg = <0x42>; + vref-supply = <®_vdd>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index e0ad886d3163..5d5359f59af5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12617,6 +12617,13 @@ F: Documentation/userspace-api/media/drivers/max2175.rst F: drivers/media/i2c/max2175* F: include/uapi/linux/max2175.h +MAX31827 TEMPERATURE SWITCH DRIVER +M: Daniel Matyas +L: linux-hwmon@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/devicetree/bindings/hwmon/adi,max31827.yaml + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER L: linux-hwmon@vger.kernel.org S: Orphan From 16d60ba8fdc4c6e4745005889dea6ed82b6b5cbd Mon Sep 17 00:00:00 2001 From: Daniel Matyas Date: Wed, 24 May 2023 19:01:30 +0300 Subject: [PATCH 24/54] hwmon: Add MAX31827 driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MAX31827 is a low-power temperature switch with I2C interface. The device is a ±1°C accuracy from -40°C to +125°C (12 bits) local temperature switch and sensor with I2C/SM- Bus interface. The combination of small 6-bump wafer-lev- el package (WLP) and high accuracy makes this temper- ature sensor/switch ideal for a wide range of applications. Signed-off-by: Daniel Matyas Link: https://lore.kernel.org/r/20230524160131.14081-2-daniel.matyas@analog.com [groeck: Improved define alignment, return -EINVAL after bad user input, fixed up compatible statement] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/max31827.rst | 90 ++++++ MAINTAINERS | 2 + drivers/hwmon/Kconfig | 11 + drivers/hwmon/Makefile | 2 +- drivers/hwmon/max31827.c | 466 +++++++++++++++++++++++++++++++ 6 files changed, 571 insertions(+), 1 deletion(-) create mode 100644 Documentation/hwmon/max31827.rst create mode 100644 drivers/hwmon/max31827.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 03b30a94a9e6..b3af03214b3e 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -140,6 +140,7 @@ Hardware Monitoring Kernel Drivers max31760 max31785 max31790 + max31827 max34440 max6620 max6639 diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst new file mode 100644 index 000000000000..b0971d05b8a4 --- /dev/null +++ b/Documentation/hwmon/max31827.rst @@ -0,0 +1,90 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver max31827 +====================== + +Supported chips: + + * Maxim MAX31827 + + Prefix: 'max31827' + + Addresses scanned: I2C 0x40 - 0x5f + + Datasheet: Publicly available at the Analog Devices website + + * Maxim MAX31828 + + Prefix: 'max31828' + + Addresses scanned: I2C 0x40 - 0x5f + + Datasheet: Publicly available at the Analog Devices website + + * Maxim MAX31829 + + Prefix: 'max31829' + + Addresses scanned: I2C 0x40 - 0x5f + + Datasheet: Publicly available at the Analog Devices website + + +Authors: + - Daniel Matyas + +Description +----------- + +The chips supported by this driver are quite similar. The only difference +between them is found in the default power-on behaviour of the chips. While the +MAX31827's fault queue is set to 1, the other two chip's fault queue is set to +4. Besides this, the MAX31829's alarm active state is high, while the other two +chip's alarms are active on low. It is important to note that the chips can be +configured to operate in the same manner with 1 write operation to the +configuration register. From here on, we will refer to all these chips as +MAX31827. + +MAX31827 implements a temperature sensor with a 6 WLP packaging scheme. This +sensor measures the temperature of the chip itself. + +MAX31827 has low and over temperature alarms with an effective value and a +hysteresis value: -40 and -30 degrees for under temperature alarm and +100 and ++90 degrees for over temperature alarm. + +The alarm can be configured in comparator and interrupt mode. Currently only +comparator mode is implemented. In Comparator mode, the OT/UT status bits have a +value of 1 when the temperature rises above the TH value or falls below TL, +which is also subject to the Fault Queue selection. OT status returns to 0 when +the temperature drops below the TH_HYST value or when shutdown mode is entered. +Similarly, UT status returns to 0 when the temperature rises above TL_HYST value +or when shutdown mode is entered. + +Putting the MAX31827 into shutdown mode also resets the OT/UT status bits. Note +that if the mode is changed while OT/UT status bits are set, an OT/UT status +reset may be required before it begins to behave normally. To prevent this, +it is recommended to perform a read of the configuration/status register to +clear the status bits before changing the operating mode. + +The conversions can be manual with the one-shot functionality and automatic with +a set frequency. When powered on, the chip measures temperatures with 1 conv/s. +Enabling the device when it is already enabled has the side effect of setting +the conversion frequency to 1 conv/s. The conversion time varies depending on +the resolution. The conversion time doubles with every bit of increased +resolution. For 10 bit resolution 35ms are needed, while for 12 bit resolution +(default) 140ms. When chip is in shutdown mode and a read operation is +requested, one-shot is triggered, the device waits for 140 (conversion time) + 1 +(error) ms, and only after that is the temperature value register read. + +The LSB of the temperature values is 0.0625 degrees Celsius, but the values of +the temperatures are displayed in milli-degrees. This means, that some data is +lost. The step between 2 consecutive values is 62 or 63. This effect can be seen +in the writing of alarm values too. For positive numbers the user-input value +will always be rounded down to the nearest possible value, for negative numbers +the user-input will always be rounded up to the nearest possible value. + +Notes +----- + +Currently fault queue, alarm polarity and resolution cannot be modified. +PEC is not implemented either. diff --git a/MAINTAINERS b/MAINTAINERS index 5d5359f59af5..9c300a3ebb66 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12623,6 +12623,8 @@ L: linux-hwmon@vger.kernel.org S: Supported W: http://ez.analog.com/community/linux-device-drivers F: Documentation/devicetree/bindings/hwmon/adi,max31827.yaml +F: Documentation/hwmon/max31827.rst +F: drivers/hwmon/max31827.c MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER L: linux-hwmon@vger.kernel.org diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index bf73934a6eee..c52e44a393e9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1098,6 +1098,17 @@ config SENSORS_MAX31760 This driver can also be built as a module. If so, the module will be called max31760. +config MAX31827 + tristate "MAX31827 low-power temperature switch and similar devices" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for MAX31827, MAX31828 and + MAX31829 low-power temperature switches and sensors connected with I2C. + + This driver can also be built as a module. If so, the module + will be called max31827. + config SENSORS_MAX6620 tristate "Maxim MAX6620 fan controller" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index cd8c568c80a9..8a8021f9ca9e 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -149,6 +149,7 @@ obj-$(CONFIG_SENSORS_MAX6642) += max6642.o obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_MAX6697) += max6697.o obj-$(CONFIG_SENSORS_MAX31790) += max31790.o +obj-$(CONFIG_MAX31827) += max31827.o obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o @@ -224,4 +225,3 @@ obj-$(CONFIG_SENSORS_PECI) += peci/ obj-$(CONFIG_PMBUS) += pmbus/ ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG - diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c new file mode 100644 index 000000000000..7735e8087df3 --- /dev/null +++ b/drivers/hwmon/max31827.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * max31827.c - Support for Maxim Low-Power Switch + * + * Copyright (c) 2023 Daniel Matyas + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX31827_T_REG 0x0 +#define MAX31827_CONFIGURATION_REG 0x2 +#define MAX31827_TH_REG 0x4 +#define MAX31827_TL_REG 0x6 +#define MAX31827_TH_HYST_REG 0x8 +#define MAX31827_TL_HYST_REG 0xA + +#define MAX31827_CONFIGURATION_1SHOT_MASK BIT(0) +#define MAX31827_CONFIGURATION_CNV_RATE_MASK GENMASK(3, 1) +#define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK BIT(14) +#define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK BIT(15) + +#define MAX31827_12_BIT_CNV_TIME 141 + +#define MAX31827_CNV_1_DIV_64_HZ 0x1 +#define MAX31827_CNV_1_DIV_32_HZ 0x2 +#define MAX31827_CNV_1_DIV_16_HZ 0x3 +#define MAX31827_CNV_1_DIV_4_HZ 0x4 +#define MAX31827_CNV_1_HZ 0x5 +#define MAX31827_CNV_4_HZ 0x6 +#define MAX31827_CNV_8_HZ 0x7 + +#define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16) +#define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000) +#define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0) + +struct max31827_state { + /* + * Prevent simultaneous access to the i2c client. + */ + struct mutex lock; + struct regmap *regmap; + bool enable; +}; + +static const struct regmap_config max31827_regmap = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 0xA, +}; + +static int write_alarm_val(struct max31827_state *st, unsigned int reg, + long val) +{ + unsigned int cfg; + unsigned int tmp; + int ret; + + val = MAX31827_M_DGR_TO_16_BIT(val); + + /* + * Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold + * register values are changed over I2C, the part must be in shutdown + * mode. + * + * Mutex is used to ensure, that some other process doesn't change the + * configuration register. + */ + mutex_lock(&st->lock); + + if (!st->enable) { + ret = regmap_write(st->regmap, reg, val); + goto unlock; + } + + ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg); + if (ret) + goto unlock; + + tmp = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | + MAX31827_CONFIGURATION_CNV_RATE_MASK); + ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, tmp); + if (ret) + goto unlock; + + ret = regmap_write(st->regmap, reg, val); + if (ret) + goto unlock; + + ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); + +unlock: + mutex_unlock(&st->lock); + return ret; +} + +static umode_t max31827_is_visible(const void *state, + enum hwmon_sensor_types type, u32 attr, + int channel) +{ + if (type == hwmon_temp) { + switch (attr) { + case hwmon_temp_enable: + case hwmon_temp_max: + case hwmon_temp_min: + case hwmon_temp_max_hyst: + case hwmon_temp_min_hyst: + return 0644; + case hwmon_temp_input: + case hwmon_temp_min_alarm: + case hwmon_temp_max_alarm: + return 0444; + default: + return 0; + } + } else if (type == hwmon_chip) { + if (attr == hwmon_chip_update_interval) + return 0644; + } + + return 0; +} + +static int max31827_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct max31827_state *st = dev_get_drvdata(dev); + unsigned int uval; + int ret = 0; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + ret = regmap_read(st->regmap, + MAX31827_CONFIGURATION_REG, &uval); + if (ret) + break; + + uval = FIELD_GET(MAX31827_CONFIGURATION_1SHOT_MASK | + MAX31827_CONFIGURATION_CNV_RATE_MASK, + uval); + *val = !!uval; + + break; + case hwmon_temp_input: + mutex_lock(&st->lock); + + if (!st->enable) { + /* + * This operation requires mutex protection, + * because the chip configuration should not + * be changed during the conversion process. + */ + + ret = regmap_update_bits(st->regmap, + MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_1SHOT_MASK, + 1); + if (ret) { + mutex_unlock(&st->lock); + return ret; + } + + msleep(MAX31827_12_BIT_CNV_TIME); + } + ret = regmap_read(st->regmap, MAX31827_T_REG, &uval); + + mutex_unlock(&st->lock); + + if (ret) + break; + + *val = MAX31827_16_BIT_TO_M_DGR(uval); + + break; + case hwmon_temp_max: + ret = regmap_read(st->regmap, MAX31827_TH_REG, &uval); + if (ret) + break; + + *val = MAX31827_16_BIT_TO_M_DGR(uval); + break; + case hwmon_temp_max_hyst: + ret = regmap_read(st->regmap, MAX31827_TH_HYST_REG, + &uval); + if (ret) + break; + + *val = MAX31827_16_BIT_TO_M_DGR(uval); + break; + case hwmon_temp_max_alarm: + ret = regmap_read(st->regmap, + MAX31827_CONFIGURATION_REG, &uval); + if (ret) + break; + + *val = FIELD_GET(MAX31827_CONFIGURATION_O_TEMP_STAT_MASK, + uval); + break; + case hwmon_temp_min: + ret = regmap_read(st->regmap, MAX31827_TL_REG, &uval); + if (ret) + break; + + *val = MAX31827_16_BIT_TO_M_DGR(uval); + break; + case hwmon_temp_min_hyst: + ret = regmap_read(st->regmap, MAX31827_TL_HYST_REG, + &uval); + if (ret) + break; + + *val = MAX31827_16_BIT_TO_M_DGR(uval); + break; + case hwmon_temp_min_alarm: + ret = regmap_read(st->regmap, + MAX31827_CONFIGURATION_REG, &uval); + if (ret) + break; + + *val = FIELD_GET(MAX31827_CONFIGURATION_U_TEMP_STAT_MASK, + uval); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + break; + + case hwmon_chip: + if (attr == hwmon_chip_update_interval) { + ret = regmap_read(st->regmap, + MAX31827_CONFIGURATION_REG, &uval); + if (ret) + break; + + uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK, + uval); + switch (uval) { + case MAX31827_CNV_1_DIV_64_HZ: + *val = 64000; + break; + case MAX31827_CNV_1_DIV_32_HZ: + *val = 32000; + break; + case MAX31827_CNV_1_DIV_16_HZ: + *val = 16000; + break; + case MAX31827_CNV_1_DIV_4_HZ: + *val = 4000; + break; + case MAX31827_CNV_1_HZ: + *val = 1000; + break; + case MAX31827_CNV_4_HZ: + *val = 250; + break; + case MAX31827_CNV_8_HZ: + *val = 125; + break; + default: + *val = 0; + break; + } + } + break; + + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static int max31827_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct max31827_state *st = dev_get_drvdata(dev); + int ret; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + if (val >> 1) + return -EINVAL; + + mutex_lock(&st->lock); + /** + * The chip should not be enabled while a conversion is + * performed. Neither should the chip be enabled when + * the alarm values are changed. + */ + + st->enable = val; + + ret = regmap_update_bits(st->regmap, + MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_1SHOT_MASK | + MAX31827_CONFIGURATION_CNV_RATE_MASK, + MAX31827_DEVICE_ENABLE(val)); + + mutex_unlock(&st->lock); + + return ret; + + case hwmon_temp_max: + return write_alarm_val(st, MAX31827_TH_REG, val); + + case hwmon_temp_max_hyst: + return write_alarm_val(st, MAX31827_TH_HYST_REG, val); + + case hwmon_temp_min: + return write_alarm_val(st, MAX31827_TL_REG, val); + + case hwmon_temp_min_hyst: + return write_alarm_val(st, MAX31827_TL_HYST_REG, val); + + default: + return -EOPNOTSUPP; + } + + case hwmon_chip: + if (attr == hwmon_chip_update_interval) { + if (!st->enable) + return -EINVAL; + + switch (val) { + case 125: + val = MAX31827_CNV_8_HZ; + break; + case 250: + val = MAX31827_CNV_4_HZ; + break; + case 1000: + val = MAX31827_CNV_1_HZ; + break; + case 4000: + val = MAX31827_CNV_1_DIV_4_HZ; + break; + case 16000: + val = MAX31827_CNV_1_DIV_16_HZ; + break; + case 32000: + val = MAX31827_CNV_1_DIV_32_HZ; + break; + case 64000: + val = MAX31827_CNV_1_DIV_64_HZ; + break; + default: + return -EINVAL; + } + + val = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK, + val); + + return regmap_update_bits(st->regmap, + MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_CNV_RATE_MASK, + val); + } + break; + + default: + return -EOPNOTSUPP; + } + + return -EOPNOTSUPP; +} + +static int max31827_init_client(struct max31827_state *st) +{ + st->enable = true; + + return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_1SHOT_MASK | + MAX31827_CONFIGURATION_CNV_RATE_MASK, + MAX31827_DEVICE_ENABLE(1)); +} + +static const struct hwmon_channel_info *max31827_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN | + HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM | + HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_MAX_ALARM), + HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), + NULL, +}; + +static const struct hwmon_ops max31827_hwmon_ops = { + .is_visible = max31827_is_visible, + .read = max31827_read, + .write = max31827_write, +}; + +static const struct hwmon_chip_info max31827_chip_info = { + .ops = &max31827_hwmon_ops, + .info = max31827_info, +}; + +static int max31827_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct max31827_state *st; + int err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -EOPNOTSUPP; + + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + mutex_init(&st->lock); + + st->regmap = devm_regmap_init_i2c(client, &max31827_regmap); + if (IS_ERR(st->regmap)) + return dev_err_probe(dev, PTR_ERR(st->regmap), + "Failed to allocate regmap.\n"); + + err = max31827_init_client(st); + if (err) + return err; + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st, + &max31827_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct i2c_device_id max31827_i2c_ids[] = { + { "max31827", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids); + +static const struct of_device_id max31827_of_match[] = { + { .compatible = "adi,max31827" }, + { } +}; +MODULE_DEVICE_TABLE(of, max31827_of_match); + +static struct i2c_driver max31827_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "max31827", + .of_match_table = max31827_of_match, + }, + .probe_new = max31827_probe, + .id_table = max31827_i2c_ids, +}; +module_i2c_driver(max31827_driver); + +MODULE_AUTHOR("Daniel Matyas "); +MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver"); +MODULE_LICENSE("GPL"); From 7590e659e063dc45a5743bb4e5eb4a21ee1fd651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Thu, 25 May 2023 11:26:52 -0300 Subject: [PATCH 25/54] hwmon: (oxp-sensors) Stop passing device structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't need to pass device structure to write_to_ec() so we remove that from the function declaration. The same is valid for pwm_enable() and pwm_disable() as we were passing the pointer to hand it off to write_to_ec(). Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230525142652.41981-1-samsagax@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/oxp-sensors.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index a4ee757f879f..0ec7588610ad 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -141,7 +141,7 @@ static int read_from_ec(u8 reg, int size, long *val) return 0; } -static int write_to_ec(const struct device *dev, u8 reg, u8 value) +static int write_to_ec(u8 reg, u8 value) { int ret; @@ -156,14 +156,14 @@ static int write_to_ec(const struct device *dev, u8 reg, u8 value) return ret; } -static int oxp_pwm_enable(const struct device *dev) +static int oxp_pwm_enable(void) { - return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01); + return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01); } -static int oxp_pwm_disable(const struct device *dev) +static int oxp_pwm_disable(void) { - return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00); + return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x00); } /* Callbacks for hwmon interface */ @@ -234,9 +234,9 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, switch (attr) { case hwmon_pwm_enable: if (val == 1) - return oxp_pwm_enable(dev); + return oxp_pwm_enable(); else if (val == 0) - return oxp_pwm_disable(dev); + return oxp_pwm_disable(); return -EINVAL; case hwmon_pwm_input: if (val < 0 || val > 255) @@ -254,7 +254,7 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, default: break; } - return write_to_ec(dev, OXP_SENSOR_PWM_REG, val); + return write_to_ec(OXP_SENSOR_PWM_REG, val); default: break; } From 23902f98f8d4811ab84dde6419569a5b374f8122 Mon Sep 17 00:00:00 2001 From: James Seo Date: Mon, 22 May 2023 04:56:46 -0700 Subject: [PATCH 26/54] hwmon: add HP WMI Sensors driver Hewlett-Packard (and some HP Compaq) business-class computers report hardware monitoring information via WMI. This driver exposes that information to hwmon. Initial support is provided for temperature, fan speed, and intrusion sensor types. Provisional support is provided for voltage and current sensor types. HP's WMI implementation permits many other types of numeric sensors. Therefore, a debugfs interface is also provided to enumerate and inspect all numeric sensors visible on the WMI side. This should facilitate adding support for other sensor types in the future. Tested on a HP Z420, a HP EliteOne 800 G1, and a HP Compaq Elite 8300 SFF. Note that provisionally supported sensor types are untested and seem to be rare-to-nonexistent in the wild, having been encountered neither on test systems nor in ACPI dumps from the Linux Hardware Database. They are included because their popularity in general makes their presence on past or future HP systems plausible and because no doubt exists as to how the sensors themselves would be represented in WMI (alarm attributes will need to wait for hardware to be located). A 2005 HP whitepaper gives the relevant sensor object MOF definition and sensor value scaling calculation, and both this driver and the official HP Performance Advisor utility comply with them (confirmed in the latter case by reverse engineering). Link: https://h20331.www2.hp.com/hpsub/downloads/cmi_whitepaper.pdf Signed-off-by: James Seo Link: https://lore.kernel.org/r/20230522115645.509701-1-james@equiv.tech [groeck: Set error return value for intrusion writes to -EINVAL. Always accept writes of 0 even if there was no intrusion. ] Signed-off-by: Guenter Roeck --- Documentation/hwmon/hp-wmi-sensors.rst | 140 ++ Documentation/hwmon/index.rst | 1 + MAINTAINERS | 7 + drivers/hwmon/Kconfig | 12 + drivers/hwmon/Makefile | 1 + drivers/hwmon/hp-wmi-sensors.c | 2015 ++++++++++++++++++++++++ 6 files changed, 2176 insertions(+) create mode 100644 Documentation/hwmon/hp-wmi-sensors.rst create mode 100644 drivers/hwmon/hp-wmi-sensors.c diff --git a/Documentation/hwmon/hp-wmi-sensors.rst b/Documentation/hwmon/hp-wmi-sensors.rst new file mode 100644 index 000000000000..a6bca9aecdde --- /dev/null +++ b/Documentation/hwmon/hp-wmi-sensors.rst @@ -0,0 +1,140 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +.. include:: + +=========================== +Linux HP WMI Sensors Driver +=========================== + +:Copyright: |copy| 2023 James Seo + +Description +=========== + +Hewlett-Packard (and some HP Compaq) business-class computers report hardware +monitoring information via Windows Management Instrumentation (WMI). +This driver exposes that information to the Linux hwmon subsystem, allowing +userspace utilities like ``sensors`` to gather numeric sensor readings. + +sysfs interface +=============== + +When the driver is loaded, it discovers the sensors available on the +system and creates the following sysfs attributes as necessary within +``/sys/class/hwmon/hwmon[X]``: + +(``[X]`` is some number that depends on other system components.) + +======================= ======= =================================== +Name Perm Description +======================= ======= =================================== +``curr[X]_input`` RO Current in milliamperes (mA). +``curr[X]_label`` RO Current sensor label. +``fan[X]_input`` RO Fan speed in RPM. +``fan[X]_label`` RO Fan sensor label. +``fan[X]_fault`` RO Fan sensor fault indicator. +``fan[X]_alarm`` RO Fan sensor alarm indicator. +``in[X]_input`` RO Voltage in millivolts (mV). +``in[X]_label`` RO Voltage sensor label. +``temp[X]_input`` RO Temperature in millidegrees Celsius + (m\ |deg|\ C). +``temp[X]_label`` RO Temperature sensor label. +``temp[X]_fault`` RO Temperature sensor fault indicator. +``temp[X]_alarm`` RO Temperature sensor alarm indicator. +``intrusion[X]_alarm`` RW Chassis intrusion alarm indicator. +======================= ======= =================================== + +``fault`` attributes + Reading ``1`` instead of ``0`` as the ``fault`` attribute for a sensor + indicates that it has encountered some issue during operation such that + measurements from it should not be trusted. If a sensor with the fault + condition recovers later, reading this attribute will return ``0`` again. + +``alarm`` attributes + Reading ``1`` instead of ``0`` as the ``alarm`` attribute for a sensor + indicates that one of the following has occurred, depending on its type: + + - ``fan``: The fan has stalled or has been disconnected while running. + - ``temp``: The sensor reading has reached a critical threshold. + The exact threshold is system-dependent. + - ``intrusion``: The system's chassis has been opened. + + After ``1`` is read from an ``alarm`` attribute, the attribute resets itself + and returns ``0`` on subsequent reads. As an exception, an + ``intrusion[X]_alarm`` can only be manually reset by writing ``0`` to it. + +debugfs interface +================= + +.. warning:: The debugfs interface is subject to change without notice + and is only available when the kernel is compiled with + ``CONFIG_DEBUG_FS`` defined. + +The standard hwmon interface in sysfs exposes sensors of several common types +that are connected as of driver initialization. However, there are usually +other sensors in WMI that do not meet these criteria. In addition, a number of +system-dependent "platform events objects" used for ``alarm`` attributes may +be present. A debugfs interface is therefore provided for read-only access to +all available HP WMI sensors and platform events objects. + +``/sys/kernel/debug/hp-wmi-sensors-[X]/sensor`` +contains one numbered entry per sensor with the following attributes: + +=============================== ======================================= +Name Example +=============================== ======================================= +``name`` ``CPU0 Fan`` +``description`` ``Reports CPU0 fan speed`` +``sensor_type`` ``12`` +``other_sensor_type`` (an empty string) +``operational_status`` ``2`` +``possible_states`` ``Normal,Caution,Critical,Not Present`` +``current_state`` ``Normal`` +``base_units`` ``19`` +``unit_modifier`` ``0`` +``current_reading`` ``1008`` +``rate_units`` ``0`` (only exists on some systems) +=============================== ======================================= + +If platform events objects are available, +``/sys/kernel/debug/hp-wmi-sensors-[X]/platform_events`` +contains one numbered entry per object with the following attributes: + +=============================== ==================== +Name Example +=============================== ==================== +``name`` ``CPU0 Fan Stall`` +``description`` ``CPU0 Fan Speed`` +``source_namespace`` ``root\wmi`` +``source_class`` ``HPBIOS_BIOSEvent`` +``category`` ``3`` +``possible_severity`` ``25`` +``possible_status`` ``5`` +=============================== ==================== + +These represent the properties of the underlying ``HPBIOS_BIOSNumericSensor`` +and ``HPBIOS_PlatformEvents`` WMI objects, which vary between systems. +See [#]_ for more details and Managed Object Format (MOF) definitions. + +Known issues and limitations +============================ + +- If the existing hp-wmi driver for non-business-class HP systems is already + loaded, ``alarm`` attributes will be unavailable even on systems that + support them. This is because the same WMI event GUID used by this driver + for ``alarm`` attributes is used on those systems for e.g. laptop hotkeys. +- Dubious sensor hardware and inconsistent BIOS WMI implementations have been + observed to cause inaccurate readings and peculiar behavior, such as alarms + failing to occur or occurring only once per boot. +- Only temperature, fan speed, and intrusion sensor types have been seen in + the wild so far. Support for voltage and current sensors is therefore + provisional. +- Although HP WMI sensors may claim to be of any type, any oddball sensor + types unknown to hwmon will not be supported. + +References +========== + +.. [#] Hewlett-Packard Development Company, L.P., + "HP Client Management Interface Technical White Paper", 2005. [Online]. + Available: https://h20331.www2.hp.com/hpsub/downloads/cmi_whitepaper.pdf diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index b3af03214b3e..042e1cf9501b 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -77,6 +77,7 @@ Hardware Monitoring Kernel Drivers gl518sm gxp-fan-ctrl hih6130 + hp-wmi-sensors ibmaem ibm-cffps ibmpowernv diff --git a/MAINTAINERS b/MAINTAINERS index 9c300a3ebb66..e5b7c3ee83ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9425,6 +9425,13 @@ L: platform-driver-x86@vger.kernel.org S: Orphan F: drivers/platform/x86/hp/tc1100-wmi.c +HP WMI HARDWARE MONITOR DRIVER +M: James Seo +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/hp-wmi-sensors.rst +F: drivers/hwmon/hp-wmi-sensors.c + HPET: High Precision Event Timers driver M: Clemens Ladisch S: Maintained diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c52e44a393e9..307477b8a371 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2421,6 +2421,18 @@ config SENSORS_ASUS_EC This driver can also be built as a module. If so, the module will be called asus_ec_sensors. +config SENSORS_HP_WMI + tristate "HP WMI Sensors" + depends on ACPI_WMI + help + If you say yes here you get support for the ACPI hardware monitoring + interface found in HP (and some HP Compaq) business-class computers. + Available sensors vary between systems. Temperature and fan speed + sensors are the most common. + + This driver can also be built as a module. If so, the module + will be called hp_wmi_sensors. + endif # ACPI endif # HWMON diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8a8021f9ca9e..3f4b0fda0998 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o obj-$(CONFIG_SENSORS_ASUS_EC) += asus-ec-sensors.o obj-$(CONFIG_SENSORS_ASUS_WMI) += asus_wmi_sensors.o +obj-$(CONFIG_SENSORS_HP_WMI) += hp-wmi-sensors.o # Native drivers # asb100, then w83781d go first, as they can override other drivers' addresses. diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c new file mode 100644 index 000000000000..7218945bd03f --- /dev/null +++ b/drivers/hwmon/hp-wmi-sensors.c @@ -0,0 +1,2015 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * hwmon driver for HP (and some HP Compaq) business-class computers that + * report numeric sensor data via Windows Management Instrumentation (WMI). + * + * Copyright (C) 2023 James Seo + * + * References: + * [1] Hewlett-Packard Development Company, L.P., + * "HP Client Management Interface Technical White Paper", 2005. [Online]. + * Available: https://h20331.www2.hp.com/hpsub/downloads/cmi_whitepaper.pdf + * [2] Hewlett-Packard Development Company, L.P., + * "HP Retail Manageability", 2012. [Online]. + * Available: http://h10032.www1.hp.com/ctg/Manual/c03291135.pdf + * [3] Linux Hardware Project, A. Ponomarenko et al., + * "linuxhw/ACPI - Collect ACPI table dumps", 2018. [Online]. + * Available: https://github.com/linuxhw/ACPI + * [4] P. Rohár, "bmfdec - Decompile binary MOF file (BMF) from WMI buffer", + * 2017. [Online]. Available: https://github.com/pali/bmfdec + */ + +#include +#include +#include +#include +#include +#include +#include + +#define HP_WMI_EVENT_NAMESPACE "root\\WMI" +#define HP_WMI_EVENT_CLASS "HPBIOS_BIOSEvent" +#define HP_WMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" +#define HP_WMI_NUMERIC_SENSOR_GUID "8F1F6435-9F42-42C8-BADC-0E9424F20C9A" +#define HP_WMI_PLATFORM_EVENTS_GUID "41227C2D-80E1-423F-8B8E-87E32755A0EB" + +/* Patterns for recognizing sensors and matching events to channels. */ + +#define HP_WMI_PATTERN_SYS_TEMP "Chassis Thermal Index" +#define HP_WMI_PATTERN_SYS_TEMP2 "System Ambient Temperature" +#define HP_WMI_PATTERN_CPU_TEMP "CPU Thermal Index" +#define HP_WMI_PATTERN_CPU_TEMP2 "CPU Temperature" +#define HP_WMI_PATTERN_TEMP_SENSOR "Thermal Index" +#define HP_WMI_PATTERN_TEMP_ALARM "Thermal Critical" +#define HP_WMI_PATTERN_INTRUSION_ALARM "Hood Intrusion" +#define HP_WMI_PATTERN_FAN_ALARM "Stall" +#define HP_WMI_PATTERN_TEMP "Temperature" +#define HP_WMI_PATTERN_CPU "CPU" + +/* These limits are arbitrary. The WMI implementation may vary by system. */ + +#define HP_WMI_MAX_STR_SIZE 128U +#define HP_WMI_MAX_PROPERTIES 32U +#define HP_WMI_MAX_INSTANCES 32U + +enum hp_wmi_type { + HP_WMI_TYPE_OTHER = 1, + HP_WMI_TYPE_TEMPERATURE = 2, + HP_WMI_TYPE_VOLTAGE = 3, + HP_WMI_TYPE_CURRENT = 4, + HP_WMI_TYPE_AIR_FLOW = 12, + HP_WMI_TYPE_INTRUSION = 0xabadb01, /* Custom. */ +}; + +enum hp_wmi_category { + HP_WMI_CATEGORY_SENSOR = 3, +}; + +enum hp_wmi_severity { + HP_WMI_SEVERITY_UNKNOWN = 0, + HP_WMI_SEVERITY_OK = 5, + HP_WMI_SEVERITY_DEGRADED_WARNING = 10, + HP_WMI_SEVERITY_MINOR_FAILURE = 15, + HP_WMI_SEVERITY_MAJOR_FAILURE = 20, + HP_WMI_SEVERITY_CRITICAL_FAILURE = 25, + HP_WMI_SEVERITY_NON_RECOVERABLE_ERROR = 30, +}; + +enum hp_wmi_status { + HP_WMI_STATUS_OK = 2, + HP_WMI_STATUS_DEGRADED = 3, + HP_WMI_STATUS_STRESSED = 4, + HP_WMI_STATUS_PREDICTIVE_FAILURE = 5, + HP_WMI_STATUS_ERROR = 6, + HP_WMI_STATUS_NON_RECOVERABLE_ERROR = 7, + HP_WMI_STATUS_NO_CONTACT = 12, + HP_WMI_STATUS_LOST_COMMUNICATION = 13, + HP_WMI_STATUS_ABORTED = 14, + HP_WMI_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16, + + /* Occurs combined with one of "OK", "Degraded", and "Error" [1]. */ + HP_WMI_STATUS_COMPLETED = 17, +}; + +enum hp_wmi_units { + HP_WMI_UNITS_OTHER = 1, + HP_WMI_UNITS_DEGREES_C = 2, + HP_WMI_UNITS_DEGREES_F = 3, + HP_WMI_UNITS_DEGREES_K = 4, + HP_WMI_UNITS_VOLTS = 5, + HP_WMI_UNITS_AMPS = 6, + HP_WMI_UNITS_RPM = 19, +}; + +enum hp_wmi_property { + HP_WMI_PROPERTY_NAME = 0, + HP_WMI_PROPERTY_DESCRIPTION = 1, + HP_WMI_PROPERTY_SENSOR_TYPE = 2, + HP_WMI_PROPERTY_OTHER_SENSOR_TYPE = 3, + HP_WMI_PROPERTY_OPERATIONAL_STATUS = 4, + HP_WMI_PROPERTY_SIZE = 5, + HP_WMI_PROPERTY_POSSIBLE_STATES = 6, + HP_WMI_PROPERTY_CURRENT_STATE = 7, + HP_WMI_PROPERTY_BASE_UNITS = 8, + HP_WMI_PROPERTY_UNIT_MODIFIER = 9, + HP_WMI_PROPERTY_CURRENT_READING = 10, + HP_WMI_PROPERTY_RATE_UNITS = 11, +}; + +static const acpi_object_type hp_wmi_property_map[] = { + [HP_WMI_PROPERTY_NAME] = ACPI_TYPE_STRING, + [HP_WMI_PROPERTY_DESCRIPTION] = ACPI_TYPE_STRING, + [HP_WMI_PROPERTY_SENSOR_TYPE] = ACPI_TYPE_INTEGER, + [HP_WMI_PROPERTY_OTHER_SENSOR_TYPE] = ACPI_TYPE_STRING, + [HP_WMI_PROPERTY_OPERATIONAL_STATUS] = ACPI_TYPE_INTEGER, + [HP_WMI_PROPERTY_SIZE] = ACPI_TYPE_INTEGER, + [HP_WMI_PROPERTY_POSSIBLE_STATES] = ACPI_TYPE_STRING, + [HP_WMI_PROPERTY_CURRENT_STATE] = ACPI_TYPE_STRING, + [HP_WMI_PROPERTY_BASE_UNITS] = ACPI_TYPE_INTEGER, + [HP_WMI_PROPERTY_UNIT_MODIFIER] = ACPI_TYPE_INTEGER, + [HP_WMI_PROPERTY_CURRENT_READING] = ACPI_TYPE_INTEGER, + [HP_WMI_PROPERTY_RATE_UNITS] = ACPI_TYPE_INTEGER, +}; + +enum hp_wmi_platform_events_property { + HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME = 0, + HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION = 1, + HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE = 2, + HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS = 3, + HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY = 4, + HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY = 5, + HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS = 6, +}; + +static const acpi_object_type hp_wmi_platform_events_property_map[] = { + [HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME] = ACPI_TYPE_STRING, + [HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION] = ACPI_TYPE_STRING, + [HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE] = ACPI_TYPE_STRING, + [HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS] = ACPI_TYPE_STRING, + [HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY] = ACPI_TYPE_INTEGER, + [HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY] = ACPI_TYPE_INTEGER, + [HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS] = ACPI_TYPE_INTEGER, +}; + +enum hp_wmi_event_property { + HP_WMI_EVENT_PROPERTY_NAME = 0, + HP_WMI_EVENT_PROPERTY_DESCRIPTION = 1, + HP_WMI_EVENT_PROPERTY_CATEGORY = 2, + HP_WMI_EVENT_PROPERTY_SEVERITY = 3, + HP_WMI_EVENT_PROPERTY_STATUS = 4, +}; + +static const acpi_object_type hp_wmi_event_property_map[] = { + [HP_WMI_EVENT_PROPERTY_NAME] = ACPI_TYPE_STRING, + [HP_WMI_EVENT_PROPERTY_DESCRIPTION] = ACPI_TYPE_STRING, + [HP_WMI_EVENT_PROPERTY_CATEGORY] = ACPI_TYPE_INTEGER, + [HP_WMI_EVENT_PROPERTY_SEVERITY] = ACPI_TYPE_INTEGER, + [HP_WMI_EVENT_PROPERTY_STATUS] = ACPI_TYPE_INTEGER, +}; + +static const enum hwmon_sensor_types hp_wmi_hwmon_type_map[] = { + [HP_WMI_TYPE_TEMPERATURE] = hwmon_temp, + [HP_WMI_TYPE_VOLTAGE] = hwmon_in, + [HP_WMI_TYPE_CURRENT] = hwmon_curr, + [HP_WMI_TYPE_AIR_FLOW] = hwmon_fan, +}; + +static const u32 hp_wmi_hwmon_attributes[hwmon_max] = { + [hwmon_chip] = HWMON_C_REGISTER_TZ, + [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_FAULT, + [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL, + [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL, + [hwmon_fan] = HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_FAULT, + [hwmon_intrusion] = HWMON_INTRUSION_ALARM, +}; + +/* + * struct hp_wmi_numeric_sensor - a HPBIOS_BIOSNumericSensor instance + * + * Two variants of HPBIOS_BIOSNumericSensor are known. The first is specified + * in [1] and appears to be much more widespread. The second was discovered by + * decoding BMOF blobs [4], seems to be found only in some newer ZBook systems + * [3], and has two new properties and a slightly different property order. + * + * These differences don't matter on Windows, where WMI object properties are + * accessed by name. For us, supporting both variants gets ugly and hacky at + * times. The fun begins now; this struct is defined as per the new variant. + * + * Effective MOF definition: + * + * #pragma namespace("\\\\.\\root\\HP\\InstrumentedBIOS"); + * class HPBIOS_BIOSNumericSensor { + * [read] string Name; + * [read] string Description; + * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9", + * "10","11","12"}, Values {"Unknown","Other","Temperature", + * "Voltage","Current","Tachometer","Counter","Switch","Lock", + * "Humidity","Smoke Detection","Presence","Air Flow"}] + * uint32 SensorType; + * [read] string OtherSensorType; + * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9", + * "10","11","12","13","14","15","16","17","18","..", + * "0x8000.."}, Values {"Unknown","Other","OK","Degraded", + * "Stressed","Predictive Failure","Error", + * "Non-Recoverable Error","Starting","Stopping","Stopped", + * "In Service","No Contact","Lost Communication","Aborted", + * "Dormant","Supporting Entity in Error","Completed", + * "Power Mode","DMTF Reserved","Vendor Reserved"}] + * uint32 OperationalStatus; + * [read] uint32 Size; + * [read] string PossibleStates[]; + * [read] string CurrentState; + * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9", + * "10","11","12","13","14","15","16","17","18","19","20", + * "21","22","23","24","25","26","27","28","29","30","31", + * "32","33","34","35","36","37","38","39","40","41","42", + * "43","44","45","46","47","48","49","50","51","52","53", + * "54","55","56","57","58","59","60","61","62","63","64", + * "65"}, Values {"Unknown","Other","Degrees C","Degrees F", + * "Degrees K","Volts","Amps","Watts","Joules","Coulombs", + * "VA","Nits","Lumens","Lux","Candelas","kPa","PSI", + * "Newtons","CFM","RPM","Hertz","Seconds","Minutes", + * "Hours","Days","Weeks","Mils","Inches","Feet", + * "Cubic Inches","Cubic Feet","Meters","Cubic Centimeters", + * "Cubic Meters","Liters","Fluid Ounces","Radians", + * "Steradians","Revolutions","Cycles","Gravities","Ounces", + * "Pounds","Foot-Pounds","Ounce-Inches","Gauss","Gilberts", + * "Henries","Farads","Ohms","Siemens","Moles","Becquerels", + * "PPM (parts/million)","Decibels","DbA","DbC","Grays", + * "Sieverts","Color Temperature Degrees K","Bits","Bytes", + * "Words (data)","DoubleWords","QuadWords","Percentage"}] + * uint32 BaseUnits; + * [read] sint32 UnitModifier; + * [read] uint32 CurrentReading; + * [read] uint32 RateUnits; + * }; + * + * Effective MOF definition of old variant [1] (sans redundant info): + * + * class HPBIOS_BIOSNumericSensor { + * [read] string Name; + * [read] string Description; + * [read] uint32 SensorType; + * [read] string OtherSensorType; + * [read] uint32 OperationalStatus; + * [read] string CurrentState; + * [read] string PossibleStates[]; + * [read] uint32 BaseUnits; + * [read] sint32 UnitModifier; + * [read] uint32 CurrentReading; + * }; + */ +struct hp_wmi_numeric_sensor { + const char *name; + const char *description; + u32 sensor_type; + const char *other_sensor_type; /* Explains "Other" SensorType. */ + u32 operational_status; + u8 size; /* Count of PossibleStates[]. */ + const char **possible_states; + const char *current_state; + u32 base_units; + s32 unit_modifier; + u32 current_reading; + u32 rate_units; +}; + +/* + * struct hp_wmi_platform_events - a HPBIOS_PlatformEvents instance + * + * Instances of this object reveal the set of possible HPBIOS_BIOSEvent + * instances for the current system, but it may not always be present. + * + * Effective MOF definition: + * + * #pragma namespace("\\\\.\\root\\HP\\InstrumentedBIOS"); + * class HPBIOS_PlatformEvents { + * [read] string Name; + * [read] string Description; + * [read] string SourceNamespace; + * [read] string SourceClass; + * [read, ValueMap {"0","1","2","3","4",".."}, Values { + * "Unknown","Configuration Change","Button Pressed", + * "Sensor","BIOS Settings","Reserved"}] + * uint32 Category; + * [read, ValueMap{"0","5","10","15","20","25","30",".."}, + * Values{"Unknown","OK","Degraded/Warning","Minor Failure", + * "Major Failure","Critical Failure","Non-recoverable Error", + * "DMTF Reserved"}] + * uint32 PossibleSeverity; + * [read, ValueMap {"0","1","2","3","4","5","6","7","8","9", + * "10","11","12","13","14","15","16","17","18","..", + * "0x8000.."}, Values {"Unknown","Other","OK","Degraded", + * "Stressed","Predictive Failure","Error", + * "Non-Recoverable Error","Starting","Stopping","Stopped", + * "In Service","No Contact","Lost Communication","Aborted", + * "Dormant","Supporting Entity in Error","Completed", + * "Power Mode","DMTF Reserved","Vendor Reserved"}] + * uint32 PossibleStatus; + * }; + */ +struct hp_wmi_platform_events { + const char *name; + const char *description; + const char *source_namespace; + const char *source_class; + u32 category; + u32 possible_severity; + u32 possible_status; +}; + +/* + * struct hp_wmi_event - a HPBIOS_BIOSEvent instance + * + * Effective MOF definition [1] (corrected below from original): + * + * #pragma namespace("\\\\.\\root\\WMI"); + * class HPBIOS_BIOSEvent : WMIEvent { + * [read] string Name; + * [read] string Description; + * [read ValueMap {"0","1","2","3","4"}, Values {"Unknown", + * "Configuration Change","Button Pressed","Sensor", + * "BIOS Settings"}] + * uint32 Category; + * [read, ValueMap {"0","5","10","15","20","25","30"}, + * Values {"Unknown","OK","Degraded/Warning", + * "Minor Failure","Major Failure","Critical Failure", + * "Non-recoverable Error"}] + * uint32 Severity; + * [read, ValueMap {"0","1","2","3","4","5","6","7","8", + * "9","10","11","12","13","14","15","16","17","18","..", + * "0x8000.."}, Values {"Unknown","Other","OK","Degraded", + * "Stressed","Predictive Failure","Error", + * "Non-Recoverable Error","Starting","Stopping","Stopped", + * "In Service","No Contact","Lost Communication","Aborted", + * "Dormant","Supporting Entity in Error","Completed", + * "Power Mode","DMTF Reserved","Vendor Reserved"}] + * uint32 Status; + * }; + */ +struct hp_wmi_event { + const char *name; + const char *description; + u32 category; +}; + +/* + * struct hp_wmi_info - sensor info + * @nsensor: numeric sensor properties + * @instance: its WMI instance number + * @state: pointer to driver state + * @has_alarm: whether sensor has an alarm flag + * @alarm: alarm flag + * @type: its hwmon sensor type + * @cached_val: current sensor reading value, scaled for hwmon + * @last_updated: when these readings were last updated + */ +struct hp_wmi_info { + struct hp_wmi_numeric_sensor nsensor; + u8 instance; + void *state; /* void *: Avoid forward declaration. */ + bool has_alarm; + bool alarm; + enum hwmon_sensor_types type; + long cached_val; + unsigned long last_updated; /* In jiffies. */ + +}; + +/* + * struct hp_wmi_sensors - driver state + * @wdev: pointer to the parent WMI device + * @info_map: sensor info structs by hwmon type and channel number + * @channel_count: count of hwmon channels by hwmon type + * @has_intrusion: whether an intrusion sensor is present + * @intrusion: intrusion flag + * @lock: mutex to lock polling WMI and changes to driver state + */ +struct hp_wmi_sensors { + struct wmi_device *wdev; + struct hp_wmi_info **info_map[hwmon_max]; + u8 channel_count[hwmon_max]; + bool has_intrusion; + bool intrusion; + + struct mutex lock; /* Lock polling WMI and driver state changes. */ +}; + +/* hp_wmi_strdup - devm_kstrdup, but length-limited */ +static char *hp_wmi_strdup(struct device *dev, const char *src) +{ + char *dst; + size_t len; + + len = strnlen(src, HP_WMI_MAX_STR_SIZE - 1); + + dst = devm_kmalloc(dev, (len + 1) * sizeof(*dst), GFP_KERNEL); + if (!dst) + return NULL; + + strscpy(dst, src, len + 1); + + return dst; +} + +/* + * hp_wmi_get_wobj - poll WMI for a WMI object instance + * @guid: WMI object GUID + * @instance: WMI object instance number + * + * Returns a new WMI object instance on success, or NULL on error. + * Caller must kfree() the result. + */ +static union acpi_object *hp_wmi_get_wobj(const char *guid, u8 instance) +{ + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_status err; + + err = wmi_query_block(guid, instance, &out); + if (ACPI_FAILURE(err)) + return NULL; + + return out.pointer; +} + +/* hp_wmi_wobj_instance_count - find count of WMI object instances */ +static u8 hp_wmi_wobj_instance_count(const char *guid) +{ + u8 hi = HP_WMI_MAX_INSTANCES; + union acpi_object *wobj; + u8 lo = 0; + u8 mid; + + while (lo < hi) { + mid = (lo + hi) / 2; + + wobj = hp_wmi_get_wobj(guid, mid); + if (!wobj) { + hi = mid; + continue; + } + + lo = mid + 1; + kfree(wobj); + } + + return lo; +} + +static int check_wobj(const union acpi_object *wobj, + const acpi_object_type property_map[], int last_prop) +{ + acpi_object_type type = wobj->type; + acpi_object_type valid_type; + union acpi_object *elements; + u32 elem_count; + int prop; + + if (type != ACPI_TYPE_PACKAGE) + return -EINVAL; + + elem_count = wobj->package.count; + if (elem_count != last_prop + 1) + return -EINVAL; + + elements = wobj->package.elements; + for (prop = 0; prop <= last_prop; prop++) { + type = elements[prop].type; + valid_type = property_map[prop]; + if (type != valid_type) + return -EINVAL; + } + + return 0; +} + +static int extract_acpi_value(struct device *dev, + union acpi_object *element, + acpi_object_type type, + u32 *out_value, char **out_string) +{ + switch (type) { + case ACPI_TYPE_INTEGER: + *out_value = element->integer.value; + break; + + case ACPI_TYPE_STRING: + *out_string = hp_wmi_strdup(dev, strim(element->string.pointer)); + if (!*out_string) + return -ENOMEM; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * check_numeric_sensor_wobj - validate a HPBIOS_BIOSNumericSensor instance + * @wobj: pointer to WMI object instance to check + * @out_size: out pointer to count of possible states + * @out_is_new: out pointer to whether this is a "new" variant object + * + * Returns 0 on success, or a negative error code on error. + */ +static int check_numeric_sensor_wobj(const union acpi_object *wobj, + u8 *out_size, bool *out_is_new) +{ + acpi_object_type type = wobj->type; + int prop = HP_WMI_PROPERTY_NAME; + acpi_object_type valid_type; + union acpi_object *elements; + u32 elem_count; + int last_prop; + bool is_new; + u8 count; + u32 j; + u32 i; + + if (type != ACPI_TYPE_PACKAGE) + return -EINVAL; + + /* + * elements is a variable-length array of ACPI objects, one for + * each property of the WMI object instance, except that the + * strings in PossibleStates[] are flattened into this array + * as if each individual string were a property by itself. + */ + elements = wobj->package.elements; + + elem_count = wobj->package.count; + if (elem_count <= HP_WMI_PROPERTY_SIZE || + elem_count > HP_WMI_MAX_PROPERTIES) + return -EINVAL; + + type = elements[HP_WMI_PROPERTY_SIZE].type; + switch (type) { + case ACPI_TYPE_INTEGER: + is_new = true; + last_prop = HP_WMI_PROPERTY_RATE_UNITS; + break; + + case ACPI_TYPE_STRING: + is_new = false; + last_prop = HP_WMI_PROPERTY_CURRENT_READING; + break; + + default: + return -EINVAL; + } + + /* + * In general, the count of PossibleStates[] must be > 0. + * Also, the old variant lacks the Size property, so we may need to + * reduce the value of last_prop by 1 when doing arithmetic with it. + */ + if (elem_count < last_prop - !is_new + 1) + return -EINVAL; + + count = elem_count - (last_prop - !is_new); + + for (i = 0; i < elem_count && prop <= last_prop; i++, prop++) { + type = elements[i].type; + valid_type = hp_wmi_property_map[prop]; + if (type != valid_type) + return -EINVAL; + + switch (prop) { + case HP_WMI_PROPERTY_OPERATIONAL_STATUS: + /* Old variant: CurrentState follows OperationalStatus. */ + if (!is_new) + prop = HP_WMI_PROPERTY_CURRENT_STATE - 1; + break; + + case HP_WMI_PROPERTY_SIZE: + /* New variant: Size == count of PossibleStates[]. */ + if (count != elements[i].integer.value) + return -EINVAL; + break; + + case HP_WMI_PROPERTY_POSSIBLE_STATES: + /* PossibleStates[0] has already been type-checked. */ + for (j = 0; i + 1 < elem_count && j + 1 < count; j++) { + type = elements[++i].type; + if (type != valid_type) + return -EINVAL; + } + + /* Old variant: BaseUnits follows PossibleStates[]. */ + if (!is_new) + prop = HP_WMI_PROPERTY_BASE_UNITS - 1; + break; + + case HP_WMI_PROPERTY_CURRENT_STATE: + /* Old variant: PossibleStates[] follows CurrentState. */ + if (!is_new) + prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1; + break; + } + } + + if (prop != last_prop + 1) + return -EINVAL; + + *out_size = count; + *out_is_new = is_new; + + return 0; +} + +static int +numeric_sensor_is_connected(const struct hp_wmi_numeric_sensor *nsensor) +{ + u32 operational_status = nsensor->operational_status; + + return operational_status != HP_WMI_STATUS_NO_CONTACT; +} + +static int numeric_sensor_has_fault(const struct hp_wmi_numeric_sensor *nsensor) +{ + u32 operational_status = nsensor->operational_status; + + switch (operational_status) { + case HP_WMI_STATUS_DEGRADED: + case HP_WMI_STATUS_STRESSED: /* e.g. Overload, overtemp. */ + case HP_WMI_STATUS_PREDICTIVE_FAILURE: /* e.g. Fan removed. */ + case HP_WMI_STATUS_ERROR: + case HP_WMI_STATUS_NON_RECOVERABLE_ERROR: + case HP_WMI_STATUS_NO_CONTACT: + case HP_WMI_STATUS_LOST_COMMUNICATION: + case HP_WMI_STATUS_ABORTED: + case HP_WMI_STATUS_SUPPORTING_ENTITY_IN_ERROR: + + /* Assume combination by addition; bitwise OR doesn't make sense. */ + case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_DEGRADED: + case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_ERROR: + return true; + } + + return false; +} + +/* scale_numeric_sensor - scale sensor reading for hwmon */ +static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor) +{ + u32 current_reading = nsensor->current_reading; + s32 unit_modifier = nsensor->unit_modifier; + u32 sensor_type = nsensor->sensor_type; + u32 base_units = nsensor->base_units; + s32 target_modifier; + long val; + + /* Fan readings are in RPM units; others are in milliunits. */ + target_modifier = sensor_type == HP_WMI_TYPE_AIR_FLOW ? 0 : -3; + + val = current_reading; + + for (; unit_modifier < target_modifier; unit_modifier++) + val = DIV_ROUND_CLOSEST(val, 10); + + for (; unit_modifier > target_modifier; unit_modifier--) { + if (val > LONG_MAX / 10) { + val = LONG_MAX; + break; + } + val *= 10; + } + + if (sensor_type == HP_WMI_TYPE_TEMPERATURE) { + switch (base_units) { + case HP_WMI_UNITS_DEGREES_F: + val -= MILLI * 32; + val = val <= LONG_MAX / 5 ? + DIV_ROUND_CLOSEST(val * 5, 9) : + DIV_ROUND_CLOSEST(val, 9) * 5; + break; + + case HP_WMI_UNITS_DEGREES_K: + val = milli_kelvin_to_millicelsius(val); + break; + } + } + + return val; +} + +/* + * classify_numeric_sensor - classify a numeric sensor + * @nsensor: pointer to numeric sensor struct + * + * Returns an enum hp_wmi_type value on success, + * or a negative value if the sensor type is unsupported. + */ +static int classify_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor) +{ + u32 sensor_type = nsensor->sensor_type; + u32 base_units = nsensor->base_units; + const char *name = nsensor->name; + + switch (sensor_type) { + case HP_WMI_TYPE_TEMPERATURE: + /* + * Some systems have sensors named "X Thermal Index" in "Other" + * units. Tested CPU sensor examples were found to be in °C, + * albeit perhaps "differently" accurate; e.g. readings were + * reliably -6°C vs. coretemp on a HP Compaq Elite 8300, and + * +8°C on an EliteOne G1 800. But this is still within the + * realm of plausibility for cheaply implemented motherboard + * sensors, and chassis readings were about as expected. + */ + if ((base_units == HP_WMI_UNITS_OTHER && + strstr(name, HP_WMI_PATTERN_TEMP_SENSOR)) || + base_units == HP_WMI_UNITS_DEGREES_C || + base_units == HP_WMI_UNITS_DEGREES_F || + base_units == HP_WMI_UNITS_DEGREES_K) + return HP_WMI_TYPE_TEMPERATURE; + break; + + case HP_WMI_TYPE_VOLTAGE: + if (base_units == HP_WMI_UNITS_VOLTS) + return HP_WMI_TYPE_VOLTAGE; + break; + + case HP_WMI_TYPE_CURRENT: + if (base_units == HP_WMI_UNITS_AMPS) + return HP_WMI_TYPE_CURRENT; + break; + + case HP_WMI_TYPE_AIR_FLOW: + /* + * Strangely, HP considers fan RPM sensor type to be + * "Air Flow" instead of the more intuitive "Tachometer". + */ + if (base_units == HP_WMI_UNITS_RPM) + return HP_WMI_TYPE_AIR_FLOW; + break; + } + + return -EINVAL; +} + +static int +populate_numeric_sensor_from_wobj(struct device *dev, + struct hp_wmi_numeric_sensor *nsensor, + union acpi_object *wobj, bool *out_is_new) +{ + int last_prop = HP_WMI_PROPERTY_RATE_UNITS; + int prop = HP_WMI_PROPERTY_NAME; + const char **possible_states; + union acpi_object *element; + acpi_object_type type; + char *string; + bool is_new; + u32 value; + u8 size; + int err; + + err = check_numeric_sensor_wobj(wobj, &size, &is_new); + if (err) + return err; + + possible_states = devm_kcalloc(dev, size, sizeof(*possible_states), + GFP_KERNEL); + if (!possible_states) + return -ENOMEM; + + element = wobj->package.elements; + nsensor->possible_states = possible_states; + nsensor->size = size; + + if (!is_new) + last_prop = HP_WMI_PROPERTY_CURRENT_READING; + + for (; prop <= last_prop; prop++) { + type = hp_wmi_property_map[prop]; + + err = extract_acpi_value(dev, element, type, &value, &string); + if (err) + return err; + + element++; + + switch (prop) { + case HP_WMI_PROPERTY_NAME: + nsensor->name = string; + break; + + case HP_WMI_PROPERTY_DESCRIPTION: + nsensor->description = string; + break; + + case HP_WMI_PROPERTY_SENSOR_TYPE: + if (value > HP_WMI_TYPE_AIR_FLOW) + return -EINVAL; + + nsensor->sensor_type = value; + break; + + case HP_WMI_PROPERTY_OTHER_SENSOR_TYPE: + nsensor->other_sensor_type = string; + break; + + case HP_WMI_PROPERTY_OPERATIONAL_STATUS: + nsensor->operational_status = value; + + /* Old variant: CurrentState follows OperationalStatus. */ + if (!is_new) + prop = HP_WMI_PROPERTY_CURRENT_STATE - 1; + break; + + case HP_WMI_PROPERTY_SIZE: + break; /* Already set. */ + + case HP_WMI_PROPERTY_POSSIBLE_STATES: + *possible_states++ = string; + if (--size) + prop--; + + /* Old variant: BaseUnits follows PossibleStates[]. */ + if (!is_new && !size) + prop = HP_WMI_PROPERTY_BASE_UNITS - 1; + break; + + case HP_WMI_PROPERTY_CURRENT_STATE: + nsensor->current_state = string; + + /* Old variant: PossibleStates[] follows CurrentState. */ + if (!is_new) + prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1; + break; + + case HP_WMI_PROPERTY_BASE_UNITS: + nsensor->base_units = value; + break; + + case HP_WMI_PROPERTY_UNIT_MODIFIER: + /* UnitModifier is signed. */ + nsensor->unit_modifier = (s32)value; + break; + + case HP_WMI_PROPERTY_CURRENT_READING: + nsensor->current_reading = value; + break; + + case HP_WMI_PROPERTY_RATE_UNITS: + nsensor->rate_units = value; + break; + + default: + return -EINVAL; + } + } + + *out_is_new = is_new; + + return 0; +} + +/* update_numeric_sensor_from_wobj - update fungible sensor properties */ +static void +update_numeric_sensor_from_wobj(struct device *dev, + struct hp_wmi_numeric_sensor *nsensor, + const union acpi_object *wobj) +{ + const union acpi_object *elements; + const union acpi_object *element; + const char *string; + bool is_new; + int offset; + u8 size; + int err; + + err = check_numeric_sensor_wobj(wobj, &size, &is_new); + if (err) + return; + + elements = wobj->package.elements; + + element = &elements[HP_WMI_PROPERTY_OPERATIONAL_STATUS]; + nsensor->operational_status = element->integer.value; + + /* + * In general, an index offset is needed after PossibleStates[0]. + * On a new variant, CurrentState is after PossibleStates[]. This is + * not the case on an old variant, but we still need to offset the + * read because CurrentState is where Size would be on a new variant. + */ + offset = is_new ? size - 1 : -2; + + element = &elements[HP_WMI_PROPERTY_CURRENT_STATE + offset]; + string = strim(element->string.pointer); + + if (strcmp(string, nsensor->current_state)) { + devm_kfree(dev, nsensor->current_state); + nsensor->current_state = hp_wmi_strdup(dev, string); + } + + /* Old variant: -2 (not -1) because it lacks the Size property. */ + if (!is_new) + offset = (int)size - 2; /* size is > 0, i.e. may be 1. */ + + element = &elements[HP_WMI_PROPERTY_UNIT_MODIFIER + offset]; + nsensor->unit_modifier = (s32)element->integer.value; + + element = &elements[HP_WMI_PROPERTY_CURRENT_READING + offset]; + nsensor->current_reading = element->integer.value; +} + +/* + * check_platform_events_wobj - validate a HPBIOS_PlatformEvents instance + * @wobj: pointer to WMI object instance to check + * + * Returns 0 on success, or a negative error code on error. + */ +static int check_platform_events_wobj(const union acpi_object *wobj) +{ + return check_wobj(wobj, hp_wmi_platform_events_property_map, + HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS); +} + +static int +populate_platform_events_from_wobj(struct device *dev, + struct hp_wmi_platform_events *pevents, + union acpi_object *wobj) +{ + int last_prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS; + int prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME; + union acpi_object *element; + acpi_object_type type; + char *string; + u32 value; + int err; + + err = check_platform_events_wobj(wobj); + if (err) + return err; + + element = wobj->package.elements; + + for (; prop <= last_prop; prop++, element++) { + type = hp_wmi_platform_events_property_map[prop]; + + err = extract_acpi_value(dev, element, type, &value, &string); + if (err) + return err; + + switch (prop) { + case HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME: + pevents->name = string; + break; + + case HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION: + pevents->description = string; + break; + + case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE: + if (strcasecmp(HP_WMI_EVENT_NAMESPACE, string)) + return -EINVAL; + + pevents->source_namespace = string; + break; + + case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS: + if (strcasecmp(HP_WMI_EVENT_CLASS, string)) + return -EINVAL; + + pevents->source_class = string; + break; + + case HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY: + pevents->category = value; + break; + + case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY: + pevents->possible_severity = value; + break; + + case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS: + pevents->possible_status = value; + break; + + default: + return -EINVAL; + } + } + + return 0; +} + +/* + * check_event_wobj - validate a HPBIOS_BIOSEvent instance + * @wobj: pointer to WMI object instance to check + * + * Returns 0 on success, or a negative error code on error. + */ +static int check_event_wobj(const union acpi_object *wobj) +{ + return check_wobj(wobj, hp_wmi_event_property_map, + HP_WMI_EVENT_PROPERTY_STATUS); +} + +static int populate_event_from_wobj(struct hp_wmi_event *event, + union acpi_object *wobj) +{ + int prop = HP_WMI_EVENT_PROPERTY_NAME; + union acpi_object *element; + int err; + + err = check_event_wobj(wobj); + if (err) + return err; + + element = wobj->package.elements; + + /* Extracted strings are NOT device-managed copies. */ + + for (; prop <= HP_WMI_EVENT_PROPERTY_CATEGORY; prop++, element++) { + switch (prop) { + case HP_WMI_EVENT_PROPERTY_NAME: + event->name = strim(element->string.pointer); + break; + + case HP_WMI_EVENT_PROPERTY_DESCRIPTION: + event->description = strim(element->string.pointer); + break; + + case HP_WMI_EVENT_PROPERTY_CATEGORY: + event->category = element->integer.value; + break; + + default: + return -EINVAL; + } + } + + return 0; +} + +/* + * classify_event - classify an event + * @name: event name + * @category: event category + * + * Classify instances of both HPBIOS_PlatformEvents and HPBIOS_BIOSEvent from + * property values. Recognition criteria are based on multiple ACPI dumps [3]. + * + * Returns an enum hp_wmi_type value on success, + * or a negative value if the event type is unsupported. + */ +static int classify_event(const char *event_name, u32 category) +{ + if (category != HP_WMI_CATEGORY_SENSOR) + return -EINVAL; + + /* Fan events have Name "X Stall". */ + if (strstr(event_name, HP_WMI_PATTERN_FAN_ALARM)) + return HP_WMI_TYPE_AIR_FLOW; + + /* Intrusion events have Name "Hood Intrusion". */ + if (!strcmp(event_name, HP_WMI_PATTERN_INTRUSION_ALARM)) + return HP_WMI_TYPE_INTRUSION; + + /* + * Temperature events have Name either "Thermal Caution" or + * "Thermal Critical". Deal only with "Thermal Critical" events. + * + * "Thermal Caution" events have Status "Stressed", informing us that + * the OperationalStatus of the related sensor has become "Stressed". + * However, this is already a fault condition that will clear itself + * when the sensor recovers, so we have no further interest in them. + */ + if (!strcmp(event_name, HP_WMI_PATTERN_TEMP_ALARM)) + return HP_WMI_TYPE_TEMPERATURE; + + return -EINVAL; +} + +/* + * interpret_info - interpret sensor for hwmon + * @info: pointer to sensor info struct + * + * Should be called after the numeric sensor member has been updated. + */ +static void interpret_info(struct hp_wmi_info *info) +{ + const struct hp_wmi_numeric_sensor *nsensor = &info->nsensor; + + info->cached_val = scale_numeric_sensor(nsensor); + info->last_updated = jiffies; +} + +/* + * hp_wmi_update_info - poll WMI to update sensor info + * @state: pointer to driver state + * @info: pointer to sensor info struct + * + * Returns 0 on success, or a negative error code on error. + */ +static int hp_wmi_update_info(struct hp_wmi_sensors *state, + struct hp_wmi_info *info) +{ + struct hp_wmi_numeric_sensor *nsensor = &info->nsensor; + struct device *dev = &state->wdev->dev; + const union acpi_object *wobj; + u8 instance = info->instance; + int ret = 0; + + if (time_after(jiffies, info->last_updated + HZ)) { + mutex_lock(&state->lock); + + wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, instance); + if (!wobj) { + ret = -EIO; + goto out_unlock; + } + + update_numeric_sensor_from_wobj(dev, nsensor, wobj); + + interpret_info(info); + + kfree(wobj); + +out_unlock: + mutex_unlock(&state->lock); + } + + return ret; +} + +#if CONFIG_DEBUG_FS + +static int basic_string_show(struct seq_file *seqf, void *ignored) +{ + const char *str = seqf->private; + + seq_printf(seqf, "%s\n", str); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(basic_string); + +static int fungible_show(struct seq_file *seqf, enum hp_wmi_property prop) +{ + struct hp_wmi_numeric_sensor *nsensor; + struct hp_wmi_sensors *state; + struct hp_wmi_info *info; + int err; + + info = seqf->private; + state = info->state; + nsensor = &info->nsensor; + + err = hp_wmi_update_info(state, info); + if (err) + return err; + + switch (prop) { + case HP_WMI_PROPERTY_OPERATIONAL_STATUS: + seq_printf(seqf, "%u\n", nsensor->operational_status); + break; + + case HP_WMI_PROPERTY_CURRENT_STATE: + seq_printf(seqf, "%s\n", nsensor->current_state); + break; + + case HP_WMI_PROPERTY_UNIT_MODIFIER: + seq_printf(seqf, "%d\n", nsensor->unit_modifier); + break; + + case HP_WMI_PROPERTY_CURRENT_READING: + seq_printf(seqf, "%u\n", nsensor->current_reading); + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int operational_status_show(struct seq_file *seqf, void *ignored) +{ + return fungible_show(seqf, HP_WMI_PROPERTY_OPERATIONAL_STATUS); +} +DEFINE_SHOW_ATTRIBUTE(operational_status); + +static int current_state_show(struct seq_file *seqf, void *ignored) +{ + return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_STATE); +} +DEFINE_SHOW_ATTRIBUTE(current_state); + +static int possible_states_show(struct seq_file *seqf, void *ignored) +{ + struct hp_wmi_numeric_sensor *nsensor = seqf->private; + u8 i; + + for (i = 0; i < nsensor->size; i++) + seq_printf(seqf, "%s%s", i ? "," : "", + nsensor->possible_states[i]); + + seq_puts(seqf, "\n"); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(possible_states); + +static int unit_modifier_show(struct seq_file *seqf, void *ignored) +{ + return fungible_show(seqf, HP_WMI_PROPERTY_UNIT_MODIFIER); +} +DEFINE_SHOW_ATTRIBUTE(unit_modifier); + +static int current_reading_show(struct seq_file *seqf, void *ignored) +{ + return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_READING); +} +DEFINE_SHOW_ATTRIBUTE(current_reading); + +/* hp_wmi_devm_debugfs_remove - devm callback for debugfs cleanup */ +static void hp_wmi_devm_debugfs_remove(void *res) +{ + debugfs_remove_recursive(res); +} + +/* hp_wmi_debugfs_init - create and populate debugfs directory tree */ +static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info, + struct hp_wmi_platform_events *pevents, + u8 icount, u8 pcount, bool is_new) +{ + struct hp_wmi_numeric_sensor *nsensor; + char buf[HP_WMI_MAX_STR_SIZE]; + struct dentry *debugfs; + struct dentry *entries; + struct dentry *dir; + int err; + u8 i; + + /* dev_name() gives a not-very-friendly GUID for WMI devices. */ + scnprintf(buf, sizeof(buf), "hp-wmi-sensors-%u", dev->id); + + debugfs = debugfs_create_dir(buf, NULL); + if (IS_ERR(debugfs)) + return; + + err = devm_add_action_or_reset(dev, hp_wmi_devm_debugfs_remove, + debugfs); + if (err) + return; + + entries = debugfs_create_dir("sensor", debugfs); + + for (i = 0; i < icount; i++, info++) { + nsensor = &info->nsensor; + + scnprintf(buf, sizeof(buf), "%u", i); + dir = debugfs_create_dir(buf, entries); + + debugfs_create_file("name", 0444, dir, + (void *)nsensor->name, + &basic_string_fops); + + debugfs_create_file("description", 0444, dir, + (void *)nsensor->description, + &basic_string_fops); + + debugfs_create_u32("sensor_type", 0444, dir, + &nsensor->sensor_type); + + debugfs_create_file("other_sensor_type", 0444, dir, + (void *)nsensor->other_sensor_type, + &basic_string_fops); + + debugfs_create_file("operational_status", 0444, dir, + info, &operational_status_fops); + + debugfs_create_file("possible_states", 0444, dir, + nsensor, &possible_states_fops); + + debugfs_create_file("current_state", 0444, dir, + info, ¤t_state_fops); + + debugfs_create_u32("base_units", 0444, dir, + &nsensor->base_units); + + debugfs_create_file("unit_modifier", 0444, dir, + info, &unit_modifier_fops); + + debugfs_create_file("current_reading", 0444, dir, + info, ¤t_reading_fops); + + if (is_new) + debugfs_create_u32("rate_units", 0444, dir, + &nsensor->rate_units); + } + + if (!pcount) + return; + + entries = debugfs_create_dir("platform_events", debugfs); + + for (i = 0; i < pcount; i++, pevents++) { + scnprintf(buf, sizeof(buf), "%u", i); + dir = debugfs_create_dir(buf, entries); + + debugfs_create_file("name", 0444, dir, + (void *)pevents->name, + &basic_string_fops); + + debugfs_create_file("description", 0444, dir, + (void *)pevents->description, + &basic_string_fops); + + debugfs_create_file("source_namespace", 0444, dir, + (void *)pevents->source_namespace, + &basic_string_fops); + + debugfs_create_file("source_class", 0444, dir, + (void *)pevents->source_class, + &basic_string_fops); + + debugfs_create_u32("category", 0444, dir, + &pevents->category); + + debugfs_create_u32("possible_severity", 0444, dir, + &pevents->possible_severity); + + debugfs_create_u32("possible_status", 0444, dir, + &pevents->possible_status); + } +} + +#else + +static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info, + struct hp_wmi_platform_events *pevents, + u8 icount, u8 pcount, bool is_new) +{ +} + +#endif + +static umode_t hp_wmi_hwmon_is_visible(const void *drvdata, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct hp_wmi_sensors *state = drvdata; + const struct hp_wmi_info *info; + + if (type == hwmon_intrusion) + return state->has_intrusion ? 0644 : 0; + + if (!state->info_map[type] || !state->info_map[type][channel]) + return 0; + + info = state->info_map[type][channel]; + + if ((type == hwmon_temp && attr == hwmon_temp_alarm) || + (type == hwmon_fan && attr == hwmon_fan_alarm)) + return info->has_alarm ? 0444 : 0; + + return 0444; +} + +static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *out_val) +{ + struct hp_wmi_sensors *state = dev_get_drvdata(dev); + const struct hp_wmi_numeric_sensor *nsensor; + struct hp_wmi_info *info; + int err; + + if (type == hwmon_intrusion) { + *out_val = state->intrusion ? 1 : 0; + + return 0; + } + + info = state->info_map[type][channel]; + + if ((type == hwmon_temp && attr == hwmon_temp_alarm) || + (type == hwmon_fan && attr == hwmon_fan_alarm)) { + *out_val = info->alarm ? 1 : 0; + info->alarm = false; + + return 0; + } + + nsensor = &info->nsensor; + + err = hp_wmi_update_info(state, info); + if (err) + return err; + + if ((type == hwmon_temp && attr == hwmon_temp_fault) || + (type == hwmon_fan && attr == hwmon_fan_fault)) + *out_val = numeric_sensor_has_fault(nsensor); + else + *out_val = info->cached_val; + + return 0; +} + +static int hp_wmi_hwmon_read_string(struct device *dev, + enum hwmon_sensor_types type, u32 attr, + int channel, const char **out_str) +{ + const struct hp_wmi_sensors *state = dev_get_drvdata(dev); + const struct hp_wmi_info *info; + + info = state->info_map[type][channel]; + *out_str = info->nsensor.name; + + return 0; +} + +static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct hp_wmi_sensors *state = dev_get_drvdata(dev); + + if (val) + return -EINVAL; + + mutex_lock(&state->lock); + + state->intrusion = false; + + mutex_unlock(&state->lock); + + return 0; +} + +static const struct hwmon_ops hp_wmi_hwmon_ops = { + .is_visible = hp_wmi_hwmon_is_visible, + .read = hp_wmi_hwmon_read, + .read_string = hp_wmi_hwmon_read_string, + .write = hp_wmi_hwmon_write, +}; + +static struct hwmon_chip_info hp_wmi_chip_info = { + .ops = &hp_wmi_hwmon_ops, + .info = NULL, +}; + +static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state, + const char *event_description) +{ + struct hp_wmi_info **ptr_info = state->info_map[hwmon_fan]; + u8 fan_count = state->channel_count[hwmon_fan]; + struct hp_wmi_info *info; + const char *name; + u8 i; + + /* Fan event has Description "X Speed". Sensor has Name "X[ Speed]". */ + + for (i = 0; i < fan_count; i++, ptr_info++) { + info = *ptr_info; + name = info->nsensor.name; + + if (strstr(event_description, name)) + return info; + } + + return NULL; +} + +static u8 match_temp_events(struct hp_wmi_sensors *state, + const char *event_description, + struct hp_wmi_info *temp_info[]) +{ + struct hp_wmi_info **ptr_info = state->info_map[hwmon_temp]; + u8 temp_count = state->channel_count[hwmon_temp]; + struct hp_wmi_info *info; + const char *name; + u8 count = 0; + bool is_cpu; + bool is_sys; + u8 i; + + /* Description is either "CPU Thermal Index" or "Chassis Thermal Index". */ + + is_cpu = !strcmp(event_description, HP_WMI_PATTERN_CPU_TEMP); + is_sys = !strcmp(event_description, HP_WMI_PATTERN_SYS_TEMP); + if (!is_cpu && !is_sys) + return 0; + + /* + * CPU event: Match one sensor with Name either "CPU Thermal Index" or + * "CPU Temperature", or multiple with Name(s) "CPU[#] Temperature". + * + * Chassis event: Match one sensor with Name either + * "Chassis Thermal Index" or "System Ambient Temperature". + */ + + for (i = 0; i < temp_count; i++, ptr_info++) { + info = *ptr_info; + name = info->nsensor.name; + + if ((is_cpu && (!strcmp(name, HP_WMI_PATTERN_CPU_TEMP) || + !strcmp(name, HP_WMI_PATTERN_CPU_TEMP2))) || + (is_sys && (!strcmp(name, HP_WMI_PATTERN_SYS_TEMP) || + !strcmp(name, HP_WMI_PATTERN_SYS_TEMP2)))) { + temp_info[0] = info; + return 1; + } + + if (is_cpu && (strstr(name, HP_WMI_PATTERN_CPU) && + strstr(name, HP_WMI_PATTERN_TEMP))) + temp_info[count++] = info; + } + + return count; +} + +/* hp_wmi_devm_debugfs_remove - devm callback for WMI event handler removal */ +static void hp_wmi_devm_notify_remove(void *ignored) +{ + wmi_remove_notify_handler(HP_WMI_EVENT_GUID); +} + +/* hp_wmi_notify - WMI event notification handler */ +static void hp_wmi_notify(u32 value, void *context) +{ + struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {}; + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + struct hp_wmi_sensors *state = context; + struct device *dev = &state->wdev->dev; + struct hp_wmi_info *fan_info; + struct hp_wmi_event event; + union acpi_object *wobj; + acpi_status err; + int event_type; + u8 count; + + /* + * The following warning may occur in the kernel log: + * + * ACPI Warning: \_SB.WMID._WED: Return type mismatch - + * found Package, expected Integer/String/Buffer + * + * After using [4] to decode BMOF blobs found in [3], careless copying + * of BIOS code seems the most likely explanation for this warning. + * HP_WMI_EVENT_GUID refers to \\.\root\WMI\HPBIOS_BIOSEvent on + * business-class systems, but it refers to \\.\root\WMI\hpqBEvnt on + * non-business-class systems. Per the existing hp-wmi driver, it + * looks like an instance of hpqBEvnt delivered as event data may + * indeed take the form of a raw ACPI_BUFFER on non-business-class + * systems ("may" because ASL shows some BIOSes do strange things). + * + * In any case, we can ignore this warning, because we always validate + * the event data to ensure it is an ACPI_PACKAGE containing a + * HPBIOS_BIOSEvent instance. + */ + + mutex_lock(&state->lock); + + err = wmi_get_event_data(value, &out); + if (ACPI_FAILURE(err)) + goto out_unlock; + + wobj = out.pointer; + + err = populate_event_from_wobj(&event, wobj); + if (err) { + dev_warn(dev, "Bad event data (ACPI type %d)\n", wobj->type); + goto out_free_wobj; + } + + event_type = classify_event(event.name, event.category); + switch (event_type) { + case HP_WMI_TYPE_AIR_FLOW: + fan_info = match_fan_event(state, event.description); + if (fan_info) + fan_info->alarm = true; + break; + + case HP_WMI_TYPE_INTRUSION: + state->intrusion = true; + break; + + case HP_WMI_TYPE_TEMPERATURE: + count = match_temp_events(state, event.description, temp_info); + while (count) + temp_info[--count]->alarm = true; + break; + + default: + break; + } + +out_free_wobj: + kfree(wobj); + +out_unlock: + mutex_unlock(&state->lock); +} + +static int init_platform_events(struct device *dev, + struct hp_wmi_platform_events **out_pevents, + u8 *out_pcount) +{ + struct hp_wmi_platform_events *pevents_arr; + struct hp_wmi_platform_events *pevents; + union acpi_object *wobj; + u8 count; + int err; + u8 i; + + count = hp_wmi_wobj_instance_count(HP_WMI_PLATFORM_EVENTS_GUID); + if (!count) { + *out_pcount = 0; + + dev_dbg(dev, "No platform events\n"); + + return 0; + } + + pevents_arr = devm_kcalloc(dev, count, sizeof(*pevents), GFP_KERNEL); + if (!pevents_arr) + return -ENOMEM; + + for (i = 0, pevents = pevents_arr; i < count; i++, pevents++) { + wobj = hp_wmi_get_wobj(HP_WMI_PLATFORM_EVENTS_GUID, i); + if (!wobj) + return -EIO; + + err = populate_platform_events_from_wobj(dev, pevents, wobj); + + kfree(wobj); + + if (err) + return err; + } + + *out_pevents = pevents_arr; + *out_pcount = count; + + dev_dbg(dev, "Found %u platform events\n", count); + + return 0; +} + +static int init_numeric_sensors(struct hp_wmi_sensors *state, + struct hp_wmi_info *connected[], + struct hp_wmi_info **out_info, + u8 *out_icount, u8 *out_count, + bool *out_is_new) +{ + struct hp_wmi_info ***info_map = state->info_map; + u8 *channel_count = state->channel_count; + struct device *dev = &state->wdev->dev; + struct hp_wmi_numeric_sensor *nsensor; + u8 channel_index[hwmon_max] = {}; + enum hwmon_sensor_types type; + struct hp_wmi_info *info_arr; + struct hp_wmi_info *info; + union acpi_object *wobj; + u8 count = 0; + bool is_new; + u8 icount; + int wtype; + int err; + u8 c; + u8 i; + + icount = hp_wmi_wobj_instance_count(HP_WMI_NUMERIC_SENSOR_GUID); + if (!icount) + return -ENODATA; + + info_arr = devm_kcalloc(dev, icount, sizeof(*info), GFP_KERNEL); + if (!info_arr) + return -ENOMEM; + + for (i = 0, info = info_arr; i < icount; i++, info++) { + wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, i); + if (!wobj) + return -EIO; + + info->instance = i; + info->state = state; + nsensor = &info->nsensor; + + err = populate_numeric_sensor_from_wobj(dev, nsensor, wobj, + &is_new); + + kfree(wobj); + + if (err) + return err; + + if (!numeric_sensor_is_connected(nsensor)) + continue; + + wtype = classify_numeric_sensor(nsensor); + if (wtype < 0) + continue; + + type = hp_wmi_hwmon_type_map[wtype]; + + channel_count[type]++; + + info->type = type; + + interpret_info(info); + + connected[count++] = info; + } + + dev_dbg(dev, "Found %u sensors (%u connected)\n", i, count); + + for (i = 0; i < count; i++) { + info = connected[i]; + type = info->type; + c = channel_index[type]++; + + if (!info_map[type]) { + info_map[type] = devm_kcalloc(dev, channel_count[type], + sizeof(*info_map), + GFP_KERNEL); + if (!info_map[type]) + return -ENOMEM; + } + + info_map[type][c] = info; + } + + *out_info = info_arr; + *out_icount = icount; + *out_count = count; + *out_is_new = is_new; + + return 0; +} + +static bool find_event_attributes(struct hp_wmi_sensors *state, + struct hp_wmi_platform_events *pevents, + u8 pevents_count) +{ + /* + * The existence of this HPBIOS_PlatformEvents instance: + * + * { + * Name = "Rear Chassis Fan0 Stall"; + * Description = "Rear Chassis Fan0 Speed"; + * Category = 3; // "Sensor" + * PossibleSeverity = 25; // "Critical Failure" + * PossibleStatus = 5; // "Predictive Failure" + * [...] + * } + * + * means that this HPBIOS_BIOSEvent instance may occur: + * + * { + * Name = "Rear Chassis Fan0 Stall"; + * Description = "Rear Chassis Fan0 Speed"; + * Category = 3; // "Sensor" + * Severity = 25; // "Critical Failure" + * Status = 5; // "Predictive Failure" + * } + * + * After the event occurs (e.g. because the fan was unplugged), + * polling the related HPBIOS_BIOSNumericSensor instance gives: + * + * { + * Name = "Rear Chassis Fan0"; + * Description = "Reports rear chassis fan0 speed"; + * OperationalStatus = 5; // "Predictive Failure", was 3 ("OK") + * CurrentReading = 0; + * [...] + * } + * + * In this example, the hwmon fan channel for "Rear Chassis Fan0" + * should support the alarm flag and have it be set if the related + * HPBIOS_BIOSEvent instance occurs. + * + * In addition to fan events, temperature (CPU/chassis) and intrusion + * events are relevant to hwmon [2]. Note that much information in [2] + * is unreliable; it is referenced in addition to ACPI dumps [3] merely + * to support the conclusion that sensor and event names/descriptions + * are systematic enough to allow this driver to match them. + * + * Complications and limitations: + * + * - Strings are freeform and may vary, cf. sensor Name "CPU0 Fan" + * on a Z420 vs. "CPU Fan Speed" on an EliteOne 800 G1. + * - Leading/trailing whitespace is a rare but real possibility [3]. + * - The HPBIOS_PlatformEvents object may not exist or its instances + * may show that the system only has e.g. BIOS setting-related + * events (cf. the ProBook 4540s and ProBook 470 G0 [3]). + */ + + struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {}; + const char *event_description; + struct hp_wmi_info *fan_info; + bool has_events = false; + const char *event_name; + u32 event_category; + int event_type; + u8 count; + u8 i; + + for (i = 0; i < pevents_count; i++, pevents++) { + event_name = pevents->name; + event_description = pevents->description; + event_category = pevents->category; + + event_type = classify_event(event_name, event_category); + switch (event_type) { + case HP_WMI_TYPE_AIR_FLOW: + fan_info = match_fan_event(state, event_description); + if (!fan_info) + break; + + fan_info->has_alarm = true; + has_events = true; + break; + + case HP_WMI_TYPE_INTRUSION: + state->has_intrusion = true; + has_events = true; + break; + + case HP_WMI_TYPE_TEMPERATURE: + count = match_temp_events(state, event_description, + temp_info); + if (!count) + break; + + while (count) + temp_info[--count]->has_alarm = true; + has_events = true; + break; + + default: + break; + } + } + + return has_events; +} + +static int make_chip_info(struct hp_wmi_sensors *state, bool has_events) +{ + const struct hwmon_channel_info **ptr_channel_info; + struct hp_wmi_info ***info_map = state->info_map; + u8 *channel_count = state->channel_count; + struct hwmon_channel_info *channel_info; + struct device *dev = &state->wdev->dev; + enum hwmon_sensor_types type; + u8 type_count = 0; + u32 *config; + u32 attr; + u8 count; + u8 i; + + if (channel_count[hwmon_temp]) + channel_count[hwmon_chip] = 1; + + if (has_events && state->has_intrusion) + channel_count[hwmon_intrusion] = 1; + + for (type = hwmon_chip; type < hwmon_max; type++) + if (channel_count[type]) + type_count++; + + channel_info = devm_kcalloc(dev, type_count, + sizeof(*channel_info), GFP_KERNEL); + if (!channel_info) + return -ENOMEM; + + ptr_channel_info = devm_kcalloc(dev, type_count + 1, + sizeof(*ptr_channel_info), GFP_KERNEL); + if (!ptr_channel_info) + return -ENOMEM; + + hp_wmi_chip_info.info = ptr_channel_info; + + for (type = hwmon_chip; type < hwmon_max; type++) { + count = channel_count[type]; + if (!count) + continue; + + config = devm_kcalloc(dev, count + 1, + sizeof(*config), GFP_KERNEL); + if (!config) + return -ENOMEM; + + attr = hp_wmi_hwmon_attributes[type]; + channel_info->type = type; + channel_info->config = config; + memset32(config, attr, count); + + *ptr_channel_info++ = channel_info++; + + if (!has_events || (type != hwmon_temp && type != hwmon_fan)) + continue; + + attr = type == hwmon_temp ? HWMON_T_ALARM : HWMON_F_ALARM; + + for (i = 0; i < count; i++) + if (info_map[type][i]->has_alarm) + config[i] |= attr; + } + + return 0; +} + +static bool add_event_handler(struct hp_wmi_sensors *state) +{ + struct device *dev = &state->wdev->dev; + int err; + + err = wmi_install_notify_handler(HP_WMI_EVENT_GUID, + hp_wmi_notify, state); + if (err) { + dev_info(dev, "Failed to subscribe to WMI event\n"); + return false; + } + + err = devm_add_action_or_reset(dev, hp_wmi_devm_notify_remove, NULL); + if (err) + return false; + + return true; +} + +static int hp_wmi_sensors_init(struct hp_wmi_sensors *state) +{ + struct hp_wmi_info *connected[HP_WMI_MAX_INSTANCES]; + struct hp_wmi_platform_events *pevents; + struct device *dev = &state->wdev->dev; + struct hp_wmi_info *info; + struct device *hwdev; + bool has_events; + bool is_new; + u8 icount; + u8 pcount; + u8 count; + int err; + + err = init_platform_events(dev, &pevents, &pcount); + if (err) + return err; + + err = init_numeric_sensors(state, connected, &info, + &icount, &count, &is_new); + if (err) + return err; + + hp_wmi_debugfs_init(dev, info, pevents, icount, pcount, is_new); + + if (!count) + return 0; /* No connected sensors; debugfs only. */ + + has_events = find_event_attributes(state, pevents, pcount); + + /* Survive failure to install WMI event handler. */ + if (has_events && !add_event_handler(state)) + has_events = false; + + err = make_chip_info(state, has_events); + if (err) + return err; + + hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors", + state, &hp_wmi_chip_info, + NULL); + return PTR_ERR_OR_ZERO(hwdev); +} + +static int hp_wmi_sensors_probe(struct wmi_device *wdev, const void *context) +{ + struct device *dev = &wdev->dev; + struct hp_wmi_sensors *state; + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->wdev = wdev; + + mutex_init(&state->lock); + + dev_set_drvdata(dev, state); + + return hp_wmi_sensors_init(state); +} + +static const struct wmi_device_id hp_wmi_sensors_id_table[] = { + { HP_WMI_NUMERIC_SENSOR_GUID, NULL }, + {}, +}; + +static struct wmi_driver hp_wmi_sensors_driver = { + .driver = { .name = "hp-wmi-sensors" }, + .id_table = hp_wmi_sensors_id_table, + .probe = hp_wmi_sensors_probe, +}; +module_wmi_driver(hp_wmi_sensors_driver); + +MODULE_AUTHOR("James Seo "); +MODULE_DESCRIPTION("HP WMI Sensors driver"); +MODULE_LICENSE("GPL"); From 153c9a023b1f455887a3fb7913207794eee3c6c2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 1 Jun 2023 23:31:54 +0200 Subject: [PATCH 27/54] hwmon: (hp-wmi-sensors) fix debugfs check Checking for Kconfig symbols with #if is wrong: drivers/hwmon/hp-wmi-sensors.c:1141:5: error: "CONFIG_DEBUG_FS" is not defined, evaluates to 0 [-Werror=undef] This could be an #ifdef, but an IS_ENABLED() check is even better to give the best compile coverage. Fixes: 23902f98f8d4 ("hwmon: add HP WMI Sensors driver") Signed-off-by: Arnd Bergmann Acked-by: James Seo Link: https://lore.kernel.org/r/20230601213216.3220550-1-arnd@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/hp-wmi-sensors.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c index 7218945bd03f..ebe2fb513480 100644 --- a/drivers/hwmon/hp-wmi-sensors.c +++ b/drivers/hwmon/hp-wmi-sensors.c @@ -1138,8 +1138,6 @@ out_unlock: return ret; } -#if CONFIG_DEBUG_FS - static int basic_string_show(struct seq_file *seqf, void *ignored) { const char *str = seqf->private; @@ -1341,16 +1339,6 @@ static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info, } } -#else - -static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info, - struct hp_wmi_platform_events *pevents, - u8 icount, u8 pcount, bool is_new) -{ -} - -#endif - static umode_t hp_wmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int channel) @@ -1959,7 +1947,8 @@ static int hp_wmi_sensors_init(struct hp_wmi_sensors *state) if (err) return err; - hp_wmi_debugfs_init(dev, info, pevents, icount, pcount, is_new); + if (IS_ENABLED(CONFIG_DEBUG_FS)) + hp_wmi_debugfs_init(dev, info, pevents, icount, pcount, is_new); if (!count) return 0; /* No connected sensors; debugfs only. */ From ca866920b0f35350b8b2bf9c7323051649a75bee Mon Sep 17 00:00:00 2001 From: Osama Muhammad Date: Fri, 26 May 2023 20:49:06 +0500 Subject: [PATCH 28/54] hwmon: (pmbus/ucd9000) Drop unnecessary error check for debugfs_create_dir This patch removes the error checking for debugfs_create_dir in ucd9000.c. This is because the debugfs_create_dir() does not return NULL but an ERR_PTR after an error. The DebugFS kernel API is developed in a way that the caller can safely ignore the errors that occur during the creation of DebugFS nodes.The debugfs Api handles it gracefully. The check is unnecessary. Link to the comment above debugfs_create_dir: https://elixir.bootlin.com/linux/latest/source/fs/debugfs/inode.c#L565 Signed-off-by: Osama Muhammad Link: https://lore.kernel.org/r/20230526154906.6370-1-osmtendev@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ucd9000.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index ba712ff7666f..c404d306e8f7 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -512,8 +512,6 @@ static int ucd9000_init_debugfs(struct i2c_client *client, return -ENOENT; data->debugfs = debugfs_create_dir(client->name, debugfs); - if (!data->debugfs) - return -ENOENT; /* * Of the chips this driver supports, only the UCD9090, UCD90160, From a1b6f13578e15e09fdaee5d90f05de04b59240bd Mon Sep 17 00:00:00 2001 From: Osama Muhammad Date: Fri, 26 May 2023 21:39:38 +0500 Subject: [PATCH 29/54] hwmon: (pmbus/adm1266) Drop unnecessary error check for debugfs_create_dir This patch removes the error checking for debugfs_create_dir in adm1266.c. This is because the debugfs_create_dir() does not return NULL but an ERR_PTR after an error. The DebugFS kernel API is developed in a way that the caller can safely ignore the errors that occur during the creation of DebugFS nodes.The debugfs Api handles it gracefully. The check is unnecessary. Link to the comment above debugfs_create_dir: https://elixir.bootlin.com/linux/latest/source/fs/debugfs/inode.c#L565 Signed-off-by: Osama Muhammad Link: https://lore.kernel.org/r/20230526163938.9903-1-osmtendev@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1266.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index aba70330b319..ed0a7b9fae4b 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -340,8 +340,6 @@ static void adm1266_init_debugfs(struct adm1266_data *data) return; data->debugfs_dir = debugfs_create_dir(data->client->name, root); - if (!data->debugfs_dir) - return; debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir, adm1266_state_read); From 317840cfd665d69a728424d1a85b80264442357f Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 27 May 2023 19:47:56 +1000 Subject: [PATCH 30/54] hwmon: (it87) Generalise support for FAN_CTL ON/OFF Support for FAN_CTL ON/OFF is currently disabled only for IT8603E but there are severl chips that don't support the configuration bits to turn off fan control entirely. Generalise this support for any chip. Add feature flag FEAT_FANCTL_ONOFF for chips that support configuration bits for management of fan control off and assign all chips that support the configuration. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230527094756.3464256-1-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 63 ++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 4c3641d28a6a..5deff5e5f693 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -320,31 +320,34 @@ struct it87_devices { #define FEAT_FOUR_FANS BIT(20) /* Supports four fans */ #define FEAT_FOUR_PWM BIT(21) /* Supports four fan controls */ #define FEAT_FOUR_TEMP BIT(22) +#define FEAT_FANCTL_ONOFF BIT(23) /* chip has FAN_CTL ON/OFF */ static const struct it87_devices it87_devices[] = { [it87] = { .name = "it87", .model = "IT87F", - .features = FEAT_OLD_AUTOPWM, /* may need to overwrite */ + .features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF, + /* may need to overwrite */ }, [it8712] = { .name = "it8712", .model = "IT8712F", - .features = FEAT_OLD_AUTOPWM | FEAT_VID, - /* may need to overwrite */ + .features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF, + /* may need to overwrite */ }, [it8716] = { .name = "it8716", .model = "IT8716F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID - | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2, + | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, }, [it8718] = { .name = "it8718", .model = "IT8718F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8720] = { @@ -352,7 +355,7 @@ static const struct it87_devices it87_devices[] = { .model = "IT8720F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8721] = { @@ -361,7 +364,7 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .peci_mask = 0x05, .old_peci_mask = 0x02, /* Actually reports PCH */ }, @@ -370,7 +373,8 @@ static const struct it87_devices it87_devices[] = { .model = "IT8728F", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS - | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2, + | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it8732] = { @@ -379,7 +383,7 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS - | FEAT_FOUR_PWM, + | FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, .old_peci_mask = 0x02, /* Actually reports PCH */ }, @@ -388,7 +392,7 @@ static const struct it87_devices it87_devices[] = { .model = "IT8771E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, /* PECI: guesswork */ /* 12mV ADC (OHM) */ /* 16 bit fans (OHM) */ @@ -400,7 +404,7 @@ static const struct it87_devices it87_devices[] = { .model = "IT8772E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, /* PECI (coreboot) */ /* 12mV ADC (HWSensors4, OHM) */ /* 16 bit fans (HWSensors4, OHM) */ @@ -411,21 +415,24 @@ static const struct it87_devices it87_devices[] = { .name = "it8781", .model = "IT8781F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET - | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8782] = { .name = "it8782", .model = "IT8782F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET - | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8783] = { .name = "it8783", .model = "IT8783E/F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET - | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2 + | FEAT_FANCTL_ONOFF, .old_peci_mask = 0x4, }, [it8786] = { @@ -433,7 +440,7 @@ static const struct it87_devices it87_devices[] = { .model = "IT8786E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL - | FEAT_PWM_FREQ2, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it8790] = { @@ -441,7 +448,7 @@ static const struct it87_devices it87_devices[] = { .model = "IT8790E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL - | FEAT_PWM_FREQ2 | FEAT_CONF_NOEXIT, + | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_CONF_NOEXIT, .peci_mask = 0x07, }, [it8792] = { @@ -449,7 +456,8 @@ static const struct it87_devices it87_devices[] = { .model = "IT8792E/IT8795E", .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI - | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT, + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF + | FEAT_CONF_NOEXIT, .peci_mask = 0x07, .old_peci_mask = 0x02, /* Actually reports PCH */ }, @@ -467,7 +475,7 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 - | FEAT_SIX_TEMP | FEAT_VIN3_5V, + | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it8622] = { @@ -486,7 +494,7 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 - | FEAT_SIX_TEMP | FEAT_VIN3_5V, + | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF, .peci_mask = 0x07, }, [it87952] = { @@ -494,7 +502,8 @@ static const struct it87_devices it87_devices[] = { .model = "IT87952E", .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI - | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT, + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF + | FEAT_CONF_NOEXIT, .peci_mask = 0x07, .old_peci_mask = 0x02, /* Actually reports PCH */ }, @@ -534,6 +543,7 @@ static const struct it87_devices it87_devices[] = { #define has_conf_noexit(data) ((data)->features & FEAT_CONF_NOEXIT) #define has_scaling(data) ((data)->features & (FEAT_12MV_ADC | \ FEAT_10_9MV_ADC)) +#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF) struct it87_sio_data { int sioaddr; @@ -1240,11 +1250,12 @@ static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type, static int pwm_mode(const struct it87_data *data, int nr) { - if (data->type != it8603 && nr < 3 && !(data->fan_main_ctrl & BIT(nr))) - return 0; /* Full speed */ + if (has_fanctl_onoff(data) && nr < 3 && + !(data->fan_main_ctrl & BIT(nr))) + return 0; /* Full speed */ if (data->pwm_ctrl[nr] & 0x80) - return 2; /* Automatic mode */ - if ((data->type == it8603 || nr >= 3) && + return 2; /* Automatic mode */ + if ((!has_fanctl_onoff(data) || nr >= 3) && data->pwm_duty[nr] == pwm_to_reg(data, 0xff)) return 0; /* Full speed */ @@ -1481,7 +1492,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, return err; if (val == 0) { - if (nr < 3 && data->type != it8603) { + if (nr < 3 && has_fanctl_onoff(data)) { int tmp; /* make sure the fan is on when in on/off mode */ tmp = it87_read_value(data, IT87_REG_FAN_CTL); @@ -1521,7 +1532,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, data->pwm_ctrl[nr] = ctrl; it87_write_value(data, IT87_REG_PWM[nr], ctrl); - if (data->type != it8603 && nr < 3) { + if (has_fanctl_onoff(data) && nr < 3) { /* set SmartGuardian mode */ data->fan_main_ctrl |= BIT(nr); it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, From 30841ce37321fa66c58ee79ec7b17a45df2a6b9e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 10 Jun 2023 14:59:07 +0100 Subject: [PATCH 31/54] hwmon: (lm75) Use maple tree register cache The lm75 is only capable of performing single register read and write operations which means it gains no advantage from using a rbtree register cache, convert it to using the more modern maple tree register cache instead. This should be more efficient. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230609-hwmon-maple-v1-1-8edacce86b28@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/lm75.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 182aeb388523..72e634d1b857 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -548,7 +548,7 @@ static const struct regmap_config lm75_regmap_config = { .writeable_reg = lm75_is_writeable_reg, .volatile_reg = lm75_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_read = true, .use_single_write = true, }; From 6ef3811c40eb24c061cfd8ba445bccb4ac46ca98 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 10 Jun 2023 14:59:08 +0100 Subject: [PATCH 32/54] hwmon: (lm95245) Use maple tree register cache The lm95245 is only capable of performing single register read and write operations which means it gains no advantage from using a rbtree register cache, convert it to using the more modern maple tree register cache instead. This should be more efficient. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230609-hwmon-maple-v1-2-8edacce86b28@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/lm95245.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 7f13b6b712fb..17ff54bd4015 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -518,7 +518,7 @@ static const struct regmap_config lm95245_regmap_config = { .val_bits = 8, .writeable_reg = lm95245_is_writeable_reg, .volatile_reg = lm95245_is_volatile_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_read = true, .use_single_write = true, }; From 729f1f738a76accdd9dca4d0eaeba4b263bdee60 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 10 Jun 2023 14:59:09 +0100 Subject: [PATCH 33/54] hwmon: (tmp102) Use maple tree register cache The tmp102 is only capable of performing single register read and write operations which means it gains no advantage from using a rbtree register cache, convert it to using the more modern maple tree register cache instead. This should be more efficient. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230609-hwmon-maple-v1-3-8edacce86b28@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp102.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 6359d12b2420..2506c78590af 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -184,7 +184,7 @@ static const struct regmap_config tmp102_regmap_config = { .writeable_reg = tmp102_is_writeable_reg, .volatile_reg = tmp102_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_read = true, .use_single_write = true, }; From e68953fcc69e08bdefab700e876f13f671881ad8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 10 Jun 2023 14:59:10 +0100 Subject: [PATCH 34/54] hwmon: (tmp108) Use maple tree register cache The tmp108 is only capable of performing single register read and write operations which means it gains no advantage from using a rbtree register cache, convert it to using the more modern maple tree register cache instead. This should be more efficient. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230609-hwmon-maple-v1-4-8edacce86b28@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp108.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 300b24d5586b..d7a09ab2bc11 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -318,7 +318,7 @@ static const struct regmap_config tmp108_regmap_config = { .writeable_reg = tmp108_is_writeable_reg, .volatile_reg = tmp108_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_read = true, .use_single_write = true, }; From 7357b1876b212742a5bec59786d660cfcf66defb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 10 Jun 2023 14:59:11 +0100 Subject: [PATCH 35/54] hwmon: (tmp464) Use maple tree register cache The tmp464 is only capable of performing single register read and write operations which means it gains no advantage from using a rbtree register cache, convert it to using the more modern maple tree register cache instead. This should be more efficient. Signed-off-by: Mark Brown Link: https://lore.kernel.org/r/20230609-hwmon-maple-v1-5-8edacce86b28@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp464.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c index 8a88032d8e9d..4b79c3f4d9fe 100644 --- a/drivers/hwmon/tmp464.c +++ b/drivers/hwmon/tmp464.c @@ -644,7 +644,7 @@ static const struct regmap_config tmp464_regmap_config = { .max_register = TMP464_DEVICE_ID_REG, .volatile_reg = tmp464_is_volatile_reg, .val_format_endian = REGMAP_ENDIAN_BIG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .use_single_read = true, .use_single_write = true, }; From 5e28d5e4b8bbc94526e66e808ef0ba1b91b72b3e Mon Sep 17 00:00:00 2001 From: Yongsheng Yang Date: Fri, 9 Jun 2023 11:55:10 +0400 Subject: [PATCH 36/54] Documentation/hwmon: Fix description of devm_hwmon_device_unregister() Use devm_hwmon_device_register_with_info to replace hwmon_device_register_with_info in description of devm_hwmon_device_unregister. Signed-off-by: Yongsheng Yang Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20230609075510.1305-1-iyysheng@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/hwmon-kernel-api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst index c2d1e0299d8d..6cacf7daf25c 100644 --- a/Documentation/hwmon/hwmon-kernel-api.rst +++ b/Documentation/hwmon/hwmon-kernel-api.rst @@ -66,7 +66,7 @@ hwmon_device_register_with_info. devm_hwmon_device_unregister does not normally have to be called. It is only needed for error handling, and only needed if the driver probe fails after -the call to hwmon_device_register_with_info and if the automatic (device +the call to devm_hwmon_device_register_with_info and if the automatic (device managed) removal would be too late. All supported hwmon device registration functions only accept valid device From 450d1a8ce1e5f1cadd402ae62013afff50a5cc9c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 9 Jun 2023 11:24:47 -0700 Subject: [PATCH 37/54] hwmon: (pmbus/max16601) Add support for new revisions of MAX16508 New revisions of MAX16508 report MAX16508.xx or MAX16508y.xx as device ID, but are functionally similar to MAX16508. Add support for those chip variants. Cc: Vlad Sytchenko Cc: Steve Foreman Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/max16601.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 9b0177409109..3ab219504600 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -283,10 +283,10 @@ static int max16601_get_id(struct i2c_client *client) return -ENODEV; /* - * PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx" or - * "MAX16500y.xx".cdxxcccccccccc + * PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx", + * "MAX16500y.xx".cdxxcccccccccc, or "MAX16508y.xx". */ - if (!strncmp(buf, "MAX16500", 8)) { + if (!strncmp(buf, "MAX16500", 8) || !strncmp(buf, "MAX16508", 8)) { id = max16508; } else if (!strncmp(buf, "MAX16600", 8)) { id = max16600; From fc669e922ecff02c173a8484f7a5ed4810089209 Mon Sep 17 00:00:00 2001 From: JuenKit Yip Date: Sat, 17 Jun 2023 00:00:12 +0800 Subject: [PATCH 38/54] hwmon: (sht3x) remove sht3x_platform_data Since no in-tree driver supports it, sht3x_platform_data has been removed and the relevant properties have been moved to sht3x_data. Signed-off-by: JuenKit Yip Link: https://lore.kernel.org/r/DB4PR10MB626126FB7226D5AF341197449258A@DB4PR10MB6261.EURPRD10.PROD.OUTLOOK.COM Signed-off-by: Guenter Roeck --- Documentation/hwmon/sht3x.rst | 2 +- drivers/hwmon/sht3x.c | 20 ++++++++------------ include/linux/platform_data/sht3x.h | 15 --------------- 3 files changed, 9 insertions(+), 28 deletions(-) delete mode 100644 include/linux/platform_data/sht3x.h diff --git a/Documentation/hwmon/sht3x.rst b/Documentation/hwmon/sht3x.rst index 95a850d5b2c1..31fd36b144a6 100644 --- a/Documentation/hwmon/sht3x.rst +++ b/Documentation/hwmon/sht3x.rst @@ -28,7 +28,7 @@ The device communicates with the I2C protocol. Sensors can have the I2C addresses 0x44 or 0x45, depending on the wiring. See Documentation/i2c/instantiating-devices.rst for methods to instantiate the device. -There are two options configurable by means of sht3x_platform_data: +There are two options configurable by means of sht3x_data: 1. blocking (pull the I2C clock line down while performing the measurement) or non-blocking mode. Blocking mode will guarantee the fastest result but diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 1dab3002728b..12a6f5cc96b6 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -20,7 +20,6 @@ #include #include #include -#include /* commands (high precision mode) */ static const unsigned char sht3x_cmd_measure_blocking_hpm[] = { 0x2c, 0x06 }; @@ -135,8 +134,8 @@ struct sht3x_data { const unsigned char *command; u32 wait_time; /* in us*/ unsigned long last_update; /* last update in periodic mode*/ - - struct sht3x_platform_data setup; + bool blocking_io; + bool high_precision; /* * cached values for temperature and humidity and limits @@ -441,13 +440,13 @@ static void sht3x_select_command(struct sht3x_data *data) if (data->mode > 0) { data->command = sht3x_cmd_measure_periodic_mode; data->wait_time = 0; - } else if (data->setup.blocking_io) { - data->command = data->setup.high_precision ? + } else if (data->blocking_io) { + data->command = data->high_precision ? sht3x_cmd_measure_blocking_hpm : sht3x_cmd_measure_blocking_lpm; data->wait_time = 0; } else { - if (data->setup.high_precision) { + if (data->high_precision) { data->command = sht3x_cmd_measure_nonblocking_hpm; data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_HPM; } else { @@ -595,7 +594,7 @@ static ssize_t update_interval_store(struct device *dev, } if (mode > 0) { - if (data->setup.high_precision) + if (data->high_precision) command = periodic_measure_commands_hpm[mode - 1]; else command = periodic_measure_commands_lpm[mode - 1]; @@ -690,16 +689,13 @@ static int sht3x_probe(struct i2c_client *client) if (!data) return -ENOMEM; - data->setup.blocking_io = false; - data->setup.high_precision = true; + data->blocking_io = false; + data->high_precision = true; data->mode = 0; data->last_update = jiffies - msecs_to_jiffies(3000); data->client = client; crc8_populate_msb(sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL); - if (client->dev.platform_data) - data->setup = *(struct sht3x_platform_data *)dev->platform_data; - sht3x_select_command(data); mutex_init(&data->i2c_lock); diff --git a/include/linux/platform_data/sht3x.h b/include/linux/platform_data/sht3x.h deleted file mode 100644 index 14680d2a98f7..000000000000 --- a/include/linux/platform_data/sht3x.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Sensirion AG, Switzerland - * Author: David Frey - * Author: Pascal Sachs - */ - -#ifndef __SHT3X_H_ -#define __SHT3X_H_ - -struct sht3x_platform_data { - bool blocking_io; - bool high_precision; -}; -#endif /* __SHT3X_H_ */ From 5bca68ac63571b67f905b45f6caffd12f8ab80b7 Mon Sep 17 00:00:00 2001 From: JuenKit Yip Date: Sat, 17 Jun 2023 00:00:13 +0800 Subject: [PATCH 39/54] hwmon: (sht3x) remove blocking_io property Due to no support on clock-strench, blocking mode was removed and now single-shot mode only uses non-blocking mode. Signed-off-by: JuenKit Yip Link: https://lore.kernel.org/r/DB4PR10MB6261DA9202AF37B4F6ECDD6C9258A@DB4PR10MB6261.EURPRD10.PROD.OUTLOOK.COM Signed-off-by: Guenter Roeck --- Documentation/hwmon/sht3x.rst | 12 +++++------- drivers/hwmon/sht3x.c | 33 +++++++++++---------------------- 2 files changed, 16 insertions(+), 29 deletions(-) diff --git a/Documentation/hwmon/sht3x.rst b/Documentation/hwmon/sht3x.rst index 31fd36b144a6..be70e2543f17 100644 --- a/Documentation/hwmon/sht3x.rst +++ b/Documentation/hwmon/sht3x.rst @@ -28,16 +28,14 @@ The device communicates with the I2C protocol. Sensors can have the I2C addresses 0x44 or 0x45, depending on the wiring. See Documentation/i2c/instantiating-devices.rst for methods to instantiate the device. -There are two options configurable by means of sht3x_data: +There is only one option configurable by means of sht3x_data: -1. blocking (pull the I2C clock line down while performing the measurement) or - non-blocking mode. Blocking mode will guarantee the fastest result but - the I2C bus will be busy during that time. By default, non-blocking mode - is used. Make sure clock-stretching works properly on your device if you - want to use blocking mode. -2. high or low accuracy. High accuracy is used by default and using it is + high or low accuracy. High accuracy is used by default and using it is strongly recommended. +Even if sht3x sensor supports clock-strech(blocking mode) and non-strench +(non-blocking mode) in single-shot mode, this driver only supports the latter. + The sht3x sensor supports a single shot mode as well as 5 periodic measure modes, which can be controlled with the update_interval sysfs interface. The allowed update_interval in milliseconds are as follows: diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 12a6f5cc96b6..3cfdfeabac75 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -22,12 +22,10 @@ #include /* commands (high precision mode) */ -static const unsigned char sht3x_cmd_measure_blocking_hpm[] = { 0x2c, 0x06 }; -static const unsigned char sht3x_cmd_measure_nonblocking_hpm[] = { 0x24, 0x00 }; +static const unsigned char sht3x_cmd_measure_single_hpm[] = { 0x24, 0x00 }; /* commands (low power mode) */ -static const unsigned char sht3x_cmd_measure_blocking_lpm[] = { 0x2c, 0x10 }; -static const unsigned char sht3x_cmd_measure_nonblocking_lpm[] = { 0x24, 0x16 }; +static const unsigned char sht3x_cmd_measure_single_lpm[] = { 0x24, 0x16 }; /* commands for periodic mode */ static const unsigned char sht3x_cmd_measure_periodic_mode[] = { 0xe0, 0x00 }; @@ -41,9 +39,9 @@ static const unsigned char sht3x_cmd_heater_off[] = { 0x30, 0x66 }; static const unsigned char sht3x_cmd_read_status_reg[] = { 0xf3, 0x2d }; static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 }; -/* delays for non-blocking i2c commands, both in us */ -#define SHT3X_NONBLOCKING_WAIT_TIME_HPM 15000 -#define SHT3X_NONBLOCKING_WAIT_TIME_LPM 4000 +/* delays for single-shot mode i2c commands, both in us */ +#define SHT3X_SINGLE_WAIT_TIME_HPM 15000 +#define SHT3X_SINGLE_WAIT_TIME_LPM 4000 #define SHT3X_WORD_LEN 2 #define SHT3X_CMD_LENGTH 2 @@ -134,7 +132,6 @@ struct sht3x_data { const unsigned char *command; u32 wait_time; /* in us*/ unsigned long last_update; /* last update in periodic mode*/ - bool blocking_io; bool high_precision; /* @@ -432,26 +429,19 @@ static ssize_t humidity1_limit_store(struct device *dev, static void sht3x_select_command(struct sht3x_data *data) { /* - * In blocking mode (clock stretching mode) the I2C bus - * is blocked for other traffic, thus the call to i2c_master_recv() - * will wait until the data is ready. For non blocking mode, we - * have to wait ourselves. + * For single-shot mode, only non blocking mode is support, + * we have to wait ourselves for result. */ if (data->mode > 0) { data->command = sht3x_cmd_measure_periodic_mode; data->wait_time = 0; - } else if (data->blocking_io) { - data->command = data->high_precision ? - sht3x_cmd_measure_blocking_hpm : - sht3x_cmd_measure_blocking_lpm; - data->wait_time = 0; } else { if (data->high_precision) { - data->command = sht3x_cmd_measure_nonblocking_hpm; - data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_HPM; + data->command = sht3x_cmd_measure_single_hpm; + data->wait_time = SHT3X_SINGLE_WAIT_TIME_HPM; } else { - data->command = sht3x_cmd_measure_nonblocking_lpm; - data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_LPM; + data->command = sht3x_cmd_measure_single_lpm; + data->wait_time = SHT3X_SINGLE_WAIT_TIME_LPM; } } } @@ -689,7 +679,6 @@ static int sht3x_probe(struct i2c_client *client) if (!data) return -ENOMEM; - data->blocking_io = false; data->high_precision = true; data->mode = 0; data->last_update = jiffies - msecs_to_jiffies(3000); From 7d6d53ba3bccc5497e5bda5da4868c410f3eaa02 Mon Sep 17 00:00:00 2001 From: JuenKit Yip Date: Sat, 17 Jun 2023 00:00:14 +0800 Subject: [PATCH 40/54] hwmon: (sht3x)replace "high-precision" property to "repeatability" Replace use of "precision" with "repeatability" to match datasheet terminology. No functional change. Signed-off-by: JuenKit Yip Link: https://lore.kernel.org/r/DB4PR10MB626113BFFA66DE32C3479D229258A@DB4PR10MB6261.EURPRD10.PROD.OUTLOOK.COM [groeck: Added commit description] Signed-off-by: Guenter Roeck --- Documentation/hwmon/sht3x.rst | 2 +- drivers/hwmon/sht3x.c | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/sht3x.rst b/Documentation/hwmon/sht3x.rst index be70e2543f17..b4aa561f03ab 100644 --- a/Documentation/hwmon/sht3x.rst +++ b/Documentation/hwmon/sht3x.rst @@ -30,7 +30,7 @@ Documentation/i2c/instantiating-devices.rst for methods to instantiate the devic There is only one option configurable by means of sht3x_data: - high or low accuracy. High accuracy is used by default and using it is + repeatability: high repeatability is used by default and using it is strongly recommended. Even if sht3x sensor supports clock-strech(blocking mode) and non-strench diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 3cfdfeabac75..fff92e96a6b3 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -21,10 +21,10 @@ #include #include -/* commands (high precision mode) */ +/* commands (high repeatability mode) */ static const unsigned char sht3x_cmd_measure_single_hpm[] = { 0x24, 0x00 }; -/* commands (low power mode) */ +/* commands (low repeatability mode) */ static const unsigned char sht3x_cmd_measure_single_lpm[] = { 0x24, 0x16 }; /* commands for periodic mode */ @@ -66,9 +66,14 @@ enum sht3x_limits { limit_min_hyst, }; +enum sht3x_repeatability { + low_repeatability, + high_repeatability, +}; + DECLARE_CRC8_TABLE(sht3x_crc8_table); -/* periodic measure commands (high precision mode) */ +/* periodic measure commands (high repeatability mode) */ static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = { /* 0.5 measurements per second */ {0x20, 0x32}, @@ -82,7 +87,7 @@ static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = { {0x27, 0x37}, }; -/* periodic measure commands (low power mode) */ +/* periodic measure commands (low repeatability mode) */ static const char periodic_measure_commands_lpm[][SHT3X_CMD_LENGTH] = { /* 0.5 measurements per second */ {0x20, 0x2f}, @@ -132,7 +137,7 @@ struct sht3x_data { const unsigned char *command; u32 wait_time; /* in us*/ unsigned long last_update; /* last update in periodic mode*/ - bool high_precision; + enum sht3x_repeatability repeatability; /* * cached values for temperature and humidity and limits @@ -436,7 +441,7 @@ static void sht3x_select_command(struct sht3x_data *data) data->command = sht3x_cmd_measure_periodic_mode; data->wait_time = 0; } else { - if (data->high_precision) { + if (data->repeatability == high_repeatability) { data->command = sht3x_cmd_measure_single_hpm; data->wait_time = SHT3X_SINGLE_WAIT_TIME_HPM; } else { @@ -584,7 +589,7 @@ static ssize_t update_interval_store(struct device *dev, } if (mode > 0) { - if (data->high_precision) + if (data->repeatability == high_repeatability) command = periodic_measure_commands_hpm[mode - 1]; else command = periodic_measure_commands_lpm[mode - 1]; @@ -679,7 +684,7 @@ static int sht3x_probe(struct i2c_client *client) if (!data) return -ENOMEM; - data->high_precision = true; + data->repeatability = high_repeatability; data->mode = 0; data->last_update = jiffies - msecs_to_jiffies(3000); data->client = client; From 3d2c211c0d2b5955b4ec9a1af7d59e8bed00c7fe Mon Sep 17 00:00:00 2001 From: JuenKit Yip Date: Sat, 17 Jun 2023 00:00:15 +0800 Subject: [PATCH 41/54] hwmon: (sht3x) add medium repeatability support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for medium repeatability. Per datasheet: The stated repeatability is 3 times the standard deviation (3σ) of multiple consecutive measurements at the stated repeatability and at constant ambient conditions. It is a measure for the noise on the physical sensor output. Different measurement modes allow for high/medium/low repeatability. For the humidity sensor, repeatability is documented as 0.25% RH for low repeatability, 0.15% RH for medium repeatability, and 0.10% RH for high repeatability. Support all three modes. Signed-off-by: JuenKit Yip Link: https://lore.kernel.org/r/DB4PR10MB6261A70CD0444248ADDCC3219258A@DB4PR10MB6261.EURPRD10.PROD.OUTLOOK.COM [groeck: Added details to description] Signed-off-by: Guenter Roeck --- drivers/hwmon/sht3x.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index fff92e96a6b3..111b86d9adb5 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -24,6 +24,9 @@ /* commands (high repeatability mode) */ static const unsigned char sht3x_cmd_measure_single_hpm[] = { 0x24, 0x00 }; +/* commands (medium repeatability mode) */ +static const unsigned char sht3x_cmd_measure_single_mpm[] = { 0x24, 0x0b }; + /* commands (low repeatability mode) */ static const unsigned char sht3x_cmd_measure_single_lpm[] = { 0x24, 0x16 }; @@ -41,6 +44,7 @@ static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 }; /* delays for single-shot mode i2c commands, both in us */ #define SHT3X_SINGLE_WAIT_TIME_HPM 15000 +#define SHT3X_SINGLE_WAIT_TIME_MPM 6000 #define SHT3X_SINGLE_WAIT_TIME_LPM 4000 #define SHT3X_WORD_LEN 2 @@ -68,6 +72,7 @@ enum sht3x_limits { enum sht3x_repeatability { low_repeatability, + medium_repeatability, high_repeatability, }; @@ -87,6 +92,20 @@ static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = { {0x27, 0x37}, }; +/* periodic measure commands (medium repeatability) */ +static const char periodic_measure_commands_mpm[][SHT3X_CMD_LENGTH] = { + /* 0.5 measurements per second */ + {0x20, 0x24}, + /* 1 measurements per second */ + {0x21, 0x26}, + /* 2 measurements per second */ + {0x22, 0x20}, + /* 4 measurements per second */ + {0x23, 0x22}, + /* 10 measurements per second */ + {0x27, 0x21}, +}; + /* periodic measure commands (low repeatability mode) */ static const char periodic_measure_commands_lpm[][SHT3X_CMD_LENGTH] = { /* 0.5 measurements per second */ @@ -444,6 +463,9 @@ static void sht3x_select_command(struct sht3x_data *data) if (data->repeatability == high_repeatability) { data->command = sht3x_cmd_measure_single_hpm; data->wait_time = SHT3X_SINGLE_WAIT_TIME_HPM; + } else if (data->repeatability == medium_repeatability) { + data->command = sht3x_cmd_measure_single_mpm; + data->wait_time = SHT3X_SINGLE_WAIT_TIME_MPM; } else { data->command = sht3x_cmd_measure_single_lpm; data->wait_time = SHT3X_SINGLE_WAIT_TIME_LPM; @@ -591,6 +613,8 @@ static ssize_t update_interval_store(struct device *dev, if (mode > 0) { if (data->repeatability == high_repeatability) command = periodic_measure_commands_hpm[mode - 1]; + else if (data->repeatability == medium_repeatability) + command = periodic_measure_commands_mpm[mode - 1]; else command = periodic_measure_commands_lpm[mode - 1]; From af5ab550125f1bbae0ba89ed8e1994a11f40b96a Mon Sep 17 00:00:00 2001 From: JuenKit Yip Date: Sat, 17 Jun 2023 00:00:16 +0800 Subject: [PATCH 42/54] hwmon: (sht3x) Add new non-stardard sysfs attribute Add "repeatability" attribute to sysfs, it could be read or written to control the sensor. Signed-off-by: JuenKit Yip Link: https://lore.kernel.org/r/DB4PR10MB6261B507C7656E3568DA33E39258A@DB4PR10MB6261.EURPRD10.PROD.OUTLOOK.COM [groeck: Fixed multi-line alignment; dropped check of unsigned against < 0] Signed-off-by: Guenter Roeck --- Documentation/hwmon/sht3x.rst | 12 +++++++----- drivers/hwmon/sht3x.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Documentation/hwmon/sht3x.rst b/Documentation/hwmon/sht3x.rst index b4aa561f03ab..87864ffd1777 100644 --- a/Documentation/hwmon/sht3x.rst +++ b/Documentation/hwmon/sht3x.rst @@ -28,11 +28,6 @@ The device communicates with the I2C protocol. Sensors can have the I2C addresses 0x44 or 0x45, depending on the wiring. See Documentation/i2c/instantiating-devices.rst for methods to instantiate the device. -There is only one option configurable by means of sht3x_data: - - repeatability: high repeatability is used by default and using it is - strongly recommended. - Even if sht3x sensor supports clock-strech(blocking mode) and non-strench (non-blocking mode) in single-shot mode, this driver only supports the latter. @@ -83,4 +78,11 @@ heater_enable: heater enable, heating element removes excess humidity from update_interval: update interval, 0 for single shot, interval in msec for periodic measurement. If the interval is not supported by the sensor, the next faster interval is chosen +repeatability: write or read repeatability, higher repeatability means + longer measurement duration, lower noise level and + larger energy consumption: + + - 0: low repeatability + - 1: medium repeatability + - 2: high repeatability =================== ============================================================ diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 111b86d9adb5..cbfb219cef2d 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -637,6 +637,37 @@ out: return count; } +static ssize_t repeatability_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht3x_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", data->repeatability); +} + +static ssize_t repeatability_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int ret; + u8 val; + + struct sht3x_data *data = dev_get_drvdata(dev); + + ret = kstrtou8(buf, 0, &val); + if (ret) + return ret; + + if (val > 2) + return -EINVAL; + + data->repeatability = val; + + return count; +} + static SENSOR_DEVICE_ATTR_RO(temp1_input, temp1_input, 0); static SENSOR_DEVICE_ATTR_RO(humidity1_input, humidity1_input, 0); static SENSOR_DEVICE_ATTR_RW(temp1_max, temp1_limit, limit_max); @@ -653,6 +684,7 @@ static SENSOR_DEVICE_ATTR_RO(temp1_alarm, temp1_alarm, 0); static SENSOR_DEVICE_ATTR_RO(humidity1_alarm, humidity1_alarm, 0); static SENSOR_DEVICE_ATTR_RW(heater_enable, heater_enable, 0); static SENSOR_DEVICE_ATTR_RW(update_interval, update_interval, 0); +static SENSOR_DEVICE_ATTR_RW(repeatability, repeatability, 0); static struct attribute *sht3x_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, @@ -669,6 +701,7 @@ static struct attribute *sht3x_attrs[] = { &sensor_dev_attr_humidity1_alarm.dev_attr.attr, &sensor_dev_attr_heater_enable.dev_attr.attr, &sensor_dev_attr_update_interval.dev_attr.attr, + &sensor_dev_attr_repeatability.dev_attr.attr, NULL }; From fbb5a7fee063fe97009ff28df8cd0e4af3202683 Mon Sep 17 00:00:00 2001 From: JuenKit Yip Date: Sat, 17 Jun 2023 00:00:17 +0800 Subject: [PATCH 43/54] hwmon: (sht3x) complement sysfs interface for sts3x Compared to sht3x, sts3x has the similar functions and operations but it has no humidity sensor. Signed-off-by: JuenKit Yip Link: https://lore.kernel.org/r/DB4PR10MB6261B912ADFA6BB78240596F9258A@DB4PR10MB6261.EURPRD10.PROD.OUTLOOK.COM Signed-off-by: Guenter Roeck --- drivers/hwmon/sht3x.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index cbfb219cef2d..bf18630619e0 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -707,6 +707,14 @@ static struct attribute *sht3x_attrs[] = { static struct attribute *sts3x_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_heater_enable.dev_attr.attr, + &sensor_dev_attr_update_interval.dev_attr.attr, + &sensor_dev_attr_repeatability.dev_attr.attr, NULL }; From be144ee49127216b456da26f1a32b6ba281ac505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Sun, 11 Jun 2023 11:33:20 -0300 Subject: [PATCH 44/54] hwmon: (oxp-sensors) Add tt_toggle attribute on supported boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OneXPlayer boards from the last generation (both for OneXPlayer and AOK ZOE brands) have a toggle in the EC to switch the "Turbo/Silent" button into a different keyboard event. Add a means to use that "Turbo button takeover" function and expose it to userspace in a custom sysfs `tt_toggle` attribute. It can be read to take the current state. Write 1|0 to activate the function. The specific keycode is dependent on the board but can be checked by running `evtest` utility. Newer BIOS on the OneXPlayer added this function aside from string changes. Add a board enum to differentiate it from the old OneXplayer Mini AMD BIOS. Currently known supported boards: - AOK ZOE A1 - OneXPlayer Mini AMD (only newer BIOS version supported) - OneXPlayer Mini Pro Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230611143332.40590-2-samsagax@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/oxp-sensors.rst | 17 ++++ drivers/hwmon/oxp-sensors.c | 134 +++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst index 4ab442301415..0ca1f7728c34 100644 --- a/Documentation/hwmon/oxp-sensors.rst +++ b/Documentation/hwmon/oxp-sensors.rst @@ -19,6 +19,11 @@ out the EC registers and values to write to since the EC layout and model is different. Aya Neo devices preceding the AIR may not be supportable as the EC model is different and do not appear to have manual control capabilities. +Some models have a toggle for changing the behaviour of the "Turbo/Silent" +button of the device. It will change the key event that it triggers with +a flip of the `tt_toggle` attribute. See below for boards that support this +function. + Supported devices ----------------- @@ -33,6 +38,11 @@ Currently the driver supports the following handhelds: - OneXPlayer mini AMD - OneXPlayer mini AMD PRO +"Turbo/Silent" button behaviour toggle is only supported on: + - AOK ZOE A1 + - OneXPlayer mini AMD (only with updated alpha BIOS) + - OneXPlayer mini AMD PRO + Sysfs entries ------------- @@ -49,3 +59,10 @@ pwm1 Read Write. Read this attribute to see current duty cycle in the range [0-255]. When pwm1_enable is set to "1" (manual) write any value in the range [0-255] to set fan speed. + +tt_toggle + Read Write. Read this attribute to check the status of the turbo/silent + button behaviour function. Write "1" to activate the switch and "0" to + deactivate it. The specific keycodes and behaviour is specific to the device + both with this function on and off. This attribute is attached to the platform + driver and not to the hwmon driver (/sys/devices/platform/oxp-platform/tt_toggle) diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index 0ec7588610ad..be36d38f13d9 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -47,15 +47,29 @@ enum oxp_board { aya_neo_air_pro, aya_neo_geek, oxp_mini_amd, + oxp_mini_amd_a07, oxp_mini_amd_pro, }; static enum oxp_board board; +/* Fan reading and PWM */ #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */ #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */ +/* Turbo button takeover function + * Older boards have different values and EC registers + * for the same function + */ +#define OXP_OLD_TURBO_SWITCH_REG 0x1E +#define OXP_OLD_TURBO_TAKE_VAL 0x01 +#define OXP_OLD_TURBO_RETURN_VAL 0x00 + +#define OXP_TURBO_SWITCH_REG 0xF1 +#define OXP_TURBO_TAKE_VAL 0x40 +#define OXP_TURBO_RETURN_VAL 0x00 + static const struct dmi_system_id dmi_table[] = { { .matches = { @@ -104,7 +118,7 @@ static const struct dmi_system_id dmi_table[] = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), }, - .driver_data = (void *)oxp_mini_amd, + .driver_data = (void *)oxp_mini_amd_a07, }, { .matches = { @@ -156,6 +170,102 @@ static int write_to_ec(u8 reg, u8 value) return ret; } +/* Turbo button toggle functions */ +static int tt_toggle_enable(void) +{ + u8 reg; + u8 val; + + switch (board) { + case oxp_mini_amd_a07: + reg = OXP_OLD_TURBO_SWITCH_REG; + val = OXP_OLD_TURBO_TAKE_VAL; + break; + case oxp_mini_amd_pro: + case aok_zoe_a1: + reg = OXP_TURBO_SWITCH_REG; + val = OXP_TURBO_TAKE_VAL; + break; + default: + return -EINVAL; + } + return write_to_ec(reg, val); +} + +static int tt_toggle_disable(void) +{ + u8 reg; + u8 val; + + switch (board) { + case oxp_mini_amd_a07: + reg = OXP_OLD_TURBO_SWITCH_REG; + val = OXP_OLD_TURBO_RETURN_VAL; + break; + case oxp_mini_amd_pro: + case aok_zoe_a1: + reg = OXP_TURBO_SWITCH_REG; + val = OXP_TURBO_RETURN_VAL; + break; + default: + return -EINVAL; + } + return write_to_ec(reg, val); +} + +/* Callbacks for turbo toggle attribute */ +static ssize_t tt_toggle_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int rval; + bool value; + + rval = kstrtobool(buf, &value); + if (rval) + return rval; + + if (value) { + rval = tt_toggle_enable(); + if (rval) + return rval; + } else { + rval = tt_toggle_disable(); + if (rval) + return rval; + } + return count; +} + +static ssize_t tt_toggle_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int retval; + u8 reg; + long val; + + switch (board) { + case oxp_mini_amd_a07: + reg = OXP_OLD_TURBO_SWITCH_REG; + break; + case oxp_mini_amd_pro: + case aok_zoe_a1: + reg = OXP_TURBO_SWITCH_REG; + break; + default: + return -EINVAL; + } + + retval = read_from_ec(reg, 1, &val); + if (retval) + return retval; + + return sysfs_emit(buf, "%d\n", !!val); +} + +static DEVICE_ATTR_RW(tt_toggle); + +/* PWM enable/disable functions */ static int oxp_pwm_enable(void) { return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01); @@ -206,6 +316,7 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, case aya_neo_air_pro: case aya_neo_geek: case oxp_mini_amd: + case oxp_mini_amd_a07: *val = (*val * 255) / 100; break; case oxp_mini_amd_pro: @@ -247,6 +358,7 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, case aya_neo_air_pro: case aya_neo_geek: case oxp_mini_amd: + case oxp_mini_amd_a07: val = (val * 100) / 255; break; case aok_zoe_a1: @@ -274,6 +386,13 @@ static const struct hwmon_channel_info * const oxp_platform_sensors[] = { NULL, }; +static struct attribute *oxp_ec_attrs[] = { + &dev_attr_tt_toggle.attr, + NULL +}; + +ATTRIBUTE_GROUPS(oxp_ec); + static const struct hwmon_ops oxp_ec_hwmon_ops = { .is_visible = oxp_ec_hwmon_is_visible, .read = oxp_platform_read, @@ -291,6 +410,7 @@ static int oxp_platform_probe(struct platform_device *pdev) const struct dmi_system_id *dmi_entry; struct device *dev = &pdev->dev; struct device *hwdev; + int ret; /* * Have to check for AMD processor here because DMI strings are the @@ -305,6 +425,18 @@ static int oxp_platform_probe(struct platform_device *pdev) board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; + switch (board) { + case aok_zoe_a1: + case oxp_mini_amd_a07: + case oxp_mini_amd_pro: + ret = devm_device_add_groups(dev, oxp_ec_groups); + if (ret) + return ret; + break; + default: + break; + } + hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, &oxp_ec_chip_info, NULL); From aee395bb190564a3fa22aa65c60812c25410e94a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 28 Dec 2022 05:57:44 -0800 Subject: [PATCH 45/54] hwmon: (nct6755) Add support for NCT6799D NCT6799D is mostly compatible to NCT6798D, with minor variations. Note that NCT6798D and NCT6799D have a new means to select temperature sources, and to report temperatures from those sources. This is not currently implemented, meaning that most likely not all temperatures are reported. Cc: Sebastian Arnhold Cc: Ahmad Khalifa Signed-off-by: Guenter Roeck Tested-by: Sebastian Arnhold Tested-by: Corentin Labbe Link: https://lore.kernel.org/r/20221228135744.281752-1-linux@roeck-us.net --- drivers/hwmon/nct6775-core.c | 55 ++++++++++++++++++++++++++++++-- drivers/hwmon/nct6775-i2c.c | 2 ++ drivers/hwmon/nct6775-platform.c | 41 ++++++++++++++++++++++-- drivers/hwmon/nct6775.h | 2 +- 4 files changed, 94 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index c54233f0369b..236dc97f4d22 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -33,6 +33,7 @@ * (0xd451) * nct6798d 14 7 7 2+6 0xd428 0xc1 0x5ca3 * (0xd429) + * nct6799d 14 7 7 2+6 0xd802 0xc1 0x5ca3 * * #temp lists the number of monitored temperature sources (first value) plus * the number of directly connectable temperature sensors (second value). @@ -73,6 +74,7 @@ static const char * const nct6775_device_names[] = { "nct6796", "nct6797", "nct6798", + "nct6799", }; /* Common and NCT6775 specific data */ @@ -381,7 +383,7 @@ static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = { 0x39, 0x155 }; static const u16 NCT6779_REG_TEMP_OFFSET[] = { - 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c }; + 0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c, 0x44d, 0x449 }; static const char *const nct6779_temp_label[] = { "", @@ -654,6 +656,44 @@ static const char *const nct6798_temp_label[] = { #define NCT6798_TEMP_MASK 0xbfff0ffe #define NCT6798_VIRT_TEMP_MASK 0x80000c00 +static const char *const nct6799_temp_label[] = { + "", + "SYSTIN", + "CPUTIN", + "AUXTIN0", + "AUXTIN1", + "AUXTIN2", + "AUXTIN3", + "AUXTIN4", + "SMBUSMASTER 0", + "SMBUSMASTER 1", + "Virtual_TEMP", + "Virtual_TEMP", + "", + "AUXTIN5", + "", + "", + "PECI Agent 0", + "PECI Agent 1", + "PCH_CHIP_CPU_MAX_TEMP", + "PCH_CHIP_TEMP", + "PCH_CPU_TEMP", + "PCH_MCH_TEMP", + "Agent0 Dimm0", + "Agent0 Dimm1", + "Agent1 Dimm0", + "Agent1 Dimm1", + "BYTE_TEMP0", + "BYTE_TEMP1", + "PECI Agent 0 Calibration", /* undocumented */ + "PECI Agent 1 Calibration", /* undocumented */ + "", + "Virtual_TEMP" +}; + +#define NCT6799_TEMP_MASK 0xbfff2ffe +#define NCT6799_VIRT_TEMP_MASK 0x80000c00 + /* NCT6102D/NCT6106D specific data */ #define NCT6106_REG_VBAT 0x318 @@ -1109,6 +1149,7 @@ bool nct6775_reg_is_word_sized(struct nct6775_data *data, u16 reg) case nct6796: case nct6797: case nct6798: + case nct6799: return reg == 0x150 || reg == 0x153 || reg == 0x155 || (reg & 0xfff0) == 0x4c0 || reg == 0x402 || @@ -1462,6 +1503,7 @@ static int nct6775_update_pwm_limits(struct device *dev) case nct6796: case nct6797: case nct6798: + case nct6799: err = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i], ®); if (err) return err; @@ -3109,6 +3151,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6796: case nct6797: case nct6798: + case nct6799: err = nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); if (err) break; @@ -3807,10 +3850,12 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, case nct6796: case nct6797: case nct6798: + case nct6799: data->in_num = 15; data->pwm_num = (data->kind == nct6796 || data->kind == nct6797 || - data->kind == nct6798) ? 7 : 6; + data->kind == nct6798 || + data->kind == nct6799) ? 7 : 6; data->auto_pwm_num = 4; data->has_fan_div = false; data->temp_fixed_num = 6; @@ -3859,6 +3904,11 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, data->temp_mask = NCT6798_TEMP_MASK; data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK; break; + case nct6799: + data->temp_label = nct6799_temp_label; + data->temp_mask = NCT6799_TEMP_MASK; + data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK; + break; } data->REG_CONFIG = NCT6775_REG_CONFIG; @@ -3918,6 +3968,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data, case nct6796: case nct6797: case nct6798: + case nct6799: data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP; num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP); break; diff --git a/drivers/hwmon/nct6775-i2c.c b/drivers/hwmon/nct6775-i2c.c index 8acd83e1e009..87a4fc78c571 100644 --- a/drivers/hwmon/nct6775-i2c.c +++ b/drivers/hwmon/nct6775-i2c.c @@ -87,6 +87,7 @@ static const struct of_device_id __maybe_unused nct6775_i2c_of_match[] = { { .compatible = "nuvoton,nct6796", .data = (void *)nct6796, }, { .compatible = "nuvoton,nct6797", .data = (void *)nct6797, }, { .compatible = "nuvoton,nct6798", .data = (void *)nct6798, }, + { .compatible = "nuvoton,nct6799", .data = (void *)nct6799, }, { }, }; MODULE_DEVICE_TABLE(of, nct6775_i2c_of_match); @@ -104,6 +105,7 @@ static const struct i2c_device_id nct6775_i2c_id[] = { { "nct6796", nct6796 }, { "nct6797", nct6797 }, { "nct6798", nct6798 }, + { "nct6799", nct6799 }, { } }; MODULE_DEVICE_TABLE(i2c, nct6775_i2c_id); diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 5782acfb4ee1..ada867d6b98a 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -35,6 +35,7 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6796D", "NCT6797D", "NCT6798D", + "NCT6799D", }; static unsigned short force_id; @@ -85,6 +86,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6796_ID 0xd420 #define SIO_NCT6797_ID 0xd450 #define SIO_NCT6798_ID 0xd428 +#define SIO_NCT6799_ID 0xd800 #define SIO_ID_MASK 0xFFF8 /* @@ -418,7 +420,7 @@ static int nct6775_resume(struct device *dev) if (data->kind == nct6791 || data->kind == nct6792 || data->kind == nct6793 || data->kind == nct6795 || data->kind == nct6796 || data->kind == nct6797 || - data->kind == nct6798) + data->kind == nct6798 || data->kind == nct6799) nct6791_enable_io_mapping(sio_data); sio_data->sio_exit(sio_data); @@ -565,7 +567,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio } else { /* * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, - * NCT6797D, NCT6798D + * NCT6797D, NCT6798D, NCT6799D */ int cr1a = sio_data->sio_inb(sio_data, 0x1a); int cr1b = sio_data->sio_inb(sio_data, 0x1b); @@ -575,12 +577,17 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio int cr2b = sio_data->sio_inb(sio_data, 0x2b); int cr2d = sio_data->sio_inb(sio_data, 0x2d); int cr2f = sio_data->sio_inb(sio_data, 0x2f); + bool vsb_ctl_en = cr2f & BIT(0); bool dsw_en = cr2f & BIT(3); bool ddr4_en = cr2f & BIT(4); + bool as_seq1_en = cr2f & BIT(7); int cre0; + int cre6; int creb; int cred; + cre6 = sio_data->sio_inb(sio_data, 0xe0); + sio_data->sio_select(sio_data, NCT6775_LD_12); cre0 = sio_data->sio_inb(sio_data, 0xe0); creb = sio_data->sio_inb(sio_data, 0xeb); @@ -683,6 +690,29 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio pwm7pin = !(cr1d & (BIT(2) | BIT(3))); pwm7pin |= cr2d & BIT(7); pwm7pin |= creb & BIT(2); + break; + case nct6799: + fan4pin = cr1c & BIT(6); + fan5pin = cr1c & BIT(7); + + fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3)); + fan6pin |= cre6 & BIT(5); + fan6pin |= creb & BIT(5); + fan6pin |= !as_seq1_en && (cr2a & BIT(4)); + + fan7pin = cr1b & BIT(5); + fan7pin |= !vsb_ctl_en && !(cr2b & BIT(2)); + fan7pin |= creb & BIT(3); + + pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4)); + pwm6pin |= !as_seq1_en && !(cred & BIT(2)) && (cr2a & BIT(3)); + pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0)); + pwm6pin |= cre6 & BIT(3); + + pwm7pin = !vsb_ctl_en && !(cr1d & (BIT(2) | BIT(3))); + pwm7pin |= creb & BIT(2); + pwm7pin |= cr2d & BIT(7); + break; default: /* NCT6779D */ break; @@ -838,6 +868,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data) case nct6796: case nct6797: case nct6798: + case nct6799: break; } @@ -876,6 +907,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data) case nct6796: case nct6797: case nct6798: + case nct6799: tmp |= 0x7e; break; } @@ -1005,6 +1037,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) case SIO_NCT6798_ID: sio_data->kind = nct6798; break; + case SIO_NCT6799_ID: + sio_data->kind = nct6799; + break; default: if (val != 0xffff) pr_debug("unsupported chip ID: 0x%04x\n", val); @@ -1033,7 +1068,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || sio_data->kind == nct6793 || sio_data->kind == nct6795 || sio_data->kind == nct6796 || sio_data->kind == nct6797 || - sio_data->kind == nct6798) + sio_data->kind == nct6798 || sio_data->kind == nct6799) nct6791_enable_io_mapping(sio_data); sio_data->sio_exit(sio_data); diff --git a/drivers/hwmon/nct6775.h b/drivers/hwmon/nct6775.h index be41848c3cd2..44f79c5726a9 100644 --- a/drivers/hwmon/nct6775.h +++ b/drivers/hwmon/nct6775.h @@ -5,7 +5,7 @@ #include enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792, - nct6793, nct6795, nct6796, nct6797, nct6798 }; + nct6793, nct6795, nct6796, nct6797, nct6798, nct6799 }; enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; #define NUM_TEMP 10 /* Max number of temp attribute sets w/ limits*/ From d7696214b06dae06b5c632142b1c80cf85219c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Sat, 17 Jun 2023 15:11:42 -0300 Subject: [PATCH 46/54] hwmon: (oxp-sensors) Remove unused header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are not using , remove that. Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230617181159.32844-2-samsagax@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/oxp-sensors.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index be36d38f13d9..584e48d8106e 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -16,7 +16,6 @@ */ #include -#include #include #include #include From 37f665ffa886ce49d1baaca1c3501ce93713b77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Sat, 17 Jun 2023 15:11:43 -0300 Subject: [PATCH 47/54] hwmon: (oxp-sensors) Simplify logic of error return MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take return logic on error out of if-else, eliminating duplicated code in tt_togle_store() function. Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230617181159.32844-3-samsagax@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/oxp-sensors.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index 584e48d8106e..1e59d97219c4 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -226,13 +226,12 @@ static ssize_t tt_toggle_store(struct device *dev, if (value) { rval = tt_toggle_enable(); - if (rval) - return rval; } else { rval = tt_toggle_disable(); - if (rval) - return rval; } + if (rval) + return rval; + return count; } From 98ac8af4e7b2f260236cf468762450630e73eb67 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 14 Jun 2023 09:36:04 -0700 Subject: [PATCH 48/54] hwmon: (pmbus/adm1275) Prepare for protected write to PMON_CONFIG According to ADI, changing PMON_CONFIG while ADC is running can have unexpected results. ADI recommends halting the ADC with PMON_CONTROL before setting PMON_CONFIG and then resume after. To prepare for this change, rename adm1275_read_pmon_config() and adm1275_write_pmon_config() to adm1275_read_samples() and adm1275_write_samples() to more accurately reflect the functionality of the code. Introduce new function adm1275_write_pmon_config() and use it for all code writing into the PMON_CONFIG register. Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230614163605.3688964-2-linux@roeck-us.net Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 56 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 49d59b745afe..84a1b3aa99ba 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -173,8 +173,8 @@ static const struct coefficients adm1293_coefficients[] = { [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */ }; -static int adm1275_read_pmon_config(const struct adm1275_data *data, - struct i2c_client *client, bool is_power) +static int adm1275_read_samples(const struct adm1275_data *data, + struct i2c_client *client, bool is_power) { int shift, ret; u16 mask; @@ -200,8 +200,23 @@ static int adm1275_read_pmon_config(const struct adm1275_data *data, } static int adm1275_write_pmon_config(const struct adm1275_data *data, - struct i2c_client *client, - bool is_power, u16 word) + struct i2c_client *client, u16 word) +{ + int ret; + + if (data->have_power_sampling) + ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, + word); + else + ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, + word); + + return ret; +} + +static int adm1275_write_samples(const struct adm1275_data *data, + struct i2c_client *client, + bool is_power, u16 word) { int shift, ret; u16 mask; @@ -219,14 +234,8 @@ static int adm1275_write_pmon_config(const struct adm1275_data *data, return ret; word = (ret & ~mask) | ((word << shift) & mask); - if (data->have_power_sampling) - ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, - word); - else - ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, - word); - return ret; + return adm1275_write_pmon_config(data, client, word); } static int adm1275_read_word_data(struct i2c_client *client, int page, @@ -321,14 +330,14 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, case PMBUS_VIRT_POWER_SAMPLES: if (!data->have_power_sampling) return -ENXIO; - ret = adm1275_read_pmon_config(data, client, true); + ret = adm1275_read_samples(data, client, true); if (ret < 0) break; ret = BIT(ret); break; case PMBUS_VIRT_IN_SAMPLES: case PMBUS_VIRT_CURR_SAMPLES: - ret = adm1275_read_pmon_config(data, client, false); + ret = adm1275_read_samples(data, client, false); if (ret < 0) break; ret = BIT(ret); @@ -381,14 +390,12 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, if (!data->have_power_sampling) return -ENXIO; word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); - ret = adm1275_write_pmon_config(data, client, true, - ilog2(word)); + ret = adm1275_write_samples(data, client, true, ilog2(word)); break; case PMBUS_VIRT_IN_SAMPLES: case PMBUS_VIRT_CURR_SAMPLES: word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX); - ret = adm1275_write_pmon_config(data, client, false, - ilog2(word)); + ret = adm1275_write_samples(data, client, false, ilog2(word)); break; default: ret = -ENODATA; @@ -466,13 +473,14 @@ static const struct i2c_device_id adm1275_id[] = { MODULE_DEVICE_TABLE(i2c, adm1275_id); /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ -static int adm1275_enable_vout_temp(struct i2c_client *client, int config) +static int adm1275_enable_vout_temp(struct adm1275_data *data, + struct i2c_client *client, int config) { int ret; if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) { config |= ADM1278_PMON_DEFCONFIG; - ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, config); + ret = adm1275_write_pmon_config(data, client, config); if (ret < 0) { dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n"); return ret; @@ -634,7 +642,7 @@ static int adm1275_probe(struct i2c_client *client) PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - ret = adm1275_enable_vout_temp(client, config); + ret = adm1275_enable_vout_temp(data, client, config); if (ret) return ret; @@ -694,7 +702,7 @@ static int adm1275_probe(struct i2c_client *client) PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - ret = adm1275_enable_vout_temp(client, config); + ret = adm1275_enable_vout_temp(data, client, config); if (ret) return ret; @@ -766,8 +774,7 @@ static int adm1275_probe(struct i2c_client *client) "Invalid number of power samples"); return -EINVAL; } - ret = adm1275_write_pmon_config(data, client, true, - ilog2(avg)); + ret = adm1275_write_samples(data, client, true, ilog2(avg)); if (ret < 0) { dev_err(&client->dev, "Setting power sample averaging failed with error %d", @@ -784,8 +791,7 @@ static int adm1275_probe(struct i2c_client *client) "Invalid number of voltage/current samples"); return -EINVAL; } - ret = adm1275_write_pmon_config(data, client, false, - ilog2(avg)); + ret = adm1275_write_samples(data, client, false, ilog2(avg)); if (ret < 0) { dev_err(&client->dev, "Setting voltage and current sample averaging failed with error %d", From dd5219ce4f295a129ee38baff308f9c1e4f0761b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 14 Jun 2023 09:36:05 -0700 Subject: [PATCH 49/54] hwmon: (pmbus/adm1275) Disable ADC while updating PMON_CONFIG According to ADI, changing PMON_CONFIG while the ADC is running can have unexpected results. ADI recommends halting the ADC with PMON_CONTROL before setting PMON_CONFIG and then resume after. Follow ADI recommendation and disable ADC while PMON_CONFIG is updated. Signed-off-by: Guenter Roeck Link: https://lore.kernel.org/r/20230614163605.3688964-3-linux@roeck-us.net Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 84a1b3aa99ba..e2c61d6fa521 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -27,8 +27,11 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 }; #define ADM1275_PEAK_IOUT 0xd0 #define ADM1275_PEAK_VIN 0xd1 #define ADM1275_PEAK_VOUT 0xd2 +#define ADM1275_PMON_CONTROL 0xd3 #define ADM1275_PMON_CONFIG 0xd4 +#define ADM1275_CONVERT_EN BIT(0) + #define ADM1275_VIN_VOUT_SELECT BIT(6) #define ADM1275_VRANGE BIT(5) #define ADM1075_IRANGE_50 BIT(4) @@ -202,7 +205,11 @@ static int adm1275_read_samples(const struct adm1275_data *data, static int adm1275_write_pmon_config(const struct adm1275_data *data, struct i2c_client *client, u16 word) { - int ret; + int ret, ret2; + + ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL, 0); + if (ret) + return ret; if (data->have_power_sampling) ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG, @@ -211,6 +218,15 @@ static int adm1275_write_pmon_config(const struct adm1275_data *data, ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, word); + /* + * We still want to re-enable conversions if writing into + * ADM1275_PMON_CONFIG failed. + */ + ret2 = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL, + ADM1275_CONVERT_EN); + if (!ret) + ret = ret2; + return ret; } From 0d67bbc48c7397bc97fa91c9b9c66c6570451131 Mon Sep 17 00:00:00 2001 From: Wilken Gottwalt Date: Thu, 22 Jun 2023 17:09:28 +0000 Subject: [PATCH 50/54] hwmon: (corsair-psu) add support for reading PWM values and mode Add support for reading PWM values and mode, and update documentation accordingly. Signed-off-by: Wilken Gottwalt Link: https://lore.kernel.org/r/ZJSASByXpzoZ0XyH@monster.localdomain Signed-off-by: Guenter Roeck --- Documentation/hwmon/corsair-psu.rst | 2 + drivers/hwmon/corsair-psu.c | 62 ++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index c389bd21f4f2..fc798c3df1d0 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -69,6 +69,8 @@ power1_input Total power usage power2_input Power usage of the 12v psu rail power3_input Power usage of the 5v psu rail power4_input Power usage of the 3.3v psu rail +pwm1 PWM value, read only +pwm1_enable PWM mode, read only temp1_input Temperature of the psu vrm component temp1_crit Temperature max cirtical value of the psu vrm component temp2_input Temperature of the psu case diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index dc24c566d08b..2389f605ca16 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -58,7 +58,8 @@ #define OCP_MULTI_RAIL 0x02 #define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */ -#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 /* the rest of the commands expect length 3 */ +#define PSU_CMD_FAN_PWM 0x3B /* the rest of the commands expect length 3 */ +#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 #define PSU_CMD_RAIL_VOLTS_LCRIT 0x44 #define PSU_CMD_RAIL_AMPS_HCRIT 0x46 #define PSU_CMD_TEMP_HCRIT 0x4F @@ -76,6 +77,7 @@ #define PSU_CMD_UPTIME 0xD2 #define PSU_CMD_OCPMODE 0xD8 #define PSU_CMD_TOTAL_WATTS 0xEE +#define PSU_CMD_FAN_PWM_ENABLE 0xF0 #define PSU_CMD_INIT 0xFE #define L_IN_VOLTS "v_in" @@ -145,6 +147,14 @@ static int corsairpsu_linear11_to_int(const u16 val, const int scale) return (exp >= 0) ? (result << exp) : (result >> -exp); } +/* the micro-controller uses percentage values to control pwm */ +static int corsairpsu_dutycycle_to_pwm(const long dutycycle) +{ + const int result = (256 << 16) / 100; + + return (result * dutycycle) >> 16; +} + static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data) { unsigned long time; @@ -264,6 +274,24 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l case PSU_CMD_FAN: *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); break; + case PSU_CMD_FAN_PWM_ENABLE: + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); + /* + * 0 = automatic mode, means the micro-controller controls the fan using a plan + * which can be modified, but changing this plan is not supported by this + * driver, the matching PWM mode is automatic fan speed control = PWM 2 + * 1 = fixed mode, fan runs at a fixed speed represented by a percentage + * value 0-100, this matches the PWM manual fan speed control = PWM 1 + * technically there is no PWM no fan speed control mode, it would be a combination + * of 1 at 100% + */ + if (*val == 0) + *val = 2; + break; + case PSU_CMD_FAN_PWM: + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); + *val = corsairpsu_dutycycle_to_pwm(*val); + break; case PSU_CMD_RAIL_WATTS: case PSU_CMD_TOTAL_WATTS: *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000); @@ -349,6 +377,18 @@ static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *pri } } +static umode_t corsairpsu_hwmon_pwm_is_visible(const struct corsairpsu_data *priv, u32 attr, + int channel) +{ + switch (attr) { + case hwmon_pwm_input: + case hwmon_pwm_enable: + return 0444; + default: + return 0; + } +} + static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr, int channel) { @@ -416,6 +456,8 @@ static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sens return corsairpsu_hwmon_temp_is_visible(priv, attr, channel); case hwmon_fan: return corsairpsu_hwmon_fan_is_visible(priv, attr, channel); + case hwmon_pwm: + return corsairpsu_hwmon_pwm_is_visible(priv, attr, channel); case hwmon_power: return corsairpsu_hwmon_power_is_visible(priv, attr, channel); case hwmon_in: @@ -447,6 +489,20 @@ static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, in return err; } +static int corsairpsu_hwmon_pwm_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val) +{ + switch (attr) { + case hwmon_pwm_input: + return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM, 0, val); + case hwmon_pwm_enable: + return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM_ENABLE, 0, val); + default: + break; + } + + return -EOPNOTSUPP; +} + static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val) { @@ -531,6 +587,8 @@ static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types if (attr == hwmon_fan_input) return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val); return -EOPNOTSUPP; + case hwmon_pwm: + return corsairpsu_hwmon_pwm_read(priv, attr, channel, val); case hwmon_power: return corsairpsu_hwmon_power_read(priv, attr, channel, val); case hwmon_in: @@ -579,6 +637,8 @@ static const struct hwmon_channel_info * const corsairpsu_info[] = { HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL, HWMON_P_INPUT | HWMON_P_LABEL, From b54c4b02abd1578132712eae5b294a9c77e7422b Mon Sep 17 00:00:00 2001 From: Wilken Gottwalt Date: Fri, 23 Jun 2023 13:36:28 +0000 Subject: [PATCH 51/54] hwmon: (corsair-psu) various cleanups Fix some typos, adjust documentation and comments to current state of knowledge and update coding style to be more uniform. Signed-off-by: Wilken Gottwalt Link: https://lore.kernel.org/r/ZJWf3H972hGgLK-8@monster.localdomain Signed-off-by: Guenter Roeck --- Documentation/hwmon/corsair-psu.rst | 4 ++-- drivers/hwmon/corsair-psu.c | 23 +++++++++++------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index fc798c3df1d0..47f8ff632267 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -15,11 +15,11 @@ Supported devices: Corsair HX850i - Corsair HX1000i (revision 1 and 2) + Corsair HX1000i (Series 2022 and Series 2023) Corsair HX1200i - Corsair HX1500i + Corsair HX1500i (Series 2022) Corsair RM550i diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index 2389f605ca16..9e3e3c0a3bdd 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -32,18 +32,17 @@ * but it is better to not rely on this (it is also hard to parse) * - the driver uses raw events to be accessible from userspace (though this is not really * supported, it is just there for convenience, may be removed in the future) - * - a reply always start with the length and command in the same order the request used it + * - a reply always starts with the length and command in the same order the request used it * - length of the reply data is specific to the command used * - some of the commands work on a rail and can be switched to a specific rail (0 = 12v, * 1 = 5v, 2 = 3.3v) * - the format of the init command 0xFE is swapped length/command bytes * - parameter bytes amount and values are specific to the command (rail setting is the only - * for now that uses non-zero values) - * - there are much more commands, especially for configuring the device, but they are not - * supported because a wrong command/length can lockup the micro-controller + * one for now that uses non-zero values) * - the driver supports debugfs for values not fitting into the hwmon class - * - not every device class (HXi, RMi or AXi) supports all commands - * - it is a pure sensors reading driver (will not support configuring) + * - not every device class (HXi or RMi) supports all commands + * - if configured wrong the PSU resets or shuts down, often before actually hitting the + * - reported critical temperature */ #define DRIVER_NAME "corsair-psu" @@ -254,8 +253,8 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l /* * the biggest value here comes from the uptime command and to exceed MAXINT total uptime * needs to be about 68 years, the rest are u16 values and the biggest value coming out of - * the LINEAR11 conversion are the watts values which are about 1200 for the strongest psu - * supported (HX1200i) + * the LINEAR11 conversion are the watts values which are about 1500 for the strongest psu + * supported (HX1500i) */ tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]; switch (cmd) { @@ -629,7 +628,7 @@ static const struct hwmon_ops corsairpsu_hwmon_ops = { .read_string = corsairpsu_hwmon_ops_read_string, }; -static const struct hwmon_channel_info * const corsairpsu_info[] = { +static const struct hwmon_channel_info *const corsairpsu_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, @@ -873,15 +872,15 @@ static const struct hid_device_id corsairpsu_idtable[] = { { HID_USB_DEVICE(0x1b1c, 0x1c04) }, /* Corsair HX650i */ { HID_USB_DEVICE(0x1b1c, 0x1c05) }, /* Corsair HX750i */ { HID_USB_DEVICE(0x1b1c, 0x1c06) }, /* Corsair HX850i */ - { HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i revision 1 */ + { HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i Series 2022 */ { HID_USB_DEVICE(0x1b1c, 0x1c08) }, /* Corsair HX1200i */ { HID_USB_DEVICE(0x1b1c, 0x1c09) }, /* Corsair RM550i */ { HID_USB_DEVICE(0x1b1c, 0x1c0a) }, /* Corsair RM650i */ { HID_USB_DEVICE(0x1b1c, 0x1c0b) }, /* Corsair RM750i */ { HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */ { HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */ - { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i revision 2 */ - { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i */ + { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */ + { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Series 2022 */ { }, }; MODULE_DEVICE_TABLE(hid, corsairpsu_idtable); From 741ed0856d5ef94c2dbdbf58cb13d262d89505bb Mon Sep 17 00:00:00 2001 From: Wilken Gottwalt Date: Sat, 24 Jun 2023 10:14:07 +0000 Subject: [PATCH 52/54] hwmon: (corsair-psu) update Series 2022 and 2023 support The series 2022/2023 reports slightly longer vendor/product strings and shares USB ids. Technically the reply size is the USB HID packet size (64 bytes) but all the supported commands do not use more than 8 bytes and replies reporting back strings do not use more then 24 bytes (vendor and product are in one string in the newer devices now). The rest of the reply is always filled with '\0'. Also update comments and documentation accordingly. Signed-off-by: Wilken Gottwalt Link: https://lore.kernel.org/r/ZJbB72CAPmLflhHG@monster.localdomain Signed-off-by: Guenter Roeck --- Documentation/hwmon/corsair-psu.rst | 13 ++++++++----- drivers/hwmon/corsair-psu.c | 9 ++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index 47f8ff632267..16db34d464dd 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -15,11 +15,11 @@ Supported devices: Corsair HX850i - Corsair HX1000i (Series 2022 and Series 2023) + Corsair HX1000i (Series 2022 and 2023) Corsair HX1200i - Corsair HX1500i (Series 2022) + Corsair HX1500i (Series 2022 and 2023) Corsair RM550i @@ -80,11 +80,14 @@ temp2_crit Temperature max critical value of psu case Usage Notes ----------- -It is an USB HID device, so it is auto-detected and supports hot-swapping. +It is an USB HID device, so it is auto-detected, supports hot-swapping and +several devices at once. Flickering values in the rail voltage levels can be an indicator for a failing -PSU. The driver also provides some additional useful values via debugfs, which -do not fit into the hwmon class. +PSU. Accordingly to the default automatic fan speed plan the fan starts at about +30% of the wattage rating. If this does not happen, a fan failure is likely. The +driver also provides some additional useful values via debugfs, which do not fit +into the hwmon class. Debugfs entries --------------- diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index 9e3e3c0a3bdd..904890598c11 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -42,12 +42,15 @@ * - the driver supports debugfs for values not fitting into the hwmon class * - not every device class (HXi or RMi) supports all commands * - if configured wrong the PSU resets or shuts down, often before actually hitting the - * - reported critical temperature + * reported critical temperature + * - new models like HX1500i Series 2023 have changes in the reported vendor and product + * strings, both are slightly longer now, report vendor and product in one string and are + * the same now */ #define DRIVER_NAME "corsair-psu" -#define REPLY_SIZE 16 /* max length of a reply to a single command */ +#define REPLY_SIZE 24 /* max length of a reply to a single command */ #define CMD_BUFFER_SIZE 64 #define CMD_TIMEOUT_MS 250 #define SECONDS_PER_HOUR (60 * 60) @@ -880,7 +883,7 @@ static const struct hid_device_id corsairpsu_idtable[] = { { HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */ { HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */ { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */ - { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Series 2022 */ + { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Series 2022 and 2023 */ { }, }; MODULE_DEVICE_TABLE(hid, corsairpsu_idtable); From 4dbbaf8fbdbd13adc80731b2452257857e4c2d8b Mon Sep 17 00:00:00 2001 From: Jerrod Frost Date: Sat, 24 Jun 2023 22:23:44 -0300 Subject: [PATCH 53/54] hwmon: (oxp-sensors) Add support for AOKZOE A1 PRO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This device is an iteration over the AOKZOE A1 with the same EC mapping and features. It also has support for tt_toggle. Signed-off-by: Jerrod Frost Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20230625012347.121352-2-samsagax@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/oxp-sensors.rst | 2 ++ drivers/hwmon/oxp-sensors.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst index 0ca1f7728c34..3adeb7406243 100644 --- a/Documentation/hwmon/oxp-sensors.rst +++ b/Documentation/hwmon/oxp-sensors.rst @@ -30,6 +30,7 @@ Supported devices Currently the driver supports the following handhelds: - AOK ZOE A1 + - AOK ZOE A1 PRO - Aya Neo 2 - Aya Neo AIR - Aya Neo AIR Pro @@ -40,6 +41,7 @@ Currently the driver supports the following handhelds: "Turbo/Silent" button behaviour toggle is only supported on: - AOK ZOE A1 + - AOK ZOE A1 PRO - OneXPlayer mini AMD (only with updated alpha BIOS) - OneXPlayer mini AMD PRO diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index 1e59d97219c4..e1a907cae820 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -77,6 +77,13 @@ static const struct dmi_system_id dmi_table[] = { }, .driver_data = (void *)aok_zoe_a1, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"), + }, + .driver_data = (void *)aok_zoe_a1, + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), From 90fc660e8479c5da5bb99a4fb3e0d266fa041b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 26 Jun 2023 10:51:45 +0200 Subject: [PATCH 54/54] hwmon: max31827: Switch back to use struct i2c_driver::probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit struct i2c_driver::probe_new is about to go away. Switch the driver to use the probe callback with the same prototype. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230626085145.554616-1-u.kleine-koenig@pengutronix.de 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 7735e8087df3..602f4e4f81ff 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -456,7 +456,7 @@ static struct i2c_driver max31827_driver = { .name = "max31827", .of_match_table = max31827_of_match, }, - .probe_new = max31827_probe, + .probe = max31827_probe, .id_table = max31827_i2c_ids, }; module_i2c_driver(max31827_driver);