From ca8fd8c16a8b77dfcf7f6ce52d2c863220693a78 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Sat, 24 Dec 2022 05:18:53 +0100 Subject: [PATCH 01/66] hwmon: (ftsteutates) Fix scaling of measurements A user complained that the ftsteutates driver was displaying bogus values since its introduction. This happens because the sensor measurements need to be scaled in order to produce meaningful results: - the fan speed needs to be multiplied by 60 since its in RPS - the temperature is in degrees celsius and needs an offset of 64 - the voltage is in 1/256 of 3.3V The offical datasheet says the voltage needs to be divided by 256, but this is likely an off-by-one-error, since even the BIOS devides by 255 (otherwise 3.3V could not be measured). The voltage channels additionally need a board-specific multiplier, however this can be done by the driver since its board-specific. The reason the missing scaling of measurements is the way Fujitsu used this driver when it was still out-of-tree. Back then, all scaling was done in userspace by libsensors, even the generic one. Tested on a Fujitsu DS3401-B1. Fixes: 08426eda58e0 ("hwmon: Add driver for FTS BMC chip "Teutates"") Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20221224041855.83981-2-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- Documentation/hwmon/ftsteutates.rst | 4 ++++ drivers/hwmon/ftsteutates.c | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Documentation/hwmon/ftsteutates.rst b/Documentation/hwmon/ftsteutates.rst index 58a2483d8d0d..198fa8e2819d 100644 --- a/Documentation/hwmon/ftsteutates.rst +++ b/Documentation/hwmon/ftsteutates.rst @@ -22,6 +22,10 @@ enhancements. It can monitor up to 4 voltages, 16 temperatures and 8 fans. It also contains an integrated watchdog which is currently implemented in this driver. +The 4 voltages require a board-specific multiplier, since the BMC can +only measure voltages up to 3.3V and thus relies on voltage dividers. +Consult your motherboard manual for details. + To clear a temperature or fan alarm, execute the following command with the correct path to the alarm file:: diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index f5b8e724a8ca..ffa0bb364877 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -347,13 +348,15 @@ static ssize_t in_value_show(struct device *dev, { struct fts_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(devattr)->index; - int err; + int value, err; err = fts_update_device(data); if (err < 0) return err; - return sprintf(buf, "%u\n", data->volt[index]); + value = DIV_ROUND_CLOSEST(data->volt[index] * 3300, 255); + + return sprintf(buf, "%d\n", value); } static ssize_t temp_value_show(struct device *dev, @@ -361,13 +364,15 @@ static ssize_t temp_value_show(struct device *dev, { struct fts_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(devattr)->index; - int err; + int value, err; err = fts_update_device(data); if (err < 0) return err; - return sprintf(buf, "%u\n", data->temp_input[index]); + value = (data->temp_input[index] - 64) * 1000; + + return sprintf(buf, "%d\n", value); } static ssize_t temp_fault_show(struct device *dev, @@ -436,13 +441,15 @@ static ssize_t fan_value_show(struct device *dev, { struct fts_data *data = dev_get_drvdata(dev); int index = to_sensor_dev_attr(devattr)->index; - int err; + int value, err; err = fts_update_device(data); if (err < 0) return err; - return sprintf(buf, "%u\n", data->fan_input[index]); + value = data->fan_input[index] * 60; + + return sprintf(buf, "%d\n", value); } static ssize_t fan_source_show(struct device *dev, From 2fbb848b65cde5b876cce52ebcb34de4aaa5a94a Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Mon, 2 Jan 2023 13:28:57 -0800 Subject: [PATCH 02/66] hwmon: (nct6775) Fix incorrect parenthesization in nct6775_write_fan_div() Commit 4ef2774511dc ("hwmon: (nct6775) Convert register access to regmap API") fumbled the shifting & masking of the fan_div values such that odd-numbered fan divisors would always be set to zero. Fix it so that we actually OR in the bits we meant to. Signed-off-by: Zev Weiss Fixes: 4ef2774511dc ("hwmon: (nct6775) Convert register access to regmap API") Cc: stable@kernel.org # v5.19+ Link: https://lore.kernel.org/r/20230102212857.5670-1-zev@bewilderbeest.net Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index da9ec6983e13..c54233f0369b 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -1150,7 +1150,7 @@ static int nct6775_write_fan_div(struct nct6775_data *data, int nr) if (err) return err; reg &= 0x70 >> oddshift; - reg |= data->fan_div[nr] & (0x7 << oddshift); + reg |= (data->fan_div[nr] & 0x7) << oddshift; return nct6775_write_value(data, fandiv_reg, reg); } From f00093608fa790580da309bb9feb5108fbe7c331 Mon Sep 17 00:00:00 2001 From: Zev Weiss Date: Wed, 1 Feb 2023 18:18:25 -0800 Subject: [PATCH 03/66] hwmon: (peci/cputemp) Fix off-by-one in coretemp_label allocation The find_last_bit() call produces the index of the highest-numbered core in core_mask; because cores are numbered from zero, the number of elements we need to allocate is one more than that. Signed-off-by: Zev Weiss Cc: stable@kernel.org # v5.18 Fixes: bf3608f338e9 ("hwmon: peci: Add cputemp driver") Reviewed-by: Iwona Winiarska Link: https://lore.kernel.org/r/20230202021825.21486-1-zev@bewilderbeest.net Signed-off-by: Guenter Roeck --- drivers/hwmon/peci/cputemp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c index 57470fda5f6c..30850a479f61 100644 --- a/drivers/hwmon/peci/cputemp.c +++ b/drivers/hwmon/peci/cputemp.c @@ -402,7 +402,7 @@ static int create_temp_label(struct peci_cputemp *priv) unsigned long core_max = find_last_bit(priv->core_mask, CORE_NUMS_MAX); int i; - priv->coretemp_label = devm_kzalloc(priv->dev, core_max * sizeof(char *), GFP_KERNEL); + priv->coretemp_label = devm_kzalloc(priv->dev, (core_max + 1) * sizeof(char *), GFP_KERNEL); if (!priv->coretemp_label) return -ENOMEM; From e2de0e6abd91b05411cb1f0953115dbbbe9b11ce Mon Sep 17 00:00:00 2001 From: Eugene Shalygin Date: Sat, 21 Jan 2023 12:17:28 +0100 Subject: [PATCH 04/66] hwmon: (asus-ec-sensors) add missing mutex path Add missing mutex path for ProArt X570-CREATOR WIFI. Fixes: de8fbac5e59e (hwmon: (asus-ec-sensors) implement locking via the ACPI global lock) Signed-off-by: Eugene Shalygin Link: https://lore.kernel.org/r/20230121111728.168514-2-eugene.shalygin@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/asus-ec-sensors.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index a901e4e33d81..b4d65916b3c0 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -299,6 +299,7 @@ static const struct ec_board_info board_info_pro_art_x570_creator_wifi = { .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE, + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, .family = family_amd_500_series, }; From 95a56de6ed60aa74c91f67fc37fd28fa916a3521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20Ignacio=20Aramend=C3=ADa?= Date: Mon, 12 Dec 2022 11:12:46 -0300 Subject: [PATCH 05/66] docs: hwmon: Use file modes explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As stated in the mainling list[1] and by checkpatch output, the file modes for is_visible_func should be returned explicitly. Change that in the documentation to avoid confusion. [1]https://lore.kernel.org/linux-hwmon/506a6e7f-4566-2dcf-37f3-0f41f4ce983b@roeck-us.net/ Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20221212141245.52935-1-samsagax@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 f3276b3a381a..26cf55303c61 100644 --- a/Documentation/hwmon/hwmon-kernel-api.rst +++ b/Documentation/hwmon/hwmon-kernel-api.rst @@ -299,7 +299,7 @@ Parameters: Return value: The file mode for this attribute. Typically, this will be 0 (the - attribute will not be created), S_IRUGO, or 'S_IRUGO | S_IWUSR'. + attribute will not be created), 0444, or 0644. :: From e247510e1baad04e9b7b8ed7190dbb00989387b9 Mon Sep 17 00:00:00 2001 From: Herman Fries Date: Wed, 14 Dec 2022 20:46:28 +0100 Subject: [PATCH 06/66] hwmon: (nzxt-smart2) Add device id Adding support for new device id 1e71:2019 NZXT NZXT RGB & Fan Controller Signed-off-by: Herman Fries Link: https://lore.kernel.org/r/20221214194627.135692-1-baracoder@googlemail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/nzxt-smart2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c index 533f38b0b4e9..2b93ba89610a 100644 --- a/drivers/hwmon/nzxt-smart2.c +++ b/drivers/hwmon/nzxt-smart2.c @@ -791,6 +791,7 @@ static const struct hid_device_id nzxt_smart2_hid_id_table[] = { { HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */ + { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller */ {}, }; From 0f8b916bc5b5d74cacef2b616b04db10633b8105 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Fri, 16 Dec 2022 17:24:08 -0300 Subject: [PATCH 07/66] hwmon: (coretemp) avoid RDMSR interrupts to isolated CPUs The coretemp driver uses rdmsr_on_cpu calls to read MSR_IA32_PACKAGE_THERM_STATUS/MSR_IA32_THERM_STATUS registers, which contain information about current core temperature. For certain low latency applications, the RDMSR interruption exceeds the applications requirements. So do not create core files in sysfs, for CPUs which have isolation and nohz_full enabled. Temperature information from the housekeeping cores should be sufficient to infer die temperature. Signed-off-by: Marcelo Tosatti Link: https://lore.kernel.org/r/Y5zT6B1mY9/pnwJV@tpad Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index ca7a9b373bbd..49091ea9f7b7 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -27,6 +27,7 @@ #include #include #include +#include #define DRVNAME "coretemp" @@ -502,6 +503,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, u32 eax, edx; int err, index, attr_no; + if (!housekeeping_cpu(cpu, HK_TYPE_MISC)) + return 0; + /* * Find attr number for sysfs: * We map the attr number to core id of the CPU From bc7fabde40a711fcfb1fb77946b350599f0dd392 Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Wed, 30 Nov 2022 14:08:42 -0600 Subject: [PATCH 08/66] ABI: sysfs-class-hwmon: add a description for fanY_fault Document existing fanY_fault attribute. Signed-off-by: Nick Hawkins Link: https://lore.kernel.org/r/20221130200846.4226-3-nick.hawkins@hpe.com Signed-off-by: Guenter Roeck --- Documentation/ABI/testing/sysfs-class-hwmon | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-hwmon b/Documentation/ABI/testing/sysfs-class-hwmon index 7271781a23b2..638f4c6d4ec7 100644 --- a/Documentation/ABI/testing/sysfs-class-hwmon +++ b/Documentation/ABI/testing/sysfs-class-hwmon @@ -276,6 +276,15 @@ Description: RW +What: /sys/class/hwmon/hwmonX/fanY_fault +Description: + Reports if a fan has reported failure. + + - 1: Failed + - 0: Ok + + RO + What: /sys/class/hwmon/hwmonX/pwmY Description: Pulse width modulation fan control. From b52acefcf741373a3fceea5348e137b685a2d454 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Wed, 7 Dec 2022 18:37:13 +0100 Subject: [PATCH 09/66] hwmon: (pmbus/core) Add min_uV in pmbus regulator helper macro Some regulator operates in a range of voltage which should not allow below the lower threshold. Signed-off-by: Saravanan Sekar Link: https://lore.kernel.org/r/20221207173716.123223-2-saravanan@linumiz.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 16 ++++++++-------- drivers/hwmon/pmbus/pmbus.h | 5 +++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 79f480b4425d..91df8e895147 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -570,14 +570,14 @@ MODULE_DEVICE_TABLE(i2c, ltc2978_id); #define LTC2978_N_VOLTAGES ((LTC2978_MAX_UV / LTC2978_UV_STEP) + 1) static const struct regulator_desc ltc2978_reg_desc[] = { - PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), - PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), - PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), - PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), - PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), - PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), - PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), - PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP), + PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), + PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), + PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), + PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), + PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), + PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), + PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), + PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0), }; static const struct regulator_desc ltc2978_reg_desc_default[] = { diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 10fb17879f8e..713ea7915425 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -464,7 +464,7 @@ struct pmbus_driver_info { extern const struct regulator_ops pmbus_regulator_ops; /* Macros for filling in array of struct regulator_desc */ -#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step) \ +#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step, _min_uV) \ [_id] = { \ .name = (_name # _id), \ .id = (_id), \ @@ -475,9 +475,10 @@ extern const struct regulator_ops pmbus_regulator_ops; .owner = THIS_MODULE, \ .n_voltages = _voltages, \ .uV_step = _step, \ + .min_uV = _min_uV, \ } -#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0) +#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0) /* Function declarations */ From 61d1eb025b237e29cdae0d12bc9feb56cd703bdb Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Wed, 7 Dec 2022 18:37:15 +0100 Subject: [PATCH 10/66] hwmon: (pmbus/mpq7932) Add a support for mpq7932 Power Management IC The MPQ7932 is a power management IC designed to operate from 5V buses to power a variety of Advanced driver-assistance system SOCs. Six integrated buck converters with hardware monitoring capability powers a variety of target rails configurable over PMBus interface. Signed-off-by: Saravanan Sekar Link: https://lore.kernel.org/r/20221207173716.123223-4-saravanan@linumiz.com [groeck: Modified multi-line comments to match standard comment style] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/Kconfig | 16 ++++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/mpq7932.c | 156 ++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 drivers/hwmon/pmbus/mpq7932.c diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 89668af67206..30448e049486 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -317,6 +317,22 @@ config SENSORS_MP5023 This driver can also be built as a module. If so, the module will be called mp5023. +config SENSORS_MPQ7932_REGULATOR + bool "Regulator support for MPQ7932" + depends on SENSORS_MPQ7932 && REGULATOR + help + If you say yes here you get six integrated buck converter regulator + support for power management IC MPS MPQ7932. + +config SENSORS_MPQ7932 + tristate "MPS MPQ7932" + help + If you say yes here you get hardware monitoring functionality support + for power management IC MPS MPQ7932. + + This driver can also be built as a module. If so, the module will + be called mpq7932. + config SENSORS_PIM4328 tristate "Flex PIM4328 and compatibles" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 0002dbe22d52..d9d2fa4bd6f7 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SENSORS_MAX8688) += max8688.o obj-$(CONFIG_SENSORS_MP2888) += mp2888.o obj-$(CONFIG_SENSORS_MP2975) += mp2975.o obj-$(CONFIG_SENSORS_MP5023) += mp5023.o +obj-$(CONFIG_SENSORS_MPQ7932) += mpq7932.o obj-$(CONFIG_SENSORS_PLI1209BC) += pli1209bc.o obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c new file mode 100644 index 000000000000..ff939881dc3b --- /dev/null +++ b/drivers/hwmon/pmbus/mpq7932.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * mpq7932.c - hwmon with optional regulator driver for mps mpq7932 + * Copyright 2022 Monolithic Power Systems, Inc + * + * Author: Saravanan Sekar + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pmbus.h" + +#define MPQ7932_BUCK_UV_MIN 206250 +#define MPQ7932_UV_STEP 6250 +#define MPQ7932_N_VOLTAGES 256 +#define MPQ7932_VOUT_MAX 0xFF +#define MPQ7932_NUM_PAGES 6 + +#define MPQ7932_TON_DELAY 0x60 +#define MPQ7932_VOUT_STARTUP_SLEW 0xA3 +#define MPQ7932_VOUT_SHUTDOWN_SLEW 0xA5 +#define MPQ7932_VOUT_SLEW_MASK GENMASK(1, 0) +#define MPQ7932_TON_DELAY_MASK GENMASK(4, 0) + +struct mpq7932_data { + struct pmbus_driver_info info; + struct pmbus_platform_data pdata; +}; + +#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR) +static struct regulator_desc mpq7932_regulators_desc[] = { + PMBUS_REGULATOR_STEP("buck", 0, MPQ7932_N_VOLTAGES, + MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), + PMBUS_REGULATOR_STEP("buck", 1, MPQ7932_N_VOLTAGES, + MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), + PMBUS_REGULATOR_STEP("buck", 2, MPQ7932_N_VOLTAGES, + MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), + PMBUS_REGULATOR_STEP("buck", 3, MPQ7932_N_VOLTAGES, + MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), + PMBUS_REGULATOR_STEP("buck", 4, MPQ7932_N_VOLTAGES, + MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), + PMBUS_REGULATOR_STEP("buck", 5, MPQ7932_N_VOLTAGES, + MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN), +}; +#endif + +static int mpq7932_write_word_data(struct i2c_client *client, int page, int reg, + u16 word) +{ + switch (reg) { + /* + * chip supports only byte access for VOUT_COMMAND otherwise + * access results -EREMOTEIO + */ + case PMBUS_VOUT_COMMAND: + return pmbus_write_byte_data(client, page, reg, word & 0xFF); + + default: + return -ENODATA; + } +} + +static int mpq7932_read_word_data(struct i2c_client *client, int page, + int phase, int reg) +{ + switch (reg) { + /* + * chip supports neither (PMBUS_VOUT_MARGIN_HIGH, PMBUS_VOUT_MARGIN_LOW) + * nor (PMBUS_MFR_VOUT_MIN, PMBUS_MFR_VOUT_MAX). As a result set voltage + * fails due to error in pmbus_regulator_get_low_margin, so faked. + */ + case PMBUS_MFR_VOUT_MIN: + return 0; + + case PMBUS_MFR_VOUT_MAX: + return MPQ7932_VOUT_MAX; + + /* + * chip supports only byte access for VOUT_COMMAND otherwise + * access results in -EREMOTEIO + */ + case PMBUS_READ_VOUT: + return pmbus_read_byte_data(client, page, PMBUS_VOUT_COMMAND); + + default: + return -ENODATA; + } +} + +static int mpq7932_probe(struct i2c_client *client) +{ + struct mpq7932_data *data; + struct pmbus_driver_info *info; + struct device *dev = &client->dev; + int i; + + data = devm_kzalloc(dev, sizeof(struct mpq7932_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + info = &data->info; + info->pages = MPQ7932_NUM_PAGES; + info->format[PSC_VOLTAGE_OUT] = direct; + info->m[PSC_VOLTAGE_OUT] = 160; + info->b[PSC_VOLTAGE_OUT] = -33; + for (i = 0; i < info->pages; i++) { + info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_STATUS_TEMP; + } + +#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR) + info->num_regulators = ARRAY_SIZE(mpq7932_regulators_desc); + info->reg_desc = mpq7932_regulators_desc; +#endif + + info->read_word_data = mpq7932_read_word_data; + info->write_word_data = mpq7932_write_word_data; + + data->pdata.flags = PMBUS_NO_CAPABILITY; + dev->platform_data = &data->pdata; + + return pmbus_do_probe(client, info); +} + +static const struct of_device_id mpq7932_of_match[] = { + { .compatible = "mps,mpq7932"}, + {}, +}; +MODULE_DEVICE_TABLE(of, mpq7932_of_match); + +static const struct i2c_device_id mpq7932_id[] = { + { "mpq7932", }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, mpq7932_id); + +static struct i2c_driver mpq7932_regulator_driver = { + .driver = { + .name = "mpq7932", + .of_match_table = mpq7932_of_match, + }, + .probe_new = mpq7932_probe, + .id_table = mpq7932_id, +}; +module_i2c_driver(mpq7932_regulator_driver); + +MODULE_AUTHOR("Saravanan Sekar "); +MODULE_DESCRIPTION("MPQ7932 PMIC regulator driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); From ca22c58277470ac195b47f3b4021c6e10f155bc6 Mon Sep 17 00:00:00 2001 From: Saravanan Sekar Date: Wed, 7 Dec 2022 18:37:16 +0100 Subject: [PATCH 11/66] MAINTAINERS: Update the entry for MPQ7932 PMIC driver Update the MAINTAINERS file to include the path for the MPQ7932 Signed-off-by: Saravanan Sekar Link: https://lore.kernel.org/r/20221207173716.123223-5-saravanan@linumiz.com Signed-off-by: Guenter Roeck --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7f86d02cb427..19bf9d7145ec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14142,6 +14142,7 @@ M: Saravanan Sekar S: Maintained F: Documentation/devicetree/bindings/mfd/mps,mp2629.yaml F: Documentation/devicetree/bindings/regulator/mps,mp*.yaml +F: drivers/hwmon/pmbus/mpq7932.c F: drivers/iio/adc/mp2629_adc.c F: drivers/mfd/mp2629.c F: drivers/power/supply/mp2629_charger.c From 8bcb02bdc638df3c59d2797c57b84b641501c424 Mon Sep 17 00:00:00 2001 From: Leonard Anderweit Date: Sun, 18 Dec 2022 12:31:26 +0100 Subject: [PATCH 12/66] hwmon: (aquacomputer_d5next) Rename AQC_TEMP_SENSOR_SIZE to AQC_SENSOR_SIZE Rename AQC_TEMP_SENSOR_SIZE to AQC_SENSOR_SIZE to use with other sensor types. Signed-off-by: Leonard Anderweit Link: https://lore.kernel.org/r/20221218113131.3752-2-leonard.anderweit@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 9cc10080160b..8fd9f7fd7ec4 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -60,7 +60,7 @@ static u8 secondary_ctrl_report[] = { }; /* Sensor sizes and offsets for all Aquacomputer devices */ -#define AQC_TEMP_SENSOR_SIZE 0x02 +#define AQC_SENSOR_SIZE 0x02 #define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF #define AQC_FAN_PERCENT_OFFSET 0x00 #define AQC_FAN_VOLTAGE_OFFSET 0x02 @@ -557,7 +557,7 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_temp_offset: ret = aqc_get_ctrl_val(priv, priv->temp_ctrl_offset + - channel * AQC_TEMP_SENSOR_SIZE, val); + channel * AQC_SENSOR_SIZE, val); if (ret < 0) return ret; @@ -651,7 +651,7 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, val = clamp_val(val, -15000, 15000) / 10; ret = aqc_set_ctrl_val(priv, priv->temp_ctrl_offset + - channel * AQC_TEMP_SENSOR_SIZE, val); + channel * AQC_SENSOR_SIZE, val); if (ret < 0) return ret; break; @@ -797,7 +797,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 for (i = 0; i < priv->num_temp_sensors; i++) { sensor_value = get_unaligned_be16(data + priv->temp_sensor_start_offset + - i * AQC_TEMP_SENSOR_SIZE); + i * AQC_SENSOR_SIZE); if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED) priv->temp_input[i] = -ENODATA; else @@ -808,7 +808,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 for (j = 0; j < priv->num_virtual_temp_sensors; j++) { sensor_value = get_unaligned_be16(data + priv->virtual_temp_sensor_start_offset + - j * AQC_TEMP_SENSOR_SIZE); + j * AQC_SENSOR_SIZE); if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED) priv->temp_input[i] = -ENODATA; else From a2ba7ee25c804f69a2ef0e9c7f76a31cacb685aa Mon Sep 17 00:00:00 2001 From: Leonard Anderweit Date: Sun, 18 Dec 2022 12:31:27 +0100 Subject: [PATCH 13/66] hwmon: (aquacomputer_d5next) Restructure flow sensor reading Read flow sensors the same way for all devices instead of in special cases. Implemented by Aleksa Savic [1]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/commit/1c10912c5fdc8287d88378bcf1ef14d596f29462 Originally-from: Aleksa Savic Signed-off-by: Leonard Anderweit Link: https://lore.kernel.org/r/20221218113131.3752-3-leonard.anderweit@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 8fd9f7fd7ec4..388bf1e33e0d 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -125,6 +125,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0 #define QUADRO_NUM_FANS 4 #define QUADRO_NUM_SENSORS 4 #define QUADRO_NUM_VIRTUAL_SENSORS 16 +#define QUADRO_NUM_FLOW_SENSORS 1 #define QUADRO_CTRL_REPORT_SIZE 0x3c1 /* Sensor report offsets for the Quadro */ @@ -141,6 +142,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed /* Specs of High Flow Next flow sensor */ #define HIGHFLOWNEXT_NUM_SENSORS 2 +#define HIGHFLOWNEXT_NUM_FLOW_SENSORS 1 /* Sensor report offsets for the High Flow Next */ #define HIGHFLOWNEXT_SENSOR_START 85 @@ -303,7 +305,8 @@ struct aqc_data { int virtual_temp_sensor_start_offset; u16 temp_ctrl_offset; u16 power_cycle_count_offset; - u8 flow_sensor_offset; + int num_flow_sensors; + u8 flow_sensors_start_offset; u8 flow_pulses_ctrl_offset; /* General info, same across all devices */ @@ -475,8 +478,8 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 return 0444; break; case quadro: - /* Special case to support flow sensor */ - if (channel < priv->num_fans + 1) + /* Special case to support flow sensors */ + if (channel < priv->num_fans + priv->num_flow_sensors) return 0444; break; default: @@ -830,6 +833,13 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_CURRENT_OFFSET); } + /* Flow sensor readings */ + for (j = 0; j < priv->num_flow_sensors; j++) { + priv->speed_input[i] = get_unaligned_be16(data + priv->flow_sensors_start_offset + + j * AQC_SENSOR_SIZE); + i++; + } + if (priv->power_cycle_count_offset != 0) priv->power_cycles = get_unaligned_be32(data + priv->power_cycle_count_offset); @@ -839,9 +849,6 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10; priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10; break; - case quadro: - priv->speed_input[4] = get_unaligned_be16(data + priv->flow_sensor_offset); - break; case highflownext: /* If external temp sensor is not connected, its power reading is also N/A */ if (priv->temp_input[1] == -ENODATA) @@ -854,7 +861,6 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 priv->voltage_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE_USB) * 10; - priv->speed_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_FLOW); priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY); priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY); break; @@ -1034,11 +1040,13 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->temp_sensor_start_offset = QUADRO_SENSOR_START; priv->num_virtual_temp_sensors = QUADRO_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = QUADRO_VIRTUAL_SENSORS_START; + priv->num_flow_sensors = QUADRO_NUM_FLOW_SENSORS; + priv->flow_sensors_start_offset = QUADRO_FLOW_SENSOR_OFFSET; + priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET; priv->buffer_size = QUADRO_CTRL_REPORT_SIZE; - priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET; priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET; priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; @@ -1056,6 +1064,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS; priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START; + priv->num_flow_sensors = HIGHFLOWNEXT_NUM_FLOW_SENSORS; + priv->flow_sensors_start_offset = HIGHFLOWNEXT_FLOW; priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; From 249c752110a551818f2e7080d81b93b90ae31095 Mon Sep 17 00:00:00 2001 From: Leonard Anderweit Date: Sun, 18 Dec 2022 12:31:28 +0100 Subject: [PATCH 14/66] hwmon: (aquacomputer_d5next) Add structure for fan layout Introduce structure for per device fan sensor offsets. This allows reading fan sensors in aqc_raw_event() from devices which use a different sensor layout in their status HID report. Currently only one version is implemented as all supported devices use the same structure. Signed-off-by: Leonard Anderweit Link: https://lore.kernel.org/r/20221218113131.3752-4-leonard.anderweit@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 388bf1e33e0d..1ea866fcd3ec 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -282,6 +282,21 @@ static const char *const label_highflownext_voltage[] = { "+5V USB voltage" }; +struct aqc_fan_structure_offsets { + u8 voltage; + u8 curr; + u8 power; + u8 speed; +}; + +/* Fan structure offsets for all devices except Aquaero */ +static struct aqc_fan_structure_offsets aqc_general_fan_structure = { + .voltage = AQC_FAN_VOLTAGE_OFFSET, + .curr = AQC_FAN_CURRENT_OFFSET, + .power = AQC_FAN_POWER_OFFSET, + .speed = AQC_FAN_SPEED_OFFSET +}; + struct aqc_data { struct hid_device *hdev; struct device *hwmon_dev; @@ -308,6 +323,7 @@ struct aqc_data { int num_flow_sensors; u8 flow_sensors_start_offset; u8 flow_pulses_ctrl_offset; + struct aqc_fan_structure_offsets *fan_structure; /* General info, same across all devices */ u32 serial_number[2]; @@ -822,15 +838,17 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 /* Fan speed and related readings */ for (i = 0; i < priv->num_fans; i++) { priv->speed_input[i] = - get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_SPEED_OFFSET); + get_unaligned_be16(data + priv->fan_sensor_offsets[i] + + priv->fan_structure->speed); priv->power_input[i] = get_unaligned_be16(data + priv->fan_sensor_offsets[i] + - AQC_FAN_POWER_OFFSET) * 10000; + priv->fan_structure->power) * 10000; priv->voltage_input[i] = get_unaligned_be16(data + priv->fan_sensor_offsets[i] + - AQC_FAN_VOLTAGE_OFFSET) * 10; + priv->fan_structure->voltage) * 10; priv->current_input[i] = - get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_CURRENT_OFFSET); + get_unaligned_be16(data + priv->fan_sensor_offsets[i] + + priv->fan_structure->curr); } /* Flow sensor readings */ @@ -1078,6 +1096,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) break; } + priv->fan_structure = &aqc_general_fan_structure; + if (priv->buffer_size != 0) { priv->checksum_start = 0x01; priv->checksum_length = priv->buffer_size - 3; From ad2f0811fbeb61067e7d3715a3441ece23345e94 Mon Sep 17 00:00:00 2001 From: Leonard Anderweit Date: Sun, 18 Dec 2022 12:31:29 +0100 Subject: [PATCH 15/66] hwmon: (aquacomputer_d5next) Device dependent serial number and firmware offsets Add device dependent serial number and firmware offsets to support devices with different offsets. All currently supported devices share the same offsets. Implemented by Aleksa Savic [1]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/31/commits/14c3acf78b17397edb5dd356e6f5943a9996a1f9 Originally-from: Aleksa Savic Signed-off-by: Leonard Anderweit Link: https://lore.kernel.org/r/20221218113131.3752-5-leonard.anderweit@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 1ea866fcd3ec..cc53231067f4 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -43,9 +43,7 @@ static const char *const aqc_device_names[] = { #define STATUS_REPORT_ID 0x01 #define STATUS_UPDATE_INTERVAL (2 * HZ) /* In seconds */ -#define SERIAL_FIRST_PART 3 -#define SERIAL_SECOND_PART 5 -#define FIRMWARE_VERSION 13 +#define SERIAL_PART_OFFSET 2 #define CTRL_REPORT_ID 0x03 @@ -59,7 +57,10 @@ static u8 secondary_ctrl_report[] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6 }; -/* Sensor sizes and offsets for all Aquacomputer devices */ +/* Info, sensor sizes and offsets for all Aquacomputer devices */ +#define AQC_SERIAL_START 0x3 +#define AQC_FIRMWARE_VERSION 0xD + #define AQC_SENSOR_SIZE 0x02 #define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF #define AQC_FAN_PERCENT_OFFSET 0x00 @@ -326,7 +327,9 @@ struct aqc_data { struct aqc_fan_structure_offsets *fan_structure; /* General info, same across all devices */ + u8 serial_number_start_offset; u32 serial_number[2]; + u8 firmware_version_offset; u16 firmware_version; /* How many times the device was powered on, if available */ @@ -808,9 +811,10 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 priv = hid_get_drvdata(hdev); /* Info provided with every report */ - priv->serial_number[0] = get_unaligned_be16(data + SERIAL_FIRST_PART); - priv->serial_number[1] = get_unaligned_be16(data + SERIAL_SECOND_PART); - priv->firmware_version = get_unaligned_be16(data + FIRMWARE_VERSION); + priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset); + priv->serial_number[1] = get_unaligned_be16(data + priv->serial_number_start_offset + + SERIAL_PART_OFFSET); + priv->firmware_version = get_unaligned_be16(data + priv->firmware_version_offset); /* Physical temperature sensor readings */ for (i = 0; i < priv->num_temp_sensors; i++) { @@ -1096,6 +1100,9 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) break; } + priv->serial_number_start_offset = AQC_SERIAL_START; + priv->firmware_version_offset = AQC_FIRMWARE_VERSION; + priv->fan_structure = &aqc_general_fan_structure; if (priv->buffer_size != 0) { From 1ed5036b3be7db1b694bcaa4095869bdb8657d49 Mon Sep 17 00:00:00 2001 From: Leonard Anderweit Date: Sun, 18 Dec 2022 12:31:30 +0100 Subject: [PATCH 16/66] hwmon: (aquacomputer_d5next) Make fan sensor offsets u16 Make fan sensor offsets u16 as u8 is insufficient for upcoming devices. Signed-off-by: Leonard Anderweit Link: https://lore.kernel.org/r/20221218113131.3752-6-leonard.anderweit@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 cc53231067f4..d28d7079917a 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -83,7 +83,7 @@ static u8 secondary_ctrl_report[] = { #define D5NEXT_5V_VOLTAGE 0x39 #define D5NEXT_12V_VOLTAGE 0x37 #define D5NEXT_VIRTUAL_SENSORS_START 0x3f -static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET }; +static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET }; /* Control report offsets for the D5 Next pump */ #define D5NEXT_TEMP_CTRL_OFFSET 0x2D /* Temperature sensor offsets location */ @@ -115,7 +115,7 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (fr #define OCTO_POWER_CYCLES 0x18 #define OCTO_SENSOR_START 0x3D #define OCTO_VIRTUAL_SENSORS_START 0x45 -static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 }; +static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 }; /* Control report offsets for the Octo */ #define OCTO_TEMP_CTRL_OFFSET 0xA @@ -134,7 +134,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0 #define QUADRO_SENSOR_START 0x34 #define QUADRO_VIRTUAL_SENSORS_START 0x3c #define QUADRO_FLOW_SENSOR_OFFSET 0x6e -static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 }; +static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 }; /* Control report offsets for the Quadro */ #define QUADRO_TEMP_CTRL_OFFSET 0xA @@ -313,7 +313,7 @@ struct aqc_data { int checksum_offset; int num_fans; - u8 *fan_sensor_offsets; + u16 *fan_sensor_offsets; u16 *fan_ctrl_offsets; int num_temp_sensors; int temp_sensor_start_offset; From 2c55211104b44bd1b83009f0af204237a62e28bd Mon Sep 17 00:00:00 2001 From: Leonard Anderweit Date: Sun, 18 Dec 2022 12:31:31 +0100 Subject: [PATCH 17/66] hwmon: (aquacomputer_d5next) Support sensors for Aquacomputer Aquaero Add support for reading sensors of the Aquacomputer Aquaero 5/6 fan controllers. These fan controllers supports 4 fans, 8 physical temperature sensors, 8 virtual temperature sensors and 2 flow sensors. Temperature and flow sensor reading implemented by Aleksa Savic [1] [2] [3]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/31 [2] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/51 [3] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/55 Originally-from: Aleksa Savic Signed-off-by: Leonard Anderweit Link: https://lore.kernel.org/r/20221218113131.3752-7-leonard.anderweit@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 5 + drivers/hwmon/aquacomputer_d5next.c | 108 ++++++++++++++++++-- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 637bdbc8fcad..b94ff08080bf 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -5,6 +5,7 @@ Kernel driver aquacomputer-d5next Supported devices: +* Aquacomputer Aquaero 5/6 fan controllers * Aquacomputer D5 Next watercooling pump * Aquacomputer Farbwerk RGB controller * Aquacomputer Farbwerk 360 RGB controller @@ -20,6 +21,10 @@ Description This driver exposes hardware sensors of listed Aquacomputer devices, which communicate through proprietary USB HID protocols. +The Aquaero devices expose eight temperature sensors, eight virtual temperature +sensors and two flow senors. The fans expose their speed (in RPM), power, +voltage and current. + For the D5 Next pump, available sensors are pump and fan speed, power, voltage and current, as well as coolant temperature and eight virtual temp sensors. Also available through debugfs are the serial number, firmware version and power-on diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index d28d7079917a..0fd00cfb86c8 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) + * Quadro, High Flow Next, Aquaero) * * Aquacomputer devices send HID reports (with ID 0x01) every second to report * sensor values. @@ -21,6 +21,7 @@ #include #define USB_VENDOR_ID_AQUACOMPUTER 0x0c70 +#define USB_PRODUCT_ID_AQUAERO 0xf001 #define USB_PRODUCT_ID_FARBWERK 0xf00a #define USB_PRODUCT_ID_QUADRO 0xf00d #define USB_PRODUCT_ID_D5NEXT 0xf00e @@ -28,7 +29,7 @@ #define USB_PRODUCT_ID_OCTO 0xf011 #define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012 -enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext }; +enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero }; static const char *const aqc_device_names[] = { [d5next] = "d5next", @@ -36,7 +37,8 @@ static const char *const aqc_device_names[] = { [farbwerk360] = "farbwerk360", [octo] = "octo", [quadro] = "quadro", - [highflownext] = "highflownext" + [highflownext] = "highflownext", + [aquaero] = "aquaero" }; #define DRIVER_NAME "aquacomputer_d5next" @@ -57,7 +59,7 @@ static u8 secondary_ctrl_report[] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6 }; -/* Info, sensor sizes and offsets for all Aquacomputer devices */ +/* Info, sensor sizes and offsets for most Aquacomputer devices */ #define AQC_SERIAL_START 0x3 #define AQC_FIRMWARE_VERSION 0xD @@ -69,6 +71,24 @@ static u8 secondary_ctrl_report[] = { #define AQC_FAN_POWER_OFFSET 0x06 #define AQC_FAN_SPEED_OFFSET 0x08 +/* Specs of the Aquaero fan controllers */ +#define AQUAERO_SERIAL_START 0x07 +#define AQUAERO_FIRMWARE_VERSION 0x0B +#define AQUAERO_NUM_FANS 4 +#define AQUAERO_NUM_SENSORS 8 +#define AQUAERO_NUM_VIRTUAL_SENSORS 8 +#define AQUAERO_NUM_FLOW_SENSORS 2 + +/* Sensor report offsets for Aquaero fan controllers */ +#define AQUAERO_SENSOR_START 0x65 +#define AQUAERO_VIRTUAL_SENSOR_START 0x85 +#define AQUAERO_FLOW_SENSORS_START 0xF9 +#define AQUAERO_FAN_VOLTAGE_OFFSET 0x04 +#define AQUAERO_FAN_CURRENT_OFFSET 0x06 +#define AQUAERO_FAN_POWER_OFFSET 0x08 +#define AQUAERO_FAN_SPEED_OFFSET 0x00 +static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B }; + /* Specs of the D5 Next pump */ #define D5NEXT_NUM_FANS 2 #define D5NEXT_NUM_SENSORS 1 @@ -181,12 +201,16 @@ static const char *const label_d5next_current[] = { "Fan current" }; -/* Labels for Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */ +/* Labels for Aquaero, Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */ static const char *const label_temp_sensors[] = { "Sensor 1", "Sensor 2", "Sensor 3", - "Sensor 4" + "Sensor 4", + "Sensor 5", + "Sensor 6", + "Sensor 7", + "Sensor 8" }; static const char *const label_virtual_temp_sensors[] = { @@ -262,6 +286,16 @@ static const char *const label_quadro_speeds[] = { "Flow speed [dL/h]" }; +/* Labels for Aquaero fan speeds */ +static const char *const label_aquaero_speeds[] = { + "Fan 1 speed", + "Fan 2 speed", + "Fan 3 speed", + "Fan 4 speed", + "Flow sensor 1 [dL/h]", + "Flow sensor 2 [dL/h]" +}; + /* Labels for High Flow Next */ static const char *const label_highflownext_temp_sensors[] = { "Coolant temp", @@ -290,6 +324,14 @@ struct aqc_fan_structure_offsets { u8 speed; }; +/* Fan structure offsets for Aquaero */ +static struct aqc_fan_structure_offsets aqc_aquaero_fan_structure = { + .voltage = AQUAERO_FAN_VOLTAGE_OFFSET, + .curr = AQUAERO_FAN_CURRENT_OFFSET, + .power = AQUAERO_FAN_POWER_OFFSET, + .speed = AQUAERO_FAN_SPEED_OFFSET +}; + /* Fan structure offsets for all devices except Aquaero */ static struct aqc_fan_structure_offsets aqc_general_fan_structure = { .voltage = AQC_FAN_VOLTAGE_OFFSET, @@ -496,6 +538,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 if (channel < 3) return 0444; break; + case aquaero: case quadro: /* Special case to support flow sensors */ if (channel < priv->num_fans + priv->num_flow_sensors) @@ -977,6 +1020,42 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) goto fail_and_stop; switch (hdev->product) { + case USB_PRODUCT_ID_AQUAERO: + /* + * Aquaero presents itself as three HID devices under the same product ID: + * "aquaero keyboard/mouse", "aquaero System Control" and "aquaero Device", + * which is the one we want to communicate with. Unlike most other Aquacomputer + * devices, Aquaero does not return meaningful data when explicitly requested + * using GET_FEATURE_REPORT. + * + * The difference between "aquaero Device" and the other two is in the collections + * they present. The two other devices have the type of the second element in + * their respective collections set to 1, while the real device has it set to 0. + */ + if (hdev->collection[1].type != 0) { + ret = -ENODEV; + goto fail_and_close; + } + + priv->kind = aquaero; + + priv->num_fans = AQUAERO_NUM_FANS; + priv->fan_sensor_offsets = aquaero_sensor_fan_offsets; + + priv->num_temp_sensors = AQUAERO_NUM_SENSORS; + priv->temp_sensor_start_offset = AQUAERO_SENSOR_START; + priv->num_virtual_temp_sensors = AQUAERO_NUM_VIRTUAL_SENSORS; + priv->virtual_temp_sensor_start_offset = AQUAERO_VIRTUAL_SENSOR_START; + priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS; + priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START; + + priv->temp_label = label_temp_sensors; + priv->virtual_temp_label = label_virtual_temp_sensors; + priv->speed_label = label_aquaero_speeds; + priv->power_label = label_fan_power; + priv->voltage_label = label_fan_voltage; + priv->current_label = label_fan_current; + break; case USB_PRODUCT_ID_D5NEXT: priv->kind = d5next; @@ -1100,10 +1179,20 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) break; } - priv->serial_number_start_offset = AQC_SERIAL_START; - priv->firmware_version_offset = AQC_FIRMWARE_VERSION; + switch (priv->kind) { + case aquaero: + priv->serial_number_start_offset = AQUAERO_SERIAL_START; + priv->firmware_version_offset = AQUAERO_FIRMWARE_VERSION; - priv->fan_structure = &aqc_general_fan_structure; + priv->fan_structure = &aqc_aquaero_fan_structure; + break; + default: + priv->serial_number_start_offset = AQC_SERIAL_START; + priv->firmware_version_offset = AQC_FIRMWARE_VERSION; + + priv->fan_structure = &aqc_general_fan_structure; + break; + } if (priv->buffer_size != 0) { priv->checksum_start = 0x01; @@ -1152,6 +1241,7 @@ static void aqc_remove(struct hid_device *hdev) } static const struct hid_device_id aqc_table[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUAERO) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_D5NEXT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) }, From ebd4bfee2b972d34a2f72f81767d0cf47e6c914b Mon Sep 17 00:00:00 2001 From: "Derek J. Clark" Date: Wed, 28 Dec 2022 18:56:09 -0800 Subject: [PATCH 18/66] hwmon: (oxp-sensors) Add AYANEO AIR and AIR Pro Add support for the AYANEO AIR and AYANEO AIR Pro models of handheld devices. These devices use the same EC registers and logic as the One X Player mini AMD. Previous AYANEO models are not supported as they use a different EC and do not have the necessary fan speed write enable and setting registers. The driver is tested on AYANEO AIR while AIR Pro model EC functionality and DMI data were verified using command line tools by another user. Add: - AYANEO AIR (AMD 5560U) - AYANEO AIR Pro (AMD 5560U) - AYANEO AIR Pro (AMD 5825U) While at it, fix spelling error (appart -> apart). Link: https://lore.kernel.org/r/20221229025609.147482-1-derekjohn.clark@gmail.com Signed-off-by: Derek J. Clark [groeck: Sanitize commit description] Signed-off-by: Guenter Roeck --- Documentation/hwmon/oxp-sensors.rst | 17 ++++++---- MAINTAINERS | 1 + drivers/hwmon/oxp-sensors.c | 52 ++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst index 39c588ec5c50..566a8d5bde08 100644 --- a/Documentation/hwmon/oxp-sensors.rst +++ b/Documentation/hwmon/oxp-sensors.rst @@ -3,18 +3,21 @@ Kernel driver oxp-sensors ========================= -Author: +Authors: + - Derek John Clark - Joaquín Ignacio Aramendía Description: ------------ -One X Player devices from One Netbook provide fan readings and fan control -through its Embedded Controller. +Handheld devices from One Netbook and Aya Neo provide fan readings and fan +control through their embedded controllers. -Currently only supports AMD boards from the One X Player and AOK ZOE lineup. -Intel boards could be supported if we could figure out the EC registers and -values to write to since the EC layout and model is different. +Currently only supports AMD boards from One X Player, AOK ZOE, and some Aya +Neo devices. One X Player Intel boards could be supported if we could figure +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. Supported devices ----------------- @@ -22,6 +25,8 @@ Supported devices Currently the driver supports the following handhelds: - AOK ZOE A1 + - Aya Neo AIR + - Aya Neo AIR Pro - OneXPlayer AMD - OneXPlayer mini AMD - OneXPlayer mini AMD PRO diff --git a/MAINTAINERS b/MAINTAINERS index 19bf9d7145ec..cae2897bc702 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15574,6 +15574,7 @@ F: drivers/mtd/nand/onenand/ F: include/linux/mtd/onenand*.h ONEXPLAYER FAN DRIVER +M: Derek John Clark M: Joaquín Ignacio Aramendía L: linux-hwmon@vger.kernel.org S: Maintained diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index f84ec8f8eda9..36872b57912a 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Platform driver for OXP Handhelds that expose fan reading and control - * via hwmon sysfs. + * Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose + * fan reading and control via hwmon sysfs. * - * Old boards have the same DMI strings and they are told appart by the - * boot cpu vendor (Intel/AMD). Currently only AMD boards are supported - * but the code is made to be simple to add other handheld boards in the - * future. + * Old OXP boards have the same DMI strings and they are told apart by + * the boot cpu vendor (Intel/AMD). Currently only AMD boards are + * supported but the code is made to be simple to add other handheld + * boards in the future. * Fan control is provided via pwm interface in the range [0-255]. * Old AMD boards use [0-100] as range in the EC, the written value is * scaled to accommodate for that. Newer boards like the mini PRO and @@ -42,6 +42,8 @@ static bool unlock_global_acpi_lock(void) enum oxp_board { aok_zoe_a1 = 1, + aya_neo_air, + aya_neo_air_pro, oxp_mini_amd, oxp_mini_amd_pro, }; @@ -60,6 +62,20 @@ 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, "AIR"), + }, + .driver_data = (void *) &(enum oxp_board) {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}, + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), @@ -161,8 +177,17 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); if (ret) return ret; - if (board == oxp_mini_amd) + switch (board) { + case aya_neo_air: + case aya_neo_air_pro: + case oxp_mini_amd: *val = (*val * 255) / 100; + break; + case oxp_mini_amd_pro: + case aok_zoe_a1: + default: + break; + } return 0; case hwmon_pwm_enable: return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); @@ -191,8 +216,17 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, case hwmon_pwm_input: if (val < 0 || val > 255) return -EINVAL; - if (board == oxp_mini_amd) + switch (board) { + case aya_neo_air: + case aya_neo_air_pro: + case oxp_mini_amd: val = (val * 100) / 255; + break; + case aok_zoe_a1: + case oxp_mini_amd_pro: + default: + break; + } return write_to_ec(dev, OXP_SENSOR_PWM_REG, val); default: break; @@ -233,7 +267,7 @@ static int oxp_platform_probe(struct platform_device *pdev) /* * Have to check for AMD processor here because DMI strings are the - * same between Intel and AMD boards, the only way to tell them appart + * same between Intel and AMD boards, the only way to tell them apart * is the CPU. * Intel boards seem to have different EC registers and values to * read/write. From e1515a749276efeff18b091f3367c3e4640ad497 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Sat, 24 Dec 2022 05:18:55 +0100 Subject: [PATCH 19/66] hwmon: (ftsteutates) Use devm_watchdog_register_device() Use devm_watchdog_register_device() to let devres take care of unregistering the watchdog at device removal. Remove the now pointless fts_remove() function. Tested on a Fujitsu DS3401-B1. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20221224041855.83981-4-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ftsteutates.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index ffa0bb364877..e860924f90aa 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -337,7 +337,7 @@ static int fts_watchdog_init(struct fts_data *data) /* max timeout 255 minutes. */ data->wdd.max_hw_heartbeat_ms = 0xFF * 60 * MSEC_PER_SEC; - return watchdog_register_device(&data->wdd); + return devm_watchdog_register_device(&data->client->dev, &data->wdd); } /*****************************************************************************/ @@ -751,13 +751,6 @@ static int fts_detect(struct i2c_client *client, return 0; } -static void fts_remove(struct i2c_client *client) -{ - struct fts_data *data = dev_get_drvdata(&client->dev); - - watchdog_unregister_device(&data->wdd); -} - static int fts_probe(struct i2c_client *client) { u8 revision; @@ -826,7 +819,6 @@ static struct i2c_driver fts_driver = { }, .id_table = fts_id, .probe_new = fts_probe, - .remove = fts_remove, .detect = fts_detect, .address_list = normal_i2c, }; From 4b8e5a9326258507f0a796afef1f10e85d50b7bb Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 23 Dec 2022 16:10:56 +0800 Subject: [PATCH 20/66] hwmon: (aht10) Fix some kernel-doc comments Make the description of @aht10_data to @data in aht10_read_values() and remove @client in aht10_init() to clear the below warnings: drivers/hwmon/aht10.c:87: warning: Excess function parameter 'client' description in 'aht10_init' drivers/hwmon/aht10.c:131: warning: Function parameter or member 'data' not described in 'aht10_read_values' drivers/hwmon/aht10.c:131: warning: Excess function parameter 'aht10_data' description in 'aht10_read_values' Link: https://bugzilla.openanolis.cn/show_bug.cgi?id=3543 Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20221223081056.88345-1-yang.lee@linux.alibaba.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aht10.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index d76f3441ecf1..9babd69d54a3 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -79,7 +79,6 @@ struct aht10_data { /** * aht10_init() - Initialize an AHT10 chip - * @client: the i2c client associated with the AHT10 * @data: the data associated with this AHT10 chip * Return: 0 if succesfull, 1 if not */ @@ -124,7 +123,7 @@ static int aht10_polltime_expired(struct aht10_data *data) /** * aht10_read_values() - read and parse the raw data from the AHT10 - * @aht10_data: the struct aht10_data to use for the lock + * @data: the struct aht10_data to use for the lock * Return: 0 if succesfull, 1 if not */ static int aht10_read_values(struct aht10_data *data) From 3d2e9f582a8e024b5f0516c1895ce586aea9c334 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Sun, 1 Jan 2023 20:00:56 +0100 Subject: [PATCH 21/66] hwmon: (aquacomputer_d5next) Add support for reading calculated Aquaero sensors Add support for reading four calculated virtual temp sensors on the Aquacomputer Aquaero. Values of these sensors are calculated on the device itself based on what the user configured in the official software. Configuring these sensors is not currently reverse engineered. Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20230101190056.1357124-1-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 6 +-- drivers/hwmon/aquacomputer_d5next.c | 49 ++++++++++++++++++--- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index b94ff08080bf..3f7880fb8116 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -21,9 +21,9 @@ Description This driver exposes hardware sensors of listed Aquacomputer devices, which communicate through proprietary USB HID protocols. -The Aquaero devices expose eight temperature sensors, eight virtual temperature -sensors and two flow senors. The fans expose their speed (in RPM), power, -voltage and current. +The Aquaero devices expose eight physical, eight virtual and four calculated +virtual temperature sensors, as well as two flow sensors. The fans expose their +speed (in RPM), power, voltage and current. For the D5 Next pump, available sensors are pump and fan speed, power, voltage and current, as well as coolant temperature and eight virtual temp sensors. Also diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 0fd00cfb86c8..c1b885240ddf 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -77,11 +77,13 @@ static u8 secondary_ctrl_report[] = { #define AQUAERO_NUM_FANS 4 #define AQUAERO_NUM_SENSORS 8 #define AQUAERO_NUM_VIRTUAL_SENSORS 8 +#define AQUAERO_NUM_CALC_VIRTUAL_SENSORS 4 #define AQUAERO_NUM_FLOW_SENSORS 2 /* Sensor report offsets for Aquaero fan controllers */ #define AQUAERO_SENSOR_START 0x65 #define AQUAERO_VIRTUAL_SENSOR_START 0x85 +#define AQUAERO_CALC_VIRTUAL_SENSOR_START 0x95 #define AQUAERO_FLOW_SENSORS_START 0xF9 #define AQUAERO_FAN_VOLTAGE_OFFSET 0x04 #define AQUAERO_FAN_CURRENT_OFFSET 0x06 @@ -232,6 +234,13 @@ static const char *const label_virtual_temp_sensors[] = { "Virtual sensor 16", }; +static const char *const label_aquaero_calc_temp_sensors[] = { + "Calc. virtual sensor 1", + "Calc. virtual sensor 2", + "Calc. virtual sensor 3", + "Calc. virtual sensor 4" +}; + /* Labels for Octo and Quadro (except speed) */ static const char *const label_fan_speed[] = { "Fan 1 speed", @@ -361,6 +370,8 @@ struct aqc_data { int temp_sensor_start_offset; int num_virtual_temp_sensors; int virtual_temp_sensor_start_offset; + int num_calc_virt_temp_sensors; + int calc_virt_temp_sensor_start_offset; u16 temp_ctrl_offset; u16 power_cycle_count_offset; int num_flow_sensors; @@ -378,7 +389,7 @@ struct aqc_data { u32 power_cycles; /* Sensor values */ - s32 temp_input[20]; /* Max 4 physical and 16 virtual */ + s32 temp_input[20]; /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */ u16 speed_input[8]; u32 power_input[8]; u16 voltage_input[8]; @@ -387,6 +398,7 @@ struct aqc_data { /* Label values */ const char *const *temp_label; const char *const *virtual_temp_label; + const char *const *calc_virt_temp_label; /* For Aquaero */ const char *const *speed_label; const char *const *power_label; const char *const *voltage_label; @@ -507,7 +519,9 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 } } - if (channel < priv->num_temp_sensors + priv->num_virtual_temp_sensors) + if (channel < + priv->num_temp_sensors + priv->num_virtual_temp_sensors + + priv->num_calc_virt_temp_sensors) switch (attr) { case hwmon_temp_label: case hwmon_temp_input: @@ -676,12 +690,20 @@ static int aqc_read_string(struct device *dev, enum hwmon_sensor_types type, u32 { struct aqc_data *priv = dev_get_drvdata(dev); + /* Number of sensors that are not calculated */ + int num_non_calc_sensors = priv->num_temp_sensors + priv->num_virtual_temp_sensors; + switch (type) { case hwmon_temp: - if (channel < priv->num_temp_sensors) + if (channel < priv->num_temp_sensors) { *str = priv->temp_label[channel]; - else - *str = priv->virtual_temp_label[channel - priv->num_temp_sensors]; + } else { + if (priv->kind == aquaero && channel >= num_non_calc_sensors) + *str = + priv->calc_virt_temp_label[channel - num_non_calc_sensors]; + else + *str = priv->virtual_temp_label[channel - priv->num_temp_sensors]; + } break; case hwmon_fan: *str = priv->speed_label[channel]; @@ -910,6 +932,20 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 /* Special-case sensor readings */ switch (priv->kind) { + case aquaero: + /* Read calculated virtual temp sensors */ + i = priv->num_temp_sensors + priv->num_virtual_temp_sensors; + for (j = 0; j < priv->num_calc_virt_temp_sensors; j++) { + sensor_value = get_unaligned_be16(data + + priv->calc_virt_temp_sensor_start_offset + + j * AQC_SENSOR_SIZE); + if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED) + priv->temp_input[i] = -ENODATA; + else + priv->temp_input[i] = sensor_value * 10; + i++; + } + break; case d5next: priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10; priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10; @@ -1046,11 +1082,14 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->temp_sensor_start_offset = AQUAERO_SENSOR_START; priv->num_virtual_temp_sensors = AQUAERO_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = AQUAERO_VIRTUAL_SENSOR_START; + priv->num_calc_virt_temp_sensors = AQUAERO_NUM_CALC_VIRTUAL_SENSORS; + priv->calc_virt_temp_sensor_start_offset = AQUAERO_CALC_VIRTUAL_SENSOR_START; priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS; priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; + priv->calc_virt_temp_label = label_aquaero_calc_temp_sensors; priv->speed_label = label_aquaero_speeds; priv->power_label = label_fan_power; priv->voltage_label = label_fan_voltage; From 6d03bbff456befeccdd4d663177c4d6c75d0c4ff Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 3 Jan 2023 12:46:20 +0100 Subject: [PATCH 22/66] hwmon: (coretemp) Simplify platform device handling Coretemp's platform driver is unconventional. All the real work is done globally by the initcall and CPU hotplug notifiers, while the "driver" effectively just wraps an allocation and the registration of the hwmon interface in a long-winded round-trip through the driver core. The whole logic of dynamically creating and destroying platform devices to bring the interfaces up and down is error prone, since it assumes platform_device_add() will synchronously bind the driver and set drvdata before it returns, thus results in a NULL dereference if drivers_autoprobe is turned off for the platform bus. Furthermore, the unusual approach of doing that from within a CPU hotplug notifier, already commented in the code that it deadlocks suspend, also causes lockdep issues for other drivers or subsystems which may want to legitimately register a CPU hotplug notifier from a platform bus notifier. All of these issues can be solved by ripping this unusual behaviour out completely, simply tying the platform devices to the lifetime of the module itself, and directly managing the hwmon interfaces from the hotplug notifiers. There is a slight user-visible change in that /sys/bus/platform/drivers/coretemp will no longer appear, and /sys/devices/platform/coretemp.n will remain present if package n is hotplugged off, but hwmon users should really only be looking for the presence of the hwmon interfaces, whose behaviour remains unchanged. Link: https://lore.kernel.org/lkml/20220922101036.87457-1-janusz.krzysztofik@linux.intel.com/ Link: https://gitlab.freedesktop.org/drm/intel/issues/6641 Signed-off-by: Robin Murphy Signed-off-by: Janusz Krzysztofik Link: https://lore.kernel.org/r/20230103114620.15319-1-janusz.krzysztofik@linux.intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 134 ++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 73 deletions(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 49091ea9f7b7..30d77f451937 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -592,66 +592,49 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx) ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO); } -static int coretemp_probe(struct platform_device *pdev) +static int coretemp_device_add(int zoneid) { - struct device *dev = &pdev->dev; + struct platform_device *pdev; struct platform_data *pdata; + int err; /* Initialize the per-zone data structures */ - pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL); + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - pdata->pkg_id = pdev->id; + pdata->pkg_id = zoneid; ida_init(&pdata->ida); - platform_set_drvdata(pdev, pdata); - - pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME, - pdata, NULL); - return PTR_ERR_OR_ZERO(pdata->hwmon_dev); -} - -static int coretemp_remove(struct platform_device *pdev) -{ - struct platform_data *pdata = platform_get_drvdata(pdev); - int i; - - for (i = MAX_CORE_DATA - 1; i >= 0; --i) - if (pdata->core_data[i]) - coretemp_remove_core(pdata, i); - - ida_destroy(&pdata->ida); - return 0; -} - -static struct platform_driver coretemp_driver = { - .driver = { - .name = DRVNAME, - }, - .probe = coretemp_probe, - .remove = coretemp_remove, -}; - -static struct platform_device *coretemp_device_add(unsigned int cpu) -{ - int err, zoneid = topology_logical_die_id(cpu); - struct platform_device *pdev; - - if (zoneid < 0) - return ERR_PTR(-ENOMEM); pdev = platform_device_alloc(DRVNAME, zoneid); - if (!pdev) - return ERR_PTR(-ENOMEM); - - err = platform_device_add(pdev); - if (err) { - platform_device_put(pdev); - return ERR_PTR(err); + if (!pdev) { + err = -ENOMEM; + goto err_free_pdata; } + err = platform_device_add(pdev); + if (err) + goto err_put_dev; + + platform_set_drvdata(pdev, pdata); zone_devices[zoneid] = pdev; - return pdev; + return 0; + +err_put_dev: + platform_device_put(pdev); +err_free_pdata: + kfree(pdata); + return err; +} + +static void coretemp_device_remove(int zoneid) +{ + struct platform_device *pdev = zone_devices[zoneid]; + struct platform_data *pdata = platform_get_drvdata(pdev); + + ida_destroy(&pdata->ida); + kfree(pdata); + platform_device_unregister(pdev); } static int coretemp_cpu_online(unsigned int cpu) @@ -675,7 +658,10 @@ static int coretemp_cpu_online(unsigned int cpu) if (!cpu_has(c, X86_FEATURE_DTHERM)) return -ENODEV; - if (!pdev) { + pdata = platform_get_drvdata(pdev); + if (!pdata->hwmon_dev) { + struct device *hwmon; + /* Check the microcode version of the CPU */ if (chk_ucode_version(cpu)) return -EINVAL; @@ -686,9 +672,11 @@ static int coretemp_cpu_online(unsigned int cpu) * online. So, initialize per-pkg data structures and * then bring this core online. */ - pdev = coretemp_device_add(cpu); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); + hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME, + pdata, NULL); + if (IS_ERR(hwmon)) + return PTR_ERR(hwmon); + pdata->hwmon_dev = hwmon; /* * Check whether pkgtemp support is available. @@ -698,7 +686,6 @@ static int coretemp_cpu_online(unsigned int cpu) coretemp_add_core(pdev, cpu, 1); } - pdata = platform_get_drvdata(pdev); /* * Check whether a thread sibling is already online. If not add the * interface for this CPU core. @@ -717,18 +704,14 @@ static int coretemp_cpu_offline(unsigned int cpu) struct temp_data *tdata; int i, indx = -1, target; - /* - * Don't execute this on suspend as the device remove locks - * up the machine. - */ + /* No need to tear down any interfaces for suspend */ if (cpuhp_tasks_frozen) return 0; /* If the physical CPU device does not exist, just return */ - if (!pdev) - return 0; - pd = platform_get_drvdata(pdev); + if (!pd->hwmon_dev) + return 0; for (i = 0; i < NUM_REAL_CORES; i++) { if (pd->cpu_map[i] == topology_core_id(cpu)) { @@ -760,13 +743,14 @@ static int coretemp_cpu_offline(unsigned int cpu) } /* - * If all cores in this pkg are offline, remove the device. This - * will invoke the platform driver remove function, which cleans up - * the rest. + * If all cores in this pkg are offline, remove the interface. */ + tdata = pd->core_data[PKG_SYSFS_ATTR_NO]; if (cpumask_empty(&pd->cpumask)) { - zone_devices[topology_logical_die_id(cpu)] = NULL; - platform_device_unregister(pdev); + if (tdata) + coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO); + hwmon_device_unregister(pd->hwmon_dev); + pd->hwmon_dev = NULL; return 0; } @@ -774,7 +758,6 @@ static int coretemp_cpu_offline(unsigned int cpu) * Check whether this core is the target for the package * interface. We need to assign it to some other cpu. */ - tdata = pd->core_data[PKG_SYSFS_ATTR_NO]; if (tdata && tdata->cpu == cpu) { target = cpumask_first(&pd->cpumask); mutex_lock(&tdata->update_lock); @@ -793,7 +776,7 @@ static enum cpuhp_state coretemp_hp_online; static int __init coretemp_init(void) { - int err; + int i, err; /* * CPUID.06H.EAX[0] indicates whether the CPU has thermal @@ -809,20 +792,22 @@ static int __init coretemp_init(void) if (!zone_devices) return -ENOMEM; - err = platform_driver_register(&coretemp_driver); - if (err) - goto outzone; + for (i = 0; i < max_zones; i++) { + err = coretemp_device_add(i); + if (err) + goto outzone; + } err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online", coretemp_cpu_online, coretemp_cpu_offline); if (err < 0) - goto outdrv; + goto outzone; coretemp_hp_online = err; return 0; -outdrv: - platform_driver_unregister(&coretemp_driver); outzone: + while (i--) + coretemp_device_remove(i); kfree(zone_devices); return err; } @@ -830,8 +815,11 @@ module_init(coretemp_init) static void __exit coretemp_exit(void) { + int i; + cpuhp_remove_state(coretemp_hp_online); - platform_driver_unregister(&coretemp_driver); + for (i = 0; i < max_zones; i++) + coretemp_device_remove(i); kfree(zone_devices); } module_exit(coretemp_exit) From 90905f7c40910a68677ea452ecf0023f31d6b08f Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Tue, 3 Jan 2023 14:36:50 -0600 Subject: [PATCH 23/66] hwmon: (gxp-fan-ctrl) Add GXP fan controller The GXP SoC can support up to 16 fans through the interface provided by the CPLD. The current support is limited to 8 fans. The fans speeds are controlled via 8 different PWMs which can vary in value from 0-255. The fans are also capable of reporting if they have failed to the CPLD which in turn reports the status to the GXP SoC. Signed-off-by: Nick Hawkins Link: https://lore.kernel.org/r/20230103203654.59322-2-nick.hawkins@hpe.com [groeck: Improved alignment of defined, added missing include linux/bits.h] Signed-off-by: Guenter Roeck --- Documentation/hwmon/gxp-fan-ctrl.rst | 28 +++ Documentation/hwmon/index.rst | 1 + drivers/hwmon/Kconfig | 9 + drivers/hwmon/Makefile | 1 + drivers/hwmon/gxp-fan-ctrl.c | 255 +++++++++++++++++++++++++++ 5 files changed, 294 insertions(+) create mode 100644 Documentation/hwmon/gxp-fan-ctrl.rst create mode 100644 drivers/hwmon/gxp-fan-ctrl.c diff --git a/Documentation/hwmon/gxp-fan-ctrl.rst b/Documentation/hwmon/gxp-fan-ctrl.rst new file mode 100644 index 000000000000..ae3397e81c04 --- /dev/null +++ b/Documentation/hwmon/gxp-fan-ctrl.rst @@ -0,0 +1,28 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +Kernel driver gxp-fan-ctrl +========================== + +Supported chips: + + * HPE GXP SOC + +Author: Nick Hawkins + + +Description +----------- + +gxp-fan-ctrl is a driver which provides fan control for the hpe gxp soc. +The driver allows the gathering of fan status and the use of fan +PWM control. + + +Sysfs attributes +---------------- + +======================= =========================================================== +pwm[0-7] Fan 0 to 7 respective PWM value (0-255) +fan[0-7]_fault Fan 0 to 7 respective fault status: 1 fail, 0 ok +fan[0-7]_enable Fan 0 to 7 respective enabled status: 1 enabled, 0 disabled +======================= =========================================================== diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index fe2cc6b73634..7b36b0897230 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -73,6 +73,7 @@ Hardware Monitoring Kernel Drivers g762 gsc-hwmon gl518sm + gxp-fan-ctrl hih6130 ibmaem ibm-cffps diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3176c33af6c6..9c55b2962e40 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -714,6 +714,15 @@ config SENSORS_GPIO_FAN This driver can also be built as a module. If so, the module will be called gpio-fan. +config SENSORS_GXP_FAN_CTRL + tristate "HPE GXP fan controller" + depends on ARCH_HPE_GXP || COMPILE_TEST + help + If you say yes here you get support for GXP fan control functionality. + + The GXP controls fan function via the CPLD through the use of PWM + registers. This driver reports status and pwm setting of the fans. + config SENSORS_HIH6130 tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index e2e4e87b282f..dfea582fb9d2 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o +obj-$(CONFIG_SENSORS_GXP_FAN_CTRL) += gxp-fan-ctrl.o obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o diff --git a/drivers/hwmon/gxp-fan-ctrl.c b/drivers/hwmon/gxp-fan-ctrl.c new file mode 100644 index 000000000000..0e9225a8b805 --- /dev/null +++ b/drivers/hwmon/gxp-fan-ctrl.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */ + +#include +#include +#include +#include +#include +#include +#include + +#define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */ +#define OFS_FAN_FAIL 2 /* Is 2 bytes after base */ +#define OFS_SEVSTAT 0 /* Is 0 because fn2 base will be set at SEVSTAT */ +#define POWER_BIT 24 + +struct gxp_fan_ctrl_drvdata { + void __iomem *base; + void __iomem *plreg; + void __iomem *fn2; +}; + +static bool fan_installed(struct device *dev, int fan) +{ + struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); + u8 val; + + val = readb(drvdata->plreg + OFS_FAN_INST); + + return !!(val & BIT(fan)); +} + +static long fan_failed(struct device *dev, int fan) +{ + struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); + u8 val; + + val = readb(drvdata->plreg + OFS_FAN_FAIL); + + return !!(val & BIT(fan)); +} + +static long fan_enabled(struct device *dev, int fan) +{ + struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); + u32 val; + + /* + * Check the power status as if the platform is off the value + * reported for the PWM will be incorrect. Report fan as + * disabled. + */ + val = readl(drvdata->fn2 + OFS_SEVSTAT); + + return !!((val & BIT(POWER_BIT)) && fan_installed(dev, fan)); +} + +static int gxp_pwm_write(struct device *dev, u32 attr, int channel, long val) +{ + struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); + + switch (attr) { + case hwmon_pwm_input: + if (val > 255 || val < 0) + return -EINVAL; + writeb(val, drvdata->base + channel); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int gxp_fan_ctrl_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_pwm: + return gxp_pwm_write(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int gxp_fan_read(struct device *dev, u32 attr, int channel, long *val) +{ + switch (attr) { + case hwmon_fan_enable: + *val = fan_enabled(dev, channel); + return 0; + case hwmon_fan_fault: + *val = fan_failed(dev, channel); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int gxp_pwm_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev); + u32 reg; + + /* + * Check the power status of the platform. If the platform is off + * the value reported for the PWM will be incorrect. In this case + * report a PWM of zero. + */ + + reg = readl(drvdata->fn2 + OFS_SEVSTAT); + + if (reg & BIT(POWER_BIT)) + *val = fan_installed(dev, channel) ? readb(drvdata->base + channel) : 0; + else + *val = 0; + + return 0; +} + +static int gxp_fan_ctrl_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_fan: + return gxp_fan_read(dev, attr, channel, val); + case hwmon_pwm: + return gxp_pwm_read(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static umode_t gxp_fan_ctrl_is_visible(const void *_data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + umode_t mode = 0; + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_enable: + case hwmon_fan_fault: + mode = 0444; + break; + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + mode = 0644; + break; + default: + break; + } + break; + default: + break; + } + + return mode; +} + +static const struct hwmon_ops gxp_fan_ctrl_ops = { + .is_visible = gxp_fan_ctrl_is_visible, + .read = gxp_fan_ctrl_read, + .write = gxp_fan_ctrl_write, +}; + +static const struct hwmon_channel_info *gxp_fan_ctrl_info[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_FAULT | HWMON_F_ENABLE, + HWMON_F_FAULT | HWMON_F_ENABLE), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT), + NULL +}; + +static const struct hwmon_chip_info gxp_fan_ctrl_chip_info = { + .ops = &gxp_fan_ctrl_ops, + .info = gxp_fan_ctrl_info, + +}; + +static int gxp_fan_ctrl_probe(struct platform_device *pdev) +{ + struct gxp_fan_ctrl_drvdata *drvdata; + struct resource *res; + struct device *dev = &pdev->dev; + struct device *hwmon_dev; + + drvdata = devm_kzalloc(dev, sizeof(struct gxp_fan_ctrl_drvdata), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + drvdata->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(drvdata->base)) + return dev_err_probe(dev, PTR_ERR(drvdata->base), + "failed to map base\n"); + + drvdata->plreg = devm_platform_ioremap_resource_byname(pdev, + "pl"); + if (IS_ERR(drvdata->plreg)) + return dev_err_probe(dev, PTR_ERR(drvdata->plreg), + "failed to map plreg\n"); + + drvdata->fn2 = devm_platform_ioremap_resource_byname(pdev, + "fn2"); + if (IS_ERR(drvdata->fn2)) + return dev_err_probe(dev, PTR_ERR(drvdata->fn2), + "failed to map fn2\n"); + + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, + "hpe_gxp_fan_ctrl", + drvdata, + &gxp_fan_ctrl_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id gxp_fan_ctrl_of_match[] = { + { .compatible = "hpe,gxp-fan-ctrl", }, + {}, +}; +MODULE_DEVICE_TABLE(of, gxp_fan_ctrl_of_match); + +static struct platform_driver gxp_fan_ctrl_driver = { + .probe = gxp_fan_ctrl_probe, + .driver = { + .name = "gxp-fan-ctrl", + .of_match_table = gxp_fan_ctrl_of_match, + }, +}; +module_platform_driver(gxp_fan_ctrl_driver); + +MODULE_AUTHOR("Nick Hawkins "); +MODULE_DESCRIPTION("HPE GXP fan controller"); +MODULE_LICENSE("GPL"); From 547e9d942f3011c5ec5f4763c51dfcdb4b37b9dd Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Tue, 3 Jan 2023 14:36:51 -0600 Subject: [PATCH 24/66] dt-bindings: hwmon: Add hpe,gxp-fan-ctrl Create documentation for the binding to support control of the fans on HPE platforms. Signed-off-by: Nick Hawkins Reviewed-by: Rob Herring Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230103203654.59322-3-nick.hawkins@hpe.com Signed-off-by: Guenter Roeck --- .../bindings/hwmon/hpe,gxp-fan-ctrl.yaml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml diff --git a/Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml b/Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml new file mode 100644 index 000000000000..4a52aac6be72 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/hpe,gxp-fan-ctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HPE GXP Fan Controller + +maintainers: + - Nick Hawkins + +description: | + The HPE GXP fan controller controls the fans through an external CPLD + device that connects to the fans. + +properties: + compatible: + const: hpe,gxp-fan-ctrl + + reg: + items: + - description: Fan controller PWM + - description: Programmable logic + - description: Function 2 + + reg-names: + items: + - const: base + - const: pl + - const: fn2 + +required: + - compatible + - reg + - reg-names + +additionalProperties: false + +examples: + - | + fan-controller@1000c00 { + compatible = "hpe,gxp-fan-ctrl"; + reg = <0x1000c00 0x200>, <0xd1000000 0xff>, <0x80200000 0x100000>; + reg-names = "base", "pl", "fn2"; + }; From d5f80ff774d167d86a84a1907fa903c88dd7a7ae Mon Sep 17 00:00:00 2001 From: Nick Hawkins Date: Tue, 3 Jan 2023 14:36:54 -0600 Subject: [PATCH 25/66] MAINTAINERS: add gxp fan controller and documents Add the gxp-fan-ctrl.c and gxp-fan-ctrl.rst in hwmon driver/documentation. Signed-off-by: Nick Hawkins Reviewed-by: Guenter Roek Link: https://lore.kernel.org/r/20230103203654.59322-6-nick.hawkins@hpe.com Signed-off-by: Guenter Roeck --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index cae2897bc702..98e16168d6e9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2280,13 +2280,16 @@ ARM/HPE GXP ARCHITECTURE M: Jean-Marie Verdun M: Nick Hawkins S: Maintained +F: Documentation/hwmon/gxp-fan-ctrl.rst F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml +F: Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml F: Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml F: arch/arm/boot/dts/hpe-bmc* F: arch/arm/boot/dts/hpe-gxp* F: arch/arm/mach-hpe/ F: drivers/clocksource/timer-gxp.c +F: drivers/hwmon/gxp-fan-ctrl.c F: drivers/spi/spi-gxp.c F: drivers/watchdog/gxp-wdt.c From e11037a5e1dab64d308ebdc0ad7a2a2dcfac66d6 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Jan 2023 22:45:40 -0800 Subject: [PATCH 26/66] hwmon: (emc2305) fix kernel-doc warnings Fix kernel-doc warnings: drivers/hwmon/emc2305.c:62: warning: Cannot understand * @cdev: cooling device; on line 62 - I thought it was a doc line drivers/hwmon/emc2305.c:89: warning: Cannot understand * @client: i2c client; on line 89 - I thought it was a doc line and drop ';' at end of each struct member line. Signed-off-by: Randy Dunlap Cc: Jean Delvare Cc: Guenter Roeck Cc: linux-hwmon@vger.kernel.org Link: https://lore.kernel.org/r/20230113064540.20179-1-rdunlap@infradead.org Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2305.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 6ad055e5868e..f65467fbd86c 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -59,10 +59,11 @@ static const struct i2c_device_id emc2305_ids[] = { MODULE_DEVICE_TABLE(i2c, emc2305_ids); /** - * @cdev: cooling device; - * @curr_state: cooling current state; - * @last_hwmon_state: last cooling state updated by hwmon subsystem; - * @last_thermal_state: last cooling state updated by thermal subsystem; + * struct emc2305_cdev_data - device-specific cooling device state + * @cdev: cooling device + * @cur_state: cooling current state + * @last_hwmon_state: last cooling state updated by hwmon subsystem + * @last_thermal_state: last cooling state updated by thermal subsystem * * The 'last_hwmon_state' and 'last_thermal_state' fields are provided to support fan low limit * speed feature. The purpose of this feature is to provides ability to limit fan speed @@ -86,13 +87,14 @@ struct emc2305_cdev_data { }; /** - * @client: i2c client; - * @hwmon_dev: hwmon device; - * @max_state: maximum cooling state of the cooling device; - * @pwm_num: number of PWM channels; - * @pwm_separate: separate PWM settings for every channel; - * @pwm_min: array of minimum PWM per channel; - * @cdev_data: array of cooling devices data; + * struct emc2305_data - device-specific data + * @client: i2c client + * @hwmon_dev: hwmon device + * @max_state: maximum cooling state of the cooling device + * @pwm_num: number of PWM channels + * @pwm_separate: separate PWM settings for every channel + * @pwm_min: array of minimum PWM per channel + * @cdev_data: array of cooling devices data */ struct emc2305_data { struct i2c_client *client; From ffdb3ba034e4850fcc678594bb5375fb01f6c063 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Jan 2023 22:45:56 -0800 Subject: [PATCH 27/66] hwmon: (sht15,sht21) fix kernel-doc warnings Use the correct function names in kernel-doc comments to prevent these warnings: drivers/hwmon/sht15.c:682: warning: expecting prototype for sht15_show_status(). Prototype was for sht15_status_show() instead drivers/hwmon/sht15.c:705: warning: expecting prototype for sht15_store_heater(). Prototype was for sht15_status_store() instead drivers/hwmon/sht15.c:738: warning: expecting prototype for sht15_show_temp(). Prototype was for sht15_temp_show() instead drivers/hwmon/sht15.c:760: warning: expecting prototype for sht15_show_humidity(). Prototype was for sht15_humidity_show() instead drivers/hwmon/sht21.c:128: warning: expecting prototype for sht21_show_temperature(). Prototype was for sht21_temperature_show() instead drivers/hwmon/sht21.c:149: warning: expecting prototype for sht21_show_humidity(). Prototype was for sht21_humidity_show() instead Signed-off-by: Randy Dunlap Cc: Jean Delvare Cc: Guenter Roeck Cc: linux-hwmon@vger.kernel.org Link: https://lore.kernel.org/r/20230113064556.21685-1-rdunlap@infradead.org Signed-off-by: Guenter Roeck --- drivers/hwmon/sht15.c | 8 ++++---- drivers/hwmon/sht21.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index ae4d14257a11..32a41fc56fc9 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -668,7 +668,7 @@ static inline int sht15_calc_humid(struct sht15_data *data) } /** - * sht15_show_status() - show status information in sysfs + * sht15_status_show() - show status information in sysfs * @dev: device. * @attr: device attribute. * @buf: sysfs buffer where information is written to. @@ -690,7 +690,7 @@ static ssize_t sht15_status_show(struct device *dev, } /** - * sht15_store_heater() - change heater state via sysfs + * sht15_status_store() - change heater state via sysfs * @dev: device. * @attr: device attribute. * @buf: sysfs buffer to read the new heater state from. @@ -725,7 +725,7 @@ static ssize_t sht15_status_store(struct device *dev, } /** - * sht15_show_temp() - show temperature measurement value in sysfs + * sht15_temp_show() - show temperature measurement value in sysfs * @dev: device. * @attr: device attribute. * @buf: sysfs buffer where measurement values are written to. @@ -747,7 +747,7 @@ static ssize_t sht15_temp_show(struct device *dev, } /** - * sht15_show_humidity() - show humidity measurement value in sysfs + * sht15_humidity_show() - show humidity measurement value in sysfs * @dev: device. * @attr: device attribute. * @buf: sysfs buffer where measurement values are written to. diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index e23dbf287233..f50b90198f23 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -114,7 +114,7 @@ static int sht21_update_measurements(struct device *dev) } /** - * sht21_show_temperature() - show temperature measurement value in sysfs + * sht21_temperature_show() - show temperature measurement value in sysfs * @dev: device * @attr: device attribute * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to @@ -136,7 +136,7 @@ static ssize_t sht21_temperature_show(struct device *dev, } /** - * sht21_show_humidity() - show humidity measurement value in sysfs + * sht21_humidity_show() - show humidity measurement value in sysfs * @dev: device * @attr: device attribute * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to From 0be688d04211bed501faf0d5ed952175f7bc2706 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 12 Jan 2023 22:45:49 -0800 Subject: [PATCH 28/66] hwmon: (hih6130) fix kernel-doc warnings Use the correct function name in kernel-doc comments to prevent these warnings: drivers/hwmon/hih6130.c:164: warning: expecting prototype for hih6130_show_temperature(). Prototype was for hih6130_temperature_show() instead drivers/hwmon/hih6130.c:185: warning: expecting prototype for hih6130_show_humidity(). Prototype was for hih6130_humidity_show() instead Signed-off-by: Randy Dunlap Cc: Jean Delvare Cc: Guenter Roeck Cc: linux-hwmon@vger.kernel.org Link: https://lore.kernel.org/r/20230113064549.21289-1-rdunlap@infradead.org Signed-off-by: Guenter Roeck --- drivers/hwmon/hih6130.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index d9394e19fea8..3a7582824f94 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -150,7 +150,7 @@ static int hih6130_update_measurements(struct device *dev) } /** - * hih6130_show_temperature() - show temperature measurement value in sysfs + * hih6130_temperature_show() - show temperature measurement value in sysfs * @dev: device * @attr: device attribute * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to @@ -172,7 +172,7 @@ static ssize_t hih6130_temperature_show(struct device *dev, } /** - * hih6130_show_humidity() - show humidity measurement value in sysfs + * hih6130_humidity_show() - show humidity measurement value in sysfs * @dev: device * @attr: device attribute * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to From c3b3747d02f571da2543e719066a50dd966989d8 Mon Sep 17 00:00:00 2001 From: Denis Pauk Date: Wed, 11 Jan 2023 23:22:40 +0200 Subject: [PATCH 29/66] hwmon: (nct6775) Directly call ASUS ACPI WMI method New ASUS B650/B660/X670 boards firmware have not exposed WMI monitoring GUID and entrypoint method WMBD could be implemented for different device UID. Implement the direct call to entrypoint method for monitoring the device UID of B550/X570 boards. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204807 Signed-off-by: Denis Pauk Co-developed-by: Ahmad Khalifa Signed-off-by: Ahmad Khalifa Link: https://lore.kernel.org/r/20230111212241.7456-1-pauk.denis@gmail.com [groeck: Fix multi-line formatting] Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/nct6775-platform.c | 96 ++++++++++++++++++++++---------- 2 files changed, 69 insertions(+), 29 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9c55b2962e40..3ef56f09f25a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1525,7 +1525,7 @@ config SENSORS_NCT6775_CORE config SENSORS_NCT6775 tristate "Platform driver for Nuvoton NCT6775F and compatibles" depends on !PPC - depends on ACPI_WMI || ACPI_WMI=n + depends on ACPI || ACPI=n select HWMON_VID select SENSORS_NCT6775_CORE help diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index bf43f73dc835..e5d4a79cd5f7 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "nct6775.h" @@ -107,40 +106,50 @@ struct nct6775_sio_data { void (*sio_exit)(struct nct6775_sio_data *sio_data); }; -#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66" +#define ASUSWMI_METHOD "WMBD" #define ASUSWMI_METHODID_RSIO 0x5253494F #define ASUSWMI_METHODID_WSIO 0x5753494F #define ASUSWMI_METHODID_RHWM 0x5248574D #define ASUSWMI_METHODID_WHWM 0x5748574D #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE +#define ASUSWMI_DEVICE_HID "PNP0C14" +#define ASUSWMI_DEVICE_UID "ASUSWMI" + +#if IS_ENABLED(CONFIG_ACPI) +/* + * ASUS boards have only one device with WMI "WMBD" method and have provided + * access to only one SuperIO chip at 0x0290. + */ +static struct acpi_device *asus_acpi_dev; +#endif static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval) { -#if IS_ENABLED(CONFIG_ACPI_WMI) +#if IS_ENABLED(CONFIG_ACPI) + acpi_handle handle = acpi_device_handle(asus_acpi_dev); u32 args = bank | (reg << 8) | (val << 16); - struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_object_list input; + union acpi_object params[3]; + unsigned long long result; acpi_status status; - union acpi_object *obj; - u32 tmp = ASUSWMI_UNSUPPORTED_METHOD; - status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0, - method_id, &input, &output); + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = 0; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = method_id; + params[2].type = ACPI_TYPE_BUFFER; + params[2].buffer.length = sizeof(args); + params[2].buffer.pointer = (void *)&args; + input.count = 3; + input.pointer = params; + status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result); if (ACPI_FAILURE(status)) return -EIO; - obj = output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = obj->integer.value; - if (retval) - *retval = tmp; + *retval = (u32)result & 0xFFFFFFFF; - kfree(obj); - - if (tmp == ASUSWMI_UNSUPPORTED_METHOD) - return -ENODEV; return 0; #else return -EOPNOTSUPP; @@ -1099,6 +1108,45 @@ static const char * const asus_wmi_boards[] = { "TUF GAMING Z490-PLUS (WI-FI)", }; +#if IS_ENABLED(CONFIG_ACPI) +/* + * Callback for acpi_bus_for_each_dev() to find the right device + * by _UID and _HID and return 1 to stop iteration. + */ +static int nct6775_asuswmi_device_match(struct device *dev, void *data) +{ + struct acpi_device *adev = to_acpi_device(dev); + const char *uid = acpi_device_uid(adev); + const char *hid = acpi_device_hid(adev); + + if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) { + asus_acpi_dev = adev; + return 1; + } + + return 0; +} +#endif + +static enum sensor_access nct6775_determine_access(const char *device_uid) +{ +#if IS_ENABLED(CONFIG_ACPI) + u8 tmp; + + acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid); + if (!asus_acpi_dev) + return access_direct; + + /* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */ + if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { + pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp); + return access_asuswmi; + } +#endif + + return access_direct; +} + static int __init sensors_nct6775_platform_init(void) { int i, err; @@ -1109,7 +1157,6 @@ static int __init sensors_nct6775_platform_init(void) int sioaddr[2] = { 0x2e, 0x4e }; enum sensor_access access = access_direct; const char *board_vendor, *board_name; - u8 tmp; err = platform_driver_register(&nct6775_driver); if (err) @@ -1122,15 +1169,8 @@ static int __init sensors_nct6775_platform_init(void) !strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) { err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards), board_name); - if (err >= 0) { - /* if reading chip id via WMI succeeds, use WMI */ - if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) { - pr_info("Using Asus WMI to access %#x chip.\n", tmp); - access = access_asuswmi; - } else { - pr_err("Can't read ChipID by Asus WMI.\n"); - } - } + if (err >= 0) + access = nct6775_determine_access(ASUSWMI_DEVICE_UID); } /* From e2e09989ccc21ad428d6393450add78584b143bd Mon Sep 17 00:00:00 2001 From: Denis Pauk Date: Wed, 11 Jan 2023 23:22:41 +0200 Subject: [PATCH 30/66] hwmon: (nct6775) B650/B660/X670 ASUS boards support Boards such as: "EX-B660M-V5 PRO D4", "PRIME B650-PLUS", "PRIME B650M-A", "PRIME B650M-A AX", "PRIME B650M-A II", "PRIME B650M-A WIFI", "PRIME B650M-A WIFI II", "PRIME B660M-A D4", "PRIME B660M-A WIFI D4", "PRIME X670-P", "PRIME X670-P WIFI", "PRIME X670E-PRO WIFI", "Pro B660M-C-D4", "ProArt B660-CREATOR D4", "ProArt X670E-CREATOR WIFI", "ROG CROSSHAIR X670E EXTREME", "ROG CROSSHAIR X670E GENE", "ROG CROSSHAIR X670E HERO", "ROG MAXIMUS XIII EXTREME GLACIAL", "ROG MAXIMUS Z690 EXTREME", "ROG MAXIMUS Z690 EXTREME GLACIAL", "ROG STRIX B650-A GAMING WIFI", "ROG STRIX B650E-E GAMING WIFI", "ROG STRIX B650E-F GAMING WIFI", "ROG STRIX B650E-I GAMING WIFI", "ROG STRIX B660-A GAMING WIFI D4", "ROG STRIX B660-F GAMING WIFI", "ROG STRIX B660-G GAMING WIFI", "ROG STRIX B660-I GAMING WIFI", "ROG STRIX X670E-A GAMING WIFI", "ROG STRIX X670E-E GAMING WIFI", "ROG STRIX X670E-F GAMING WIFI", "ROG STRIX X670E-I GAMING WIFI", "ROG STRIX Z590-A GAMING WIFI II", "ROG STRIX Z690-A GAMING WIFI D4", "TUF GAMING B650-PLUS", "TUF GAMING B650-PLUS WIFI", "TUF GAMING B650M-PLUS", "TUF GAMING B650M-PLUS WIFI", "TUF GAMING B660M-PLUS WIFI", "TUF GAMING X670E-PLUS", "TUF GAMING X670E-PLUS WIFI", "TUF GAMING Z590-PLUS WIFI", have got a NCT6799D chip, but by default there's no use of it because of resource conflict with WMI method. This commit adds such boards to the monitoring list with new ACPI device UID. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204807 Signed-off-by: Denis Pauk Co-developed-by: Ahmad Khalifa Signed-off-by: Ahmad Khalifa Tested-by: Jeroen Beerstra Tested-by: Slawomir Stepien Link: https://lore.kernel.org/r/20230111212241.7456-2-pauk.denis@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775-platform.c | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index e5d4a79cd5f7..76c6b564d7fc 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -114,6 +114,7 @@ struct nct6775_sio_data { #define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE #define ASUSWMI_DEVICE_HID "PNP0C14" #define ASUSWMI_DEVICE_UID "ASUSWMI" +#define ASUSMSI_DEVICE_UID "AsusMbSwInterface" #if IS_ENABLED(CONFIG_ACPI) /* @@ -1108,6 +1109,52 @@ static const char * const asus_wmi_boards[] = { "TUF GAMING Z490-PLUS (WI-FI)", }; +static const char * const asus_msi_boards[] = { + "EX-B660M-V5 PRO D4", + "PRIME B650-PLUS", + "PRIME B650M-A", + "PRIME B650M-A AX", + "PRIME B650M-A II", + "PRIME B650M-A WIFI", + "PRIME B650M-A WIFI II", + "PRIME B660M-A D4", + "PRIME B660M-A WIFI D4", + "PRIME X670-P", + "PRIME X670-P WIFI", + "PRIME X670E-PRO WIFI", + "Pro B660M-C-D4", + "ProArt B660-CREATOR D4", + "ProArt X670E-CREATOR WIFI", + "ROG CROSSHAIR X670E EXTREME", + "ROG CROSSHAIR X670E GENE", + "ROG CROSSHAIR X670E HERO", + "ROG MAXIMUS XIII EXTREME GLACIAL", + "ROG MAXIMUS Z690 EXTREME", + "ROG MAXIMUS Z690 EXTREME GLACIAL", + "ROG STRIX B650-A GAMING WIFI", + "ROG STRIX B650E-E GAMING WIFI", + "ROG STRIX B650E-F GAMING WIFI", + "ROG STRIX B650E-I GAMING WIFI", + "ROG STRIX B660-A GAMING WIFI D4", + "ROG STRIX B660-F GAMING WIFI", + "ROG STRIX B660-G GAMING WIFI", + "ROG STRIX B660-I GAMING WIFI", + "ROG STRIX X670E-A GAMING WIFI", + "ROG STRIX X670E-E GAMING WIFI", + "ROG STRIX X670E-F GAMING WIFI", + "ROG STRIX X670E-I GAMING WIFI", + "ROG STRIX Z590-A GAMING WIFI II", + "ROG STRIX Z690-A GAMING WIFI D4", + "TUF GAMING B650-PLUS", + "TUF GAMING B650-PLUS WIFI", + "TUF GAMING B650M-PLUS", + "TUF GAMING B650M-PLUS WIFI", + "TUF GAMING B660M-PLUS WIFI", + "TUF GAMING X670E-PLUS", + "TUF GAMING X670E-PLUS WIFI", + "TUF GAMING Z590-PLUS WIFI", +}; + #if IS_ENABLED(CONFIG_ACPI) /* * Callback for acpi_bus_for_each_dev() to find the right device @@ -1171,6 +1218,11 @@ static int __init sensors_nct6775_platform_init(void) board_name); if (err >= 0) access = nct6775_determine_access(ASUSWMI_DEVICE_UID); + + err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards), + board_name); + if (err >= 0) + access = nct6775_determine_access(ASUSMSI_DEVICE_UID); } /* From 554df454e2fa117b36b2238f3b3467ef02a10fa0 Mon Sep 17 00:00:00 2001 From: XU pengfei Date: Wed, 11 Jan 2023 12:36:06 +0800 Subject: [PATCH 31/66] hwmon: ibmpex: remove unnecessary (void*) conversions Pointer variables of void * type do not require type cast. Signed-off-by: XU pengfei Link: https://lore.kernel.org/r/20230111043605.3726-1-xupengfei@nfschina.com Signed-off-by: Guenter Roeck --- drivers/hwmon/ibmpex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 1837cccd993c..db066b368918 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -546,7 +546,7 @@ static void ibmpex_bmc_gone(int iface) static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) { - struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data; + struct ibmpex_bmc_data *data = user_msg_data; if (msg->msgid != data->tx_msgid) { dev_err(data->bmc_device, From d47e377c7b27e656cdf1dfd7297a195d3e68cd2b Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Wed, 4 Jan 2023 17:09:25 +1100 Subject: [PATCH 32/66] hwmon: (it87) Allow calling __superio_enter outside muxed region Allow for superio_enter to be called without requesting the muxed memory region, in particular for initialisation of the second chipset, which must be put into configuration mode, but without an associated call to leave configuration mode. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230104060926.619686-2-frank@crawford.emu.id.au [groeck: Clarified subject] Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 9997f76b1f4a..4ebce2c661d7 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -87,6 +87,14 @@ static struct platform_device *it87_pdev[2]; #define DEVID 0x20 /* Register: Device ID */ #define DEVREV 0x22 /* Register: Device Revision */ +static inline void __superio_enter(int ioreg) +{ + outb(0x87, ioreg); + outb(0x01, ioreg); + outb(0x55, ioreg); + outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg); +} + static inline int superio_inb(int ioreg, int reg) { outb(reg, ioreg); @@ -124,10 +132,7 @@ static inline int superio_enter(int ioreg) if (!request_muxed_region(ioreg, 2, DRVNAME)) return -EBUSY; - outb(0x87, ioreg); - outb(0x01, ioreg); - outb(0x55, ioreg); - outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg); + __superio_enter(ioreg); return 0; } From ff9dedd2da87bb22fd687ef731c1114b82343f89 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Wed, 4 Jan 2023 17:09:26 +1100 Subject: [PATCH 33/66] hwmon: (it87) Set second Super-IO chip in configuration mode On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip (IT8792E) needs to be in configuration mode before accessing the first due to a bug in IT8792E which otherwise results in LPC bus access errors. This needs to be done before accessing the first Super-IO chip since the second chip may have been accessed prior to loading this driver. The problem is also reported to affect IT8795E, which is used on X299 boards and has the same chip ID as IT8792E (0x8733). It also appears to affect systems with IT8790E, which is used on some Z97X-Gaming boards as well as Z87X-OC, and other more recent Gigabyte boards. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230104060926.619686-3-frank@crawford.emu.id.au [groeck: Made description pass checkpatch] Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 4ebce2c661d7..ee48e238e46f 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -3315,6 +3315,27 @@ static int it87_dmi_cb(const struct dmi_system_id *dmi_entry) return 1; } +/* + * On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip + * (IT8792E) needs to be in configuration mode before accessing the first + * due to a bug in IT8792E which otherwise results in LPC bus access errors. + * This needs to be done before accessing the first Super-IO chip since + * the second chip may have been accessed prior to loading this driver. + * + * The problem is also reported to affect IT8795E, which is used on X299 boards + * and has the same chip ID as IT8792E (0x8733). It also appears to affect + * systems with IT8790E, which is used on some Z97X-Gaming boards as well as + * Z87X-OC. + * DMI entries for those systems will be added as they become available and + * as the problem is confirmed to affect those boards. + */ +static int it87_sio_force(const struct dmi_system_id *dmi_entry) +{ + __superio_enter(REG_4E); + + return it87_dmi_cb(dmi_entry); +}; + /* * On the Shuttle SN68PT, FAN_CTL2 is apparently not * connected to a fan, but to something else. One user @@ -3337,7 +3358,34 @@ static struct it87_dmi_data nvidia_fn68pt = { .driver_data = data, \ } +#define IT87_DMI_MATCH_GBT(name, cb, data) \ + IT87_DMI_MATCH_VND("Gigabyte Technology Co., Ltd.", name, cb, data) + static const struct dmi_system_id it87_dmi_table[] __initconst = { + IT87_DMI_MATCH_GBT("AB350", it87_sio_force, NULL), + /* ? + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("AX370", it87_sio_force, NULL), + /* ? + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("Z97X-Gaming G1", it87_sio_force, NULL), + /* ? + IT8790E */ + IT87_DMI_MATCH_GBT("TRX40 AORUS XTREME", it87_sio_force, NULL), + /* IT8688E + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("Z390 AORUS ULTRA-CF", it87_sio_force, NULL), + /* IT8688E + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("B550 AORUS PRO AC", it87_sio_force, NULL), + /* IT8688E + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("X570 AORUS MASTER", it87_sio_force, NULL), + /* IT8688E + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("X570 AORUS PRO", it87_sio_force, NULL), + /* IT8688E + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("X570 AORUS PRO WIFI", it87_sio_force, NULL), + /* IT8688E + IT8792E/IT8795E */ + IT87_DMI_MATCH_GBT("X570S AERO G", it87_sio_force, NULL), + /* IT8689E + IT87952E */ + IT87_DMI_MATCH_GBT("Z690 AORUS PRO DDR4", it87_sio_force, NULL), + /* IT8689E + IT87952E */ + IT87_DMI_MATCH_GBT("Z690 AORUS PRO", it87_sio_force, NULL), + /* IT8689E + IT87952E */ IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt), { } From dea60ff028befe061a7b4e1effd09bd7b14df9e0 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 5 Jan 2023 23:51:05 +0100 Subject: [PATCH 34/66] hwmon: (ftsteutates) Convert to devm_hwmon_device_register_with_info() Convert driver to use devm_hwmon_device_register_with_info() to reduce module size by ~30%. Tested on a Fujitsu DS3401-B1. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230105225107.58308-2-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ftsteutates.c | 546 ++++++++++++++---------------------- 1 file changed, 211 insertions(+), 335 deletions(-) diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index e860924f90aa..23dc3a74f84b 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #define FTS_DEVICE_ID_REG 0x0000 @@ -340,118 +339,6 @@ static int fts_watchdog_init(struct fts_data *data) return devm_watchdog_register_device(&data->client->dev, &data->wdd); } -/*****************************************************************************/ -/* SysFS handler functions */ -/*****************************************************************************/ -static ssize_t in_value_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - int value, err; - - err = fts_update_device(data); - if (err < 0) - return err; - - value = DIV_ROUND_CLOSEST(data->volt[index] * 3300, 255); - - return sprintf(buf, "%d\n", value); -} - -static ssize_t temp_value_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - int value, err; - - err = fts_update_device(data); - if (err < 0) - return err; - - value = (data->temp_input[index] - 64) * 1000; - - return sprintf(buf, "%d\n", value); -} - -static ssize_t temp_fault_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - int err; - - err = fts_update_device(data); - if (err < 0) - return err; - - /* 00h Temperature = Sensor Error */ - return sprintf(buf, "%d\n", data->temp_input[index] == 0); -} - -static ssize_t temp_alarm_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - int err; - - err = fts_update_device(data); - if (err < 0) - return err; - - return sprintf(buf, "%u\n", !!(data->temp_alarm & BIT(index))); -} - -static ssize_t -temp_alarm_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - long ret; - - ret = fts_update_device(data); - if (ret < 0) - return ret; - - if (kstrtoul(buf, 10, &ret) || ret != 0) - return -EINVAL; - - mutex_lock(&data->update_lock); - ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(index)); - if (ret < 0) - goto error; - - ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(index), - ret | 0x1); - if (ret < 0) - goto error; - - data->valid = false; - ret = count; -error: - mutex_unlock(&data->update_lock); - return ret; -} - -static ssize_t fan_value_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - int value, err; - - err = fts_update_device(data); - if (err < 0) - return err; - - value = data->fan_input[index] * 60; - - return sprintf(buf, "%d\n", value); -} - static ssize_t fan_source_show(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -466,172 +353,6 @@ static ssize_t fan_source_show(struct device *dev, return sprintf(buf, "%u\n", data->fan_source[index]); } -static ssize_t fan_alarm_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - int err; - - err = fts_update_device(data); - if (err < 0) - return err; - - return sprintf(buf, "%d\n", !!(data->fan_alarm & BIT(index))); -} - -static ssize_t -fan_alarm_store(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - long ret; - - ret = fts_update_device(data); - if (ret < 0) - return ret; - - if (kstrtoul(buf, 10, &ret) || ret != 0) - return -EINVAL; - - mutex_lock(&data->update_lock); - ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(index)); - if (ret < 0) - goto error; - - ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(index), - ret | 0x1); - if (ret < 0) - goto error; - - data->valid = false; - ret = count; -error: - mutex_unlock(&data->update_lock); - return ret; -} - -/*****************************************************************************/ -/* SysFS structs */ -/*****************************************************************************/ - -/* Temperature sensors */ -static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_value, 0); -static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_value, 1); -static SENSOR_DEVICE_ATTR_RO(temp3_input, temp_value, 2); -static SENSOR_DEVICE_ATTR_RO(temp4_input, temp_value, 3); -static SENSOR_DEVICE_ATTR_RO(temp5_input, temp_value, 4); -static SENSOR_DEVICE_ATTR_RO(temp6_input, temp_value, 5); -static SENSOR_DEVICE_ATTR_RO(temp7_input, temp_value, 6); -static SENSOR_DEVICE_ATTR_RO(temp8_input, temp_value, 7); -static SENSOR_DEVICE_ATTR_RO(temp9_input, temp_value, 8); -static SENSOR_DEVICE_ATTR_RO(temp10_input, temp_value, 9); -static SENSOR_DEVICE_ATTR_RO(temp11_input, temp_value, 10); -static SENSOR_DEVICE_ATTR_RO(temp12_input, temp_value, 11); -static SENSOR_DEVICE_ATTR_RO(temp13_input, temp_value, 12); -static SENSOR_DEVICE_ATTR_RO(temp14_input, temp_value, 13); -static SENSOR_DEVICE_ATTR_RO(temp15_input, temp_value, 14); -static SENSOR_DEVICE_ATTR_RO(temp16_input, temp_value, 15); - -static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0); -static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1); -static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2); -static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3); -static SENSOR_DEVICE_ATTR_RO(temp5_fault, temp_fault, 4); -static SENSOR_DEVICE_ATTR_RO(temp6_fault, temp_fault, 5); -static SENSOR_DEVICE_ATTR_RO(temp7_fault, temp_fault, 6); -static SENSOR_DEVICE_ATTR_RO(temp8_fault, temp_fault, 7); -static SENSOR_DEVICE_ATTR_RO(temp9_fault, temp_fault, 8); -static SENSOR_DEVICE_ATTR_RO(temp10_fault, temp_fault, 9); -static SENSOR_DEVICE_ATTR_RO(temp11_fault, temp_fault, 10); -static SENSOR_DEVICE_ATTR_RO(temp12_fault, temp_fault, 11); -static SENSOR_DEVICE_ATTR_RO(temp13_fault, temp_fault, 12); -static SENSOR_DEVICE_ATTR_RO(temp14_fault, temp_fault, 13); -static SENSOR_DEVICE_ATTR_RO(temp15_fault, temp_fault, 14); -static SENSOR_DEVICE_ATTR_RO(temp16_fault, temp_fault, 15); - -static SENSOR_DEVICE_ATTR_RW(temp1_alarm, temp_alarm, 0); -static SENSOR_DEVICE_ATTR_RW(temp2_alarm, temp_alarm, 1); -static SENSOR_DEVICE_ATTR_RW(temp3_alarm, temp_alarm, 2); -static SENSOR_DEVICE_ATTR_RW(temp4_alarm, temp_alarm, 3); -static SENSOR_DEVICE_ATTR_RW(temp5_alarm, temp_alarm, 4); -static SENSOR_DEVICE_ATTR_RW(temp6_alarm, temp_alarm, 5); -static SENSOR_DEVICE_ATTR_RW(temp7_alarm, temp_alarm, 6); -static SENSOR_DEVICE_ATTR_RW(temp8_alarm, temp_alarm, 7); -static SENSOR_DEVICE_ATTR_RW(temp9_alarm, temp_alarm, 8); -static SENSOR_DEVICE_ATTR_RW(temp10_alarm, temp_alarm, 9); -static SENSOR_DEVICE_ATTR_RW(temp11_alarm, temp_alarm, 10); -static SENSOR_DEVICE_ATTR_RW(temp12_alarm, temp_alarm, 11); -static SENSOR_DEVICE_ATTR_RW(temp13_alarm, temp_alarm, 12); -static SENSOR_DEVICE_ATTR_RW(temp14_alarm, temp_alarm, 13); -static SENSOR_DEVICE_ATTR_RW(temp15_alarm, temp_alarm, 14); -static SENSOR_DEVICE_ATTR_RW(temp16_alarm, temp_alarm, 15); - -static struct attribute *fts_temp_attrs[] = { - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, - &sensor_dev_attr_temp4_input.dev_attr.attr, - &sensor_dev_attr_temp5_input.dev_attr.attr, - &sensor_dev_attr_temp6_input.dev_attr.attr, - &sensor_dev_attr_temp7_input.dev_attr.attr, - &sensor_dev_attr_temp8_input.dev_attr.attr, - &sensor_dev_attr_temp9_input.dev_attr.attr, - &sensor_dev_attr_temp10_input.dev_attr.attr, - &sensor_dev_attr_temp11_input.dev_attr.attr, - &sensor_dev_attr_temp12_input.dev_attr.attr, - &sensor_dev_attr_temp13_input.dev_attr.attr, - &sensor_dev_attr_temp14_input.dev_attr.attr, - &sensor_dev_attr_temp15_input.dev_attr.attr, - &sensor_dev_attr_temp16_input.dev_attr.attr, - - &sensor_dev_attr_temp1_fault.dev_attr.attr, - &sensor_dev_attr_temp2_fault.dev_attr.attr, - &sensor_dev_attr_temp3_fault.dev_attr.attr, - &sensor_dev_attr_temp4_fault.dev_attr.attr, - &sensor_dev_attr_temp5_fault.dev_attr.attr, - &sensor_dev_attr_temp6_fault.dev_attr.attr, - &sensor_dev_attr_temp7_fault.dev_attr.attr, - &sensor_dev_attr_temp8_fault.dev_attr.attr, - &sensor_dev_attr_temp9_fault.dev_attr.attr, - &sensor_dev_attr_temp10_fault.dev_attr.attr, - &sensor_dev_attr_temp11_fault.dev_attr.attr, - &sensor_dev_attr_temp12_fault.dev_attr.attr, - &sensor_dev_attr_temp13_fault.dev_attr.attr, - &sensor_dev_attr_temp14_fault.dev_attr.attr, - &sensor_dev_attr_temp15_fault.dev_attr.attr, - &sensor_dev_attr_temp16_fault.dev_attr.attr, - - &sensor_dev_attr_temp1_alarm.dev_attr.attr, - &sensor_dev_attr_temp2_alarm.dev_attr.attr, - &sensor_dev_attr_temp3_alarm.dev_attr.attr, - &sensor_dev_attr_temp4_alarm.dev_attr.attr, - &sensor_dev_attr_temp5_alarm.dev_attr.attr, - &sensor_dev_attr_temp6_alarm.dev_attr.attr, - &sensor_dev_attr_temp7_alarm.dev_attr.attr, - &sensor_dev_attr_temp8_alarm.dev_attr.attr, - &sensor_dev_attr_temp9_alarm.dev_attr.attr, - &sensor_dev_attr_temp10_alarm.dev_attr.attr, - &sensor_dev_attr_temp11_alarm.dev_attr.attr, - &sensor_dev_attr_temp12_alarm.dev_attr.attr, - &sensor_dev_attr_temp13_alarm.dev_attr.attr, - &sensor_dev_attr_temp14_alarm.dev_attr.attr, - &sensor_dev_attr_temp15_alarm.dev_attr.attr, - &sensor_dev_attr_temp16_alarm.dev_attr.attr, - NULL -}; - -/* Fans */ -static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_value, 0); -static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_value, 1); -static SENSOR_DEVICE_ATTR_RO(fan3_input, fan_value, 2); -static SENSOR_DEVICE_ATTR_RO(fan4_input, fan_value, 3); -static SENSOR_DEVICE_ATTR_RO(fan5_input, fan_value, 4); -static SENSOR_DEVICE_ATTR_RO(fan6_input, fan_value, 5); -static SENSOR_DEVICE_ATTR_RO(fan7_input, fan_value, 6); -static SENSOR_DEVICE_ATTR_RO(fan8_input, fan_value, 7); - static SENSOR_DEVICE_ATTR_RO(fan1_source, fan_source, 0); static SENSOR_DEVICE_ATTR_RO(fan2_source, fan_source, 1); static SENSOR_DEVICE_ATTR_RO(fan3_source, fan_source, 2); @@ -641,25 +362,7 @@ static SENSOR_DEVICE_ATTR_RO(fan6_source, fan_source, 5); static SENSOR_DEVICE_ATTR_RO(fan7_source, fan_source, 6); static SENSOR_DEVICE_ATTR_RO(fan8_source, fan_source, 7); -static SENSOR_DEVICE_ATTR_RW(fan1_alarm, fan_alarm, 0); -static SENSOR_DEVICE_ATTR_RW(fan2_alarm, fan_alarm, 1); -static SENSOR_DEVICE_ATTR_RW(fan3_alarm, fan_alarm, 2); -static SENSOR_DEVICE_ATTR_RW(fan4_alarm, fan_alarm, 3); -static SENSOR_DEVICE_ATTR_RW(fan5_alarm, fan_alarm, 4); -static SENSOR_DEVICE_ATTR_RW(fan6_alarm, fan_alarm, 5); -static SENSOR_DEVICE_ATTR_RW(fan7_alarm, fan_alarm, 6); -static SENSOR_DEVICE_ATTR_RW(fan8_alarm, fan_alarm, 7); - static struct attribute *fts_fan_attrs[] = { - &sensor_dev_attr_fan1_input.dev_attr.attr, - &sensor_dev_attr_fan2_input.dev_attr.attr, - &sensor_dev_attr_fan3_input.dev_attr.attr, - &sensor_dev_attr_fan4_input.dev_attr.attr, - &sensor_dev_attr_fan5_input.dev_attr.attr, - &sensor_dev_attr_fan6_input.dev_attr.attr, - &sensor_dev_attr_fan7_input.dev_attr.attr, - &sensor_dev_attr_fan8_input.dev_attr.attr, - &sensor_dev_attr_fan1_source.dev_attr.attr, &sensor_dev_attr_fan2_source.dev_attr.attr, &sensor_dev_attr_fan3_source.dev_attr.attr, @@ -668,50 +371,225 @@ static struct attribute *fts_fan_attrs[] = { &sensor_dev_attr_fan6_source.dev_attr.attr, &sensor_dev_attr_fan7_source.dev_attr.attr, &sensor_dev_attr_fan8_source.dev_attr.attr, - - &sensor_dev_attr_fan1_alarm.dev_attr.attr, - &sensor_dev_attr_fan2_alarm.dev_attr.attr, - &sensor_dev_attr_fan3_alarm.dev_attr.attr, - &sensor_dev_attr_fan4_alarm.dev_attr.attr, - &sensor_dev_attr_fan5_alarm.dev_attr.attr, - &sensor_dev_attr_fan6_alarm.dev_attr.attr, - &sensor_dev_attr_fan7_alarm.dev_attr.attr, - &sensor_dev_attr_fan8_alarm.dev_attr.attr, NULL }; -/* Voltages */ -static SENSOR_DEVICE_ATTR_RO(in1_input, in_value, 0); -static SENSOR_DEVICE_ATTR_RO(in2_input, in_value, 1); -static SENSOR_DEVICE_ATTR_RO(in3_input, in_value, 2); -static SENSOR_DEVICE_ATTR_RO(in4_input, in_value, 3); -static struct attribute *fts_voltage_attrs[] = { - &sensor_dev_attr_in1_input.dev_attr.attr, - &sensor_dev_attr_in2_input.dev_attr.attr, - &sensor_dev_attr_in3_input.dev_attr.attr, - &sensor_dev_attr_in4_input.dev_attr.attr, - NULL -}; - -static const struct attribute_group fts_voltage_attr_group = { - .attrs = fts_voltage_attrs -}; - -static const struct attribute_group fts_temp_attr_group = { - .attrs = fts_temp_attrs -}; - -static const struct attribute_group fts_fan_attr_group = { +static const struct attribute_group fts_attr_group = { .attrs = fts_fan_attrs }; static const struct attribute_group *fts_attr_groups[] = { - &fts_voltage_attr_group, - &fts_temp_attr_group, - &fts_fan_attr_group, + &fts_attr_group, NULL }; +static umode_t fts_is_visible(const void *devdata, enum hwmon_sensor_types type, u32 attr, + int channel) +{ + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_fault: + return 0444; + case hwmon_temp_alarm: + return 0644; + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + return 0444; + case hwmon_fan_alarm: + return 0644; + default: + break; + } + break; + case hwmon_in: + return 0444; + default: + break; + } + + return 0; +} + +static int fts_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long *val) +{ + struct fts_data *data = dev_get_drvdata(dev); + int ret = fts_update_device(data); + + if (ret < 0) + return ret; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + *val = (data->temp_input[channel] - 64) * 1000; + + return 0; + case hwmon_temp_alarm: + *val = !!(data->temp_alarm & BIT(channel)); + + return 0; + case hwmon_temp_fault: + /* 00h Temperature = Sensor Error */; + *val = (data->temp_input[channel] == 0); + + return 0; + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + *val = data->fan_input[channel] * 60; + + return 0; + case hwmon_fan_alarm: + *val = !!(data->fan_alarm & BIT(channel)); + + return 0; + default: + break; + } + break; + case hwmon_in: + switch (attr) { + case hwmon_in_input: + *val = DIV_ROUND_CLOSEST(data->volt[channel] * 3300, 255); + + return 0; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +} + +static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, + long val) +{ + struct fts_data *data = dev_get_drvdata(dev); + int ret = fts_update_device(data); + + if (ret < 0) + return ret; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_alarm: + if (val) + return -EINVAL; + + mutex_lock(&data->update_lock); + ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(channel)); + if (ret >= 0) + ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel), + ret | 0x1); + if (ret >= 0) + data->valid = false; + + mutex_unlock(&data->update_lock); + if (ret < 0) + return ret; + + return 0; + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_alarm: + if (val) + return -EINVAL; + + mutex_lock(&data->update_lock); + ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(channel)); + if (ret >= 0) + ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel), + ret | 0x1); + if (ret >= 0) + data->valid = false; + + mutex_unlock(&data->update_lock); + if (ret < 0) + return ret; + + return 0; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +} + +static const struct hwmon_ops fts_ops = { + .is_visible = fts_is_visible, + .read = fts_read, + .write = fts_write, +}; + +static const struct hwmon_channel_info *fts_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, + HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT + ), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_ALARM + ), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT + ), + NULL +}; + +static const struct hwmon_chip_info fts_chip_info = { + .ops = &fts_ops, + .info = fts_info, +}; + /*****************************************************************************/ /* Module initialization / remove functions */ /*****************************************************************************/ @@ -793,10 +671,8 @@ static int fts_probe(struct i2c_client *client) return err; revision = err; - hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, - "ftsteutates", - data, - fts_attr_groups); + hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, "ftsteutates", data, + &fts_chip_info, fts_attr_groups); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); From 1c5759d8ce054961b454af69568a41e7e3210ee1 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 5 Jan 2023 23:51:06 +0100 Subject: [PATCH 35/66] hwmon: (ftsteutates) Replace fanX_source with pwmX_auto_channels_temp Replace the nonstandard fanX_source attributes with the standardized pwmX_auto_channels_temp attributes and document the special behaviour associated with those attributes. Tested on a Fujitsu DS3401-B1. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230105225107.58308-3-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- Documentation/hwmon/ftsteutates.rst | 5 ++ drivers/hwmon/ftsteutates.c | 77 +++++++++++------------------ 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/Documentation/hwmon/ftsteutates.rst b/Documentation/hwmon/ftsteutates.rst index 198fa8e2819d..b3bfec36661d 100644 --- a/Documentation/hwmon/ftsteutates.rst +++ b/Documentation/hwmon/ftsteutates.rst @@ -22,6 +22,11 @@ enhancements. It can monitor up to 4 voltages, 16 temperatures and 8 fans. It also contains an integrated watchdog which is currently implemented in this driver. +The ``pwmX_auto_channels_temp`` attributes show which temperature sensor +is currently driving which fan channel. This value might dynamically change +during runtime depending on the temperature sensor selected by +the fan control circuit. + The 4 voltages require a board-specific multiplier, since the BMC can only measure voltages up to 3.3V and thus relies on voltage dividers. Consult your motherboard manual for details. diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index 23dc3a74f84b..0d8ab94250a9 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -6,9 +6,7 @@ * Thilo Cestonaro */ #include -#include #include -#include #include #include #include @@ -16,7 +14,6 @@ #include #include #include -#include #include #define FTS_DEVICE_ID_REG 0x0000 @@ -48,6 +45,8 @@ #define FTS_NO_TEMP_SENSORS 0x10 #define FTS_NO_VOLT_SENSORS 0x04 +#define FTS_FAN_SOURCE_INVALID 0xff + static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; static const struct i2c_device_id fts_id[] = { @@ -187,7 +186,7 @@ static int fts_update_device(struct fts_data *data) data->fan_source[i] = err; } else { data->fan_input[i] = 0; - data->fan_source[i] = 0; + data->fan_source[i] = FTS_FAN_SOURCE_INVALID; } } @@ -339,50 +338,6 @@ static int fts_watchdog_init(struct fts_data *data) return devm_watchdog_register_device(&data->client->dev, &data->wdd); } -static ssize_t fan_source_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct fts_data *data = dev_get_drvdata(dev); - int index = to_sensor_dev_attr(devattr)->index; - int err; - - err = fts_update_device(data); - if (err < 0) - return err; - - return sprintf(buf, "%u\n", data->fan_source[index]); -} - -static SENSOR_DEVICE_ATTR_RO(fan1_source, fan_source, 0); -static SENSOR_DEVICE_ATTR_RO(fan2_source, fan_source, 1); -static SENSOR_DEVICE_ATTR_RO(fan3_source, fan_source, 2); -static SENSOR_DEVICE_ATTR_RO(fan4_source, fan_source, 3); -static SENSOR_DEVICE_ATTR_RO(fan5_source, fan_source, 4); -static SENSOR_DEVICE_ATTR_RO(fan6_source, fan_source, 5); -static SENSOR_DEVICE_ATTR_RO(fan7_source, fan_source, 6); -static SENSOR_DEVICE_ATTR_RO(fan8_source, fan_source, 7); - -static struct attribute *fts_fan_attrs[] = { - &sensor_dev_attr_fan1_source.dev_attr.attr, - &sensor_dev_attr_fan2_source.dev_attr.attr, - &sensor_dev_attr_fan3_source.dev_attr.attr, - &sensor_dev_attr_fan4_source.dev_attr.attr, - &sensor_dev_attr_fan5_source.dev_attr.attr, - &sensor_dev_attr_fan6_source.dev_attr.attr, - &sensor_dev_attr_fan7_source.dev_attr.attr, - &sensor_dev_attr_fan8_source.dev_attr.attr, - NULL -}; - -static const struct attribute_group fts_attr_group = { - .attrs = fts_fan_attrs -}; - -static const struct attribute_group *fts_attr_groups[] = { - &fts_attr_group, - NULL -}; - static umode_t fts_is_visible(const void *devdata, enum hwmon_sensor_types type, u32 attr, int channel) { @@ -408,6 +363,7 @@ static umode_t fts_is_visible(const void *devdata, enum hwmon_sensor_types type, break; } break; + case hwmon_pwm: case hwmon_in: return 0444; default: @@ -460,6 +416,19 @@ static int fts_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, break; } break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_auto_channels_temp: + if (data->fan_source[channel] == FTS_FAN_SOURCE_INVALID) + *val = 0; + else + *val = BIT(data->fan_source[channel]); + + return 0; + default: + break; + } + break; case hwmon_in: switch (attr) { case hwmon_in_input: @@ -576,6 +545,16 @@ static const struct hwmon_channel_info *fts_info[] = { HWMON_F_INPUT | HWMON_F_ALARM, HWMON_F_INPUT | HWMON_F_ALARM ), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_AUTO_CHANNELS_TEMP, + HWMON_PWM_AUTO_CHANNELS_TEMP, + HWMON_PWM_AUTO_CHANNELS_TEMP, + HWMON_PWM_AUTO_CHANNELS_TEMP, + HWMON_PWM_AUTO_CHANNELS_TEMP, + HWMON_PWM_AUTO_CHANNELS_TEMP, + HWMON_PWM_AUTO_CHANNELS_TEMP, + HWMON_PWM_AUTO_CHANNELS_TEMP + ), HWMON_CHANNEL_INFO(in, HWMON_I_INPUT, HWMON_I_INPUT, @@ -672,7 +651,7 @@ static int fts_probe(struct i2c_client *client) revision = err; hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, "ftsteutates", data, - &fts_chip_info, fts_attr_groups); + &fts_chip_info, NULL); if (IS_ERR(hwmon_dev)) return PTR_ERR(hwmon_dev); From c184f377a4cc9078d42563ef0fe3de6ea574b0cf Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 5 Jan 2023 23:51:07 +0100 Subject: [PATCH 36/66] hwmon: (ftsteutates) Add support for fanX_fault attributes The driver knows internally when a fan is not connected, but does not export this knowledge to userspace. Use the standard fanX_fault attributes to notify userspace if a fan is not connected. Tested on a Fujitsu DS3401-B1. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230105225107.58308-4-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ftsteutates.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index 0d8ab94250a9..25afd9167a34 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -356,6 +356,7 @@ static umode_t fts_is_visible(const void *devdata, enum hwmon_sensor_types type, case hwmon_fan: switch (attr) { case hwmon_fan_input: + case hwmon_fan_fault: return 0444; case hwmon_fan_alarm: return 0644; @@ -411,6 +412,10 @@ static int fts_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_fan_alarm: *val = !!(data->fan_alarm & BIT(channel)); + return 0; + case hwmon_fan_fault: + *val = !(data->fan_present & BIT(channel)); + return 0; default: break; @@ -536,14 +541,14 @@ static const struct hwmon_channel_info *fts_info[] = { HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT ), HWMON_CHANNEL_INFO(fan, - HWMON_F_INPUT | HWMON_F_ALARM, - HWMON_F_INPUT | HWMON_F_ALARM, - HWMON_F_INPUT | HWMON_F_ALARM, - HWMON_F_INPUT | HWMON_F_ALARM, - HWMON_F_INPUT | HWMON_F_ALARM, - HWMON_F_INPUT | HWMON_F_ALARM, - HWMON_F_INPUT | HWMON_F_ALARM, - HWMON_F_INPUT | HWMON_F_ALARM + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT, + HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT ), HWMON_CHANNEL_INFO(pwm, HWMON_PWM_AUTO_CHANNELS_TEMP, From 22f0fd208d981622b988b8f91e8afd92189dda1c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 18 Jan 2023 18:22:36 +0100 Subject: [PATCH 37/66] dt-bindings: hwmon: adi,ltc2992: correct unit address in example lower-case hex is expected for unit addresses: adi,ltc2992.example.dts:22.24-38.15: Warning (i2c_bus_reg): /example-0/i2c/ltc2992@6F: I2C bus unit address format error, expected "6f" Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230118172237.349111-1-krzysztof.kozlowski@linaro.org Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml b/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml index 64a8fcb7bc46..ec984248219e 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml @@ -59,12 +59,12 @@ examples: #address-cells = <1>; #size-cells = <0>; - ltc2992@6F { + ltc2992@6f { #address-cells = <1>; #size-cells = <0>; compatible = "adi,ltc2992"; - reg = <0x6F>; + reg = <0x6f>; channel@0 { reg = <0x0>; From 08be4233521a8ad2de68ebca859c084419b6989f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 18 Jan 2023 18:22:37 +0100 Subject: [PATCH 38/66] dt-bindings: hwmon: correct indentation and style in examples Fix mixed indentation to 4-spaces, remove unnecessary suffix from i2c node name and use lower-case hex. No functional impact. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230118172237.349111-2-krzysztof.kozlowski@linaro.org Signed-off-by: Guenter Roeck --- .../bindings/hwmon/adi,adm1177.yaml | 12 +++--- .../bindings/hwmon/adi,adm1266.yaml | 6 +-- .../bindings/hwmon/adi,axi-fan-control.yaml | 18 ++++----- .../bindings/hwmon/adi,ltc2947.yaml | 18 ++++----- .../bindings/hwmon/adi,ltc2992.yaml | 26 ++++++------ .../devicetree/bindings/hwmon/amd,sbrmi.yaml | 6 +-- .../devicetree/bindings/hwmon/amd,sbtsi.yaml | 6 +-- .../devicetree/bindings/hwmon/iio-hwmon.yaml | 8 ++-- .../bindings/hwmon/national,lm90.yaml | 40 +++++++++---------- .../bindings/hwmon/ntc-thermistor.yaml | 2 +- .../bindings/hwmon/nuvoton,nct7802.yaml | 16 ++++---- .../devicetree/bindings/hwmon/ti,tmp513.yaml | 20 +++++----- .../bindings/hwmon/ti,tps23861.yaml | 14 +++---- 13 files changed, 96 insertions(+), 96 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml index d794deb08bb7..ca2b47320689 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,adm1177.yaml @@ -52,16 +52,16 @@ examples: - | #include #include - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; pwmon@5a { - compatible = "adi,adm1177"; - reg = <0x5a>; - shunt-resistor-micro-ohms = <50000>; /* 50 mOhm */ - adi,shutdown-threshold-microamp = <1059000>; /* 1.059 A */ - adi,vrange-high-enable; + compatible = "adi,adm1177"; + reg = <0x5a>; + shunt-resistor-micro-ohms = <50000>; /* 50 mOhm */ + adi,shutdown-threshold-microamp = <1059000>; /* 1.059 A */ + adi,vrange-high-enable; }; }; ... diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml index 43b4f4f57b49..4f8e11bd5142 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,adm1266.yaml @@ -39,13 +39,13 @@ additionalProperties: false examples: - | - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; adm1266@40 { - compatible = "adi,adm1266"; - reg = <0x40>; + compatible = "adi,adm1266"; + reg = <0x40>; }; }; ... diff --git a/Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml b/Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml index f2f99afb3a3b..0cf3ed6212a6 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml @@ -49,15 +49,15 @@ additionalProperties: false examples: - | fpga_axi: fpga-axi { - #address-cells = <0x2>; - #size-cells = <0x1>; + #address-cells = <0x2>; + #size-cells = <0x1>; - axi_fan_control: axi-fan-control@80000000 { - compatible = "adi,axi-fan-control-1.00.a"; - reg = <0x0 0x80000000 0x10000>; - clocks = <&clk 71>; - interrupts = <0 110 0>; - pulses-per-revolution = <2>; - }; + axi_fan_control: axi-fan-control@80000000 { + compatible = "adi,axi-fan-control-1.00.a"; + reg = <0x0 0x80000000 0x10000>; + clocks = <&clk 71>; + interrupts = <0 110 0>; + pulses-per-revolution = <2>; + }; }; ... diff --git a/Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml b/Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml index bf04151b63d2..152935334c76 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml @@ -87,15 +87,15 @@ additionalProperties: false examples: - | spi { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - ltc2947_spi: ltc2947@0 { - compatible = "adi,ltc2947"; - reg = <0>; - /* accumulation takes place always for energ1/charge1. */ - /* accumulation only on positive current for energy2/charge2. */ - adi,accumulator-ctl-pol = <0 1>; - }; + ltc2947_spi: ltc2947@0 { + compatible = "adi,ltc2947"; + reg = <0>; + /* accumulation takes place always for energ1/charge1. */ + /* accumulation only on positive current for energy2/charge2. */ + adi,accumulator-ctl-pol = <0 1>; + }; }; ... diff --git a/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml b/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml index ec984248219e..dba74f400bc2 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml @@ -55,26 +55,26 @@ additionalProperties: false examples: - | - i2c1 { + i2c { #address-cells = <1>; #size-cells = <0>; ltc2992@6f { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - compatible = "adi,ltc2992"; - reg = <0x6f>; + compatible = "adi,ltc2992"; + reg = <0x6f>; - channel@0 { - reg = <0x0>; - shunt-resistor-micro-ohms = <10000>; - }; + channel@0 { + reg = <0x0>; + shunt-resistor-micro-ohms = <10000>; + }; - channel@1 { - reg = <0x1>; - shunt-resistor-micro-ohms = <10000>; - }; + channel@1 { + reg = <0x1>; + shunt-resistor-micro-ohms = <10000>; + }; }; }; ... diff --git a/Documentation/devicetree/bindings/hwmon/amd,sbrmi.yaml b/Documentation/devicetree/bindings/hwmon/amd,sbrmi.yaml index 7598b083979c..353d81d89bf5 100644 --- a/Documentation/devicetree/bindings/hwmon/amd,sbrmi.yaml +++ b/Documentation/devicetree/bindings/hwmon/amd,sbrmi.yaml @@ -41,13 +41,13 @@ additionalProperties: false examples: - | - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; sbrmi@3c { - compatible = "amd,sbrmi"; - reg = <0x3c>; + compatible = "amd,sbrmi"; + reg = <0x3c>; }; }; ... diff --git a/Documentation/devicetree/bindings/hwmon/amd,sbtsi.yaml b/Documentation/devicetree/bindings/hwmon/amd,sbtsi.yaml index 446b09f1ce94..75088244a274 100644 --- a/Documentation/devicetree/bindings/hwmon/amd,sbtsi.yaml +++ b/Documentation/devicetree/bindings/hwmon/amd,sbtsi.yaml @@ -42,13 +42,13 @@ additionalProperties: false examples: - | - i2c0 { + i2c { #address-cells = <1>; #size-cells = <0>; sbtsi@4c { - compatible = "amd,sbtsi"; - reg = <0x4c>; + compatible = "amd,sbtsi"; + reg = <0x4c>; }; }; ... diff --git a/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml b/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml index e1ccbd30e0eb..c54b5986b365 100644 --- a/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml +++ b/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml @@ -31,7 +31,7 @@ additionalProperties: false examples: - | - iio-hwmon { - compatible = "iio-hwmon"; - io-channels = <&adc 1>, <&adc 2>; - }; + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc 1>, <&adc 2>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/national,lm90.yaml b/Documentation/devicetree/bindings/hwmon/national,lm90.yaml index e1719839faf0..7b9d48d6d6da 100644 --- a/Documentation/devicetree/bindings/hwmon/national,lm90.yaml +++ b/Documentation/devicetree/bindings/hwmon/national,lm90.yaml @@ -198,30 +198,30 @@ examples: }; - | i2c { - #address-cells = <1>; - #size-cells = <0>; - - sensor@4c { - compatible = "adi,adt7481"; - reg = <0x4c>; #address-cells = <1>; #size-cells = <0>; - channel@0 { - reg = <0x0>; - label = "local"; - }; + sensor@4c { + compatible = "adi,adt7481"; + reg = <0x4c>; + #address-cells = <1>; + #size-cells = <0>; - channel@1 { - reg = <0x1>; - label = "front"; - temperature-offset-millicelsius = <4000>; - }; + channel@0 { + reg = <0x0>; + label = "local"; + }; - channel@2 { - reg = <0x2>; - label = "back"; - temperature-offset-millicelsius = <750>; + channel@1 { + reg = <0x1>; + label = "front"; + temperature-offset-millicelsius = <4000>; + }; + + channel@2 { + reg = <0x2>; + label = "back"; + temperature-offset-millicelsius = <750>; + }; }; - }; }; diff --git a/Documentation/devicetree/bindings/hwmon/ntc-thermistor.yaml b/Documentation/devicetree/bindings/hwmon/ntc-thermistor.yaml index 6a1920712fb9..3d0146e20d3e 100644 --- a/Documentation/devicetree/bindings/hwmon/ntc-thermistor.yaml +++ b/Documentation/devicetree/bindings/hwmon/ntc-thermistor.yaml @@ -131,7 +131,7 @@ additionalProperties: false examples: - | - thermistor0 { + thermistor { compatible = "murata,ncp18wb473"; io-channels = <&gpadc 0x06>; pullup-uv = <1800000>; diff --git a/Documentation/devicetree/bindings/hwmon/nuvoton,nct7802.yaml b/Documentation/devicetree/bindings/hwmon/nuvoton,nct7802.yaml index 2f0620ecccc9..cd8dcd797031 100644 --- a/Documentation/devicetree/bindings/hwmon/nuvoton,nct7802.yaml +++ b/Documentation/devicetree/bindings/hwmon/nuvoton,nct7802.yaml @@ -123,23 +123,23 @@ examples: #size-cells = <0>; channel@0 { /* LTD */ - reg = <0>; + reg = <0>; }; channel@1 { /* RTD1 */ - reg = <1>; - sensor-type = "voltage"; + reg = <1>; + sensor-type = "voltage"; }; channel@2 { /* RTD2 */ - reg = <2>; - sensor-type = "temperature"; - temperature-mode = "thermal-diode"; + reg = <2>; + sensor-type = "temperature"; + temperature-mode = "thermal-diode"; }; channel@3 { /* RTD3 */ - reg = <3>; - sensor-type = "temperature"; + reg = <3>; + sensor-type = "temperature"; }; }; }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,tmp513.yaml b/Documentation/devicetree/bindings/hwmon/ti,tmp513.yaml index 1502b22c77cc..fde5225ce012 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,tmp513.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,tmp513.yaml @@ -77,15 +77,15 @@ additionalProperties: false examples: - | i2c { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - tmp513@5c { - compatible = "ti,tmp513"; - reg = <0x5C>; - shunt-resistor-micro-ohms = <330000>; - ti,bus-range-microvolt = <32000000>; - ti,pga-gain = <8>; - ti,nfactor = <0x1 0xF3 0x00>; - }; + tmp513@5c { + compatible = "ti,tmp513"; + reg = <0x5c>; + shunt-resistor-micro-ohms = <330000>; + ti,bus-range-microvolt = <32000000>; + ti,pga-gain = <8>; + ti,nfactor = <0x1 0xf3 0x00>; + }; }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml b/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml index 3bc8e73dfbf0..bce68a326919 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,tps23861.yaml @@ -40,12 +40,12 @@ additionalProperties: false examples: - | i2c { - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <1>; + #size-cells = <0>; - tps23861@30 { - compatible = "ti,tps23861"; - reg = <0x30>; - shunt-resistor-micro-ohms = <255000>; - }; + tps23861@30 { + compatible = "ti,tps23861"; + reg = <0x30>; + shunt-resistor-micro-ohms = <255000>; + }; }; From b361a1cf624546c9ce71c68066b809b9490e0267 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 21 Jan 2023 19:57:53 +1100 Subject: [PATCH 39/66] hwmon: (it87) Group all related MODULE_PARM definitions together Group the MODULE_PARM definitions together to make them easier for future maintenance, rather than having them spread across the file. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230121085754.1693336-2-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index ee48e238e46f..a8a6a0ffee82 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -65,14 +65,6 @@ enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8792, it8603, it8620, it8622, it8628 }; -static unsigned short force_id; -module_param(force_id, ushort, 0); -MODULE_PARM_DESC(force_id, "Override the detected device ID"); - -static bool ignore_resource_conflict; -module_param(ignore_resource_conflict, bool, 0); -MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict"); - static struct platform_device *it87_pdev[2]; #define REG_2E 0x2e /* The register to read/write */ @@ -181,6 +173,12 @@ static inline void superio_exit(int ioreg) #define IT87_SIO_VID_REG 0xfc /* VID value */ #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ +/* Force chip ID to specified value. Should only be used for testing */ +static unsigned short force_id; + +/* ACPI resource conflicts are ignored if this parameter is set to 1 */ +static bool ignore_resource_conflict; + /* Update battery voltage after every reading if true */ static bool update_vbat; @@ -3457,11 +3455,20 @@ static void __exit sm_it87_exit(void) MODULE_AUTHOR("Chris Gauthron, Jean Delvare "); MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver"); + +module_param(force_id, ushort, 0); +MODULE_PARM_DESC(force_id, "Override the detected device ID"); + +module_param(ignore_resource_conflict, bool, 0); +MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict"); + module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); + module_param(fix_pwm_polarity, bool, 0); MODULE_PARM_DESC(fix_pwm_polarity, "Force PWM polarity to active high (DANGEROUS)"); + MODULE_LICENSE("GPL"); module_init(sm_it87_init); From 363ab25324754ed77dbc50aad77e16c67f829c08 Mon Sep 17 00:00:00 2001 From: Mario Kicherer Date: Wed, 18 Jan 2023 13:30:17 +0100 Subject: [PATCH 40/66] dt-bindings: hwmon: add nxp,mc34vr500 Add dt-bindings for the NXP MC34VR500 PMIC. Signed-off-by: Mario Kicherer Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230118123019.3041303-2-dev@kicherer.org Signed-off-by: Guenter Roeck --- .../bindings/hwmon/nxp,mc34vr500.yaml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/nxp,mc34vr500.yaml diff --git a/Documentation/devicetree/bindings/hwmon/nxp,mc34vr500.yaml b/Documentation/devicetree/bindings/hwmon/nxp,mc34vr500.yaml new file mode 100644 index 000000000000..306f67315835 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/nxp,mc34vr500.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/nxp,mc34vr500.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP MC34VR500 hwmon sensor + +maintainers: + - Mario Kicherer + +properties: + compatible: + enum: + - nxp,mc34vr500 + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@8 { + compatible = "nxp,mc34vr500"; + reg = <0x08>; + }; + }; From a66c9147916fefc66dba06236ff5307180d95cd4 Mon Sep 17 00:00:00 2001 From: Mario Kicherer Date: Wed, 18 Jan 2023 13:30:18 +0100 Subject: [PATCH 41/66] docs: hwmon: add docs for the NXP MC34VR500 PMIC Add documentation for the NXP MC34VR500 PMIC. Signed-off-by: Mario Kicherer Link: https://lore.kernel.org/r/20230118123019.3041303-3-dev@kicherer.org [groeck: Added to index] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/mc34vr500.rst | 32 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 Documentation/hwmon/mc34vr500.rst diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 7b36b0897230..95f5459ed2c9 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -145,6 +145,7 @@ Hardware Monitoring Kernel Drivers max6697 max8688 mc13783-adc + mc34vr500 mcp3021 menf21bmc mlxreg-fan diff --git a/Documentation/hwmon/mc34vr500.rst b/Documentation/hwmon/mc34vr500.rst new file mode 100644 index 000000000000..f82d872477ac --- /dev/null +++ b/Documentation/hwmon/mc34vr500.rst @@ -0,0 +1,32 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver mc34vr500 +======================= + +Supported Chips: + + * NXP MC34VR500 + + Prefix: 'mc34vr500' + + Datasheet: https://www.nxp.com/docs/en/data-sheet/MC34VR500.pdf + +Author: Mario Kicherer + +Description +----------- + +This driver implements initial support for the NXP MC34VR500 PMIC. The MC34VR500 +monitors the temperature, input voltage and output currents and provides +corresponding alarms. For the temperature, the chip can send interrupts if +the temperature rises above one of the following values: 110°, 120°, 125° and +130° Celsius. For the input voltage, an interrupt is sent when the voltage +drops below 2.8V. + +Currently, this driver only implements the input voltage and temperature +alarms. The interrupts are mapped as follows: + +<= 2.8V -> in0_min_alarm +>110°c -> temp1_max_alarm +>120°c -> temp1_crit_alarm +>130°c -> temp1_emergency_alarm From 07830d9ab34c0622f577a88286746aa17c144afd Mon Sep 17 00:00:00 2001 From: Mario Kicherer Date: Wed, 18 Jan 2023 13:30:19 +0100 Subject: [PATCH 42/66] hwmon: add initial NXP MC34VR500 PMIC monitoring support Add initial monitoring support for the MC34VR500 PMIC. In its current state, input voltage and temperature alarms are reported to hwmon. Datasheet: - https://www.nxp.com/docs/en/data-sheet/MC34VR500.pdf Signed-off-by: Mario Kicherer Link: https://lore.kernel.org/r/20230118123019.3041303-4-dev@kicherer.org [groeck: Silence stray compiler warning, terminate struct of_device_id] Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 7 + drivers/hwmon/Makefile | 1 + drivers/hwmon/mc34vr500.c | 263 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 drivers/hwmon/mc34vr500.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3ef56f09f25a..29a6f7e10166 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1175,6 +1175,13 @@ config SENSORS_MAX31790 This driver can also be built as a module. If so, the module will be called max31790. +config SENSORS_MC34VR500 + tristate "NXP MC34VR500 hardware monitoring driver" + depends on I2C + help + If you say yes here you get support for the temperature and input + voltage sensors of the NXP MC34VR500. + config SENSORS_MCP3021 tristate "Microchip MCP3021 and compatibles" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index dfea582fb9d2..f41485b8a852 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -150,6 +150,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_MAX6697) += max6697.o obj-$(CONFIG_SENSORS_MAX31790) += max31790.o obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o +obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o obj-$(CONFIG_SENSORS_TC654) += tc654.o obj-$(CONFIG_SENSORS_TPS23861) += tps23861.o diff --git a/drivers/hwmon/mc34vr500.c b/drivers/hwmon/mc34vr500.c new file mode 100644 index 000000000000..6268e973049c --- /dev/null +++ b/drivers/hwmon/mc34vr500.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * An hwmon driver for the NXP MC34VR500 PMIC + * + * Author: Mario Kicherer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MC34VR500_I2C_ADDR 0x08 +#define MC34VR500_DEVICEID_VALUE 0x14 + +/* INTSENSE0 */ +#define ENS_BIT BIT(0) +#define LOWVINS_BIT BIT(1) +#define THERM110S_BIT BIT(2) +#define THERM120S_BIT BIT(3) +#define THERM125S_BIT BIT(4) +#define THERM130S_BIT BIT(5) + +#define MC34VR500_DEVICEID 0x00 + +#define MC34VR500_SILICONREVID 0x03 +#define MC34VR500_FABID 0x04 +#define MC34VR500_INTSTAT0 0x05 +#define MC34VR500_INTMASK0 0x06 +#define MC34VR500_INTSENSE0 0x07 + +struct mc34vr500_data { + struct device *hwmon_dev; + struct regmap *regmap; +}; + +static irqreturn_t mc34vr500_process_interrupt(int irq, void *userdata) +{ + struct mc34vr500_data *data = (struct mc34vr500_data *)userdata; + unsigned int reg; + int ret; + + ret = regmap_read(data->regmap, MC34VR500_INTSTAT0, ®); + if (ret < 0) + return IRQ_HANDLED; + + if (reg) { + if (reg & LOWVINS_BIT) + hwmon_notify_event(data->hwmon_dev, hwmon_in, + hwmon_in_min_alarm, 0); + + if (reg & THERM110S_BIT) + hwmon_notify_event(data->hwmon_dev, hwmon_temp, + hwmon_temp_max_alarm, 0); + + if (reg & THERM120S_BIT) + hwmon_notify_event(data->hwmon_dev, hwmon_temp, + hwmon_temp_crit_alarm, 0); + + if (reg & THERM130S_BIT) + hwmon_notify_event(data->hwmon_dev, hwmon_temp, + hwmon_temp_emergency_alarm, 0); + + /* write 1 to clear */ + regmap_write(data->regmap, MC34VR500_INTSTAT0, LOWVINS_BIT | + THERM110S_BIT | THERM120S_BIT | THERM130S_BIT); + } + + return IRQ_HANDLED; +} + +static umode_t mc34vr500_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (attr) { + case hwmon_in_min_alarm: + case hwmon_temp_max_alarm: + case hwmon_temp_crit_alarm: + case hwmon_temp_emergency_alarm: + return 0444; + default: + break; + } + + return 0; +} + +static int mc34vr500_alarm_read(struct mc34vr500_data *data, int index, + long *val) +{ + unsigned int reg; + int ret; + + ret = regmap_read(data->regmap, MC34VR500_INTSENSE0, ®); + if (ret < 0) + return ret; + + *val = !!(reg & index); + + return 0; +} + +static int mc34vr500_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct mc34vr500_data *data = dev_get_drvdata(dev); + + switch (type) { + case hwmon_in: + switch (attr) { + case hwmon_in_min_alarm: + return mc34vr500_alarm_read(data, LOWVINS_BIT, val); + default: + return -EOPNOTSUPP; + } + case hwmon_temp: + switch (attr) { + case hwmon_temp_max_alarm: + return mc34vr500_alarm_read(data, THERM110S_BIT, val); + case hwmon_temp_crit_alarm: + return mc34vr500_alarm_read(data, THERM120S_BIT, val); + case hwmon_temp_emergency_alarm: + return mc34vr500_alarm_read(data, THERM130S_BIT, val); + default: + return -EOPNOTSUPP; + } + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info *mc34vr500_info[] = { + HWMON_CHANNEL_INFO(in, HWMON_I_MIN_ALARM), + HWMON_CHANNEL_INFO(temp, HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM + | HWMON_T_EMERGENCY_ALARM), + NULL, +}; + +static const struct hwmon_ops mc34vr500_hwmon_ops = { + .is_visible = mc34vr500_is_visible, + .read = mc34vr500_read, +}; + +static const struct hwmon_chip_info mc34vr500_chip_info = { + .ops = &mc34vr500_hwmon_ops, + .info = mc34vr500_info, +}; + +static const struct regmap_config mc34vr500_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MC34VR500_INTSENSE0, +}; + +static int mc34vr500_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct mc34vr500_data *data; + struct device *hwmon_dev; + int ret; + unsigned int reg, revid, fabid; + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &mc34vr500_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + data = devm_kzalloc(dev, sizeof(struct mc34vr500_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->regmap = regmap; + + ret = regmap_read(regmap, MC34VR500_DEVICEID, ®); + if (ret < 0) + return ret; + + if (reg != MC34VR500_DEVICEID_VALUE) + return -ENODEV; + + ret = regmap_read(regmap, MC34VR500_SILICONREVID, &revid); + if (ret < 0) + return ret; + + ret = regmap_read(regmap, MC34VR500_FABID, &fabid); + if (ret < 0) + return ret; + + dev_dbg(dev, "mc34vr500: revid 0x%x fabid 0x%x\n", revid, fabid); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + data, + &mc34vr500_chip_info, + NULL); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + data->hwmon_dev = hwmon_dev; + + if (client->irq) { + ret = devm_request_threaded_irq(dev, client->irq, NULL, + mc34vr500_process_interrupt, + IRQF_TRIGGER_RISING | + IRQF_ONESHOT | + IRQF_SHARED, + dev_name(dev), data); + if (ret) + return ret; + + /* write 1 to clear interrupts */ + ret = regmap_write(regmap, MC34VR500_INTSTAT0, LOWVINS_BIT | + THERM110S_BIT | THERM120S_BIT | + THERM130S_BIT); + if (ret) + return ret; + + /* unmask interrupts */ + ret = regmap_write(regmap, MC34VR500_INTMASK0, + (unsigned int) ~(LOWVINS_BIT | THERM110S_BIT | + THERM120S_BIT | THERM130S_BIT)); + if (ret) + return ret; + } + + return 0; +} + +static const struct i2c_device_id mc34vr500_id[] = { + { "mc34vr500", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, mc34vr500_id); + +static const struct of_device_id __maybe_unused mc34vr500_of_match[] = { + { .compatible = "nxp,mc34vr500" }, + { }, +}; +MODULE_DEVICE_TABLE(of, mc34vr500_of_match); + +static struct i2c_driver mc34vr500_driver = { + .driver = { + .name = "mc34vr500", + .of_match_table = of_match_ptr(mc34vr500_of_match), + }, + .probe_new = mc34vr500_probe, + .id_table = mc34vr500_id, +}; + +module_i2c_driver(mc34vr500_driver); + +MODULE_AUTHOR("Mario Kicherer "); + +MODULE_DESCRIPTION("MC34VR500 driver"); +MODULE_LICENSE("GPL"); From 195f46e5afeedc4a40a7649932f042218b3b58e5 Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Sat, 28 Jan 2023 11:21:34 +0100 Subject: [PATCH 43/66] hwmon: (asus-ec-sensors) add zenith ii extreme alpha The ROG ZENITH II EXTREME ALPHA provides the same set of sensors as the no-ALPHA version. Tested with the hardware [1]. [1] https://github.com/zeule/asus-ec-sensors/issues/31 Signed-off-by: Eric Nguyen Signed-off-by: Eugene Shalygin Link: https://lore.kernel.org/r/20230128102135.5199-1-eugene.shalygin@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/asus_ec_sensors.rst | 1 + drivers/hwmon/asus-ec-sensors.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index 02f4ad314a1e..a4039f2f9ca4 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -23,6 +23,7 @@ Supported boards: * ROG STRIX X570-I GAMING * ROG STRIX Z690-A GAMING WIFI D4 * ROG ZENITH II EXTREME + * ROG ZENITH II EXTREME ALPHA Authors: - Eugene Shalygin diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index b4d65916b3c0..2768b7511684 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -467,6 +467,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_strix_z690_a_gaming_wifi_d4), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME", &board_info_zenith_ii_extreme), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA", + &board_info_zenith_ii_extreme), {}, }; From af499400dc117f0254468bc29b05e16dd6b0a56d Mon Sep 17 00:00:00 2001 From: Naresh Solanki Date: Tue, 24 Jan 2023 21:23:16 +0100 Subject: [PATCH 44/66] dt-bindings: trivial-devices: Add Infineon TDA38640 Voltage Regulator Infineon TDA38640 is PMBUS compliant voltage regulator. Signed-off-by: Naresh Solanki Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230124202317.3704963-1-Naresh.Solanki@9elements.com Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/trivial-devices.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index f5c0a6283e61..a28b02036489 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -141,6 +141,8 @@ properties: - infineon,slb9645tt # Infineon SLB9673 I2C TPM 2.0 - infineon,slb9673 + # Infineon TDA38640 Voltage Regulator + - infineon,tda38640 # Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor - infineon,tlv493d-a1b6 # Infineon Multi-phase Digital VR Controller xdpe11280 From 95b80c48cfcbe4d752ef229f80a47de92a51cf24 Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Tue, 24 Jan 2023 21:23:17 +0100 Subject: [PATCH 45/66] hwmon: (pmbus/tda38640) Add driver for Infineon TDA38640 Voltage Regulator Add the pmbus driver for the Infineon TDA38640 voltage regulator. Signed-off-by: Patrick Rudolph Signed-off-by: Naresh Solanki Link: https://lore.kernel.org/r/20230124202317.3704963-2-Naresh.Solanki@9elements.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/Kconfig | 16 ++++++++ drivers/hwmon/pmbus/Makefile | 1 + drivers/hwmon/pmbus/tda38640.c | 74 ++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 drivers/hwmon/pmbus/tda38640.c diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 30448e049486..9f4bbb9c487a 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -395,6 +395,22 @@ config SENSORS_STPDDC60 This driver can also be built as a module. If so, the module will be called stpddc60. +config SENSORS_TDA38640 + tristate "Infineon TDA38640" + help + If you say yes here you get hardware monitoring support for Infineon + TDA38640. + + This driver can also be built as a module. If so, the module will + be called tda38640. + +config SENSORS_TDA38640_REGULATOR + bool "Regulator support for TDA38640 and compatibles" + depends on SENSORS_TDA38640 && REGULATOR + help + If you say yes here you get regulator support for Infineon + TDA38640 as regulator. + config SENSORS_TPS40422 tristate "TI TPS40422" help diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index d9d2fa4bd6f7..3ae019916267 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o +obj-$(CONFIG_SENSORS_TDA38640) += tda38640.o obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o diff --git a/drivers/hwmon/pmbus/tda38640.c b/drivers/hwmon/pmbus/tda38640.c new file mode 100644 index 000000000000..c3e781319cd1 --- /dev/null +++ b/drivers/hwmon/pmbus/tda38640.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Hardware monitoring driver for Infineon TDA38640 + * + * Copyright (c) 2023 9elements GmbH + * + */ + +#include +#include +#include +#include +#include +#include +#include "pmbus.h" + +static const struct regulator_desc __maybe_unused tda38640_reg_desc[] = { + PMBUS_REGULATOR("vout", 0), +}; + +static struct pmbus_driver_info tda38640_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP + | PMBUS_HAVE_IIN + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT + | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN, +#if IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR) + .num_regulators = 1, + .reg_desc = tda38640_reg_desc, +#endif +}; + +static int tda38640_probe(struct i2c_client *client) +{ + return pmbus_do_probe(client, &tda38640_info); +} + +static const struct i2c_device_id tda38640_id[] = { + {"tda38640", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, tda38640_id); + +static const struct of_device_id __maybe_unused tda38640_of_match[] = { + { .compatible = "infineon,tda38640"}, + { }, +}; +MODULE_DEVICE_TABLE(of, tda38640_of_match); + +/* This is the driver that will be inserted */ +static struct i2c_driver tda38640_driver = { + .driver = { + .name = "tda38640", + .of_match_table = of_match_ptr(tda38640_of_match), + }, + .probe_new = tda38640_probe, + .id_table = tda38640_id, +}; + +module_i2c_driver(tda38640_driver); + +MODULE_AUTHOR("Patrick Rudolph "); +MODULE_DESCRIPTION("PMBus driver for Infineon TDA38640"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); From 7c81970baf8a8fe4f3d8705c6327aa740ae14f53 Mon Sep 17 00:00:00 2001 From: Jonathan Cormier Date: Thu, 26 Jan 2023 17:32:23 -0500 Subject: [PATCH 46/66] dt-bindings: hwmon: adi,ltc2945: Add binding Create initial binding for the LTC2945 I2C power monitor. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cormier Signed-off-by: Guenter Roeck --- .../bindings/hwmon/adi,ltc2945.yaml | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/adi,ltc2945.yaml diff --git a/Documentation/devicetree/bindings/hwmon/adi,ltc2945.yaml b/Documentation/devicetree/bindings/hwmon/adi,ltc2945.yaml new file mode 100644 index 000000000000..5cb66e97e816 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/adi,ltc2945.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/adi,ltc2945.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices LTC2945 wide range i2c power monitor + +maintainers: + - Guenter Roeck + +description: | + Analog Devices LTC2945 wide range i2c power monitor over I2C. + + https://www.analog.com/media/en/technical-documentation/data-sheets/LTC2945.pdf + +properties: + compatible: + enum: + - adi,ltc2945 + + reg: + maxItems: 1 + + shunt-resistor-micro-ohms: + description: + Shunt resistor value in micro-Ohms + default: 1000 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + power-monitor@6e { + compatible = "adi,ltc2945"; + reg = <0x6e>; + /* 10 milli-Ohm shunt resistor */ + shunt-resistor-micro-ohms = <10000>; + }; + }; +... From 4b0654e2c35938f5613edb3bc7550130145ebe62 Mon Sep 17 00:00:00 2001 From: Jonathan Cormier Date: Thu, 26 Jan 2023 17:32:24 -0500 Subject: [PATCH 47/66] hwmon: (ltc2945) Add devicetree match table Add adi,ltc2945 compatible Signed-off-by: Jonathan Cormier Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc2945.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index 9adebb59f604..9af3e3821152 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -58,6 +58,12 @@ #define CONTROL_MULT_SELECT (1 << 0) #define CONTROL_TEST_MODE (1 << 4) +static const struct of_device_id __maybe_unused ltc2945_of_match[] = { + { .compatible = "adi,ltc2945" }, + { } +}; +MODULE_DEVICE_TABLE(of, ltc2945_of_match); + static inline bool is_power_reg(u8 reg) { return reg < LTC2945_SENSE_H; @@ -475,8 +481,9 @@ MODULE_DEVICE_TABLE(i2c, ltc2945_id); static struct i2c_driver ltc2945_driver = { .driver = { - .name = "ltc2945", - }, + .name = "ltc2945", + .of_match_table = of_match_ptr(ltc2945_of_match), + }, .probe_new = ltc2945_probe, .id_table = ltc2945_id, }; From 178b01eccfb0b8149682f61388400bd3d903dddc Mon Sep 17 00:00:00 2001 From: Jonathan Cormier Date: Thu, 26 Jan 2023 17:32:25 -0500 Subject: [PATCH 48/66] hwmon: (ltc2945) Handle error case in ltc2945_value_store ltc2945_val_to_reg errors were not being handled which would have resulted in register being set to 0 (clamped) instead of being left alone. Fixes: 6700ce035f83 ("hwmon: Driver for Linear Technologies LTC2945") Signed-off-by: Jonathan Cormier Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc2945.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index 9af3e3821152..ac15298a6558 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -254,6 +254,8 @@ static ssize_t ltc2945_value_store(struct device *dev, /* convert to register value, then clamp and write result */ regval = ltc2945_val_to_reg(dev, reg, val); + if (regval < 0) + return regval; if (is_power_reg(reg)) { regval = clamp_val(regval, 0, 0xffffff); regbuf[0] = regval >> 16; From b11f3d47c0e74e6c0515e31788651713a3a94a50 Mon Sep 17 00:00:00 2001 From: John Pruitt Date: Thu, 26 Jan 2023 17:32:26 -0500 Subject: [PATCH 49/66] hwmon: (ltc2945) Allow setting shunt resistor Add the ability to specify the value of the shunt resistor in the device tree instead of assuming it is 1 milliOhm. The value in the device tree has the name shunt-resistor-micro-ohms and the default value is 1000 micro-ohms in order to preserve the current behavior. Signed-off-by: Jonathan Cormier Signed-off-by: John Pruitt [groeck: Fixed multi-line alignment, squashed last patch of series] Signed-off-by: Guenter Roeck --- drivers/hwmon/ltc2945.c | 119 +++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 43 deletions(-) diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index ac15298a6558..3494f7261ebf 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -64,6 +64,16 @@ static const struct of_device_id __maybe_unused ltc2945_of_match[] = { }; MODULE_DEVICE_TABLE(of, ltc2945_of_match); +/** + * struct ltc2945_data - LTC2945 device data + * @regmap: regmap device + * @shunt_resistor: shunt resistor value in micro ohms (1000 by default) + */ +struct ltc2945_data { + struct regmap *regmap; + u32 shunt_resistor; +}; + static inline bool is_power_reg(u8 reg) { return reg < LTC2945_SENSE_H; @@ -72,7 +82,9 @@ static inline bool is_power_reg(u8 reg) /* Return the value from the given register in uW, mV, or mA */ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) { - struct regmap *regmap = dev_get_drvdata(dev); + struct ltc2945_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + u32 shunt_resistor = data->shunt_resistor; unsigned int control; u8 buf[3]; long long val; @@ -84,10 +96,10 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) return ret; if (is_power_reg(reg)) { - /* power */ + /* 24-bit power */ val = (buf[0] << 16) + (buf[1] << 8) + buf[2]; } else { - /* current, voltage */ + /* 12-bit current, voltage */ val = (buf[0] << 4) + (buf[1] >> 4); } @@ -98,9 +110,7 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) case LTC2945_MAX_POWER_THRES_H: case LTC2945_MIN_POWER_THRES_H: /* - * Convert to uW by assuming current is measured with - * an 1mOhm sense resistor, similar to current - * measurements. + * Convert to uW * Control register bit 0 selects if voltage at SENSE+/VDD * or voltage at ADIN is used to measure power. */ @@ -114,6 +124,14 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) /* 0.5 mV * 25 uV = 0.0125 uV resolution. */ val = (val * 25LL) >> 1; } + val *= 1000; + /* Overflow check: Assuming max 24-bit power, val is at most 53 bits right now. */ + val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor); + /* + * Overflow check: After division, depending on shunt resistor, + * val can still be > 32 bits so returning long long makes sense + */ + break; case LTC2945_VIN_H: case LTC2945_MAX_VIN_H: @@ -136,14 +154,11 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) case LTC2945_MIN_SENSE_H: case LTC2945_MAX_SENSE_THRES_H: case LTC2945_MIN_SENSE_THRES_H: - /* - * 25 uV resolution. Convert to current as measured with - * an 1 mOhm sense resistor, in mA. If a different sense - * resistor is installed, calculate the actual current by - * dividing the reported current by the sense resistor value - * in mOhm. - */ - val *= 25; + /* 25 uV resolution. Convert to mA. */ + val *= 25 * 1000; + /* Overflow check: Assuming max 12-bit sense, val is at most 27 bits right now */ + val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor); + /* Overflow check: After division, <= 27 bits */ break; default: return -EINVAL; @@ -151,13 +166,18 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) return val; } -static int ltc2945_val_to_reg(struct device *dev, u8 reg, - unsigned long val) +static long long ltc2945_val_to_reg(struct device *dev, u8 reg, + unsigned long long val) { - struct regmap *regmap = dev_get_drvdata(dev); + struct ltc2945_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + u32 shunt_resistor = data->shunt_resistor; unsigned int control; int ret; + /* Ensure we don't overflow */ + val = clamp_val(val, 0, U32_MAX); + switch (reg) { case LTC2945_POWER_H: case LTC2945_MAX_POWER_H: @@ -165,9 +185,6 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, case LTC2945_MAX_POWER_THRES_H: case LTC2945_MIN_POWER_THRES_H: /* - * Convert to register value by assuming current is measured - * with an 1mOhm sense resistor, similar to current - * measurements. * Control register bit 0 selects if voltage at SENSE+/VDD * or voltage at ADIN is used to measure power, which in turn * determines register calculations. @@ -177,14 +194,16 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, return ret; if (control & CONTROL_MULT_SELECT) { /* 25 mV * 25 uV = 0.625 uV resolution. */ - val = DIV_ROUND_CLOSEST(val, 625); + val *= shunt_resistor; + /* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */ + val = DIV_ROUND_CLOSEST_ULL(val, 625 * 1000); + /* Overflow check: val is now <= 44 bits */ } else { - /* - * 0.5 mV * 25 uV = 0.0125 uV resolution. - * Divide first to avoid overflow; - * accept loss of accuracy. - */ - val = DIV_ROUND_CLOSEST(val, 25) * 2; + /* 0.5 mV * 25 uV = 0.0125 uV resolution. */ + val *= shunt_resistor; + /* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */ + val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000) * 2; + /* Overflow check: val is now <= 51 bits */ } break; case LTC2945_VIN_H: @@ -193,7 +212,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, case LTC2945_MAX_VIN_THRES_H: case LTC2945_MIN_VIN_THRES_H: /* 25 mV resolution. */ - val /= 25; + val = DIV_ROUND_CLOSEST_ULL(val, 25); break; case LTC2945_ADIN_H: case LTC2945_MAX_ADIN_H: @@ -208,14 +227,11 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, case LTC2945_MIN_SENSE_H: case LTC2945_MAX_SENSE_THRES_H: case LTC2945_MIN_SENSE_THRES_H: - /* - * 25 uV resolution. Convert to current as measured with - * an 1 mOhm sense resistor, in mA. If a different sense - * resistor is installed, calculate the actual current by - * dividing the reported current by the sense resistor value - * in mOhm. - */ - val = DIV_ROUND_CLOSEST(val, 25); + /* 25 uV resolution. Convert to mA. */ + val *= shunt_resistor; + /* Overflow check: Assuming 32-bit val and 32-bit shunt resistor, val is 64bits */ + val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000); + /* Overflow check: val is now <= 50 bits */ break; default: return -EINVAL; @@ -240,15 +256,16 @@ static ssize_t ltc2945_value_store(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct regmap *regmap = dev_get_drvdata(dev); + struct ltc2945_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; u8 reg = attr->index; - unsigned long val; + unsigned int val; u8 regbuf[3]; int num_regs; - int regval; + long long regval; int ret; - ret = kstrtoul(buf, 10, &val); + ret = kstrtouint(buf, 10, &val); if (ret) return ret; @@ -277,7 +294,8 @@ static ssize_t ltc2945_history_store(struct device *dev, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct regmap *regmap = dev_get_drvdata(dev); + struct ltc2945_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; u8 reg = attr->index; int num_regs = is_power_reg(reg) ? 3 : 2; u8 buf_min[3] = { 0xff, 0xff, 0xff }; @@ -329,7 +347,8 @@ static ssize_t ltc2945_bool_show(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct regmap *regmap = dev_get_drvdata(dev); + struct ltc2945_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; unsigned int fault; int ret; @@ -458,6 +477,12 @@ static int ltc2945_probe(struct i2c_client *client) struct device *dev = &client->dev; struct device *hwmon_dev; struct regmap *regmap; + struct ltc2945_data *data; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + dev_set_drvdata(dev, data); regmap = devm_regmap_init_i2c(client, <c2945_regmap_config); if (IS_ERR(regmap)) { @@ -465,11 +490,19 @@ static int ltc2945_probe(struct i2c_client *client) return PTR_ERR(regmap); } + data->regmap = regmap; + if (device_property_read_u32(dev, "shunt-resistor-micro-ohms", + &data->shunt_resistor)) + data->shunt_resistor = 1000; + + if (data->shunt_resistor == 0) + return -EINVAL; + /* Clear faults */ regmap_write(regmap, LTC2945_FAULT, 0x00); hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, - regmap, + data, ltc2945_groups); return PTR_ERR_OR_ZERO(hwmon_dev); } From a6f7c5d0e72ea0000cc03ed2d26559658939b16f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 24 Jan 2023 08:15:08 -0800 Subject: [PATCH 50/66] hwmon: (pmbus/max16601) Add support for MAX16600 From programming perspective, MAX16600 is identical to MAX16601 and MAX16602. Add support for it. Cc: Steve Foreman Cc: Holly Barrett Signed-off-by: Guenter Roeck --- Documentation/hwmon/max16601.rst | 11 ++++++++++- drivers/hwmon/pmbus/Kconfig | 4 ++-- drivers/hwmon/pmbus/max16601.c | 14 +++++++++----- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Documentation/hwmon/max16601.rst b/Documentation/hwmon/max16601.rst index 6a4eef8efbaf..c8c63a053e40 100644 --- a/Documentation/hwmon/max16601.rst +++ b/Documentation/hwmon/max16601.rst @@ -13,6 +13,14 @@ Supported chips: Datasheet: Not published + * Maxim MAX16600 + + Prefix: 'max16600' + + Addresses scanned: - + + Datasheet: Not published + * Maxim MAX16601 Prefix: 'max16601' @@ -36,7 +44,8 @@ Description ----------- This driver supports the MAX16508 VR13 Dual-Output Voltage Regulator -as well as the MAX16601 VR13.HC Dual-Output Voltage Regulator chipsets. +as well as the MAX16600, MAX16601, and MAX16602 VR13.HC Dual-Output +Voltage Regulator chipsets. The driver is a client driver to the core PMBus driver. Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers. diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 9f4bbb9c487a..59d9a7430499 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -237,10 +237,10 @@ config SENSORS_MAX16064 be called max16064. config SENSORS_MAX16601 - tristate "Maxim MAX16508, MAX16601, MAX16602" + tristate "Maxim MAX16508, MAX16600, MAX16601, and MAX16602" help If you say yes here you get hardware monitoring support for Maxim - MAX16508, MAX16601 and MAX16602. + MAX16508, MAX16600, MAX16601, and MAX16602. This driver can also be built as a module. If so, the module will be called max16601. diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index b628405e6586..6724f723f74c 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Hardware monitoring driver for Maxim MAX16508, MAX16601 and MAX16602. + * Hardware monitoring driver for Maxim MAX16508, MAX16600, MAX16601, + * and MAX16602. * * Implementation notes: * @@ -31,7 +32,7 @@ #include "pmbus.h" -enum chips { max16508, max16601, max16602 }; +enum chips { max16508, max16600, max16601, max16602 }; #define REG_DEFAULT_NUM_POP 0xc4 #define REG_SETPT_DVID 0xd1 @@ -202,7 +203,7 @@ static int max16601_identify(struct i2c_client *client, else info->vrm_version[0] = vr12; - if (data->id != max16601 && data->id != max16602) + if (data->id != max16600 && data->id != max16601 && data->id != max16602) return 0; reg = i2c_smbus_read_byte_data(client, REG_DEFAULT_NUM_POP); @@ -263,6 +264,7 @@ static void max16601_remove(void *_data) static const struct i2c_device_id max16601_id[] = { {"max16508", max16508}, + {"max16600", max16600}, {"max16601", max16601}, {"max16602", max16602}, {} @@ -281,11 +283,13 @@ static int max16601_get_id(struct i2c_client *client) return -ENODEV; /* - * PMBUS_IC_DEVICE_ID is expected to return "MAX16601y.xx" or - * MAX16602y.xx or "MAX16500y.xx".cdxxcccccccccc + * PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx" or + * "MAX16500y.xx".cdxxcccccccccc */ if (!strncmp(buf, "MAX16500", 8)) { id = max16508; + } else if (!strncmp(buf, "MAX16600", 8)) { + id = max16600; } else if (!strncmp(buf, "MAX16601", 8)) { id = max16601; } else if (!strncmp(buf, "MAX16602", 8)) { From 12087a365f06eca4c3d9ec0de35728bc5215216d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 29 Jan 2023 15:10:47 -0800 Subject: [PATCH 51/66] Documentation: hwmon: correct spelling Correct spelling problems for Documentation/hwmon/ as reported by codespell. Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: Jean Delvare Cc: Guenter Roeck Cc: linux-hwmon@vger.kernel.org Link: https://lore.kernel.org/r/20230129231053.20863-4-rdunlap@infradead.org Signed-off-by: Guenter Roeck --- Documentation/hwmon/aht10.rst | 2 +- Documentation/hwmon/aspeed-pwm-tacho.rst | 2 +- Documentation/hwmon/corsair-psu.rst | 2 +- Documentation/hwmon/gsc-hwmon.rst | 6 +++--- Documentation/hwmon/hwmon-kernel-api.rst | 4 ++-- Documentation/hwmon/ltc2978.rst | 2 +- Documentation/hwmon/max6697.rst | 2 +- Documentation/hwmon/menf21bmc.rst | 2 +- Documentation/hwmon/pmbus-core.rst | 2 +- Documentation/hwmon/sht4x.rst | 2 +- Documentation/hwmon/smm665.rst | 2 +- Documentation/hwmon/stpddc60.rst | 2 +- Documentation/hwmon/vexpress.rst | 2 +- Documentation/hwmon/via686a.rst | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Documentation/hwmon/aht10.rst b/Documentation/hwmon/aht10.rst index 482262ca117c..4e198c5eb683 100644 --- a/Documentation/hwmon/aht10.rst +++ b/Documentation/hwmon/aht10.rst @@ -38,7 +38,7 @@ Sysfs entries ------------- =============== ============================================ -temp1_input Measured temperature in millidegrees Celcius +temp1_input Measured temperature in millidegrees Celsius humidity1_input Measured humidity in %H update_interval The minimum interval for polling the sensor, in milliseconds. Writable. Must be at diff --git a/Documentation/hwmon/aspeed-pwm-tacho.rst b/Documentation/hwmon/aspeed-pwm-tacho.rst index 6dcec845fbc7..f7bbe96f4bc8 100644 --- a/Documentation/hwmon/aspeed-pwm-tacho.rst +++ b/Documentation/hwmon/aspeed-pwm-tacho.rst @@ -10,7 +10,7 @@ Authors: Description: ------------ This driver implements support for ASPEED AST2400/2500 PWM and Fan Tacho -controller. The PWM controller supports upto 8 PWM outputs. The Fan tacho +controller. The PWM controller supports up to 8 PWM outputs. The Fan tacho controller supports up to 16 tachometer inputs. The driver provides the following sensor accesses in sysfs: diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index 6a03edb551a8..c389bd21f4f2 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -40,7 +40,7 @@ This driver implements the sysfs interface for the Corsair PSUs with a HID proto interface of the HXi and RMi series. These power supplies provide access to a micro-controller with 2 attached temperature sensors, 1 fan rpm sensor, 4 sensors for volt levels, 4 sensors for -power usage and 4 sensors for current levels and addtional non-sensor information +power usage and 4 sensors for current levels and additional non-sensor information like uptimes. Sysfs entries diff --git a/Documentation/hwmon/gsc-hwmon.rst b/Documentation/hwmon/gsc-hwmon.rst index ffac392a7129..e9ab27940d02 100644 --- a/Documentation/hwmon/gsc-hwmon.rst +++ b/Documentation/hwmon/gsc-hwmon.rst @@ -31,7 +31,7 @@ Temperature Monitoring Temperatures are measured with 12-bit or 10-bit resolution and are scaled either internally or by the driver depending on the GSC version and firmware. -The values returned by the driver reflect millidegree Celcius: +The values returned by the driver reflect millidegree Celsius: tempX_input Measured temperature. tempX_label Name of temperature input. @@ -41,8 +41,8 @@ PWM Output Control ------------------ The GSC features 1 PWM output that operates in automatic mode where the -PWM value will be scalled depending on 6 temperature boundaries. -The tempeature boundaries are read-write and in millidegree Celcius and the +PWM value will be scaled depending on 6 temperature boundaries. +The tempeature boundaries are read-write and in millidegree Celsius and the read-only PWM values range from 0 (off) to 255 (full speed). Fan speed will be set to minimum (off) when the temperature sensor reads less than pwm1_auto_point1_temp and maximum when the temperature sensor diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst index 26cf55303c61..5451a6d4c874 100644 --- a/Documentation/hwmon/hwmon-kernel-api.rst +++ b/Documentation/hwmon/hwmon-kernel-api.rst @@ -57,7 +57,7 @@ register/unregister functions:: hwmon_device_register_with_groups registers a hardware monitoring device. The first parameter of this function is a pointer to the parent device. The name parameter is a pointer to the hwmon device name. The registration -function wil create a name sysfs attribute pointing to this name. +function will create a name sysfs attribute pointing to this name. The drvdata parameter is the pointer to the local driver data. hwmon_device_register_with_groups will attach this pointer to the newly allocated hwmon device. The pointer can be retrieved by the driver using @@ -360,7 +360,7 @@ functions is used. The header file linux/hwmon-sysfs.h provides a number of useful macros to declare and use hardware monitoring sysfs attributes. -In many cases, you can use the exsting define DEVICE_ATTR or its variants +In many cases, you can use the existing define DEVICE_ATTR or its variants DEVICE_ATTR_{RW,RO,WO} to declare such attributes. This is feasible if an attribute has no additional context. However, in many cases there will be additional information such as a sensor index which will need to be passed diff --git a/Documentation/hwmon/ltc2978.rst b/Documentation/hwmon/ltc2978.rst index b99a63965cfb..edf24e5e1e11 100644 --- a/Documentation/hwmon/ltc2978.rst +++ b/Documentation/hwmon/ltc2978.rst @@ -333,7 +333,7 @@ temp[N]_input Measured temperature. - On LTC3883, temp1 reports an external temperature, and temp2 reports the chip temperature. -temp[N]_min Mimimum temperature. +temp[N]_min Minimum temperature. LTC2972, LTC2974, LCT2977, LTM2980, LTC2978, LTC2979, and LTM2987 only. diff --git a/Documentation/hwmon/max6697.rst b/Documentation/hwmon/max6697.rst index ffc5a7d8d33b..90ca224c446a 100644 --- a/Documentation/hwmon/max6697.rst +++ b/Documentation/hwmon/max6697.rst @@ -73,7 +73,7 @@ Description This driver implements support for several MAX6697 compatible temperature sensor chips. The chips support one local temperature sensor plus four, six, or seven remote temperature sensors. Remote temperature sensors are diode-connected -thermal transitors, except for MAX6698 which supports three diode-connected +thermal transistors, except for MAX6698 which supports three diode-connected thermal transistors plus three thermistors in addition to the local temperature sensor. diff --git a/Documentation/hwmon/menf21bmc.rst b/Documentation/hwmon/menf21bmc.rst index 978691d5956d..e7f3f67b38d4 100644 --- a/Documentation/hwmon/menf21bmc.rst +++ b/Documentation/hwmon/menf21bmc.rst @@ -7,7 +7,7 @@ Supported chips: Prefix: 'menf21bmc_hwmon' - Adresses scanned: - + Addresses scanned: - Author: Andreas Werner diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 84c5a4e40c40..cff93adf6e42 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -174,7 +174,7 @@ Read byte from page , register . int (*read_word_data)(struct i2c_client *client, int page, int phase, int reg); -Read word from page , phase , register . If the chip does not +Read word from page , phase , register . If the chip does not support multiple phases, the phase parameter can be ignored. If the chip supports multiple phases, a phase value of 0xff indicates all phases. diff --git a/Documentation/hwmon/sht4x.rst b/Documentation/hwmon/sht4x.rst index c318e5582ead..daf21e763425 100644 --- a/Documentation/hwmon/sht4x.rst +++ b/Documentation/hwmon/sht4x.rst @@ -37,7 +37,7 @@ Sysfs entries ------------- =============== ============================================ -temp1_input Measured temperature in millidegrees Celcius +temp1_input Measured temperature in millidegrees Celsius humidity1_input Measured humidity in %H update_interval The minimum interval for polling the sensor, in milliseconds. Writable. Must be at least diff --git a/Documentation/hwmon/smm665.rst b/Documentation/hwmon/smm665.rst index a0e27f62b57b..481e69d8bf39 100644 --- a/Documentation/hwmon/smm665.rst +++ b/Documentation/hwmon/smm665.rst @@ -180,7 +180,7 @@ in9_crit_alarm AIN1 critical alarm in10_crit_alarm AIN2 critical alarm temp1_input Chip temperature -temp1_min Mimimum chip temperature +temp1_min Minimum chip temperature temp1_max Maximum chip temperature temp1_crit Critical chip temperature temp1_crit_alarm Temperature critical alarm diff --git a/Documentation/hwmon/stpddc60.rst b/Documentation/hwmon/stpddc60.rst index 7f7ce7f7871b..0c31f78fe58b 100644 --- a/Documentation/hwmon/stpddc60.rst +++ b/Documentation/hwmon/stpddc60.rst @@ -39,7 +39,7 @@ output voltage as a positive or negative offset in the interval 50mV to 400mV in 50mV steps. This means that the absolute values of the limits will change when the commanded output voltage changes. Also, care should be taken when writing to those limits since in the worst case the commanded output voltage -could change at the same time as the limit is written to, wich will lead to +could change at the same time as the limit is written to, which will lead to unpredictable results. diff --git a/Documentation/hwmon/vexpress.rst b/Documentation/hwmon/vexpress.rst index 8c861c8151ac..7fc99f75b3b1 100644 --- a/Documentation/hwmon/vexpress.rst +++ b/Documentation/hwmon/vexpress.rst @@ -27,7 +27,7 @@ Versatile Express platform (http://www.arm.com/versatileexpress/) is a reference & prototyping system for ARM Ltd. processors. It can be set up from a wide range of boards, each of them containing (apart of the main chip/FPGA) a number of microcontrollers responsible for platform -configuration and control. Theses microcontrollers can also monitor the +configuration and control. These microcontrollers can also monitor the board and its environment by a number of internal and external sensors, providing information about power lines voltages and currents, board temperature and power usage. Some of them also calculate consumed energy diff --git a/Documentation/hwmon/via686a.rst b/Documentation/hwmon/via686a.rst index 7ab9ddebcf79..8c52a9207bcb 100644 --- a/Documentation/hwmon/via686a.rst +++ b/Documentation/hwmon/via686a.rst @@ -58,7 +58,7 @@ representable value is around 2600 RPM. Voltage sensors (also known as IN sensors) report their values in volts. An alarm is triggered if the voltage has crossed a programmable minimum -or maximum limit. Voltages are internally scalled, so each voltage channel +or maximum limit. Voltages are internally scaled, so each voltage channel has a different resolution and range. If an alarm triggers, it will remain triggered until the hardware register From 4119693bd260dabbbf34abf262ece477bc3ed57c Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 28 Jan 2023 17:03:02 +1100 Subject: [PATCH 52/66] hwmon: (it87) Allow disabling exiting of configuration mode Disabling configuration mode on some chips can result in system hang-ups and access failures to the Super-IO chip at the second SIO address. Never exit configuration mode on these chips to avoid the problem. This patch should be applied in conjunction with a previous one to initialise the second chip for certain mother boards. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230128060308.1549707-2-frank@crawford.emu.id.au [groeck: Change feature bit from 28 to 19 to be continuous] Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index a8a6a0ffee82..8c0001be1127 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -128,10 +128,12 @@ static inline int superio_enter(int ioreg) return 0; } -static inline void superio_exit(int ioreg) +static inline void superio_exit(int ioreg, bool noexit) { - outb(0x02, ioreg); - outb(0x02, ioreg + 1); + if (!noexit) { + outb(0x02, ioreg); + outb(0x02, ioreg + 1); + } release_region(ioreg, 2); } @@ -300,6 +302,13 @@ struct it87_devices { #define FEAT_PWM_FREQ2 BIT(16) /* Separate pwm freq 2 */ #define FEAT_SIX_TEMP BIT(17) /* Up to 6 temp sensors */ #define FEAT_VIN3_5V BIT(18) /* VIN3 connected to +5V */ +/* + * Disabling configuration mode on some chips can result in system + * hang-ups and access failures to the Super-IO chip at the + * second SIO address. Never exit configuration mode on these + * chips to avoid the problem. + */ +#define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */ static const struct it87_devices it87_devices[] = { [it87] = { @@ -493,6 +502,7 @@ static const struct it87_devices it87_devices[] = { #define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2) #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) struct it87_sio_data { int sioaddr; @@ -2404,7 +2414,7 @@ static int __init it87_find(int sioaddr, unsigned short *address, { int err; u16 chip_type; - const struct it87_devices *config; + const struct it87_devices *config = NULL; err = superio_enter(sioaddr); if (err) @@ -2489,6 +2499,8 @@ static int __init it87_find(int sioaddr, unsigned short *address, goto exit; } + config = &it87_devices[sio_data->type]; + superio_select(sioaddr, PME); if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) { pr_info("Device not activated, skipping\n"); @@ -2508,8 +2520,6 @@ static int __init it87_find(int sioaddr, unsigned short *address, it87_devices[sio_data->type].suffix, *address, sio_data->revision); - config = &it87_devices[sio_data->type]; - /* in7 (VSB or VCCH5V) is always internal on some chips */ if (has_in7_internal(config)) sio_data->internal |= BIT(1); @@ -2827,7 +2837,7 @@ static int __init it87_find(int sioaddr, unsigned short *address, sio_data->skip_pwm |= dmi_data->skip_pwm; exit: - superio_exit(sioaddr); + superio_exit(sioaddr, config ? has_conf_noexit(config) : false); return err; } @@ -3213,7 +3223,7 @@ static void it87_resume_sio(struct platform_device *pdev) reg2c); } - superio_exit(data->sioaddr); + superio_exit(data->sioaddr, has_conf_noexit(data)); } static int it87_resume(struct device *dev) From e114737850668d4e14be4460e8aa45e668b87b80 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 28 Jan 2023 17:03:03 +1100 Subject: [PATCH 53/66] hwmon: (it87) Disable configuration exit for certain chips IT8790E and IT8792E/IT8795E have been identified as chips that can have issues when disabling configuration mode. Set to never exit configuration mode. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230128060308.1549707-3-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 8c0001be1127..fc38a6af30d9 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -429,7 +429,7 @@ static const struct it87_devices it87_devices[] = { .suffix = "E", .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_CONF_NOEXIT, .peci_mask = 0x07, }, [it8792] = { @@ -437,7 +437,7 @@ static const struct it87_devices it87_devices[] = { .suffix = "E", .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_CONF_NOEXIT, .peci_mask = 0x07, .old_peci_mask = 0x02, /* Actually reports PCH */ }, From 1f21531d4f42360971a6ebf9d3a4f20a2f4b3be1 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 28 Jan 2023 17:03:04 +1100 Subject: [PATCH 54/66] hwmon: (it87) List full chip model name ITE model names do not always match the chip ID. Convert from just adding a suffix to specifying the full model name. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230128060308.1549707-4-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 46 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index fc38a6af30d9..95bd4ca1d4d5 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -277,7 +277,7 @@ static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 }; struct it87_devices { const char *name; - const char * const suffix; + const char * const model; u32 features; u8 peci_mask; u8 old_peci_mask; @@ -313,24 +313,24 @@ struct it87_devices { static const struct it87_devices it87_devices[] = { [it87] = { .name = "it87", - .suffix = "F", + .model = "IT87F", .features = FEAT_OLD_AUTOPWM, /* may need to overwrite */ }, [it8712] = { .name = "it8712", - .suffix = "F", + .model = "IT8712F", .features = FEAT_OLD_AUTOPWM | FEAT_VID, /* may need to overwrite */ }, [it8716] = { .name = "it8716", - .suffix = "F", + .model = "IT8716F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2, }, [it8718] = { .name = "it8718", - .suffix = "F", + .model = "IT8718F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2, @@ -338,7 +338,7 @@ static const struct it87_devices it87_devices[] = { }, [it8720] = { .name = "it8720", - .suffix = "F", + .model = "IT8720F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2, @@ -346,7 +346,7 @@ static const struct it87_devices it87_devices[] = { }, [it8721] = { .name = "it8721", - .suffix = "F", + .model = "IT8721F", .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 @@ -356,7 +356,7 @@ static const struct it87_devices it87_devices[] = { }, [it8728] = { .name = "it8728", - .suffix = "F", + .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, @@ -364,7 +364,7 @@ static const struct it87_devices it87_devices[] = { }, [it8732] = { .name = "it8732", - .suffix = "F", + .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, @@ -373,7 +373,7 @@ static const struct it87_devices it87_devices[] = { }, [it8771] = { .name = "it8771", - .suffix = "E", + .model = "IT8771E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2, @@ -385,7 +385,7 @@ static const struct it87_devices it87_devices[] = { }, [it8772] = { .name = "it8772", - .suffix = "E", + .model = "IT8772E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2, @@ -397,28 +397,28 @@ static const struct it87_devices it87_devices[] = { }, [it8781] = { .name = "it8781", - .suffix = "F", + .model = "IT8781F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, .old_peci_mask = 0x4, }, [it8782] = { .name = "it8782", - .suffix = "F", + .model = "IT8782F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, .old_peci_mask = 0x4, }, [it8783] = { .name = "it8783", - .suffix = "E/F", + .model = "IT8783E/F", .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, .old_peci_mask = 0x4, }, [it8786] = { .name = "it8786", - .suffix = "E", + .model = "IT8786E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2, @@ -426,7 +426,7 @@ static const struct it87_devices it87_devices[] = { }, [it8790] = { .name = "it8790", - .suffix = "E", + .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, @@ -434,7 +434,7 @@ static const struct it87_devices it87_devices[] = { }, [it8792] = { .name = "it8792", - .suffix = "E", + .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, @@ -443,7 +443,7 @@ static const struct it87_devices it87_devices[] = { }, [it8603] = { .name = "it8603", - .suffix = "E", + .model = "IT8603E", .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL | FEAT_AVCC3 | FEAT_PWM_FREQ2, @@ -451,7 +451,7 @@ static const struct it87_devices it87_devices[] = { }, [it8620] = { .name = "it8620", - .suffix = "E", + .model = "IT8620E", .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 @@ -460,7 +460,7 @@ static const struct it87_devices it87_devices[] = { }, [it8622] = { .name = "it8622", - .suffix = "E", + .model = "IT8622E", .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 @@ -469,7 +469,7 @@ static const struct it87_devices it87_devices[] = { }, [it8628] = { .name = "it8628", - .suffix = "E", + .model = "IT8628E", .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 @@ -2516,8 +2516,8 @@ static int __init it87_find(int sioaddr, unsigned short *address, err = 0; sio_data->sioaddr = sioaddr; sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f; - pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type, - it87_devices[sio_data->type].suffix, + pr_info("Found %s chip at 0x%x, revision %d\n", + it87_devices[sio_data->type].model, *address, sio_data->revision); /* in7 (VSB or VCCH5V) is always internal on some chips */ From f09c7965053e1608e508e9e2c18b1d77b350cff1 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 28 Jan 2023 17:03:05 +1100 Subject: [PATCH 55/66] hwmon: (it87) Add chip_id in some info message In cases where there are multiple chips, print out which chip is referred to, in the informational message. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230128060308.1549707-5-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 95bd4ca1d4d5..01d890a00b85 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -2503,13 +2503,15 @@ static int __init it87_find(int sioaddr, unsigned short *address, superio_select(sioaddr, PME); if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) { - pr_info("Device not activated, skipping\n"); + pr_info("Device (chip %s ioreg 0x%x) not activated, skipping\n", + config->model, sioaddr); goto exit; } *address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1); if (*address == 0) { - pr_info("Base address not set, skipping\n"); + pr_info("Base address not set (chip %s ioreg 0x%x), skipping\n", + config->model, sioaddr); goto exit; } From 2a64e9d4451758fe4e1dc9106177b3b937b8c186 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 28 Jan 2023 17:03:06 +1100 Subject: [PATCH 56/66] hwmon: (it87) Allow multiple chip IDs for force_id Extend the force_id module parameter to allow specifying one or both chip IDs separately. If only a single parameter is given it defaults to using that value for all chips, similar to previous usage. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230128060308.1549707-6-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 01d890a00b85..5a1d11a66032 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -175,8 +175,9 @@ static inline void superio_exit(int ioreg, bool noexit) #define IT87_SIO_VID_REG 0xfc /* VID value */ #define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ -/* Force chip ID to specified value. Should only be used for testing */ -static unsigned short force_id; +/* Force chip IDs to specified values. Should only be used for testing */ +static unsigned short force_id[2]; +static unsigned int force_id_cnt; /* ACPI resource conflicts are ignored if this parameter is set to 1 */ static bool ignore_resource_conflict; @@ -2410,7 +2411,7 @@ static const struct attribute_group it87_group_auto_pwm = { /* SuperIO detection - will change isa_address if a chip is found */ static int __init it87_find(int sioaddr, unsigned short *address, - struct it87_sio_data *sio_data) + struct it87_sio_data *sio_data, int chip_cnt) { int err; u16 chip_type; @@ -2426,8 +2427,12 @@ static int __init it87_find(int sioaddr, unsigned short *address, if (chip_type == 0xffff) goto exit; - if (force_id) - chip_type = force_id; + if (force_id_cnt == 1) { + /* If only one value given use for all chips */ + if (force_id[0]) + chip_type = force_id[0]; + } else if (force_id[chip_cnt]) + chip_type = force_id[chip_cnt]; switch (chip_type) { case IT8705F_DEVID: @@ -3419,7 +3424,7 @@ static int __init sm_it87_init(void) for (i = 0; i < ARRAY_SIZE(sioaddr); i++) { memset(&sio_data, 0, sizeof(struct it87_sio_data)); isa_address[i] = 0; - err = it87_find(sioaddr[i], &isa_address[i], &sio_data); + err = it87_find(sioaddr[i], &isa_address[i], &sio_data, i); if (err || isa_address[i] == 0) continue; /* @@ -3468,8 +3473,8 @@ static void __exit sm_it87_exit(void) MODULE_AUTHOR("Chris Gauthron, Jean Delvare "); MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver"); -module_param(force_id, ushort, 0); -MODULE_PARM_DESC(force_id, "Override the detected device ID"); +module_param_array(force_id, ushort, &force_id_cnt, 0); +MODULE_PARM_DESC(force_id, "Override one or more detected device ID(s)"); module_param(ignore_resource_conflict, bool, 0); MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict"); From d44cb4cd7456b6eef2689fdfed7bf361ffc8e5ce Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 28 Jan 2023 17:03:07 +1100 Subject: [PATCH 57/66] hwmon: (it87) Add new chipset IT87952E Add IT87952E, a new chip ID (DEV ID 0x8695), which appears to be an updated version of the IT8792E and takes the same configuration. The model name comes from the model name printed on the chip. There is no datasheet publicly available. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230128060308.1549707-7-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 5a1d11a66032..66f7ceaa7c3f 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -34,6 +34,7 @@ * IT8786E Super I/O chip w/LPC interface * IT8790E Super I/O chip w/LPC interface * IT8792E Super I/O chip w/LPC interface + * IT87952E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * * Copyright (C) 2001 Chris Gauthron @@ -63,7 +64,7 @@ enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, it8771, it8772, it8781, it8782, it8783, it8786, it8790, - it8792, it8603, it8620, it8622, it8628 }; + it8792, it8603, it8620, it8622, it8628, it87952 }; static struct platform_device *it87_pdev[2]; @@ -160,6 +161,7 @@ static inline void superio_exit(int ioreg, bool noexit) #define IT8622E_DEVID 0x8622 #define IT8623E_DEVID 0x8623 #define IT8628E_DEVID 0x8628 +#define IT87952E_DEVID 0x8695 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -477,6 +479,15 @@ static const struct it87_devices it87_devices[] = { | FEAT_SIX_TEMP | FEAT_VIN3_5V, .peci_mask = 0x07, }, + [it87952] = { + .name = "it87952", + .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, + .peci_mask = 0x07, + .old_peci_mask = 0x02, /* Actually reports PCH */ + }, }; #define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) @@ -2497,6 +2508,9 @@ static int __init it87_find(int sioaddr, unsigned short *address, case IT8628E_DEVID: sio_data->type = it8628; break; + case IT87952E_DEVID: + sio_data->type = it87952; + break; case 0xffff: /* No device at all */ goto exit; default: From 01189055605cf66096bd3effa49dea490037d7dc Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sat, 28 Jan 2023 17:03:08 +1100 Subject: [PATCH 58/66] hwmon: (it87) Updated documentation for recent updates to it87 Updated the driver documentation to list all current chips and describe the module parameters as per descriptions in the code. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20230128060308.1549707-8-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- Documentation/hwmon/it87.rst | 47 ++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/Documentation/hwmon/it87.rst b/Documentation/hwmon/it87.rst index 2d83f23bee93..5cef4f265000 100644 --- a/Documentation/hwmon/it87.rst +++ b/Documentation/hwmon/it87.rst @@ -145,6 +145,22 @@ Supported chips: Datasheet: Not publicly available + * IT8792E/IT8795E + + Prefix: 'it8792' + + Addresses scanned: from Super I/O config space (8 I/O ports) + + Datasheet: Not publicly available + + * IT87952E + + Prefix: 'it87952' + + Addresses scanned: from Super I/O config space (8 I/O ports) + + Datasheet: Not publicly available + * SiS950 [clone of IT8705F] Prefix: 'it87' @@ -162,7 +178,7 @@ Authors: Module Parameters ----------------- -* update_vbat: int +* update_vbat bool 0 if vbat should report power on value, 1 if vbat should be updated after each read. Default is 0. On some boards the battery voltage is provided by either the battery or the onboard power supply. Only the first reading @@ -171,11 +187,31 @@ Module Parameters the chip so can be read at any time. Excessive reading may decrease battery life but no information is given in the datasheet. -* fix_pwm_polarity int +* fix_pwm_polarity bool Force PWM polarity to active high (DANGEROUS). Some chips are misconfigured by BIOS - PWM values would be inverted. This option tries to fix this. Please contact your BIOS manufacturer and ask him for fix. +* force_id short, short + + Force multiple chip ID to specified value, separated by ','. + For example "force_id=0x8689,0x8633". A value of 0 is ignored + for that chip. + Note: A single force_id value (e.g. "force_id=0x8689") is used for + all chips, to only set the first chip use "force_id=0x8689,0". + Should only be used for testing. + +* ignore_resource_conflict bool + + Similar to acpi_enforce_resources=lax, but only affects this driver. + ACPI resource conflicts are ignored if this parameter is provided and + set to 1. + Provided since there are reports that system-wide acpi_enfore_resources=lax + can result in boot failures on some systems. + Note: This is inherently risky since it means that both ACPI and this driver + may access the chip at the same time. This can result in race conditions and, + worst case, result in unexpected system reboots. + Hardware Interfaces ------------------- @@ -193,8 +229,8 @@ Description This driver implements support for the IT8603E, IT8620E, IT8623E, IT8628E, IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, -IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and -SiS950 chips. +IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, +IT8792E/IT8795E, IT87952E and SiS950 chips. These chips are 'Super I/O chips', supporting floppy disks, infrared ports, joysticks and other miscellaneous stuff. For hardware monitoring, they @@ -238,7 +274,8 @@ of the fan is not supported (value 0 of pwmX_enable). The IT8620E and IT8628E are custom designs, hardware monitoring part is similar to IT8728F. It only supports 16-bit fan mode. Both chips support up to 6 fans. -The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled. +The IT8790E, IT8792E/IT8795E and IT87952E support up to 3 fans. 16-bit fan +mode is always enabled. The IT8732F supports a closed-loop mode for fan control, but this is not currently implemented by the driver. From a37672b072d1d56634db7e164e095abf65c45ebd Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Sun, 22 Jan 2023 21:36:46 +0000 Subject: [PATCH 59/66] Docs/hwmon/index: Add missing SPDX License Identifier Add missing SPDX License Identifier for hwmon documentation index file. Signed-off-by: SeongJae Park Reviewed-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/20230122213650.187710-5-sj@kernel.org Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 95f5459ed2c9..96ce91b7d9a8 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + ========================= Linux Hardware Monitoring ========================= From e1983220ae14ae7bdc8db4fb64e78bb55122c32b Mon Sep 17 00:00:00 2001 From: Tianfei zhang Date: Tue, 31 Jan 2023 15:54:50 +0200 Subject: [PATCH 60/66] hwmon: intel-m10-bmc-hwmon: Add N6000 sensors Add sensors supported by N6000 card with MAX10 BMC to monitor temperature, voltage, current, and power on board. Signed-off-by: Tianfei zhang Link: https://lore.kernel.org/r/20230131135450.43072-1-ilpo.jarvinen@linux.intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/intel-m10-bmc-hwmon.c | 229 ++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index 6e82f7200d1c..2f0323c14bab 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -340,6 +340,231 @@ static const struct m10bmc_hwmon_board_data n5010bmc_hwmon_bdata = { .hinfo = n5010bmc_hinfo, }; +static const struct m10bmc_sdata n6000bmc_temp_tbl[] = { + { 0x444, 0x448, 0x44c, 0x0, 0x0, 500, "FPGA E-TILE Temperature #1" }, + { 0x450, 0x454, 0x458, 0x0, 0x0, 500, "FPGA E-TILE Temperature #2" }, + { 0x45c, 0x460, 0x464, 0x0, 0x0, 500, "FPGA E-TILE Temperature #3" }, + { 0x468, 0x46c, 0x470, 0x0, 0x0, 500, "FPGA E-TILE Temperature #4" }, + { 0x474, 0x478, 0x47c, 0x0, 0x0, 500, "FPGA P-TILE Temperature" }, + { 0x484, 0x488, 0x48c, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #1" }, + { 0x490, 0x494, 0x498, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #2" }, + { 0x49c, 0x4a0, 0x4a4, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #3" }, + { 0x4a8, 0x4ac, 0x4b0, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #4" }, + { 0x4b4, 0x4b8, 0x4bc, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #5" }, + { 0x4c0, 0x4c4, 0x4c8, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #1" }, + { 0x4cc, 0x4d0, 0x4d4, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #2" }, + { 0x4d8, 0x4dc, 0x4e0, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #3" }, + { 0x4e4, 0x4e8, 0x4ec, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #4" }, + { 0x4f0, 0x4f4, 0x4f8, 0x52c, 0x0, 500, "Board Top Near FPGA Temperature" }, + { 0x4fc, 0x500, 0x504, 0x52c, 0x0, 500, "Board Bottom Near CVL Temperature" }, + { 0x508, 0x50c, 0x510, 0x52c, 0x0, 500, "Board Top East Near VRs Temperature" }, + { 0x514, 0x518, 0x51c, 0x52c, 0x0, 500, "Columbiaville Die Temperature" }, + { 0x520, 0x524, 0x528, 0x52c, 0x0, 500, "Board Rear Side Temperature" }, + { 0x530, 0x534, 0x538, 0x52c, 0x0, 500, "Board Front Side Temperature" }, + { 0x53c, 0x540, 0x544, 0x0, 0x0, 500, "QSFP1 Case Temperature" }, + { 0x548, 0x54c, 0x550, 0x0, 0x0, 500, "QSFP2 Case Temperature" }, + { 0x554, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 0 VR Temperature" }, + { 0x560, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 1 VR Temperature" }, + { 0x56c, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 2 VR Temperature" }, + { 0x578, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage VR Controller Temperature" }, + { 0x584, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCCH VR Temperature" }, + { 0x590, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCC_1V2 VR Temperature" }, + { 0x59c, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCCH, VCC_1V2 VR Controller Temperature" }, + { 0x5a8, 0x0, 0x0, 0x0, 0x0, 500, "3V3 VR Temperature" }, + { 0x5b4, 0x0, 0x0, 0x0, 0x0, 500, "CVL Core Voltage VR Temperature" }, + { 0x5c4, 0x5c8, 0x5cc, 0x5c0, 0x0, 500, "FPGA P-Tile Temperature [Remote]" }, + { 0x5d0, 0x5d4, 0x5d8, 0x5c0, 0x0, 500, "FPGA E-Tile Temperature [Remote]" }, + { 0x5dc, 0x5e0, 0x5e4, 0x5c0, 0x0, 500, "FPGA SDM Temperature [Remote]" }, + { 0x5e8, 0x5ec, 0x5f0, 0x5c0, 0x0, 500, "FPGA Corner Temperature [Remote]" }, +}; + +static const struct m10bmc_sdata n6000bmc_in_tbl[] = { + { 0x5f4, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Voltage" }, + { 0x60c, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V Aux Rail Voltage" }, + { 0x624, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Voltage" }, + { 0x63c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage Rail Voltage" }, + { 0x644, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH Rail Voltage" }, + { 0x64c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_1V2 Rail Voltage" }, + { 0x654, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH_GXER_1V1, VCCA_1V8 Voltage" }, + { 0x664, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCIO_1V2 Voltage" }, + { 0x674, 0x0, 0x0, 0x0, 0x0, 1, "CVL Non Core Rails Inlet Voltage" }, + { 0x684, 0x0, 0x0, 0x0, 0x0, 1, "MAX10 & Board CLK PWR 3V3 Inlet Voltage" }, + { 0x694, 0x0, 0x0, 0x0, 0x0, 1, "CVL Core Voltage Rail Voltage" }, + { 0x6ac, 0x0, 0x0, 0x0, 0x0, 1, "Board 3V3 VR Voltage" }, + { 0x6b4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP 3V3 Rail Voltage" }, + { 0x6c4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Primary) Supply Rail Voltage" }, + { 0x6c8, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Secondary) Supply Rail Voltage" }, + { 0x6cc, 0x0, 0x0, 0x0, 0x0, 1, "VCCCLK_GXER_2V5 Voltage" }, + { 0x6d0, 0x0, 0x0, 0x0, 0x0, 1, "AVDDH_1V1_CVL Voltage" }, + { 0x6d4, 0x0, 0x0, 0x0, 0x0, 1, "VDDH_1V8_CVL Voltage" }, + { 0x6d8, 0x0, 0x0, 0x0, 0x0, 1, "VCCA_PLL Voltage" }, + { 0x6e0, 0x0, 0x0, 0x0, 0x0, 1, "VCCRT_GXER_0V9 Voltage" }, + { 0x6e8, 0x0, 0x0, 0x0, 0x0, 1, "VCCRT_GXPL_0V9 Voltage" }, + { 0x6f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCH_GXPL_1V8 Voltage" }, + { 0x6f4, 0x0, 0x0, 0x0, 0x0, 1, "VCCPT_1V8 Voltage" }, + { 0x6fc, 0x0, 0x0, 0x0, 0x0, 1, "VCC_3V3_M10 Voltage" }, + { 0x700, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V8_M10 Voltage" }, + { 0x704, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V2_EMIF1_2_3 Voltage" }, + { 0x70c, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V2_EMIF4_5 Voltage" }, + { 0x714, 0x0, 0x0, 0x0, 0x0, 1, "VCCA_1V8 Voltage" }, + { 0x718, 0x0, 0x0, 0x0, 0x0, 1, "VCCH_GXER_1V1 Voltage" }, + { 0x71c, 0x0, 0x0, 0x0, 0x0, 1, "AVDD_ETH_0V9_CVL Voltage" }, + { 0x720, 0x0, 0x0, 0x0, 0x0, 1, "AVDD_PCIE_0V9_CVL Voltage" }, +}; + +static const struct m10bmc_sdata n6000bmc_curr_tbl[] = { + { 0x600, 0x604, 0x608, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Current" }, + { 0x618, 0x61c, 0x620, 0x0, 0x0, 1, "Inlet 12V Aux Rail Current" }, + { 0x630, 0x634, 0x638, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Current" }, + { 0x640, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage Rail Current" }, + { 0x648, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH Rail Current" }, + { 0x650, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_1V2 Rail Current" }, + { 0x658, 0x65c, 0x660, 0x0, 0x0, 1, "FPGA VCCH_GXER_1V1, VCCA_1V8 Current" }, + { 0x668, 0x66c, 0x670, 0x0, 0x0, 1, "FPGA VCCIO_1V2 Current" }, + { 0x678, 0x67c, 0x680, 0x0, 0x0, 1, "CVL Non Core Rails Inlet Current" }, + { 0x688, 0x68c, 0x690, 0x0, 0x0, 1, "MAX10 & Board CLK PWR 3V3 Inlet Current" }, + { 0x698, 0x0, 0x0, 0x0, 0x0, 1, "CVL Core Voltage Rail Current" }, + { 0x6b0, 0x0, 0x0, 0x0, 0x0, 1, "Board 3V3 VR Current" }, + { 0x6b8, 0x6bc, 0x6c0, 0x0, 0x0, 1, "QSFP 3V3 Rail Current" }, +}; + +static const struct m10bmc_sdata n6000bmc_power_tbl[] = { + { 0x724, 0x0, 0x0, 0x0, 0x0, 1, "Board Power" }, +}; + +static const struct hwmon_channel_info *n6000bmc_hinfo[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | + HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT | + HWMON_C_LABEL), + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT | HWMON_P_LABEL), + NULL +}; + +static const struct m10bmc_hwmon_board_data n6000bmc_hwmon_bdata = { + .tables = { + [hwmon_temp] = n6000bmc_temp_tbl, + [hwmon_in] = n6000bmc_in_tbl, + [hwmon_curr] = n6000bmc_curr_tbl, + [hwmon_power] = n6000bmc_power_tbl, + }, + + .hinfo = n6000bmc_hinfo, +}; + static umode_t m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -549,6 +774,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = { .name = "n5010bmc-hwmon", .driver_data = (unsigned long)&n5010bmc_hwmon_bdata, }, + { + .name = "n6000bmc-hwmon", + .driver_data = (unsigned long)&n6000bmc_hwmon_bdata, + }, { } }; From 1c999af509b3f834d3d65a90fb72860a6d6a8370 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 31 Jan 2023 11:33:59 +0100 Subject: [PATCH 61/66] hwmon: (iio_hwmon) use dev_err_probe Instead of just returning an error code, add an error message as well. While at it, simplify the code and use a common return path. Upon deferral this also nicely lists the following message in /sys/kernel/debug/devices_deferred: adc iio_hwmon: Failed to get channels Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20230131103359.625081-1-alexander.stein@ew.tq-group.com Signed-off-by: Guenter Roeck --- drivers/hwmon/iio_hwmon.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index 3aa40893fc09..4c8a80847891 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -77,9 +77,11 @@ static int iio_hwmon_probe(struct platform_device *pdev) channels = devm_iio_channel_get_all(dev); if (IS_ERR(channels)) { - if (PTR_ERR(channels) == -ENODEV) - return -EPROBE_DEFER; - return PTR_ERR(channels); + ret = PTR_ERR(channels); + if (ret == -ENODEV) + ret = -EPROBE_DEFER; + return dev_err_probe(dev, ret, + "Failed to get channels\n"); } st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); From e0f6c370f0ad2b02637ba4ead082d39cc9a1b094 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Tue, 31 Jan 2023 11:12:09 +0100 Subject: [PATCH 62/66] hwmon: (aquacomputer_d5next) Add support for Aquacomputer Poweradjust 3 Extend aquacomputer_d5next driver to expose the temp sensor of the Aquacomputer Poweradjust 3 fan controller, which communicates through a proprietary USB HID protocol. The Poweradjust 3 is not currently known to expose firmware version and serial number, so don't create debugfs entries if their values can't be retrieved. Tested by a user on Github [1]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/57 Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20230131101210.8095-1-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 3 + drivers/hwmon/aquacomputer_d5next.c | 88 +++++++++++++++++++-- 2 files changed, 84 insertions(+), 7 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 3f7880fb8116..527bcd3edda9 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 Poweradjust 3 fan controller Author: Aleksa Savic @@ -53,6 +54,8 @@ 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 Poweradjust 3 controller exposes a single external temperature sensor. + Depending on the device, not all sysfs and debugfs entries will be available. Writing to virtual temperature sensors is not currently supported. diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index c1b885240ddf..2945b630b4a0 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -4,7 +4,8 @@ * Quadro, High Flow Next, Aquaero) * * Aquacomputer devices send HID reports (with ID 0x01) every second to report - * sensor values. + * sensor values, except for devices that communicate through the + * legacy way (currently, Poweradjust 3). * * Copyright 2021 Aleksa Savic * Copyright 2022 Jack Doan @@ -28,8 +29,9 @@ #define USB_PRODUCT_ID_FARBWERK360 0xf010 #define USB_PRODUCT_ID_OCTO 0xf011 #define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012 +#define USB_PRODUCT_ID_POWERADJUST3 0xf0bd -enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero }; +enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero, poweradjust3 }; static const char *const aqc_device_names[] = { [d5next] = "d5next", @@ -38,7 +40,8 @@ static const char *const aqc_device_names[] = { [octo] = "octo", [quadro] = "quadro", [highflownext] = "highflownext", - [aquaero] = "aquaero" + [aquaero] = "aquaero", + [poweradjust3] = "poweradjust3" }; #define DRIVER_NAME "aquacomputer_d5next" @@ -59,6 +62,9 @@ static u8 secondary_ctrl_report[] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6 }; +/* Report IDs for legacy devices */ +#define POWERADJUST3_STATUS_REPORT_ID 0x03 + /* Info, sensor sizes and offsets for most Aquacomputer devices */ #define AQC_SERIAL_START 0x3 #define AQC_FIRMWARE_VERSION 0xD @@ -176,6 +182,13 @@ 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 Poweradjust 3 */ +#define POWERADJUST3_NUM_SENSORS 1 +#define POWERADJUST3_SENSOR_REPORT_SIZE 0x32 + +/* Sensor report offsets for the Poweradjust 3 */ +#define POWERADJUST3_SENSOR_START 0x03 + /* Labels for D5 Next */ static const char *const label_d5next_temp[] = { "Coolant temp" @@ -326,6 +339,11 @@ static const char *const label_highflownext_voltage[] = { "+5V USB voltage" }; +/* Labels for Poweradjust 3 */ +static const char *const label_poweradjust3_temp_sensors[] = { + "External sensor" +}; + struct aqc_fan_structure_offsets { u8 voltage; u8 curr; @@ -357,6 +375,8 @@ struct aqc_data { enum kinds kind; const char *name; + int status_report_id; /* Used for legacy devices, report is stored in buffer */ + int buffer_size; u8 *buffer; int checksum_start; @@ -615,14 +635,49 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 return 0; } +/* Read device sensors by manually requesting the sensor report (legacy way) */ +static int aqc_legacy_read(struct aqc_data *priv) +{ + int ret, i, sensor_value; + + mutex_lock(&priv->mutex); + + memset(priv->buffer, 0x00, priv->buffer_size); + ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer, + priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < 0) + goto unlock_and_return; + + /* Temperature sensor readings */ + for (i = 0; i < priv->num_temp_sensors; i++) { + sensor_value = get_unaligned_le16(priv->buffer + priv->temp_sensor_start_offset + + i * AQC_SENSOR_SIZE); + priv->temp_input[i] = sensor_value * 10; + } + + priv->updated = jiffies; + +unlock_and_return: + mutex_unlock(&priv->mutex); + return ret; +} + static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { int ret; struct aqc_data *priv = dev_get_drvdata(dev); - if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL)) - return -ENODATA; + if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL)) { + if (priv->status_report_id != 0) { + /* Legacy devices require manual reads */ + ret = aqc_legacy_read(priv); + if (ret < 0) + return -ENODATA; + } else { + return -ENODATA; + } + } switch (type) { case hwmon_temp: @@ -1014,9 +1069,13 @@ static void aqc_debugfs_init(struct aqc_data *priv) dev_name(&priv->hdev->dev)); priv->debugfs = debugfs_create_dir(name, NULL); - debugfs_create_file("serial_number", 0444, priv->debugfs, priv, &serial_number_fops); - debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops); + if (priv->serial_number_start_offset != 0) + debugfs_create_file("serial_number", 0444, priv->debugfs, priv, + &serial_number_fops); + if (priv->firmware_version_offset != 0) + debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, + &firmware_version_fops); if (priv->power_cycle_count_offset != 0) debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops); } @@ -1214,6 +1273,17 @@ 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_POWERADJUST3: + priv->kind = poweradjust3; + + priv->num_fans = 0; + + priv->num_temp_sensors = POWERADJUST3_NUM_SENSORS; + priv->temp_sensor_start_offset = POWERADJUST3_SENSOR_START; + priv->buffer_size = POWERADJUST3_SENSOR_REPORT_SIZE; + + priv->temp_label = label_poweradjust3_temp_sensors; + break; default: break; } @@ -1225,6 +1295,9 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->fan_structure = &aqc_aquaero_fan_structure; break; + case poweradjust3: + priv->status_report_id = POWERADJUST3_STATUS_REPORT_ID; + break; default: priv->serial_number_start_offset = AQC_SERIAL_START; priv->firmware_version_offset = AQC_FIRMWARE_VERSION; @@ -1287,6 +1360,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_POWERADJUST3) }, { } }; From 7505dab78f58c953b863753208eeca682e8126ff Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Fri, 3 Feb 2023 13:03:24 +0100 Subject: [PATCH 63/66] hwmon: (aquacomputer_d5next) Add support for Aquacomputer Aquastream Ultimate Extend aquacomputer_d5next driver to expose various hardware sensors of the Aquacomputer Aquastream Ultimate watercooling pump, which communicates through a proprietary USB HID protocol. Coolant temp and external temp sensor readings are available, along with speed, power, voltage and current of both the pump and optionally connected fan. It also exposes pressure and flow speed readings. Additionally, serial number and firmware version are exposed through debugfs. Tested by a user on Github [1]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/issues/50 Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20230203120324.579808-1-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 5 + drivers/hwmon/aquacomputer_d5next.c | 126 +++++++++++++++++++- 2 files changed, 125 insertions(+), 6 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 527bcd3edda9..7d0d015b1a52 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 Aquastream Ultimate watercooling pump * Aquacomputer Poweradjust 3 fan controller Author: Aleksa Savic @@ -54,6 +55,10 @@ 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 Aquastream Ultimate pump exposes coolant temp and an external temp sensor, along +with speed, power, voltage and current of both the pump and optionally connected fan. +It also exposes pressure and flow speed readings. + The Poweradjust 3 controller exposes a single external temperature sensor. Depending on the device, not all sysfs and debugfs entries will be available. diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 2945b630b4a0..12682a610ce7 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) + * Quadro, High Flow Next, Aquaero, Aquastream Ultimate) * * Aquacomputer devices send HID reports (with ID 0x01) every second to report * sensor values, except for devices that communicate through the @@ -29,9 +29,13 @@ #define USB_PRODUCT_ID_FARBWERK360 0xf010 #define USB_PRODUCT_ID_OCTO 0xf011 #define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012 +#define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b #define USB_PRODUCT_ID_POWERADJUST3 0xf0bd -enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext, aquaero, poweradjust3 }; +enum kinds { + d5next, farbwerk, farbwerk360, octo, quadro, + highflownext, aquaero, poweradjust3, aquastreamult +}; static const char *const aqc_device_names[] = { [d5next] = "d5next", @@ -41,6 +45,7 @@ static const char *const aqc_device_names[] = { [quadro] = "quadro", [highflownext] = "highflownext", [aquaero] = "aquaero", + [aquastreamult] = "aquastreamultimate", [poweradjust3] = "poweradjust3" }; @@ -117,6 +122,26 @@ static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET #define D5NEXT_TEMP_CTRL_OFFSET 0x2D /* Temperature sensor offsets location */ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (from 0-100%) */ +/* Specs of the Aquastream Ultimate pump */ +/* Pump does not follow the standard structure, so only consider the fan */ +#define AQUASTREAMULT_NUM_FANS 1 +#define AQUASTREAMULT_NUM_SENSORS 2 + +/* Sensor report offsets for the Aquastream Ultimate pump */ +#define AQUASTREAMULT_SENSOR_START 0x2D +#define AQUASTREAMULT_PUMP_OFFSET 0x51 +#define AQUASTREAMULT_PUMP_VOLTAGE 0x3D +#define AQUASTREAMULT_PUMP_CURRENT 0x53 +#define AQUASTREAMULT_PUMP_POWER 0x55 +#define AQUASTREAMULT_FAN_OFFSET 0x41 +#define AQUASTREAMULT_PRESSURE_OFFSET 0x57 +#define AQUASTREAMULT_FLOW_SENSOR_OFFSET 0x37 +#define AQUASTREAMULT_FAN_VOLTAGE_OFFSET 0x02 +#define AQUASTREAMULT_FAN_CURRENT_OFFSET 0x00 +#define AQUASTREAMULT_FAN_POWER_OFFSET 0x04 +#define AQUASTREAMULT_FAN_SPEED_OFFSET 0x06 +static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET }; + /* Spec and sensor report offset for the Farbwerk RGB controller */ #define FARBWERK_NUM_SENSORS 4 #define FARBWERK_SENSOR_START 0x2f @@ -339,6 +364,34 @@ static const char *const label_highflownext_voltage[] = { "+5V USB voltage" }; +/* Labels for Aquastream Ultimate */ +static const char *const label_aquastreamult_temp[] = { + "Coolant temp", + "External temp" +}; + +static const char *const label_aquastreamult_speeds[] = { + "Fan speed", + "Pump speed", + "Pressure [mbar]", + "Flow speed [dL/h]" +}; + +static const char *const label_aquastreamult_power[] = { + "Fan power", + "Pump power" +}; + +static const char *const label_aquastreamult_voltages[] = { + "Fan voltage", + "Pump voltage" +}; + +static const char *const label_aquastreamult_current[] = { + "Fan current", + "Pump current" +}; + /* Labels for Poweradjust 3 */ static const char *const label_poweradjust3_temp_sensors[] = { "External sensor" @@ -359,7 +412,15 @@ static struct aqc_fan_structure_offsets aqc_aquaero_fan_structure = { .speed = AQUAERO_FAN_SPEED_OFFSET }; -/* Fan structure offsets for all devices except Aquaero */ +/* Fan structure offsets for Aquastream Ultimate */ +static struct aqc_fan_structure_offsets aqc_aquastreamult_fan_structure = { + .voltage = AQUASTREAMULT_FAN_VOLTAGE_OFFSET, + .curr = AQUASTREAMULT_FAN_CURRENT_OFFSET, + .power = AQUASTREAMULT_FAN_POWER_OFFSET, + .speed = AQUASTREAMULT_FAN_SPEED_OFFSET +}; + +/* Fan structure offsets for all devices except those above */ static struct aqc_fan_structure_offsets aqc_general_fan_structure = { .voltage = AQC_FAN_VOLTAGE_OFFSET, .curr = AQC_FAN_CURRENT_OFFSET, @@ -565,6 +626,14 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 case hwmon_fan_input: case hwmon_fan_label: switch (priv->kind) { + case aquastreamult: + /* + * Special case to support pump RPM, fan RPM, + * pressure and flow sensor + */ + if (channel < 4) + return 0444; + break; case highflownext: /* Special case to support flow sensor, water quality * and conductivity @@ -595,6 +664,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 break; case hwmon_power: switch (priv->kind) { + case aquastreamult: + /* Special case to support pump and fan power */ + if (channel < 2) + return 0444; + break; case highflownext: /* Special case to support one power sensor */ if (channel == 0) @@ -607,8 +681,17 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 } break; case hwmon_curr: - if (channel < priv->num_fans) - return 0444; + switch (priv->kind) { + case aquastreamult: + /* Special case to support pump and fan current */ + if (channel < 2) + return 0444; + break; + default: + if (channel < priv->num_fans) + return 0444; + break; + } break; case hwmon_in: switch (priv->kind) { @@ -617,6 +700,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 if (channel < priv->num_fans + 2) return 0444; break; + case aquastreamult: case highflownext: /* Special case to support two voltage sensors */ if (channel < 2) @@ -1001,6 +1085,17 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8 i++; } break; + case aquastreamult: + priv->speed_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_OFFSET); + priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET); + priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET); + + priv->power_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000; + + priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10; + + priv->current_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_CURRENT); + break; case d5next: priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10; priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10; @@ -1273,6 +1368,21 @@ 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_AQUASTREAMULT: + priv->kind = aquastreamult; + + priv->num_fans = AQUASTREAMULT_NUM_FANS; + priv->fan_sensor_offsets = aquastreamult_sensor_fan_offsets; + + priv->num_temp_sensors = AQUASTREAMULT_NUM_SENSORS; + priv->temp_sensor_start_offset = AQUASTREAMULT_SENSOR_START; + + priv->temp_label = label_aquastreamult_temp; + priv->speed_label = label_aquastreamult_speeds; + priv->power_label = label_aquastreamult_power; + priv->voltage_label = label_aquastreamult_voltages; + priv->current_label = label_aquastreamult_current; + break; case USB_PRODUCT_ID_POWERADJUST3: priv->kind = poweradjust3; @@ -1302,7 +1412,10 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->serial_number_start_offset = AQC_SERIAL_START; priv->firmware_version_offset = AQC_FIRMWARE_VERSION; - priv->fan_structure = &aqc_general_fan_structure; + if (priv->kind == aquastreamult) + priv->fan_structure = &aqc_aquastreamult_fan_structure; + else + priv->fan_structure = &aqc_general_fan_structure; break; } @@ -1360,6 +1473,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_AQUASTREAMULT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) }, { } }; From 102be2c2420bd156a94ea509932c9eaef89b9424 Mon Sep 17 00:00:00 2001 From: Ye Xingchen Date: Wed, 8 Feb 2023 15:46:06 +0800 Subject: [PATCH 64/66] =?UTF-8?q?hwmon:=20(gxp-fan-ctrl)=20use=C2=A0devm?= =?UTF-8?q?=5Fplatform=5Fget=5Fand=5Fioremap=5Fresource()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Ye Xingchen Link: https://lore.kernel.org/r/202302081546067270324@zte.com.cn Signed-off-by: Guenter Roeck --- drivers/hwmon/gxp-fan-ctrl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hwmon/gxp-fan-ctrl.c b/drivers/hwmon/gxp-fan-ctrl.c index 0e9225a8b805..0014b8b0fd41 100644 --- a/drivers/hwmon/gxp-fan-ctrl.c +++ b/drivers/hwmon/gxp-fan-ctrl.c @@ -199,7 +199,6 @@ static const struct hwmon_chip_info gxp_fan_ctrl_chip_info = { static int gxp_fan_ctrl_probe(struct platform_device *pdev) { struct gxp_fan_ctrl_drvdata *drvdata; - struct resource *res; struct device *dev = &pdev->dev; struct device *hwmon_dev; @@ -208,8 +207,7 @@ static int gxp_fan_ctrl_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drvdata->base = devm_ioremap_resource(&pdev->dev, res); + drvdata->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(drvdata->base)) return dev_err_probe(dev, PTR_ERR(drvdata->base), "failed to map base\n"); From a1ffd3c46267ee5c807acd780e15df9bb692223f Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 12 Feb 2023 16:57:30 +0200 Subject: [PATCH 65/66] hwmon: (mlxreg-fan) Return zero speed for broken fan Currently for broken fan driver returns value calculated based on error code (0xFF) in related fan speed register. Thus, for such fan user gets fan{n}_fault to 1 and fan{n}_input with misleading value. Add check for fan fault prior return speed value and return zero if fault is detected. Fixes: 65afb4c8e7e4 ("hwmon: (mlxreg-fan) Add support for Mellanox FAN driver") Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20230212145730.24247-1-vadimp@nvidia.com Signed-off-by: Guenter Roeck --- drivers/hwmon/mlxreg-fan.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c index b48bd7c961d6..96017cc8da7e 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -155,6 +155,12 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, if (err) return err; + if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) { + /* FAN is broken - return zero for FAN speed. */ + *val = 0; + return 0; + } + *val = MLXREG_FAN_GET_RPM(regval, fan->divider, fan->samples); break; From 5720a18baa4686d56d0a235e6ecbcc55f8d716d7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 16 Feb 2023 11:34:19 -0800 Subject: [PATCH 66/66] hwmon: Deprecate [devm_]hwmon_device_register_with_groups Even though the hardware monitoring documentation already stated that new drivers should use [devm_]devm_hwmon_device_register_with_info() to register with the hardware monitoring subsystem, we still get submissions for new drivers using the older APIs. There is no benefit to use those APIs. On the contrary, using the older APIs results in substantially larger code size. Explicitly deprecate [devm_]hwmon_device_register_with_groups() to ensure that all new drivers use the latest API. Signed-off-by: Guenter Roeck --- Documentation/hwmon/submitting-patches.rst | 2 +- include/linux/hwmon.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/submitting-patches.rst b/Documentation/hwmon/submitting-patches.rst index d953ee763c96..6482c4f137dc 100644 --- a/Documentation/hwmon/submitting-patches.rst +++ b/Documentation/hwmon/submitting-patches.rst @@ -126,7 +126,7 @@ increase the chances of your change being accepted. * Use devm_hwmon_device_register_with_info() or, if your driver needs a remove function, hwmon_device_register_with_info() to register your driver with the hwmon subsystem. Try using devm_add_action() instead of a remove function if - possible. Do not use hwmon_device_register(). + possible. Do not use any of the deprecated registration functions. * Your driver should be buildable as module. If not, please be prepared to explain why it has to be built into the kernel. diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 14325f93c6b2..c1b62384b6ee 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -436,6 +436,10 @@ struct hwmon_chip_info { /* hwmon_device_register() is deprecated */ struct device *hwmon_device_register(struct device *dev); +/* + * hwmon_device_register_with_groups() and + * devm_hwmon_device_register_with_groups() are deprecated. + */ struct device * hwmon_device_register_with_groups(struct device *dev, const char *name, void *drvdata,