From 415519ad6966ce35f2535fc3ff95549414beb032 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 5 Oct 2022 16:27:52 +0100 Subject: hwmon: (fschmd) Make const arrays static const Don't populate the read-only const arrays names and watchdog_minors on the stack but instead make them static const. Also makes the object code a little smaller. Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20221005152752.318493-1-colin.i.king@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/fschmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 0a77d61619288e..e1f426e86f36c2 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -1083,9 +1083,9 @@ static int fschmd_detect(struct i2c_client *client, static int fschmd_probe(struct i2c_client *client) { struct fschmd_data *data; - const char * const names[7] = { "Poseidon", "Hermes", "Scylla", + static const char * const names[7] = { "Poseidon", "Hermes", "Scylla", "Heracles", "Heimdall", "Hades", "Syleus" }; - const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; + static const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; int i, err; enum chips kind = i2c_match_id(fschmd_id, client)->driver_data; -- cgit 1.2.3-korg From 12c44ab8b401c29d8d3569aaea34da662b8ece1d Mon Sep 17 00:00:00 2001 From: Ahmad Khalifa Date: Tue, 4 Oct 2022 22:01:01 +0100 Subject: hwmon: (it87) Add param to ignore ACPI resource conflicts Add parameter to ignore ACPI resource conflicts as an alternate to using 'acpi_enforce_resources=lax'. Some BIOSes reserve resources and don't use them and the system wide parameter may result in failures to certain drivers. Signed-off-by: Ahmad Khalifa Link: https://lore.kernel.org/r/20221004210100.540120-2-ahmad@khalifa.ws Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 7bd154ba351b90..e920dd26225ff8 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -69,6 +69,10 @@ 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 */ @@ -3261,8 +3265,10 @@ static int __init it87_device_add(int index, unsigned short address, int err; err = acpi_check_resource_conflict(&res); - if (err) - return err; + if (err) { + if (!ignore_resource_conflict) + return err; + } pdev = platform_device_alloc(DRVNAME, address); if (!pdev) -- cgit 1.2.3-korg From b3b19931a5c22f5a09f846e037b23f8a74455d0a Mon Sep 17 00:00:00 2001 From: Ahmad Khalifa Date: Tue, 4 Oct 2022 22:01:03 +0100 Subject: hwmon: (it87) Check for a valid chip before using force_id Check there is a chip before using force_id parameter as there is no value in registering a non-existent chip Signed-off-by: Ahmad Khalifa Link: https://lore.kernel.org/r/20221004210100.540120-3-ahmad@khalifa.ws Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index e920dd26225ff8..73ed21ab325ba6 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -2401,7 +2401,13 @@ static int __init it87_find(int sioaddr, unsigned short *address, return err; err = -ENODEV; - chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID); + chip_type = superio_inw(sioaddr, DEVID); + /* check first for a valid chip before forcing chip id */ + if (chip_type == 0xffff) + goto exit; + + if (force_id) + chip_type = force_id; switch (chip_type) { case IT8705F_DEVID: -- cgit 1.2.3-korg From deeab9ea40dbaabdf0e2828b5c3da3418ae7dd39 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 11 Oct 2022 16:33:08 +0200 Subject: hwmon: use simple i2c probe All these drivers have an i2c probe function which doesn't use the "struct i2c_device_id *id" parameter, so they can trivially be converted to the "probe_new" style of probe with a single argument. This is part of an ongoing transition to single-argument i2c probe functions. Old-style probe functions involve a call to i2c_match_id: in drivers/i2c/i2c-core-base.c, /* * When there are no more users of probe(), * rename probe_new to probe. */ if (driver->probe_new) status = driver->probe_new(client); else if (driver->probe) status = driver->probe(client, i2c_match_id(driver->id_table, client)); else status = -EINVAL; Drivers which don't need the second parameter can be declared using probe_new instead, avoiding the call to i2c_match_id. Drivers which do can still be converted to probe_new-style, calling i2c_match_id themselves (as is done currently for of_match_id). This change was done using the following Coccinelle script, and fixed up for whitespace changes: @ rule1 @ identifier fn; identifier client, id; @@ - static int fn(struct i2c_client *client, const struct i2c_device_id *id) + static int fn(struct i2c_client *client) { ...when != id } @ rule2 depends on rule1 @ identifier rule1.fn; identifier driver; @@ struct i2c_driver driver = { - .probe + .probe_new = ( fn | - &fn + fn ) , }; Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20221011143309.3141267-1-steve@sk2.org Signed-off-by: Guenter Roeck --- drivers/hwmon/aht10.c | 5 ++--- drivers/hwmon/emc2305.c | 4 ++-- drivers/hwmon/ltc2992.c | 4 ++-- drivers/hwmon/max127.c | 5 ++--- drivers/hwmon/sbrmi.c | 5 ++--- drivers/hwmon/sbtsi_temp.c | 5 ++--- drivers/hwmon/sht4x.c | 5 ++--- 7 files changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index 2d9770cb4401b7..d76f3441ecf1a5 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -289,8 +289,7 @@ static const struct hwmon_chip_info aht10_chip_info = { .info = aht10_info, }; -static int aht10_probe(struct i2c_client *client, - const struct i2c_device_id *aht10_id) +static int aht10_probe(struct i2c_client *client) { struct device *device = &client->dev; struct device *hwmon_dev; @@ -336,7 +335,7 @@ static struct i2c_driver aht10_driver = { .driver = { .name = "aht10", }, - .probe = aht10_probe, + .probe_new = aht10_probe, .id_table = aht10_id, }; diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index aa1f25add0b6b3..f222fcf3b6aa1c 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -518,7 +518,7 @@ static int emc2305_identify(struct device *dev) return 0; } -static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int emc2305_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -607,7 +607,7 @@ static struct i2c_driver emc2305_driver = { .driver = { .name = "emc2305", }, - .probe = emc2305_probe, + .probe_new = emc2305_probe, .remove = emc2305_remove, .id_table = emc2305_ids, .address_list = emc2305_normal_i2c, diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c index 72489d5d7eaf97..88514152d9306f 100644 --- a/drivers/hwmon/ltc2992.c +++ b/drivers/hwmon/ltc2992.c @@ -881,7 +881,7 @@ static int ltc2992_parse_dt(struct ltc2992_state *st) return 0; } -static int ltc2992_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int ltc2992_i2c_probe(struct i2c_client *client) { struct device *hwmon_dev; struct ltc2992_state *st; @@ -927,7 +927,7 @@ static struct i2c_driver ltc2992_i2c_driver = { .name = "ltc2992", .of_match_table = ltc2992_of_match, }, - .probe = ltc2992_i2c_probe, + .probe_new = ltc2992_i2c_probe, .id_table = ltc2992_i2c_id, }; diff --git a/drivers/hwmon/max127.c b/drivers/hwmon/max127.c index 402ffdc2f425b1..0e21e7e6bbd2e5 100644 --- a/drivers/hwmon/max127.c +++ b/drivers/hwmon/max127.c @@ -303,8 +303,7 @@ static const struct hwmon_chip_info max127_chip_info = { .info = max127_info, }; -static int max127_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max127_probe(struct i2c_client *client) { int i; struct device *hwmon_dev; @@ -340,7 +339,7 @@ static struct i2c_driver max127_driver = { .driver = { .name = "max127", }, - .probe = max127_probe, + .probe_new = max127_probe, .id_table = max127_id, }; diff --git a/drivers/hwmon/sbrmi.c b/drivers/hwmon/sbrmi.c index 7bf0c3fba75fef..8ea5a4d3219fff 100644 --- a/drivers/hwmon/sbrmi.c +++ b/drivers/hwmon/sbrmi.c @@ -297,8 +297,7 @@ static int sbrmi_get_max_pwr_limit(struct sbrmi_data *data) return ret; } -static int sbrmi_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sbrmi_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -348,7 +347,7 @@ static struct i2c_driver sbrmi_driver = { .name = "sbrmi", .of_match_table = of_match_ptr(sbrmi_of_match), }, - .probe = sbrmi_probe, + .probe_new = sbrmi_probe, .id_table = sbrmi_id, }; diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c index e35357c48b8e60..4c37de846f93be 100644 --- a/drivers/hwmon/sbtsi_temp.c +++ b/drivers/hwmon/sbtsi_temp.c @@ -199,8 +199,7 @@ static const struct hwmon_chip_info sbtsi_chip_info = { .info = sbtsi_info, }; -static int sbtsi_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sbtsi_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -239,7 +238,7 @@ static struct i2c_driver sbtsi_driver = { .name = "sbtsi", .of_match_table = of_match_ptr(sbtsi_of_match), }, - .probe = sbtsi_probe, + .probe_new = sbtsi_probe, .id_table = sbtsi_id, }; diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 13ac2d8f22c79b..13e042927bf89e 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -232,8 +232,7 @@ static const struct hwmon_chip_info sht4x_chip_info = { .info = sht4x_info, }; -static int sht4x_probe(struct i2c_client *client, - const struct i2c_device_id *sht4x_id) +static int sht4x_probe(struct i2c_client *client) { struct device *device = &client->dev; struct device *hwmon_dev; @@ -292,7 +291,7 @@ static struct i2c_driver sht4x_driver = { .name = "sht4x", .of_match_table = sht4x_of_match, }, - .probe = sht4x_probe, + .probe_new = sht4x_probe, .id_table = sht4x_id, }; -- cgit 1.2.3-korg From ad804a4d82fc7ececb457c06c8ba8b3a9d0e3bfd Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Fri, 21 Oct 2022 16:18:43 +0300 Subject: hwmon: (lm90) simplify using devm_regulator_get_enable() Drop open-coded pattern: 'devm_regulator_get(), regulator_enable(), add_action_or_reset(regulator_disable)' and use the devm_regulator_get_enable(). Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/a1fa4364cbb775de25478117dd22dda0742089e3.1666357434.git.mazziesaccount@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/lm90.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index db595f7d01f8ad..a3f95ba00dbffe 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -2663,11 +2663,6 @@ static void lm90_remove_pec(void *dev) device_remove_file(dev, &dev_attr_pec); } -static void lm90_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int lm90_probe_channel_from_dt(struct i2c_client *client, struct device_node *child, struct lm90_data *data) @@ -2749,24 +2744,13 @@ static int lm90_probe(struct i2c_client *client) struct device *dev = &client->dev; struct i2c_adapter *adapter = client->adapter; struct hwmon_channel_info *info; - struct regulator *regulator; struct device *hwmon_dev; struct lm90_data *data; int err; - regulator = devm_regulator_get(dev, "vcc"); - if (IS_ERR(regulator)) - return PTR_ERR(regulator); - - err = regulator_enable(regulator); - if (err < 0) { - dev_err(dev, "Failed to enable regulator: %d\n", err); - return err; - } - - err = devm_add_action_or_reset(dev, lm90_regulator_disable, regulator); + err = devm_regulator_get_enable(dev, "vcc"); if (err) - return err; + return dev_err_probe(dev, err, "Failed to enable regulator\n"); data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL); if (!data) -- cgit 1.2.3-korg From bba63de0c7a7e69584266872cb278cf12fe9ae83 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Fri, 21 Oct 2022 16:19:04 +0300 Subject: hwmon: (adm1177) simplify using devm_regulator_get_enable() Drop open-coded pattern: 'devm_regulator_get(), regulator_enable(), add_action_or_reset(regulator_disable)' and use the devm_regulator_get_enable() and drop the pointer to the regulator. This simplifies code and makes it less tempting to add manual control for the regulator which is also controlled by devm. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/7773541795f280db31dd981ffc21df8a630b794a.1666357434.git.mazziesaccount@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/adm1177.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c index 0c5dbc5e33b468..be17a26a84f19a 100644 --- a/drivers/hwmon/adm1177.c +++ b/drivers/hwmon/adm1177.c @@ -26,14 +26,12 @@ /** * struct adm1177_state - driver instance specific data * @client: pointer to i2c client - * @reg: regulator info for the power supply of the device * @r_sense_uohm: current sense resistor value * @alert_threshold_ua: current limit for shutdown * @vrange_high: internal voltage divider */ struct adm1177_state { struct i2c_client *client; - struct regulator *reg; u32 r_sense_uohm; u32 alert_threshold_ua; bool vrange_high; @@ -189,13 +187,6 @@ static const struct hwmon_chip_info adm1177_chip_info = { .info = adm1177_info, }; -static void adm1177_remove(void *data) -{ - struct adm1177_state *st = data; - - regulator_disable(st->reg); -} - static int adm1177_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -210,21 +201,9 @@ static int adm1177_probe(struct i2c_client *client) st->client = client; - st->reg = devm_regulator_get_optional(&client->dev, "vref"); - if (IS_ERR(st->reg)) { - if (PTR_ERR(st->reg) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - st->reg = NULL; - } else { - ret = regulator_enable(st->reg); - if (ret) - return ret; - ret = devm_add_action_or_reset(&client->dev, adm1177_remove, - st); - if (ret) - return ret; - } + ret = devm_regulator_get_enable_optional(&client->dev, "vref"); + if (ret == -EPROBE_DEFER) + return -EPROBE_DEFER; if (device_property_read_u32(dev, "shunt-resistor-micro-ohms", &st->r_sense_uohm)) -- cgit 1.2.3-korg From 7bce898147000718084c842e150519319dc202c6 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Thu, 29 Sep 2022 16:43:13 +0700 Subject: hwmon: Add Ampere's Altra smpro-hwmon driver This commit adds support for Ampere SMpro hwmon driver. This driver supports accessing various CPU sensors provided by the SMpro co-processor including temperature, power, voltages, and current. Signed-off-by: Quan Nguyen Link: https://lore.kernel.org/r/20220929094321.770125-2-quan@os.amperecomputing.com Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 8 + drivers/hwmon/Makefile | 1 + drivers/hwmon/smpro-hwmon.c | 463 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 472 insertions(+) create mode 100644 drivers/hwmon/smpro-hwmon.c diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7ac3daaf59ce06..e7ec6af309c79d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -67,6 +67,14 @@ config SENSORS_ABITUGURU3 This driver can also be built as a module. If so, the module will be called abituguru3. +config SENSORS_SMPRO + tristate "Ampere's Altra SMpro hardware monitoring driver" + depends on MFD_SMPRO + help + If you say yes here you get support for the thermal, voltage, + current and power sensors of Ampere's Altra processor family SoC + with SMpro co-processor. + config SENSORS_AD7314 tristate "Analog Devices AD7314 and compatibles" depends on SPI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 11d076cad8a2db..c5cd7e3a67ffd0 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -187,6 +187,7 @@ obj-$(CONFIG_SENSORS_SHT4x) += sht4x.o obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o +obj-$(CONFIG_SENSORS_SMPRO) += smpro-hwmon.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o diff --git a/drivers/hwmon/smpro-hwmon.c b/drivers/hwmon/smpro-hwmon.c new file mode 100644 index 00000000000000..ee54e21c2c123f --- /dev/null +++ b/drivers/hwmon/smpro-hwmon.c @@ -0,0 +1,463 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Ampere Computing SoC's SMPro Hardware Monitoring Driver + * + * Copyright (c) 2022, Ampere Computing LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Logical Power Sensor Registers */ +#define SOC_TEMP 0x10 +#define SOC_VRD_TEMP 0x11 +#define DIMM_VRD_TEMP 0x12 +#define CORE_VRD_TEMP 0x13 +#define CH0_DIMM_TEMP 0x14 +#define CH1_DIMM_TEMP 0x15 +#define CH2_DIMM_TEMP 0x16 +#define CH3_DIMM_TEMP 0x17 +#define CH4_DIMM_TEMP 0x18 +#define CH5_DIMM_TEMP 0x19 +#define CH6_DIMM_TEMP 0x1A +#define CH7_DIMM_TEMP 0x1B +#define RCA_VRD_TEMP 0x1C + +#define CORE_VRD_PWR 0x20 +#define SOC_PWR 0x21 +#define DIMM_VRD1_PWR 0x22 +#define DIMM_VRD2_PWR 0x23 +#define CORE_VRD_PWR_MW 0x26 +#define SOC_PWR_MW 0x27 +#define DIMM_VRD1_PWR_MW 0x28 +#define DIMM_VRD2_PWR_MW 0x29 +#define RCA_VRD_PWR 0x2A +#define RCA_VRD_PWR_MW 0x2B + +#define MEM_HOT_THRESHOLD 0x32 +#define SOC_VR_HOT_THRESHOLD 0x33 +#define CORE_VRD_VOLT 0x34 +#define SOC_VRD_VOLT 0x35 +#define DIMM_VRD1_VOLT 0x36 +#define DIMM_VRD2_VOLT 0x37 +#define RCA_VRD_VOLT 0x38 + +#define CORE_VRD_CURR 0x39 +#define SOC_VRD_CURR 0x3A +#define DIMM_VRD1_CURR 0x3B +#define DIMM_VRD2_CURR 0x3C +#define RCA_VRD_CURR 0x3D + +struct smpro_hwmon { + struct regmap *regmap; +}; + +struct smpro_sensor { + const u8 reg; + const u8 reg_ext; + const char *label; +}; + +static const struct smpro_sensor temperature[] = { + { + .reg = SOC_TEMP, + .label = "temp1 SoC" + }, + { + .reg = SOC_VRD_TEMP, + .reg_ext = SOC_VR_HOT_THRESHOLD, + .label = "temp2 SoC VRD" + }, + { + .reg = DIMM_VRD_TEMP, + .label = "temp3 DIMM VRD" + }, + { + .reg = CORE_VRD_TEMP, + .label = "temp4 CORE VRD" + }, + { + .reg = CH0_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp5 CH0 DIMM" + }, + { + .reg = CH1_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp6 CH1 DIMM" + }, + { + .reg = CH2_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp7 CH2 DIMM" + }, + { + .reg = CH3_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp8 CH3 DIMM" + }, + { + .reg = CH4_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp9 CH4 DIMM" + }, + { + .reg = CH5_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp10 CH5 DIMM" + }, + { + .reg = CH6_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp11 CH6 DIMM" + }, + { + .reg = CH7_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp12 CH7 DIMM" + }, + { + .reg = RCA_VRD_TEMP, + .label = "temp13 RCA VRD" + }, +}; + +static const struct smpro_sensor voltage[] = { + { + .reg = CORE_VRD_VOLT, + .label = "vout0 CORE VRD" + }, + { + .reg = SOC_VRD_VOLT, + .label = "vout1 SoC VRD" + }, + { + .reg = DIMM_VRD1_VOLT, + .label = "vout2 DIMM VRD1" + }, + { + .reg = DIMM_VRD2_VOLT, + .label = "vout3 DIMM VRD2" + }, + { + .reg = RCA_VRD_VOLT, + .label = "vout4 RCA VRD" + }, +}; + +static const struct smpro_sensor curr_sensor[] = { + { + .reg = CORE_VRD_CURR, + .label = "iout1 CORE VRD" + }, + { + .reg = SOC_VRD_CURR, + .label = "iout2 SoC VRD" + }, + { + .reg = DIMM_VRD1_CURR, + .label = "iout3 DIMM VRD1" + }, + { + .reg = DIMM_VRD2_CURR, + .label = "iout4 DIMM VRD2" + }, + { + .reg = RCA_VRD_CURR, + .label = "iout5 RCA VRD" + }, +}; + +static const struct smpro_sensor power[] = { + { + .reg = CORE_VRD_PWR, + .reg_ext = CORE_VRD_PWR_MW, + .label = "power1 CORE VRD" + }, + { + .reg = SOC_PWR, + .reg_ext = SOC_PWR_MW, + .label = "power2 SoC" + }, + { + .reg = DIMM_VRD1_PWR, + .reg_ext = DIMM_VRD1_PWR_MW, + .label = "power3 DIMM VRD1" + }, + { + .reg = DIMM_VRD2_PWR, + .reg_ext = DIMM_VRD2_PWR_MW, + .label = "power4 DIMM VRD2" + }, + { + .reg = RCA_VRD_PWR, + .reg_ext = RCA_VRD_PWR_MW, + .label = "power5 RCA VRD" + }, +}; + +static int smpro_read_temp(struct device *dev, u32 attr, int channel, long *val) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int value; + int ret; + + switch (attr) { + case hwmon_temp_input: + ret = regmap_read(hwmon->regmap, temperature[channel].reg, &value); + if (ret) + return ret; + break; + case hwmon_temp_crit: + ret = regmap_read(hwmon->regmap, temperature[channel].reg_ext, &value); + if (ret) + return ret; + break; + default: + return -EOPNOTSUPP; + } + + *val = sign_extend32(value, 8) * 1000; + return 0; +} + +static int smpro_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int value; + int ret; + + switch (attr) { + case hwmon_in_input: + ret = regmap_read(hwmon->regmap, voltage[channel].reg, &value); + if (ret < 0) + return ret; + /* 15-bit value in 1mV */ + *val = value & 0x7fff; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read_curr(struct device *dev, u32 attr, int channel, long *val) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int value; + int ret; + + switch (attr) { + case hwmon_curr_input: + ret = regmap_read(hwmon->regmap, curr_sensor[channel].reg, &value); + if (ret < 0) + return ret; + /* Scale reported by the hardware is 1mA */ + *val = value & 0x7fff; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read_power(struct device *dev, u32 attr, int channel, long *val_pwr) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int val = 0, val_mw = 0; + int ret; + + switch (attr) { + case hwmon_power_input: + ret = regmap_read(hwmon->regmap, power[channel].reg, &val); + if (ret) + return ret; + + ret = regmap_read(hwmon->regmap, power[channel].reg_ext, &val_mw); + if (ret) + return ret; + /* 10-bit value */ + *val_pwr = (val & 0x3ff) * 1000000 + (val_mw & 0x3ff) * 1000; + return 0; + + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_temp: + return smpro_read_temp(dev, attr, channel, val); + case hwmon_in: + return smpro_read_in(dev, attr, channel, val); + case hwmon_power: + return smpro_read_power(dev, attr, channel, val); + case hwmon_curr: + return smpro_read_curr(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_label: + *str = temperature[channel].label; + return 0; + default: + break; + } + break; + + case hwmon_in: + switch (attr) { + case hwmon_in_label: + *str = voltage[channel].label; + return 0; + default: + break; + } + break; + + case hwmon_curr: + switch (attr) { + case hwmon_curr_label: + *str = curr_sensor[channel].label; + return 0; + default: + break; + } + break; + + case hwmon_power: + switch (attr) { + case hwmon_power_label: + *str = power[channel].label; + return 0; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +} + +static umode_t smpro_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct smpro_hwmon *hwmon = data; + unsigned int value; + int ret; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_label: + case hwmon_temp_crit: + ret = regmap_read(hwmon->regmap, temperature[channel].reg, &value); + if (ret || value == 0xFFFF) + return 0; + break; + } + default: + break; + } + + return 0444; +} + +static const struct hwmon_channel_info *smpro_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | 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_CHANNEL_INFO(power, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | 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_LABEL), + NULL +}; + +static const struct hwmon_ops smpro_hwmon_ops = { + .is_visible = smpro_is_visible, + .read = smpro_read, + .read_string = smpro_read_string, +}; + +static const struct hwmon_chip_info smpro_chip_info = { + .ops = &smpro_hwmon_ops, + .info = smpro_info, +}; + +static int smpro_hwmon_probe(struct platform_device *pdev) +{ + struct smpro_hwmon *hwmon; + struct device *hwmon_dev; + + hwmon = devm_kzalloc(&pdev->dev, sizeof(struct smpro_hwmon), GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!hwmon->regmap) + return -ENODEV; + + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "smpro_hwmon", + hwmon, &smpro_chip_info, NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static struct platform_driver smpro_hwmon_driver = { + .probe = smpro_hwmon_probe, + .driver = { + .name = "smpro-hwmon", + }, +}; + +module_platform_driver(smpro_hwmon_driver); + +MODULE_AUTHOR("Thu Nguyen "); +MODULE_AUTHOR("Quan Nguyen "); +MODULE_DESCRIPTION("Ampere Altra SMPro hwmon driver"); +MODULE_LICENSE("GPL"); -- cgit 1.2.3-korg From 694144b215fc077087d68dfc3d1ef7dae9fec387 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Thu, 29 Sep 2022 16:43:14 +0700 Subject: docs: hwmon: (smpro-hwmon) Add documentation Add documentation for the Ampere(R)'s Altra(R) SMpro hwmon driver. Signed-off-by: Thu Nguyen Signed-off-by: Quan Nguyen Link: https://lore.kernel.org/r/20220929094321.770125-3-quan@os.amperecomputing.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/smpro-hwmon.rst | 101 ++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 Documentation/hwmon/smpro-hwmon.rst diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index c1d11cf13eef16..ddff3c5713d74e 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -187,6 +187,7 @@ Hardware Monitoring Kernel Drivers sis5595 sl28cpld smm665 + smpro-hwmon smsc47b397 smsc47m192 smsc47m1 diff --git a/Documentation/hwmon/smpro-hwmon.rst b/Documentation/hwmon/smpro-hwmon.rst new file mode 100644 index 00000000000000..3a9b14dacf8975 --- /dev/null +++ b/Documentation/hwmon/smpro-hwmon.rst @@ -0,0 +1,101 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +Kernel driver Ampere(R)'s Altra(R) SMpro hwmon +============================================== + +Supported chips: + + * Ampere(R) Altra(R) + + Prefix: 'smpro' + + Reference: Altra SoC BMC Interface Specification + +Author: Thu Nguyen + +Description +----------- +This driver supports hardware monitoring for Ampere(R) Altra(R) SoC's based on the +SMpro co-processor (SMpro). +The following sensor types are supported by the driver: + + * temperature + * voltage + * current + * power + +The SMpro interface provides the registers to query the various sensors and +their values which are then exported to userspace by this driver. + +Usage Notes +----------- + +SMpro hwmon driver creates at least two sysfs files for each sensor. + +* File ``_label`` reports the sensor label. +* File ``_input`` returns the sensor value. + +The sysfs files are allocated in the SMpro root fs folder. +There is one root folder for each SMpro instance. + +When the SoC is turned off, the driver will fail to read registers +and return -ENXIO. + +Sysfs entries +------------- + +The following sysfs files are supported: + +* Ampere(R) Altra(R): + +============ ============= ====== =============================================== +Name Unit Perm Description +temp1_input milli Celsius RO SoC temperature +temp2_input milli Celsius RO Max temperature reported among SoC VRDs +temp2_crit milli Celsius RO SoC VRD HOT Threshold temperature +temp3_input milli Celsius RO Max temperature reported among DIMM VRDs +temp4_input milli Celsius RO Max temperature reported among Core VRDs +temp5_input milli Celsius RO Temperature of DIMM0 on CH0 +temp5_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp6_input milli Celsius RO Temperature of DIMM0 on CH1 +temp6_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp7_input milli Celsius RO Temperature of DIMM0 on CH2 +temp7_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp8_input milli Celsius RO Temperature of DIMM0 on CH3 +temp8_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp9_input milli Celsius RO Temperature of DIMM0 on CH4 +temp9_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp10_input milli Celsius RO Temperature of DIMM0 on CH5 +temp10_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp11_input milli Celsius RO Temperature of DIMM0 on CH6 +temp11_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp12_input milli Celsius RO Temperature of DIMM0 on CH7 +temp12_crit milli Celsius RO MEM HOT Threshold for all DIMMs +temp13_input milli Celsius RO Max temperature reported among RCA VRDs +in0_input milli Volts RO Core voltage +in1_input milli Volts RO SoC voltage +in2_input milli Volts RO DIMM VRD1 voltage +in3_input milli Volts RO DIMM VRD2 voltage +in4_input milli Volts RO RCA VRD voltage +cur1_input milli Amperes RO Core VRD current +cur2_input milli Amperes RO SoC VRD current +cur3_input milli Amperes RO DIMM VRD1 current +cur4_input milli Amperes RO DIMM VRD2 current +cur5_input milli Amperes RO RCA VRD current +power1_input micro Watts RO Core VRD power +power2_input micro Watts RO SoC VRD power +power3_input micro Watts RO DIMM VRD1 power +power4_input micro Watts RO DIMM VRD2 power +power5_input micro Watts RO RCA VRD power +============ ============= ====== =============================================== + +Example:: + + # cat in0_input + 830 + # cat temp1_input + 37000 + # cat curr1_input + 9000 + # cat power5_input + 19500000 -- cgit 1.2.3-korg From 6d270868cd529c39ac746e9ae3522c43f2764aca Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Mon, 24 Oct 2022 16:15:27 +0800 Subject: hwmon: (occ) OCC sensors aren't arch-specific Commit c112d75840fb ("hwmon: OCC drivers are ARM-only") made the OCC sensor drivers not selectable on powerpc64: These drivers are for a BMC inside PowerPC servers. The BMC runs on ARM hardware, so only propose the drivers on this architecture, unless build-testing. ... but we now have a powerpc64 BMC (still for a powerpc64 host), so drop the `depends on` that excludes building for this platform. Signed-off-by: Jeremy Kerr Acked-by: Joel Stanley Link: https://lore.kernel.org/r/20221024081527.3842565-1-jk@codeconstruct.com.au Signed-off-by: Guenter Roeck --- drivers/hwmon/occ/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/hwmon/occ/Kconfig b/drivers/hwmon/occ/Kconfig index 35a7070db82776..348c21100a3729 100644 --- a/drivers/hwmon/occ/Kconfig +++ b/drivers/hwmon/occ/Kconfig @@ -6,7 +6,6 @@ config SENSORS_OCC_P8_I2C tristate "POWER8 OCC through I2C" depends on I2C - depends on ARM || ARM64 || COMPILE_TEST select SENSORS_OCC help This option enables support for monitoring sensors provided by the @@ -21,7 +20,6 @@ config SENSORS_OCC_P8_I2C config SENSORS_OCC_P9_SBE tristate "POWER9 OCC through SBE" depends on FSI_OCC - depends on ARM || ARM64 || COMPILE_TEST select SENSORS_OCC help This option enables support for monitoring sensors provided by the -- cgit 1.2.3-korg From 662d20b3a5afee888e805c5326ccdb7ebbd23012 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Mon, 24 Oct 2022 17:10:39 +0200 Subject: hwmon: (aquacomputer_d5next) Add support for temperature sensor offsets Add support for reading and writing temperature sensor offsets on the Aquacomputer D5 Next, Farbwerk 360, Octo and Quadro, for which the needed offsets are known. Implemented by Leonard Anderweit [1]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/22 Originally-from: Leonard Anderweit Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20221024151039.7222-1-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 1 + drivers/hwmon/aquacomputer_d5next.c | 88 ++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 14 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index e238533b5fe01e..15226346434dd1 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -62,6 +62,7 @@ Sysfs entries ================ ============================================================== temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius) +temp[1-4]_offset Temperature sensor correction offset (in millidegrees Celsius) fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h) power[1-8]_input Pump/fan power (in micro Watts) in[0-7]_input Pump/fan voltage (in milli Volts) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index c51a2678f0eb55..608f57f59cf94e 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -80,6 +80,7 @@ static u8 secondary_ctrl_report[] = { #define D5NEXT_5V_VOLTAGE 0x39 #define D5NEXT_12V_VOLTAGE 0x37 #define D5NEXT_CTRL_REPORT_SIZE 0x329 +#define D5NEXT_TEMP_CTRL_OFFSET 0x2D static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET }; /* Pump and fan speed registers in D5 Next control report (from 0-100%) */ @@ -94,6 +95,8 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; #define FARBWERK360_SENSOR_START 0x32 #define FARBWERK360_NUM_VIRTUAL_SENSORS 16 #define FARBWERK360_VIRTUAL_SENSORS_START 0x3a +#define FARBWERK360_CTRL_REPORT_SIZE 0x682 +#define FARBWERK360_TEMP_CTRL_OFFSET 0x8 /* Register offsets for the Octo fan controller */ #define OCTO_POWER_CYCLES 0x18 @@ -103,6 +106,7 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; #define OCTO_NUM_VIRTUAL_SENSORS 16 #define OCTO_VIRTUAL_SENSORS_START 0x45 #define OCTO_CTRL_REPORT_SIZE 0x65F +#define OCTO_TEMP_CTRL_OFFSET 0xA static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 }; /* Fan speed registers in Octo control report (from 0-100%) */ @@ -117,6 +121,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0 #define QUADRO_VIRTUAL_SENSORS_START 0x3c #define QUADRO_CTRL_REPORT_SIZE 0x3c1 #define QUADRO_FLOW_SENSOR_OFFSET 0x6e +#define QUADRO_TEMP_CTRL_OFFSET 0xA static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 }; /* Fan speed registers in Quadro control report (from 0-100%) */ @@ -282,6 +287,7 @@ struct aqc_data { int temp_sensor_start_offset; int num_virtual_temp_sensors; int virtual_temp_sensor_start_offset; + u16 temp_ctrl_offset; u16 power_cycle_count_offset; u8 flow_sensor_offset; @@ -365,8 +371,8 @@ static int aqc_send_ctrl_data(struct aqc_data *priv) return ret; } -/* Refreshes the control buffer and returns value at offset */ -static int aqc_get_ctrl_val(struct aqc_data *priv, int offset) +/* Refreshes the control buffer and stores value at offset in val */ +static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val) { int ret; @@ -376,7 +382,7 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset) if (ret < 0) goto unlock_and_return; - ret = get_unaligned_be16(priv->buffer + offset); + *val = (s16)get_unaligned_be16(priv->buffer + offset); unlock_and_return: mutex_unlock(&priv->mutex); @@ -393,7 +399,7 @@ static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val) if (ret < 0) goto unlock_and_return; - put_unaligned_be16((u16)val, priv->buffer + offset); + put_unaligned_be16((s16)val, priv->buffer + offset); ret = aqc_send_ctrl_data(priv); @@ -408,8 +414,28 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 switch (type) { case hwmon_temp: + if (channel < priv->num_temp_sensors) { + switch (attr) { + case hwmon_temp_label: + case hwmon_temp_input: + return 0444; + case hwmon_temp_offset: + if (priv->temp_ctrl_offset != 0) + return 0644; + break; + default: + break; + } + } + if (channel < priv->num_temp_sensors + priv->num_virtual_temp_sensors) - return 0444; + switch (attr) { + case hwmon_temp_label: + case hwmon_temp_input: + return 0444; + default: + break; + } break; case hwmon_pwm: if (priv->fan_ctrl_offsets && channel < priv->num_fans) { @@ -492,10 +518,25 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, switch (type) { case hwmon_temp: - if (priv->temp_input[channel] == -ENODATA) - return -ENODATA; + switch (attr) { + case hwmon_temp_input: + if (priv->temp_input[channel] == -ENODATA) + return -ENODATA; + + *val = priv->temp_input[channel]; + break; + case hwmon_temp_offset: + ret = + aqc_get_ctrl_val(priv, priv->temp_ctrl_offset + + channel * AQC_TEMP_SENSOR_SIZE, val); + if (ret < 0) + return ret; - *val = priv->temp_input[channel]; + *val *= 10; + break; + default: + break; + } break; case hwmon_fan: *val = priv->speed_input[channel]; @@ -505,7 +546,7 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, break; case hwmon_pwm: if (priv->fan_ctrl_offsets) { - ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel]); + ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel], val); if (ret < 0) return ret; @@ -563,6 +604,21 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, struct aqc_data *priv = dev_get_drvdata(dev); switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_offset: + /* Limit temp offset to +/- 15K as in the official software */ + val = clamp_val(val, -15000, 15000) / 10; + ret = + aqc_set_ctrl_val(priv, priv->temp_ctrl_offset + + channel * AQC_TEMP_SENSOR_SIZE, val); + if (ret < 0) + return ret; + break; + default: + return -EOPNOTSUPP; + } + break; case hwmon_pwm: switch (attr) { case hwmon_pwm_input: @@ -597,10 +653,10 @@ static const struct hwmon_ops aqc_hwmon_ops = { static const struct hwmon_channel_info *aqc_info[] = { HWMON_CHANNEL_INFO(temp, - 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_OFFSET, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, @@ -853,6 +909,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->virtual_temp_sensor_start_offset = D5NEXT_VIRTUAL_SENSORS_START; priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES; priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE; + priv->temp_ctrl_offset = D5NEXT_TEMP_CTRL_OFFSET; priv->temp_label = label_d5next_temp; priv->virtual_temp_label = label_virtual_temp_sensors; @@ -877,7 +934,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->temp_sensor_start_offset = FARBWERK360_SENSOR_START; priv->num_virtual_temp_sensors = FARBWERK360_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = FARBWERK360_VIRTUAL_SENSORS_START; - + priv->buffer_size = FARBWERK360_CTRL_REPORT_SIZE; + priv->temp_ctrl_offset = FARBWERK360_TEMP_CTRL_OFFSET; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; break; @@ -893,6 +951,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->virtual_temp_sensor_start_offset = OCTO_VIRTUAL_SENSORS_START; priv->power_cycle_count_offset = OCTO_POWER_CYCLES; priv->buffer_size = OCTO_CTRL_REPORT_SIZE; + priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; @@ -914,6 +973,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; priv->buffer_size = QUADRO_CTRL_REPORT_SIZE; priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET; + priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; -- cgit 1.2.3-korg From 8f2fa4726faf01094d7a5be7bd0c120c565f54d9 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sun, 23 Oct 2022 23:31:56 +0200 Subject: hwmon: (jc42) Convert register access and caching to regmap/regcache Switch the jc42 driver to use an I2C regmap to access the registers. Also move over to regmap's built-in caching instead of adding a custom caching implementation. This works for JC42_REG_TEMP_UPPER, JC42_REG_TEMP_LOWER and JC42_REG_TEMP_CRITICAL as these values never change except when explicitly written. The cache For JC42_REG_TEMP is dropped (regmap can't cache it because it's volatile, meaning it can change at any time) as well for simplicity and consistency with other drivers. Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20221023213157.11078-2-martin.blumenstingl@googlemail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/jc42.c | 233 ++++++++++++++++++++++++++++---------------------- 2 files changed, 132 insertions(+), 102 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e7ec6af309c79d..a5253abb7ea722 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -807,6 +807,7 @@ config SENSORS_IT87 config SENSORS_JC42 tristate "JEDEC JC42.4 compliant memory module temperature sensors" depends on I2C + select REGMAP_I2C help If you say yes here, you get support for JEDEC JC42.4 compliant temperature sensors, which are used on many DDR3 memory modules for diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 30888feaf589bf..355639d208d049 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -19,6 +19,7 @@ #include #include #include +#include /* Addresses to scan */ static const unsigned short normal_i2c[] = { @@ -199,31 +200,14 @@ static struct jc42_chips jc42_chips[] = { { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK }, }; -enum temp_index { - t_input = 0, - t_crit, - t_min, - t_max, - t_num_temp -}; - -static const u8 temp_regs[t_num_temp] = { - [t_input] = JC42_REG_TEMP, - [t_crit] = JC42_REG_TEMP_CRITICAL, - [t_min] = JC42_REG_TEMP_LOWER, - [t_max] = JC42_REG_TEMP_UPPER, -}; - /* Each client has this additional data */ struct jc42_data { - struct i2c_client *client; struct mutex update_lock; /* protect register access */ + struct regmap *regmap; bool extended; /* true if extended range supported */ bool valid; - unsigned long last_updated; /* In jiffies */ u16 orig_config; /* original configuration */ u16 config; /* current configuration */ - u16 temp[t_num_temp];/* Temperatures */ }; #define JC42_TEMP_MIN_EXTENDED (-40000) @@ -248,85 +232,102 @@ static int jc42_temp_from_reg(s16 reg) return reg * 125 / 2; } -static struct jc42_data *jc42_update_device(struct device *dev) -{ - struct jc42_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - struct jc42_data *ret = data; - int i, val; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - for (i = 0; i < t_num_temp; i++) { - val = i2c_smbus_read_word_swapped(client, temp_regs[i]); - if (val < 0) { - ret = ERR_PTR(val); - goto abort; - } - data->temp[i] = val; - } - data->last_updated = jiffies; - data->valid = true; - } -abort: - mutex_unlock(&data->update_lock); - return ret; -} - static int jc42_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { - struct jc42_data *data = jc42_update_device(dev); - int temp, hyst; + struct jc42_data *data = dev_get_drvdata(dev); + unsigned int regval; + int ret, temp, hyst; - if (IS_ERR(data)) - return PTR_ERR(data); + mutex_lock(&data->update_lock); switch (attr) { case hwmon_temp_input: - *val = jc42_temp_from_reg(data->temp[t_input]); - return 0; + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); + if (ret) + break; + + *val = jc42_temp_from_reg(regval); + break; case hwmon_temp_min: - *val = jc42_temp_from_reg(data->temp[t_min]); - return 0; + ret = regmap_read(data->regmap, JC42_REG_TEMP_LOWER, ®val); + if (ret) + break; + + *val = jc42_temp_from_reg(regval); + break; case hwmon_temp_max: - *val = jc42_temp_from_reg(data->temp[t_max]); - return 0; + ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, ®val); + if (ret) + break; + + *val = jc42_temp_from_reg(regval); + break; case hwmon_temp_crit: - *val = jc42_temp_from_reg(data->temp[t_crit]); - return 0; + ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL, + ®val); + if (ret) + break; + + *val = jc42_temp_from_reg(regval); + break; case hwmon_temp_max_hyst: - temp = jc42_temp_from_reg(data->temp[t_max]); + ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, ®val); + if (ret) + break; + + temp = jc42_temp_from_reg(regval); hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) >> JC42_CFG_HYST_SHIFT]; *val = temp - hyst; - return 0; + break; case hwmon_temp_crit_hyst: - temp = jc42_temp_from_reg(data->temp[t_crit]); + ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL, + ®val); + if (ret) + break; + + temp = jc42_temp_from_reg(regval); hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) >> JC42_CFG_HYST_SHIFT]; *val = temp - hyst; - return 0; + break; case hwmon_temp_min_alarm: - *val = (data->temp[t_input] >> JC42_ALARM_MIN_BIT) & 1; - return 0; + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); + if (ret) + break; + + *val = (regval >> JC42_ALARM_MIN_BIT) & 1; + break; case hwmon_temp_max_alarm: - *val = (data->temp[t_input] >> JC42_ALARM_MAX_BIT) & 1; - return 0; + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); + if (ret) + break; + + *val = (regval >> JC42_ALARM_MAX_BIT) & 1; + break; case hwmon_temp_crit_alarm: - *val = (data->temp[t_input] >> JC42_ALARM_CRIT_BIT) & 1; - return 0; + ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); + if (ret) + break; + + *val = (regval >> JC42_ALARM_CRIT_BIT) & 1; + break; default: - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + break; } + + mutex_unlock(&data->update_lock); + + return ret; } static int jc42_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { struct jc42_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + unsigned int regval; int diff, hyst; int ret; @@ -334,21 +335,23 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type, switch (attr) { case hwmon_temp_min: - data->temp[t_min] = jc42_temp_to_reg(val, data->extended); - ret = i2c_smbus_write_word_swapped(client, temp_regs[t_min], - data->temp[t_min]); + ret = regmap_write(data->regmap, JC42_REG_TEMP_LOWER, + jc42_temp_to_reg(val, data->extended)); break; case hwmon_temp_max: - data->temp[t_max] = jc42_temp_to_reg(val, data->extended); - ret = i2c_smbus_write_word_swapped(client, temp_regs[t_max], - data->temp[t_max]); + ret = regmap_write(data->regmap, JC42_REG_TEMP_UPPER, + jc42_temp_to_reg(val, data->extended)); break; case hwmon_temp_crit: - data->temp[t_crit] = jc42_temp_to_reg(val, data->extended); - ret = i2c_smbus_write_word_swapped(client, temp_regs[t_crit], - data->temp[t_crit]); + ret = regmap_write(data->regmap, JC42_REG_TEMP_CRITICAL, + jc42_temp_to_reg(val, data->extended)); break; case hwmon_temp_crit_hyst: + ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL, + ®val); + if (ret) + return ret; + /* * JC42.4 compliant chips only support four hysteresis values. * Pick best choice and go from there. @@ -356,7 +359,7 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type, val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED : JC42_TEMP_MIN) - 6000, JC42_TEMP_MAX); - diff = jc42_temp_from_reg(data->temp[t_crit]) - val; + diff = jc42_temp_from_reg(regval) - val; hyst = 0; if (diff > 0) { if (diff < 2250) @@ -368,9 +371,8 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type, } data->config = (data->config & ~JC42_CFG_HYST_MASK) | (hyst << JC42_CFG_HYST_SHIFT); - ret = i2c_smbus_write_word_swapped(data->client, - JC42_REG_CONFIG, - data->config); + ret = regmap_write(data->regmap, JC42_REG_CONFIG, + data->config); break; default: ret = -EOPNOTSUPP; @@ -470,51 +472,80 @@ static const struct hwmon_chip_info jc42_chip_info = { .info = jc42_info, }; +static bool jc42_readable_reg(struct device *dev, unsigned int reg) +{ + return (reg >= JC42_REG_CAP && reg <= JC42_REG_DEVICEID) || + reg == JC42_REG_SMBUS; +} + +static bool jc42_writable_reg(struct device *dev, unsigned int reg) +{ + return (reg >= JC42_REG_CONFIG && reg <= JC42_REG_TEMP_CRITICAL) || + reg == JC42_REG_SMBUS; +} + +static bool jc42_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg == JC42_REG_CONFIG || reg == JC42_REG_TEMP; +} + +static const struct regmap_config jc42_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = JC42_REG_SMBUS, + .writeable_reg = jc42_writable_reg, + .readable_reg = jc42_readable_reg, + .volatile_reg = jc42_volatile_reg, + .cache_type = REGCACHE_RBTREE, +}; + static int jc42_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; + unsigned int config, cap; struct jc42_data *data; - int config, cap; + int ret; data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL); if (!data) return -ENOMEM; - data->client = client; + data->regmap = devm_regmap_init_i2c(client, &jc42_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP); - if (cap < 0) - return cap; + ret = regmap_read(data->regmap, JC42_REG_CAP, &cap); + if (ret) + return ret; data->extended = !!(cap & JC42_CAP_RANGE); if (device_property_read_bool(dev, "smbus-timeout-disable")) { - int smbus; - /* * Not all chips support this register, but from a * quick read of various datasheets no chip appears * incompatible with the below attempt to disable * the timeout. And the whole thing is opt-in... */ - smbus = i2c_smbus_read_word_swapped(client, JC42_REG_SMBUS); - if (smbus < 0) - return smbus; - i2c_smbus_write_word_swapped(client, JC42_REG_SMBUS, - smbus | SMBUS_STMOUT); + ret = regmap_set_bits(data->regmap, JC42_REG_SMBUS, + SMBUS_STMOUT); + if (ret) + return ret; } - config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG); - if (config < 0) - return config; + ret = regmap_read(data->regmap, JC42_REG_CONFIG, &config); + if (ret) + return ret; data->orig_config = config; if (config & JC42_CFG_SHUTDOWN) { config &= ~JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config); + regmap_write(data->regmap, JC42_REG_CONFIG, config); } data->config = config; @@ -535,7 +566,7 @@ static void jc42_remove(struct i2c_client *client) config = (data->orig_config & ~JC42_CFG_HYST_MASK) | (data->config & JC42_CFG_HYST_MASK); - i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config); + regmap_write(data->regmap, JC42_REG_CONFIG, config); } } @@ -546,8 +577,7 @@ static int jc42_suspend(struct device *dev) struct jc42_data *data = dev_get_drvdata(dev); data->config |= JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, - data->config); + regmap_write(data->regmap, JC42_REG_CONFIG, data->config); return 0; } @@ -556,8 +586,7 @@ static int jc42_resume(struct device *dev) struct jc42_data *data = dev_get_drvdata(dev); data->config &= ~JC42_CFG_SHUTDOWN; - i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG, - data->config); + regmap_write(data->regmap, JC42_REG_CONFIG, data->config); return 0; } -- cgit 1.2.3-korg From 084ed144c448fd5bc8ed5a58247153fbbfd115c3 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sun, 23 Oct 2022 23:31:57 +0200 Subject: hwmon: (jc42) Restore the min/max/critical temperatures on resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JC42 compatible thermal sensor on Kingston KSM32ES8/16ME DIMMs (using Micron E-Die) is an ST Microelectronics STTS2004 (manufacturer 0x104a, device 0x2201). It does not keep the previously programmed minimum, maximum and critical temperatures after system suspend and resume (which is a shutdown / startup cycle for the JC42 temperature sensor). This results in an alarm on system resume because the hardware default for these values is 0°C (so any environment temperature greater than 0°C will trigger the alarm). Example before system suspend: jc42-i2c-0-1a Adapter: SMBus PIIX4 adapter port 0 at 0b00 temp1: +34.8°C (low = +0.0°C) (high = +85.0°C, hyst = +85.0°C) (crit = +95.0°C, hyst = +95.0°C) Example after system resume (without this change): jc42-i2c-0-1a Adapter: SMBus PIIX4 adapter port 0 at 0b00 temp1: +34.8°C (low = +0.0°C) ALARM (HIGH, CRIT) (high = +0.0°C, hyst = +0.0°C) (crit = +0.0°C, hyst = +0.0°C) Apply the cached values from the JC42_REG_TEMP_UPPER, JC42_REG_TEMP_LOWER, JC42_REG_TEMP_CRITICAL and JC42_REG_SMBUS (where the SMBUS register is not related to this issue but a side-effect of using regcache_sync() during system resume with the previously cached/programmed values. This fixes the alarm due to the hardware defaults of 0°C because the previously applied limits (set by userspace) are re-applied on system resume. Fixes: 175c490c9e7f ("hwmon: (jc42) Add support for STTS2004 and AT30TSE004") Reviewed-by: Guenter Roeck Signed-off-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20221023213157.11078-3-martin.blumenstingl@googlemail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/jc42.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 355639d208d049..0554b41c32bc7f 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -578,6 +578,10 @@ static int jc42_suspend(struct device *dev) data->config |= JC42_CFG_SHUTDOWN; regmap_write(data->regmap, JC42_REG_CONFIG, data->config); + + regcache_cache_only(data->regmap, true); + regcache_mark_dirty(data->regmap); + return 0; } @@ -585,9 +589,13 @@ static int jc42_resume(struct device *dev) { struct jc42_data *data = dev_get_drvdata(dev); + regcache_cache_only(data->regmap, false); + data->config &= ~JC42_CFG_SHUTDOWN; regmap_write(data->regmap, JC42_REG_CONFIG, data->config); - return 0; + + /* Restore cached register values to hardware */ + return regcache_sync(data->regmap); } static const struct dev_pm_ops jc42_dev_pm_ops = { -- cgit 1.2.3-korg From b744db17abf6a2efc2bfa80870cc88e9799a8ccc Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 27 Oct 2022 14:29:31 +0800 Subject: hwmon: (jc42) Fix missing unlock on error in jc42_write() Add the missing unlock before return from function jc42_write() in the error handling case. Fixes: 37dedaee8bc6 ("hwmon: (jc42) Convert register access and caching to regmap/regcache") Signed-off-by: Yang Yingliang Reviewed-by: Martin Blumenstingl Link: https://lore.kernel.org/r/20221027062931.598247-1-yangyingliang@huawei.com Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Guenter Roeck --- drivers/hwmon/jc42.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 0554b41c32bc7f..6593d81cb901be 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -350,7 +350,7 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type, ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL, ®val); if (ret) - return ret; + break; /* * JC42.4 compliant chips only support four hysteresis values. -- cgit 1.2.3-korg From 9e913888647be447c3d114042428f02d24676390 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 27 Oct 2022 16:16:12 -0700 Subject: hwmon: (smpro-hwmon) Improve switch statments in smpro_is_visible() Clang warns: drivers/hwmon/smpro-hwmon.c:378:2: error: unannotated fall-through between switch labels [-Werror,-Wimplicit-fallthrough] default: ^ drivers/hwmon/smpro-hwmon.c:378:2: note: insert 'break;' to avoid fall-through default: ^ break; 1 error generated. Clang is a little more pedantic than GCC, which does not warn when falling through to a case that is just break or return. Clang's version is more in line with the kernel's own stance in deprecated.rst, which states that all switch/case blocks must end in either break, fallthrough, continue, goto, or return. Add the missing break to silence the warning. Additionally, adjust the indentation of a break and add a default case to the inner switch statement. Fixes: a87456864cbb ("hwmon: Add Ampere's Altra smpro-hwmon driver") Link: https://github.com/ClangBuiltLinux/linux/issues/1751 Signed-off-by: Nathan Chancellor Link: https://lore.kernel.org/r/20221027231611.3824800-1-nathan@kernel.org Signed-off-by: Guenter Roeck --- drivers/hwmon/smpro-hwmon.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/smpro-hwmon.c b/drivers/hwmon/smpro-hwmon.c index ee54e21c2c123f..a76c49dd8438dc 100644 --- a/drivers/hwmon/smpro-hwmon.c +++ b/drivers/hwmon/smpro-hwmon.c @@ -373,8 +373,11 @@ static umode_t smpro_is_visible(const void *data, enum hwmon_sensor_types type, ret = regmap_read(hwmon->regmap, temperature[channel].reg, &value); if (ret || value == 0xFFFF) return 0; - break; + break; + default: + break; } + break; default: break; } -- cgit 1.2.3-korg From daec55ce62ad0bb6948c8edf84e7ec3b95720177 Mon Sep 17 00:00:00 2001 From: Felix Nieuwenhuizen Date: Thu, 27 Oct 2022 16:51:35 +0200 Subject: hwmon: (pmbus/ltc2978) add support for LTC7132 Add support for LTC7132. The relevant registers in the LTC7132 are identical to the LTC7880. So it's just a matter of adding the chip id. Signed-off-by: Felix Nieuwenhuizen Link: https://lore.kernel.org/r/20221027145135.31802-1-Felix.Nieuwenhuizen@etas.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/ltc2978.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 6d2592731ba3dc..79f480b4425d25 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -23,7 +23,7 @@ enum chips { /* Managers */ ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980, /* Controllers */ - ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7880, + ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, ltc7880, /* Modules */ ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686, ltm4700, @@ -45,15 +45,14 @@ enum chips { #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, LTM4676, LTC7132 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883, LTC3884, LTC3886, LTC3889 and LTC7880 only */ +/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7880 */ #define LTC3883_MFR_IIN_PEAK 0xe1 - /* LTC2975 only */ #define LTC2975_MFR_IIN_PEAK 0xc4 #define LTC2975_MFR_IIN_MIN 0xc5 @@ -79,10 +78,11 @@ enum chips { #define LTC3884_ID 0x4C00 #define LTC3886_ID 0x4600 #define LTC3887_ID 0x4700 -#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ -#define LTM2987_ID_B 0x8020 #define LTC3889_ID 0x4900 +#define LTC7132_ID 0x4CE0 #define LTC7880_ID 0x49E0 +#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ +#define LTM2987_ID_B 0x8020 #define LTM4664_ID 0x4120 #define LTM4675_ID 0x47a0 #define LTM4676_ID_REV1 0x4400 @@ -547,6 +547,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3886", ltc3886}, {"ltc3887", ltc3887}, {"ltc3889", ltc3889}, + {"ltc7132", ltc7132}, {"ltc7880", ltc7880}, {"ltm2987", ltm2987}, {"ltm4664", ltm4664}, @@ -651,6 +652,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3887; else if (chip_id == LTC3889_ID) return ltc3889; + else if (chip_id == LTC7132_ID) + return ltc7132; else if (chip_id == LTC7880_ID) return ltc7880; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) @@ -831,6 +834,7 @@ static int ltc2978_probe(struct i2c_client *client) case ltc3884: case ltc3886: case ltc3889: + case ltc7132: case ltc7880: case ltm4664: case ltm4678: @@ -902,6 +906,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3886" }, { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltc3889" }, + { .compatible = "lltc,ltc7132" }, { .compatible = "lltc,ltc7880" }, { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4664" }, -- cgit 1.2.3-korg From 78d448a3725584b7c46d3d881035943f759135fd Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 31 Oct 2022 22:51:40 +0100 Subject: hwmon: (jc42) Consistently use bit and bitfield macros in the driver Use BIT() and GENMASK() macros for defining the bitfields inside the registers. Also use FIELD_GET() and FIELD_PREP() where appropriate. This makes the coding style within the driver consistent. No functional changes intended. Signed-off-by: Martin Blumenstingl Signed-off-by: Guenter Roeck --- drivers/hwmon/jc42.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 6593d81cb901be..8523bf974310bf 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -37,20 +38,19 @@ static const unsigned short normal_i2c[] = { #define JC42_REG_SMBUS 0x22 /* NXP and Atmel, possibly others? */ /* Status bits in temperature register */ -#define JC42_ALARM_CRIT_BIT 15 -#define JC42_ALARM_MAX_BIT 14 -#define JC42_ALARM_MIN_BIT 13 +#define JC42_ALARM_CRIT BIT(15) +#define JC42_ALARM_MAX BIT(14) +#define JC42_ALARM_MIN BIT(13) /* Configuration register defines */ -#define JC42_CFG_CRIT_ONLY (1 << 2) -#define JC42_CFG_TCRIT_LOCK (1 << 6) -#define JC42_CFG_EVENT_LOCK (1 << 7) -#define JC42_CFG_SHUTDOWN (1 << 8) -#define JC42_CFG_HYST_SHIFT 9 -#define JC42_CFG_HYST_MASK (0x03 << 9) +#define JC42_CFG_CRIT_ONLY BIT(2) +#define JC42_CFG_TCRIT_LOCK BIT(6) +#define JC42_CFG_EVENT_LOCK BIT(7) +#define JC42_CFG_SHUTDOWN BIT(8) +#define JC42_CFG_HYST_MASK GENMASK(10, 9) /* Capabilities */ -#define JC42_CAP_RANGE (1 << 2) +#define JC42_CAP_RANGE BIT(2) /* Manufacturer IDs */ #define ADT_MANID 0x11d4 /* Analog Devices */ @@ -277,8 +277,8 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type, break; temp = jc42_temp_from_reg(regval); - hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) - >> JC42_CFG_HYST_SHIFT]; + hyst = jc42_hysteresis[FIELD_GET(JC42_CFG_HYST_MASK, + data->config)]; *val = temp - hyst; break; case hwmon_temp_crit_hyst: @@ -288,8 +288,8 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type, break; temp = jc42_temp_from_reg(regval); - hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) - >> JC42_CFG_HYST_SHIFT]; + hyst = jc42_hysteresis[FIELD_GET(JC42_CFG_HYST_MASK, + data->config)]; *val = temp - hyst; break; case hwmon_temp_min_alarm: @@ -297,21 +297,21 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type, if (ret) break; - *val = (regval >> JC42_ALARM_MIN_BIT) & 1; + *val = FIELD_GET(JC42_ALARM_MIN, regval); break; case hwmon_temp_max_alarm: ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); if (ret) break; - *val = (regval >> JC42_ALARM_MAX_BIT) & 1; + *val = FIELD_GET(JC42_ALARM_MAX, regval); break; case hwmon_temp_crit_alarm: ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); if (ret) break; - *val = (regval >> JC42_ALARM_CRIT_BIT) & 1; + *val = FIELD_GET(JC42_ALARM_CRIT, regval); break; default: ret = -EOPNOTSUPP; @@ -370,7 +370,7 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type, hyst = 3; /* 6.0 degrees C */ } data->config = (data->config & ~JC42_CFG_HYST_MASK) | - (hyst << JC42_CFG_HYST_SHIFT); + FIELD_PREP(JC42_CFG_HYST_MASK, hyst); ret = regmap_write(data->regmap, JC42_REG_CONFIG, data->config); break; -- cgit 1.2.3-korg From c1cb98c55f470447479298aaec7f92219562613e Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 2 Nov 2022 13:21:03 +0700 Subject: docs: hwmon: (smpro-hwmon) Improve grammar and formatting Improve documentation grammar and formatting for the Ampere(R)'s Altra(R) SMpro hwmon driver. Thanks Bagas for the changes in the link below. Link: https://lore.kernel.org/lkml/Y1aHiaZ1OpHZIzS9@google.com/T/#mfea2167b99384486a1b75d9304536015116c1821 Signed-off-by: Quan Nguyen Reviewed-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20221102062103.3135417-1-quan@os.amperecomputing.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/smpro-hwmon.rst | 111 ++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/Documentation/hwmon/smpro-hwmon.rst b/Documentation/hwmon/smpro-hwmon.rst index 3a9b14dacf8975..fb7b3665735bba 100644 --- a/Documentation/hwmon/smpro-hwmon.rst +++ b/Documentation/hwmon/smpro-hwmon.rst @@ -7,39 +7,39 @@ Supported chips: * Ampere(R) Altra(R) - Prefix: 'smpro' + Prefix: ``smpro`` - Reference: Altra SoC BMC Interface Specification + Reference: `Altra SoC BMC Interface Specification` Author: Thu Nguyen Description ----------- -This driver supports hardware monitoring for Ampere(R) Altra(R) SoC's based on the -SMpro co-processor (SMpro). -The following sensor types are supported by the driver: +The smpro-hwmon driver supports hardware monitoring for Ampere(R) Altra(R) +SoCs based on the SMpro co-processor (SMpro). The following sensor metrics +are supported by the driver: * temperature * voltage * current * power -The SMpro interface provides the registers to query the various sensors and +The interface provides the registers to query the various sensors and their values which are then exported to userspace by this driver. Usage Notes ----------- -SMpro hwmon driver creates at least two sysfs files for each sensor. +The driver creates at least two sysfs files for each sensor. -* File ``_label`` reports the sensor label. -* File ``_input`` returns the sensor value. +* ``_label`` reports the sensor label. +* ``_input`` returns the sensor value. -The sysfs files are allocated in the SMpro root fs folder. -There is one root folder for each SMpro instance. +The sysfs files are allocated in the SMpro rootfs folder, with one root +directory for each instance. -When the SoC is turned off, the driver will fail to read registers -and return -ENXIO. +When the SoC is turned off, the driver will fail to read registers and +return ``-ENXIO``. Sysfs entries ------------- @@ -48,48 +48,49 @@ The following sysfs files are supported: * Ampere(R) Altra(R): -============ ============= ====== =============================================== -Name Unit Perm Description -temp1_input milli Celsius RO SoC temperature -temp2_input milli Celsius RO Max temperature reported among SoC VRDs -temp2_crit milli Celsius RO SoC VRD HOT Threshold temperature -temp3_input milli Celsius RO Max temperature reported among DIMM VRDs -temp4_input milli Celsius RO Max temperature reported among Core VRDs -temp5_input milli Celsius RO Temperature of DIMM0 on CH0 -temp5_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp6_input milli Celsius RO Temperature of DIMM0 on CH1 -temp6_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp7_input milli Celsius RO Temperature of DIMM0 on CH2 -temp7_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp8_input milli Celsius RO Temperature of DIMM0 on CH3 -temp8_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp9_input milli Celsius RO Temperature of DIMM0 on CH4 -temp9_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp10_input milli Celsius RO Temperature of DIMM0 on CH5 -temp10_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp11_input milli Celsius RO Temperature of DIMM0 on CH6 -temp11_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp12_input milli Celsius RO Temperature of DIMM0 on CH7 -temp12_crit milli Celsius RO MEM HOT Threshold for all DIMMs -temp13_input milli Celsius RO Max temperature reported among RCA VRDs -in0_input milli Volts RO Core voltage -in1_input milli Volts RO SoC voltage -in2_input milli Volts RO DIMM VRD1 voltage -in3_input milli Volts RO DIMM VRD2 voltage -in4_input milli Volts RO RCA VRD voltage -cur1_input milli Amperes RO Core VRD current -cur2_input milli Amperes RO SoC VRD current -cur3_input milli Amperes RO DIMM VRD1 current -cur4_input milli Amperes RO DIMM VRD2 current -cur5_input milli Amperes RO RCA VRD current -power1_input micro Watts RO Core VRD power -power2_input micro Watts RO SoC VRD power -power3_input micro Watts RO DIMM VRD1 power -power4_input micro Watts RO DIMM VRD2 power -power5_input micro Watts RO RCA VRD power -============ ============= ====== =============================================== - -Example:: + ============ ============= ====== =============================================== + Name Unit Perm Description + ============ ============= ====== =============================================== + temp1_input millicelsius RO SoC temperature + temp2_input millicelsius RO Max temperature reported among SoC VRDs + temp2_crit millicelsius RO SoC VRD HOT Threshold temperature + temp3_input millicelsius RO Max temperature reported among DIMM VRDs + temp4_input millicelsius RO Max temperature reported among Core VRDs + temp5_input millicelsius RO Temperature of DIMM0 on CH0 + temp5_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp6_input millicelsius RO Temperature of DIMM0 on CH1 + temp6_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp7_input millicelsius RO Temperature of DIMM0 on CH2 + temp7_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp8_input millicelsius RO Temperature of DIMM0 on CH3 + temp8_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp9_input millicelsius RO Temperature of DIMM0 on CH4 + temp9_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp10_input millicelsius RO Temperature of DIMM0 on CH5 + temp10_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp11_input millicelsius RO Temperature of DIMM0 on CH6 + temp11_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp12_input millicelsius RO Temperature of DIMM0 on CH7 + temp12_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp13_input millicelsius RO Max temperature reported among RCA VRDs + in0_input millivolts RO Core voltage + in1_input millivolts RO SoC voltage + in2_input millivolts RO DIMM VRD1 voltage + in3_input millivolts RO DIMM VRD2 voltage + in4_input millivolts RO RCA VRD voltage + cur1_input milliamperes RO Core VRD current + cur2_input milliamperes RO SoC VRD current + cur3_input milliamperes RO DIMM VRD1 current + cur4_input milliamperes RO DIMM VRD2 current + cur5_input milliamperes RO RCA VRD current + power1_input microwatts RO Core VRD power + power2_input microwatts RO SoC VRD power + power3_input microwatts RO DIMM VRD1 power + power4_input microwatts RO DIMM VRD2 power + power5_input microwatts RO RCA VRD power + ============ ============= ====== =============================================== + + Example:: # cat in0_input 830 -- cgit 1.2.3-korg From 25f986887dd54a93edcc5cb499b2e42f4d9c359c Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 6 Nov 2022 20:34:16 +0100 Subject: hwmon: Include when appropriate The kstrto() functions have been moved from kernel.h to kstrtox.h. So, include the latter directly in the appropriate files. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/51688cf50bda44e2731381a31287c62319388783.1667763218.git.christophe.jaillet@wanadoo.fr Signed-off-by: Guenter Roeck --- drivers/hwmon/atxp1.c | 1 + drivers/hwmon/gpio-fan.c | 1 + drivers/hwmon/hwmon.c | 1 + drivers/hwmon/lm90.c | 1 + drivers/hwmon/mr75203.c | 1 + drivers/hwmon/pcf8591.c | 1 + drivers/hwmon/pmbus/q54sj108a2.c | 1 + include/linux/hwmon-sysfs.h | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 4fd8de8022bc72..118297ea1dcfa6 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index ba408942dbe73b..e75db6f64e8cee 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 4218750d5a66ba..33edb5c02f7d79 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index a3f95ba00dbffe..6498d5acf70555 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -103,6 +103,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 394a4c7e46abcc..50a8b9c3f94d6e 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index af9614e918a452..1dbe209ae13f5f 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -14,6 +14,7 @@ #include #include #include +#include /* Insmod parameters */ diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c index fa298b4265a1c6..d3ba129513240a 100644 --- a/drivers/hwmon/pmbus/q54sj108a2.c +++ b/drivers/hwmon/pmbus/q54sj108a2.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include "pmbus.h" diff --git a/include/linux/hwmon-sysfs.h b/include/linux/hwmon-sysfs.h index cb26d02f52f378..d896713359cdc7 100644 --- a/include/linux/hwmon-sysfs.h +++ b/include/linux/hwmon-sysfs.h @@ -8,6 +8,7 @@ #define _LINUX_HWMON_SYSFS_H #include +#include struct sensor_device_attribute{ struct device_attribute dev_attr; -- cgit 1.2.3-korg From a1bedbcc1cf7c3d2b6b75156a6f90cadcb5e4809 Mon Sep 17 00:00:00 2001 From: Frank Crawford Date: Sun, 6 Nov 2022 10:25:32 +1100 Subject: hwmon: (it87) Add DMI table for future extensions Add in DMI matching table to match various board quirks and settings. This will be useful for future extentions, but will start with the existing definition of the Shuttle SN68PT. Signed-off-by: Frank Crawford Link: https://lore.kernel.org/r/20221105232531.1619387-1-frank@crawford.emu.id.au Signed-off-by: Guenter Roeck --- drivers/hwmon/it87.c | 72 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 73ed21ab325ba6..9997f76b1f4aa3 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -567,6 +567,14 @@ struct it87_data { s8 auto_temp[NUM_AUTO_PWM][5]; /* [nr][0] is point1_temp_hyst */ }; +/* Board specific settings from DMI matching */ +struct it87_dmi_data { + u8 skip_pwm; /* pwm channels to skip for this board */ +}; + +/* Global for results from DMI matching, if needed */ +static struct it87_dmi_data *dmi_data; + static int adc_lsb(const struct it87_data *data, int nr) { int lsb; @@ -2393,7 +2401,6 @@ static int __init it87_find(int sioaddr, unsigned short *address, { int err; u16 chip_type; - const char *board_vendor, *board_name; const struct it87_devices *config; err = superio_enter(sioaddr); @@ -2812,24 +2819,9 @@ static int __init it87_find(int sioaddr, unsigned short *address, if (sio_data->beep_pin) pr_info("Beeping is supported\n"); - /* Disable specific features based on DMI strings */ - board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); - board_name = dmi_get_system_info(DMI_BOARD_NAME); - if (board_vendor && board_name) { - if (strcmp(board_vendor, "nVIDIA") == 0 && - strcmp(board_name, "FN68PT") == 0) { - /* - * On the Shuttle SN68PT, FAN_CTL2 is apparently not - * connected to a fan, but to something else. One user - * has reported instant system power-off when changing - * the PWM2 duty cycle, so we disable it. - * I use the board name string as the trigger in case - * the same board is ever used in other systems. - */ - pr_info("Disabling pwm2 due to hardware constraints\n"); - sio_data->skip_pwm = BIT(1); - } - } + /* Set values based on DMI matches */ + if (dmi_data) + sio_data->skip_pwm |= dmi_data->skip_pwm; exit: superio_exit(sioaddr); @@ -3307,6 +3299,46 @@ exit_device_put: return err; } +/* callback function for DMI */ +static int it87_dmi_cb(const struct dmi_system_id *dmi_entry) +{ + dmi_data = dmi_entry->driver_data; + + if (dmi_data && dmi_data->skip_pwm) + pr_info("Disabling pwm2 due to hardware constraints\n"); + + return 1; +} + +/* + * On the Shuttle SN68PT, FAN_CTL2 is apparently not + * connected to a fan, but to something else. One user + * has reported instant system power-off when changing + * the PWM2 duty cycle, so we disable it. + * I use the board name string as the trigger in case + * the same board is ever used in other systems. + */ +static struct it87_dmi_data nvidia_fn68pt = { + .skip_pwm = BIT(1), +}; + +#define IT87_DMI_MATCH_VND(vendor, name, cb, data) \ + { \ + .callback = cb, \ + .matches = { \ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, vendor), \ + DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \ + }, \ + .driver_data = data, \ + } + +static const struct dmi_system_id it87_dmi_table[] __initconst = { + IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt), + { } + +}; +MODULE_DEVICE_TABLE(dmi, it87_dmi_table); + static int __init sm_it87_init(void) { int sioaddr[2] = { REG_2E, REG_4E }; @@ -3319,6 +3351,8 @@ static int __init sm_it87_init(void) if (err) return err; + dmi_check_system(it87_dmi_table); + for (i = 0; i < ARRAY_SIZE(sioaddr); i++) { memset(&sio_data, 0, sizeof(struct it87_sio_data)); isa_address[i] = 0; -- cgit 1.2.3-korg From d5d896b838222fcd037c91c9e0e8f6ab719db05f Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Mon, 7 Nov 2022 15:24:55 +0100 Subject: hwmon: (aquacomputer_d5next) Clear up macros and comments Reorganize macro definitions into sections for each supported device, with additional comments on their purpose. This should make it easier to follow what report each offset is coming from. Also, reformat per-device initializations in aqc_probe() to organize them into sections (fan info, temp sensors, other parameters and lastly labels). No functional changes. Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20221107142455.655998-1-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/aquacomputer_d5next.c | 97 ++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 34 deletions(-) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 608f57f59cf94e..49d3f9876fe80b 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -59,7 +59,7 @@ static u8 secondary_ctrl_report[] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6 }; -/* Register offsets for all Aquacomputer devices */ +/* Sensor sizes and offsets for all Aquacomputer devices */ #define AQC_TEMP_SENSOR_SIZE 0x02 #define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF #define AQC_FAN_PERCENT_OFFSET 0x00 @@ -68,67 +68,80 @@ static u8 secondary_ctrl_report[] = { #define AQC_FAN_POWER_OFFSET 0x06 #define AQC_FAN_SPEED_OFFSET 0x08 -/* Register offsets for the D5 Next pump */ -#define D5NEXT_POWER_CYCLES 0x18 -#define D5NEXT_COOLANT_TEMP 0x57 +/* Specs of the D5 Next pump */ #define D5NEXT_NUM_FANS 2 #define D5NEXT_NUM_SENSORS 1 #define D5NEXT_NUM_VIRTUAL_SENSORS 8 -#define D5NEXT_VIRTUAL_SENSORS_START 0x3f +#define D5NEXT_CTRL_REPORT_SIZE 0x329 + +/* Sensor report offsets for the D5 Next pump */ +#define D5NEXT_POWER_CYCLES 0x18 +#define D5NEXT_COOLANT_TEMP 0x57 #define D5NEXT_PUMP_OFFSET 0x6c #define D5NEXT_FAN_OFFSET 0x5f #define D5NEXT_5V_VOLTAGE 0x39 #define D5NEXT_12V_VOLTAGE 0x37 -#define D5NEXT_CTRL_REPORT_SIZE 0x329 -#define D5NEXT_TEMP_CTRL_OFFSET 0x2D +#define D5NEXT_VIRTUAL_SENSORS_START 0x3f static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET }; -/* Pump and fan speed registers in D5 Next control report (from 0-100%) */ -static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; +/* Control report offsets for the D5 Next pump */ +#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%) */ -/* Register offsets for the Farbwerk RGB controller */ +/* Spec and sensor report offset for the Farbwerk RGB controller */ #define FARBWERK_NUM_SENSORS 4 #define FARBWERK_SENSOR_START 0x2f -/* Register offsets for the Farbwerk 360 RGB controller */ +/* Specs of the Farbwerk 360 RGB controller */ #define FARBWERK360_NUM_SENSORS 4 -#define FARBWERK360_SENSOR_START 0x32 #define FARBWERK360_NUM_VIRTUAL_SENSORS 16 -#define FARBWERK360_VIRTUAL_SENSORS_START 0x3a #define FARBWERK360_CTRL_REPORT_SIZE 0x682 + +/* Sensor report offsets for the Farbwerk 360 */ +#define FARBWERK360_SENSOR_START 0x32 +#define FARBWERK360_VIRTUAL_SENSORS_START 0x3a + +/* Control report offsets for the Farbwerk 360 */ #define FARBWERK360_TEMP_CTRL_OFFSET 0x8 -/* Register offsets for the Octo fan controller */ -#define OCTO_POWER_CYCLES 0x18 +/* Specs of the Octo fan controller */ #define OCTO_NUM_FANS 8 #define OCTO_NUM_SENSORS 4 -#define OCTO_SENSOR_START 0x3D #define OCTO_NUM_VIRTUAL_SENSORS 16 -#define OCTO_VIRTUAL_SENSORS_START 0x45 #define OCTO_CTRL_REPORT_SIZE 0x65F -#define OCTO_TEMP_CTRL_OFFSET 0xA + +/* Sensor report offsets for the Octo */ +#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 }; -/* Fan speed registers in Octo control report (from 0-100%) */ +/* Control report offsets for the Octo */ +#define OCTO_TEMP_CTRL_OFFSET 0xA +/* Fan speed offsets (0-100%) */ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0x259, 0x2AE }; -/* Register offsets for the Quadro fan controller */ -#define QUADRO_POWER_CYCLES 0x18 +/* Specs of Quadro fan controller */ #define QUADRO_NUM_FANS 4 #define QUADRO_NUM_SENSORS 4 -#define QUADRO_SENSOR_START 0x34 #define QUADRO_NUM_VIRTUAL_SENSORS 16 -#define QUADRO_VIRTUAL_SENSORS_START 0x3c #define QUADRO_CTRL_REPORT_SIZE 0x3c1 + +/* Sensor report offsets for the Quadro */ +#define QUADRO_POWER_CYCLES 0x18 +#define QUADRO_SENSOR_START 0x34 +#define QUADRO_VIRTUAL_SENSORS_START 0x3c #define QUADRO_FLOW_SENSOR_OFFSET 0x6e -#define QUADRO_TEMP_CTRL_OFFSET 0xA static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 }; -/* Fan speed registers in Quadro control report (from 0-100%) */ -static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; +/* Control report offsets for the Quadro */ +#define QUADRO_TEMP_CTRL_OFFSET 0xA +static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed offsets (0-100%) */ -/* Register offsets for the High Flow Next */ +/* Specs of High Flow Next flow sensor */ #define HIGHFLOWNEXT_NUM_SENSORS 2 + +/* Sensor report offsets for the High Flow Next */ #define HIGHFLOWNEXT_SENSOR_START 85 #define HIGHFLOWNEXT_FLOW 81 #define HIGHFLOWNEXT_WATER_QUALITY 89 @@ -903,14 +916,17 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->num_fans = D5NEXT_NUM_FANS; priv->fan_sensor_offsets = d5next_sensor_fan_offsets; priv->fan_ctrl_offsets = d5next_ctrl_fan_offsets; + priv->num_temp_sensors = D5NEXT_NUM_SENSORS; priv->temp_sensor_start_offset = D5NEXT_COOLANT_TEMP; priv->num_virtual_temp_sensors = D5NEXT_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = D5NEXT_VIRTUAL_SENSORS_START; - priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES; - priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE; priv->temp_ctrl_offset = D5NEXT_TEMP_CTRL_OFFSET; + priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE; + + priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES; + priv->temp_label = label_d5next_temp; priv->virtual_temp_label = label_virtual_temp_sensors; priv->speed_label = label_d5next_speeds; @@ -922,20 +938,25 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->kind = farbwerk; priv->num_fans = 0; + priv->num_temp_sensors = FARBWERK_NUM_SENSORS; priv->temp_sensor_start_offset = FARBWERK_SENSOR_START; + priv->temp_label = label_temp_sensors; break; case USB_PRODUCT_ID_FARBWERK360: priv->kind = farbwerk360; priv->num_fans = 0; + priv->num_temp_sensors = FARBWERK360_NUM_SENSORS; priv->temp_sensor_start_offset = FARBWERK360_SENSOR_START; priv->num_virtual_temp_sensors = FARBWERK360_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = FARBWERK360_VIRTUAL_SENSORS_START; - priv->buffer_size = FARBWERK360_CTRL_REPORT_SIZE; priv->temp_ctrl_offset = FARBWERK360_TEMP_CTRL_OFFSET; + + priv->buffer_size = FARBWERK360_CTRL_REPORT_SIZE; + priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; break; @@ -945,14 +966,17 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->num_fans = OCTO_NUM_FANS; priv->fan_sensor_offsets = octo_sensor_fan_offsets; priv->fan_ctrl_offsets = octo_ctrl_fan_offsets; + priv->num_temp_sensors = OCTO_NUM_SENSORS; priv->temp_sensor_start_offset = OCTO_SENSOR_START; priv->num_virtual_temp_sensors = OCTO_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = OCTO_VIRTUAL_SENSORS_START; - priv->power_cycle_count_offset = OCTO_POWER_CYCLES; - priv->buffer_size = OCTO_CTRL_REPORT_SIZE; priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET; + priv->buffer_size = OCTO_CTRL_REPORT_SIZE; + + priv->power_cycle_count_offset = OCTO_POWER_CYCLES; + priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; priv->speed_label = label_fan_speed; @@ -966,14 +990,17 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->num_fans = QUADRO_NUM_FANS; priv->fan_sensor_offsets = quadro_sensor_fan_offsets; priv->fan_ctrl_offsets = quadro_ctrl_fan_offsets; + priv->num_temp_sensors = QUADRO_NUM_SENSORS; 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->power_cycle_count_offset = QUADRO_POWER_CYCLES; + priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET; + priv->buffer_size = QUADRO_CTRL_REPORT_SIZE; + priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET; - priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET; + priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; @@ -986,8 +1013,10 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->kind = highflownext; priv->num_fans = 0; + priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS; priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START; + priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; priv->temp_label = label_highflownext_temp_sensors; -- cgit 1.2.3-korg From ed264e8a7d18c5fec2587ed750c87b75d5348210 Mon Sep 17 00:00:00 2001 From: Joaquín Ignacio Aramendía Date: Fri, 4 Nov 2022 11:07:00 -0300 Subject: hwmon: add OneXPlayer mini AMD sensors driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sensors driver for OXP Handhelds from One-Netbook that expose fan reading and control via hwmon sysfs. As far as I could gather all OXP boards have the same DMI strings and they can be told appart only by the boot cpu vendor (Intel/AMD). Currently only AMD boards are supported since Intel have different EC registers and values to read/write. Fan control is provided via pwm interface in the range [0-255]. AMD boards have [0-100] as range in the EC, the written value is scaled to accommodate for that. Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20221104140659.593608-1-samsagax@gmail.com [groeck: Removed misleading comment about module_platform_driver()] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/oxp-sensors.rst | 34 +++++ MAINTAINERS | 6 + drivers/hwmon/Kconfig | 11 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/oxp-sensors.c | 256 ++++++++++++++++++++++++++++++++++++ 6 files changed, 309 insertions(+) create mode 100644 Documentation/hwmon/oxp-sensors.rst create mode 100644 drivers/hwmon/oxp-sensors.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index ddff3c5713d74e..fe2cc6b73634c3 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -160,6 +160,7 @@ Hardware Monitoring Kernel Drivers nzxt-kraken2 nzxt-smart2 occ + oxp-sensors pc87360 pc87427 pcf8591 diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst new file mode 100644 index 00000000000000..f612dddc964ae4 --- /dev/null +++ b/Documentation/hwmon/oxp-sensors.rst @@ -0,0 +1,34 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver oxp-sensors +========================= + +Author: + - Joaquín Ignacio Aramendía + +Description: +------------ + +One X Player devices from One Netbook provide fan readings and fan control +through its Embedded Controller. + +Currently only supports AMD boards from the One X Player 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. + +Sysfs entries +------------- + +The following attributes are supported: + +fan1_input + Read Only. Reads current fan RMP. + +pwm1_enable + Read Write. Enable manual fan control. Write "1" to set to manual, write "0" + to let the EC control de fan speed. Read this attribute to see current status. + +pwm1 + Read Write. Read this attribute to see current duty cycle in the range [0-255]. + When pwm1_enable is set to "1" (manual) write any value in the range [0-255] + to set fan speed. diff --git a/MAINTAINERS b/MAINTAINERS index 1daadaa4d48be1..90220659206cbf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15345,6 +15345,12 @@ S: Maintained F: drivers/mtd/nand/onenand/ F: include/linux/mtd/onenand*.h +ONEXPLAYER FAN DRIVER +M: Joaquín Ignacio Aramendía +L: linux-hwmon@vger.kernel.org +S: Maintained +F: drivers/hwmon/oxp-sensors.c + ONION OMEGA2+ BOARD M: Harvey Hunt L: linux-mips@vger.kernel.org diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index a5253abb7ea722..3176c33af6c699 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1616,6 +1616,17 @@ config SENSORS_NZXT_SMART2 source "drivers/hwmon/occ/Kconfig" +config SENSORS_OXP + tristate "OneXPlayer EC fan control" + depends on ACPI + depends on X86 + help + If you say yes here you get support for fan readings and control over + OneXPlayer handheld devices. Only OneXPlayer mini AMD handheld variant + boards are supported. + + Can also be built as a module. In that case it will be called oxp-sensors. + config SENSORS_PCF8591 tristate "Philips PCF8591 ADC/DAC" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index c5cd7e3a67ffd0..e2e4e87b282f53 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -167,6 +167,7 @@ obj-$(CONFIG_SENSORS_NSA320) += nsa320-hwmon.o obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_NZXT_KRAKEN2) += nzxt-kraken2.o obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o +obj-$(CONFIG_SENSORS_OXP) += oxp-sensors.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c new file mode 100644 index 00000000000000..b1653eb5e67075 --- /dev/null +++ b/drivers/hwmon/oxp-sensors.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Platform driver for OXP Handhelds that expose fan reading and control + * via hwmon sysfs. + * + * All 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. + * Fan control is provided via pwm interface in the range [0-255]. AMD + * boards use [0-100] as range in the EC, the written value is scaled to + * accommodate for that. + * + * Copyright (C) 2022 Joaquín I. Aramendía + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Handle ACPI lock mechanism */ +static u32 oxp_mutex; + +#define ACPI_LOCK_DELAY_MS 500 + +static bool lock_global_acpi_lock(void) +{ + return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex)); +} + +static bool unlock_global_acpi_lock(void) +{ + return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex)); +} + +#define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ +#define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */ +#define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */ + +static const struct dmi_system_id dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"), + }, + }, + {}, +}; + +/* Helper functions to handle EC read/write */ +static int read_from_ec(u8 reg, int size, long *val) +{ + int i; + int ret; + u8 buffer; + + if (!lock_global_acpi_lock()) + return -EBUSY; + + *val = 0; + for (i = 0; i < size; i++) { + ret = ec_read(reg + i, &buffer); + if (ret) + return ret; + *val <<= i * 8; + *val += buffer; + } + + if (!unlock_global_acpi_lock()) + return -EBUSY; + + return 0; +} + +static int write_to_ec(const struct device *dev, u8 reg, u8 value) +{ + int ret; + + if (!lock_global_acpi_lock()) + return -EBUSY; + + ret = ec_write(reg, value); + + if (!unlock_global_acpi_lock()) + return -EBUSY; + + return ret; +} + +static int oxp_pwm_enable(const struct device *dev) +{ + return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01); +} + +static int oxp_pwm_disable(const struct device *dev) +{ + return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00); +} + +/* Callbacks for hwmon interface */ +static umode_t oxp_ec_hwmon_is_visible(const void *drvdata, + enum hwmon_sensor_types type, u32 attr, int channel) +{ + switch (type) { + case hwmon_fan: + return 0444; + case hwmon_pwm: + return 0644; + default: + return 0; + } +} + +static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + int ret; + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + ret = read_from_ec(OXP_SENSOR_PWM_REG, 2, val); + if (ret) + return ret; + *val = (*val * 255) / 100; + return 0; + case hwmon_pwm_enable: + return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_enable: + if (val == 1) + return oxp_pwm_enable(dev); + else if (val == 0) + return oxp_pwm_disable(dev); + return -EINVAL; + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + val = (val * 100) / 255; + return write_to_ec(dev, OXP_SENSOR_PWM_REG, val); + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +/* Known sensors in the OXP EC controllers */ +static const struct hwmon_channel_info *oxp_platform_sensors[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), + NULL, +}; + +static const struct hwmon_ops oxp_ec_hwmon_ops = { + .is_visible = oxp_ec_hwmon_is_visible, + .read = oxp_platform_read, + .write = oxp_platform_write, +}; + +static const struct hwmon_chip_info oxp_ec_chip_info = { + .ops = &oxp_ec_hwmon_ops, + .info = oxp_platform_sensors, +}; + +/* Initialization logic */ +static int oxp_platform_probe(struct platform_device *pdev) +{ + const struct dmi_system_id *dmi_entry; + struct device *dev = &pdev->dev; + struct device *hwdev; + + /* + * 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 + * is the CPU. + * Intel boards seem to have different EC registers and values to + * read/write. + */ + dmi_entry = dmi_first_match(dmi_table); + if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return -ENODEV; + + hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, + &oxp_ec_chip_info, NULL); + + return PTR_ERR_OR_ZERO(hwdev); +} + +static struct platform_driver oxp_platform_driver = { + .driver = { + .name = "oxp-platform", + }, + .probe = oxp_platform_probe, +}; + +static struct platform_device *oxp_platform_device; + +static int __init oxp_platform_init(void) +{ + oxp_platform_device = + platform_create_bundle(&oxp_platform_driver, + oxp_platform_probe, NULL, 0, NULL, 0); + + return PTR_ERR_OR_ZERO(oxp_platform_device); +} + +static void __exit oxp_platform_exit(void) +{ + platform_device_unregister(oxp_platform_device); + platform_driver_unregister(&oxp_platform_driver); +} + +MODULE_DEVICE_TABLE(dmi, dmi_table); + +module_init(oxp_platform_init); +module_exit(oxp_platform_exit); + +MODULE_AUTHOR("Joaquín Ignacio Aramendía "); +MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices"); +MODULE_LICENSE("GPL"); -- cgit 1.2.3-korg From 5c0e64dde80ffe78d930db4e38e6218598aecd85 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 8 Nov 2022 15:50:49 +0800 Subject: hwmon: (coretemp) Remove obsolete temp_data->valid Checking for the valid bit of IA32_THERM_STATUS is removed in commit bf6ea084ebb5 ("hwmon: (coretemp) Do not return -EAGAIN for low temperatures"), and temp_data->valid is set and never cleared when the temperature has been read once. Remove the obsolete temp_data->valid field. Signed-off-by: Zhang Rui Link: https://lore.kernel.org/r/20221108075051.5139-2-rui.zhang@intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 9bee4d33fbdf0a..27d88c3a3487f0 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -64,7 +64,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); * @attr_size: Total number of pre-core attrs displayed in the sysfs. * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data. * Otherwise, temp_data holds coretemp data. - * @valid: If this is 1, the current temperature is valid. */ struct temp_data { int temp; @@ -76,7 +75,6 @@ struct temp_data { u32 status_reg; int attr_size; bool is_pkg_data; - bool valid; struct sensor_device_attribute sd_attrs[TOTAL_ATTRS]; char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH]; struct attribute *attrs[TOTAL_ATTRS + 1]; @@ -157,7 +155,7 @@ static ssize_t show_temp(struct device *dev, mutex_lock(&tdata->update_lock); /* Check whether the time interval has elapsed */ - if (!tdata->valid || time_after(jiffies, tdata->last_updated + HZ)) { + if (time_after(jiffies, tdata->last_updated + HZ)) { rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); /* * Ignore the valid bit. In all observed cases the register @@ -166,7 +164,6 @@ static ssize_t show_temp(struct device *dev, * really help at all. */ tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; - tdata->valid = true; tdata->last_updated = jiffies; } -- cgit 1.2.3-korg From 07619140e2a12484ea262b8845fd09e099f843a8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 13 Nov 2022 10:13:16 +0100 Subject: hwmon: Remove some useless #include is not needed for these drivers. Remove the corresponding #include. Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/41610f64a69bd0245ebc811fcff10ee54e93ac46.1668330765.git.christophe.jaillet@wanadoo.fr Signed-off-by: Guenter Roeck --- drivers/hwmon/vt8231.c | 1 - drivers/hwmon/w83l786ng.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 3b7f8922b0d5a6..b7c6392ba67374 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 2c4646fa84260d..5597e1c2d95cf3 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include -- cgit 1.2.3-korg From 2bc0e6d07ee50497043112d677fdd34327cf025c Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Sun, 13 Nov 2022 23:31:43 +0800 Subject: hwmon: (coretemp) rearrange tjmax handing code Rearrange the tjmax handling code so that it can be used directly in the sysfs attribute callbacks without forward declarations. No functional change in this patch. Signed-off-by: Zhang Rui Link: https://lore.kernel.org/r/20221113153145.32696-2-rui.zhang@intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 156 +++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 27d88c3a3487f0..6b6ee563e0087e 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -93,84 +93,6 @@ struct platform_data { struct device_attribute name_attr; }; -/* Keep track of how many zone pointers we allocated in init() */ -static int max_zones __read_mostly; -/* Array of zone pointers. Serialized by cpu hotplug lock */ -static struct platform_device **zone_devices; - -static ssize_t show_label(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - if (tdata->is_pkg_data) - return sprintf(buf, "Package id %u\n", pdata->pkg_id); - - return sprintf(buf, "Core %u\n", tdata->cpu_core_id); -} - -static ssize_t show_crit_alarm(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - u32 eax, edx; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - mutex_lock(&tdata->update_lock); - rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); - mutex_unlock(&tdata->update_lock); - - return sprintf(buf, "%d\n", (eax >> 5) & 1); -} - -static ssize_t show_tjmax(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax); -} - -static ssize_t show_ttarget(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); -} - -static ssize_t show_temp(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - u32 eax, edx; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - mutex_lock(&tdata->update_lock); - - /* Check whether the time interval has elapsed */ - if (time_after(jiffies, tdata->last_updated + HZ)) { - rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); - /* - * Ignore the valid bit. In all observed cases the register - * value is either low or zero if the valid bit is 0. - * Return it instead of reporting an error which doesn't - * really help at all. - */ - tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; - tdata->last_updated = jiffies; - } - - mutex_unlock(&tdata->update_lock); - return sprintf(buf, "%d\n", tdata->temp); -} - struct tjmax_pci { unsigned int device; int tjmax; @@ -376,6 +298,84 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) return adjust_tjmax(c, id, dev); } +/* Keep track of how many zone pointers we allocated in init() */ +static int max_zones __read_mostly; +/* Array of zone pointers. Serialized by cpu hotplug lock */ +static struct platform_device **zone_devices; + +static ssize_t show_label(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + + if (tdata->is_pkg_data) + return sprintf(buf, "Package id %u\n", pdata->pkg_id); + + return sprintf(buf, "Core %u\n", tdata->cpu_core_id); +} + +static ssize_t show_crit_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u32 eax, edx; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + + mutex_lock(&tdata->update_lock); + rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); + mutex_unlock(&tdata->update_lock); + + return sprintf(buf, "%d\n", (eax >> 5) & 1); +} + +static ssize_t show_tjmax(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax); +} + +static ssize_t show_ttarget(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); +} + +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u32 eax, edx; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + + mutex_lock(&tdata->update_lock); + + /* Check whether the time interval has elapsed */ + if (time_after(jiffies, tdata->last_updated + HZ)) { + rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); + /* + * Ignore the valid bit. In all observed cases the register + * value is either low or zero if the valid bit is 0. + * Return it instead of reporting an error which doesn't + * really help at all. + */ + tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; + tdata->last_updated = jiffies; + } + + mutex_unlock(&tdata->update_lock); + return sprintf(buf, "%d\n", tdata->temp); +} + static int create_core_attrs(struct temp_data *tdata, struct device *dev, int attr_no) { -- cgit 1.2.3-korg From c0c67f8761cec1fe36c21d85b1a5400ea7ac30cd Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Sun, 13 Nov 2022 23:31:44 +0800 Subject: hwmon: (coretemp) Add support for dynamic tjmax Tjmax value retrieved from MSR_IA32_TEMPERATURE_TARGET can be changed at runtime when the Intel SST-PP (Intel Speed Select Technology - Performance Profile) level is changed. Improve the code to always use updated tjmax when it can be retrieved from MSR_IA32_TEMPERATURE_TARGET. When tjmax can not be retrieved from MSR_IA32_TEMPERATURE_TARGET, still follow the previous logic and always use a static tjmax value. Signed-off-by: Zhang Rui Link: https://lore.kernel.org/r/20221113153145.32696-3-rui.zhang@intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 6b6ee563e0087e..5e03cfbbe99b8d 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -55,6 +55,8 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); /* * Per-Core Temperature Data + * @tjmax: The static tjmax value when tjmax cannot be retrieved from + * IA32_TEMPERATURE_TARGET MSR. * @last_updated: The time when the current temperature value was updated * earlier (in jiffies). * @cpu_core_id: The CPU Core from which temperature values should be read @@ -259,20 +261,25 @@ static bool cpu_has_tjmax(struct cpuinfo_x86 *c) model != 0x36; } -static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) +static int get_tjmax(struct temp_data *tdata, struct device *dev) { + struct cpuinfo_x86 *c = &cpu_data(tdata->cpu); int err; u32 eax, edx; u32 val; + /* use static tjmax once it is set */ + if (tdata->tjmax) + return tdata->tjmax; + /* * A new feature of current Intel(R) processors, the * IA32_TEMPERATURE_TARGET contains the TjMax value */ - err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + err = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); if (err) { if (cpu_has_tjmax(c)) - dev_warn(dev, "Unable to read TjMax from CPU %u\n", id); + dev_warn(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu); } else { val = (eax >> 16) & 0xff; /* @@ -288,14 +295,15 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) if (force_tjmax) { dev_notice(dev, "TjMax forced to %d degrees C by user\n", force_tjmax); - return force_tjmax * 1000; + tdata->tjmax = force_tjmax * 1000; + } else { + /* + * An assumption is made for early CPUs and unreadable MSR. + * NOTE: the calculated value may not be correct. + */ + tdata->tjmax = adjust_tjmax(c, tdata->cpu, dev); } - - /* - * An assumption is made for early CPUs and unreadable MSR. - * NOTE: the calculated value may not be correct. - */ - return adjust_tjmax(c, id, dev); + return tdata->tjmax; } /* Keep track of how many zone pointers we allocated in init() */ @@ -336,8 +344,14 @@ static ssize_t show_tjmax(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + int tjmax; + + mutex_lock(&tdata->update_lock); + tjmax = get_tjmax(tdata, dev); + mutex_unlock(&tdata->update_lock); - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax); + return sprintf(buf, "%d\n", tjmax); } static ssize_t show_ttarget(struct device *dev, @@ -356,9 +370,11 @@ static ssize_t show_temp(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct platform_data *pdata = dev_get_drvdata(dev); struct temp_data *tdata = pdata->core_data[attr->index]; + int tjmax; mutex_lock(&tdata->update_lock); + tjmax = get_tjmax(tdata, dev); /* Check whether the time interval has elapsed */ if (time_after(jiffies, tdata->last_updated + HZ)) { rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); @@ -368,7 +384,7 @@ static ssize_t show_temp(struct device *dev, * Return it instead of reporting an error which doesn't * really help at all. */ - tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; + tdata->temp = tjmax - ((eax >> 16) & 0x7f) * 1000; tdata->last_updated = jiffies; } @@ -453,7 +469,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, struct platform_data *pdata = platform_get_drvdata(pdev); struct cpuinfo_x86 *c = &cpu_data(cpu); u32 eax, edx; - int err, index, attr_no; + int err, index, attr_no, tjmax; /* * Find attr number for sysfs: @@ -488,7 +504,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, goto exit_free; /* We can access status register. Get Critical Temperature */ - tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); + tjmax = get_tjmax(tdata, &pdev->dev); /* * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. @@ -500,7 +516,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, &eax, &edx); if (!err) { tdata->ttarget - = tdata->tjmax - ((eax >> 8) & 0xff) * 1000; + = tjmax - ((eax >> 8) & 0xff) * 1000; tdata->attr_size++; } } -- cgit 1.2.3-korg From fae30e3c203e0f854d0420b50e54e31a75b6a8a4 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Sun, 13 Nov 2022 23:31:45 +0800 Subject: hwmon: (coretemp) Add support for dynamic ttarget Tjmax value retrieved from MSR_IA32_TEMPERATURE_TARGET can be changed at runtime when the Intel SST-PP (Intel Speed Select Technology - Performance Profile) level is changed. As a result, the ttarget value also becomes dyamic. Improve the code to always get updated ttarget value. Signed-off-by: Zhang Rui Link: https://lore.kernel.org/r/20221113153145.32696-4-rui.zhang@intel.com Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 57 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 5e03cfbbe99b8d..ca7a9b373bbd63 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -69,7 +69,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); */ struct temp_data { int temp; - int ttarget; int tjmax; unsigned long last_updated; unsigned int cpu; @@ -306,6 +305,30 @@ static int get_tjmax(struct temp_data *tdata, struct device *dev) return tdata->tjmax; } +static int get_ttarget(struct temp_data *tdata, struct device *dev) +{ + u32 eax, edx; + int tjmax, ttarget_offset, ret; + + /* + * ttarget is valid only if tjmax can be retrieved from + * MSR_IA32_TEMPERATURE_TARGET + */ + if (tdata->tjmax) + return -ENODEV; + + ret = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + if (ret) + return ret; + + tjmax = (eax >> 16) & 0xff; + + /* Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. */ + ttarget_offset = (eax >> 8) & 0xff; + + return (tjmax - ttarget_offset) * 1000; +} + /* Keep track of how many zone pointers we allocated in init() */ static int max_zones __read_mostly; /* Array of zone pointers. Serialized by cpu hotplug lock */ @@ -359,8 +382,16 @@ static ssize_t show_ttarget(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + int ttarget; - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); + mutex_lock(&tdata->update_lock); + ttarget = get_ttarget(tdata, dev); + mutex_unlock(&tdata->update_lock); + + if (ttarget < 0) + return ttarget; + return sprintf(buf, "%d\n", ttarget); } static ssize_t show_temp(struct device *dev, @@ -469,7 +500,7 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, struct platform_data *pdata = platform_get_drvdata(pdev); struct cpuinfo_x86 *c = &cpu_data(cpu); u32 eax, edx; - int err, index, attr_no, tjmax; + int err, index, attr_no; /* * Find attr number for sysfs: @@ -503,23 +534,17 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu, if (err) goto exit_free; - /* We can access status register. Get Critical Temperature */ - tjmax = get_tjmax(tdata, &pdev->dev); + /* Make sure tdata->tjmax is a valid indicator for dynamic/static tjmax */ + get_tjmax(tdata, &pdev->dev); /* - * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. - * The target temperature is available on older CPUs but not in this - * register. Atoms don't have the register at all. + * The target temperature is available on older CPUs but not in the + * MSR_IA32_TEMPERATURE_TARGET register. Atoms don't have the register + * at all. */ - if (c->x86_model > 0xe && c->x86_model != 0x1c) { - err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, - &eax, &edx); - if (!err) { - tdata->ttarget - = tjmax - ((eax >> 8) & 0xff) * 1000; + if (c->x86_model > 0xe && c->x86_model != 0x1c) + if (get_ttarget(tdata, &pdev->dev) >= 0) tdata->attr_size++; - } - } pdata->core_data[attr_no] = tdata; -- cgit 1.2.3-korg From 1864069c695d475e0ce98a335c62274b81be57b4 Mon Sep 17 00:00:00 2001 From: Denis Pauk Date: Mon, 14 Nov 2022 23:44:56 +0200 Subject: hwmon: (nct6775) add ASUS CROSSHAIR VIII/TUF/ProArt B550M Boards such as * ProArt B550-CREATOR * ProArt Z490-CREATOR 10G * ROG CROSSHAIR VIII EXTREME * ROG CROSSHAIR VIII HERO (WI-FI) * TUF GAMING B550M-E * TUF GAMING B550M-E (WI-FI) * TUF GAMING B550M-PLUS WIFI II have got a nct6775 chip, but by default there's no use of it because of resource conflict with WMI method. This commit adds such boards to the WMI monitoring list. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204807 Signed-off-by: Denis Pauk Reported-by: yutesdb Tested-by: yutesdb Link: https://lore.kernel.org/r/20221114214456.3891-1-pauk.denis@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6775-platform.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index b347837842139f..bf43f73dc835fb 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -1043,7 +1043,9 @@ static struct platform_device *pdev[2]; static const char * const asus_wmi_boards[] = { "PRO H410T", + "ProArt B550-CREATOR", "ProArt X570-CREATOR WIFI", + "ProArt Z490-CREATOR 10G", "Pro B550M-C", "Pro WS X570-ACE", "PRIME B360-PLUS", @@ -1055,8 +1057,10 @@ static const char * const asus_wmi_boards[] = { "PRIME X570-P", "PRIME X570-PRO", "ROG CROSSHAIR VIII DARK HERO", + "ROG CROSSHAIR VIII EXTREME", "ROG CROSSHAIR VIII FORMULA", "ROG CROSSHAIR VIII HERO", + "ROG CROSSHAIR VIII HERO (WI-FI)", "ROG CROSSHAIR VIII IMPACT", "ROG STRIX B550-A GAMING", "ROG STRIX B550-E GAMING", @@ -1080,8 +1084,11 @@ static const char * const asus_wmi_boards[] = { "ROG STRIX Z490-G GAMING (WI-FI)", "ROG STRIX Z490-H GAMING", "ROG STRIX Z490-I GAMING", + "TUF GAMING B550M-E", + "TUF GAMING B550M-E (WI-FI)", "TUF GAMING B550M-PLUS", "TUF GAMING B550M-PLUS (WI-FI)", + "TUF GAMING B550M-PLUS WIFI II", "TUF GAMING B550-PLUS", "TUF GAMING B550-PLUS WIFI II", "TUF GAMING B550-PRO", -- cgit 1.2.3-korg From ef9948dfe1056a89f699edc8eb691a8ed99eda5e Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Thu, 17 Nov 2022 19:40:22 +0100 Subject: hwmon: (pmbus) Add power good support Update error flags with regulation out if regulator is on & power good status bit is set Signed-off-by: Patrick Rudolph Signed-off-by: Naresh Solanki Link: https://lore.kernel.org/r/20221117184022.1808508-1-Naresh.Solanki@9elements.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 7ec04934747e12..20ca26e19db756 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2827,9 +2827,13 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned if (status < 0) return status; - if (pmbus_regulator_is_enabled(rdev) && (status & PB_STATUS_OFF)) - *flags |= REGULATOR_ERROR_FAIL; + if (pmbus_regulator_is_enabled(rdev)) { + if (status & PB_STATUS_OFF) + *flags |= REGULATOR_ERROR_FAIL; + if (status & PB_STATUS_POWER_GOOD_N) + *flags |= REGULATOR_ERROR_REGULATION_OUT; + } /* * Unlike most other status bits, PB_STATUS_{IOUT_OC,VOUT_OV} are * defined strictly as fault indicators (not warnings). -- cgit 1.2.3-korg From 59882c7f6714141300882af3d39ca6ffecf54ec2 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 20 Nov 2022 10:34:41 +0100 Subject: hwmon: (gsc-hwmon) Switch to flexible array to simplify code Using flexible array is more straight forward. It - saves 1 pointer in the 'gsc_hwmon_platform_data' structure - saves an indirection when using this array - saves some LoC and avoids some always spurious pointer arithmetic Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/61a23e1d642397cfcecc4ac3bb0ab485d257987d.1668936855.git.christophe.jaillet@wanadoo.fr Signed-off-by: Guenter Roeck --- drivers/hwmon/gsc-hwmon.c | 6 ++---- include/linux/platform_data/gsc_hwmon.h | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index b60ec95b5edbf2..73e5d92b200b0c 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -257,13 +257,10 @@ gsc_hwmon_get_devtree_pdata(struct device *dev) if (nchannels == 0) return ERR_PTR(-ENODEV); - pdata = devm_kzalloc(dev, - sizeof(*pdata) + nchannels * sizeof(*ch), + pdata = devm_kzalloc(dev, struct_size(pdata, channels, nchannels), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - ch = (struct gsc_hwmon_channel *)(pdata + 1); - pdata->channels = ch; pdata->nchannels = nchannels; /* fan controller base address */ @@ -277,6 +274,7 @@ gsc_hwmon_get_devtree_pdata(struct device *dev) of_node_put(fan); + ch = pdata->channels; /* allocate structures for channels and count instances of each type */ device_for_each_child_node(dev, child) { if (fwnode_property_read_string(child, "label", &ch->name)) { diff --git a/include/linux/platform_data/gsc_hwmon.h b/include/linux/platform_data/gsc_hwmon.h index 281f499eda9790..f2781aa7eff85f 100644 --- a/include/linux/platform_data/gsc_hwmon.h +++ b/include/linux/platform_data/gsc_hwmon.h @@ -29,18 +29,17 @@ struct gsc_hwmon_channel { /** * struct gsc_hwmon_platform_data - platform data for gsc_hwmon driver - * @channels: pointer to array of gsc_hwmon_channel structures - * describing channels * @nchannels: number of elements in @channels array * @vreference: voltage reference (mV) * @resolution: ADC bit resolution * @fan_base: register base for FAN controller + * @channels: array of gsc_hwmon_channel structures describing channels */ struct gsc_hwmon_platform_data { - const struct gsc_hwmon_channel *channels; int nchannels; unsigned int resolution; unsigned int vreference; unsigned int fan_base; + struct gsc_hwmon_channel channels[]; }; #endif -- cgit 1.2.3-korg From 3ca0f12a02582c3dd4029294ab0245ba77c27a77 Mon Sep 17 00:00:00 2001 From: Joaquín Ignacio Aramendía Date: Fri, 25 Nov 2022 08:49:01 -0300 Subject: hwmon: (oxp-sensors) Add AOK ZOE and Mini PRO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the AOK ZOE A1 and OXP Mini PRO handheld devices. DMI strings are added to this driver since the same EC layout is used and has similar specs as the OXP mini AMD. The added devices are: - OneXPlayer mini PRO (AMD 6800U) - AOK ZOE A1 (AMD 6800U) Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20221125114901.11309-1-samsagax@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/oxp-sensors.rst | 16 ++++++++++++--- drivers/hwmon/oxp-sensors.c | 40 +++++++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst index f612dddc964ae4..39c588ec5c5060 100644 --- a/Documentation/hwmon/oxp-sensors.rst +++ b/Documentation/hwmon/oxp-sensors.rst @@ -12,9 +12,19 @@ Description: One X Player devices from One Netbook provide fan readings and fan control through its Embedded Controller. -Currently only supports AMD boards from the One X Player 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 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. + +Supported devices +----------------- + +Currently the driver supports the following handhelds: + + - AOK ZOE A1 + - OneXPlayer AMD + - OneXPlayer mini AMD + - OneXPlayer mini AMD PRO Sysfs entries ------------- diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index b1653eb5e67075..c04277676b7271 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -3,13 +3,14 @@ * Platform driver for OXP Handhelds that expose fan reading and control * via hwmon sysfs. * - * All boards have the same DMI strings and they are told appart by the + * 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. - * Fan control is provided via pwm interface in the range [0-255]. AMD - * boards use [0-100] as range in the EC, the written value is scaled to - * accommodate for that. + * 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 + * AOK ZOE are not scaled but have the same EC layout. * * Copyright (C) 2022 Joaquín I. Aramendía */ @@ -39,16 +40,39 @@ static bool unlock_global_acpi_lock(void) return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex)); } +enum oxp_board { + aok_zoe_a1 = 1, + oxp_mini_amd, + oxp_mini_amd_pro, +}; + +static enum oxp_board board; + #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */ #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */ static const struct dmi_system_id dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"), + }, + .driver_data = (void *) &(enum oxp_board) {aok_zoe_a1}, + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"), }, + .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd}, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"), + }, + .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro}, }, {}, }; @@ -137,7 +161,8 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, ret = read_from_ec(OXP_SENSOR_PWM_REG, 2, val); if (ret) return ret; - *val = (*val * 255) / 100; + if (board == oxp_mini_amd) + *val = (*val * 255) / 100; return 0; case hwmon_pwm_enable: return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); @@ -166,7 +191,8 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, case hwmon_pwm_input: if (val < 0 || val > 255) return -EINVAL; - val = (val * 100) / 255; + if (board == oxp_mini_amd) + val = (val * 100) / 255; return write_to_ec(dev, OXP_SENSOR_PWM_REG, val); default: break; @@ -216,6 +242,8 @@ static int oxp_platform_probe(struct platform_device *pdev) if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD) return -ENODEV; + board = *((enum oxp_board *) dmi_entry->driver_data); + hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, &oxp_ec_chip_info, NULL); -- cgit 1.2.3-korg From c05f477c4ba36e007c03ff4f834f43bc4e37692b Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Thu, 24 Nov 2022 20:36:42 +0100 Subject: hwmon: (pmbus/core) Implement regulator get_status Add get_status for pmbus_regulator_ops. Signed-off-by: Patrick Rudolph Signed-off-by: Naresh Solanki Link: https://lore.kernel.org/r/20221124193642.4081054-1-Naresh.Solanki@9elements.com Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 20ca26e19db756..95e95783972abb 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2855,6 +2855,49 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned return 0; } +static int pmbus_regulator_get_status(struct regulator_dev *rdev) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_data *data = i2c_get_clientdata(client); + u8 page = rdev_get_id(rdev); + int status, ret; + + mutex_lock(&data->update_lock); + status = pmbus_get_status(client, page, PMBUS_STATUS_WORD); + if (status < 0) { + ret = status; + goto unlock; + } + + if (status & PB_STATUS_OFF) { + ret = REGULATOR_STATUS_OFF; + goto unlock; + } + + /* If regulator is ON & reports power good then return ON */ + if (!(status & PB_STATUS_POWER_GOOD_N)) { + ret = REGULATOR_STATUS_ON; + goto unlock; + } + + ret = pmbus_regulator_get_error_flags(rdev, &status); + if (ret) + goto unlock; + + if (status & (REGULATOR_ERROR_UNDER_VOLTAGE | REGULATOR_ERROR_OVER_CURRENT | + REGULATOR_ERROR_REGULATION_OUT | REGULATOR_ERROR_FAIL | REGULATOR_ERROR_OVER_TEMP)) { + ret = REGULATOR_STATUS_ERROR; + goto unlock; + } + + ret = REGULATOR_STATUS_UNDEFINED; + +unlock: + mutex_unlock(&data->update_lock); + return ret; +} + static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page) { struct pmbus_data *data = i2c_get_clientdata(client); @@ -2995,6 +3038,7 @@ const struct regulator_ops pmbus_regulator_ops = { .disable = pmbus_regulator_disable, .is_enabled = pmbus_regulator_is_enabled, .get_error_flags = pmbus_regulator_get_error_flags, + .get_status = pmbus_regulator_get_status, .get_voltage = pmbus_regulator_get_voltage, .set_voltage = pmbus_regulator_set_voltage, .list_voltage = pmbus_regulator_list_voltage, -- cgit 1.2.3-korg From 6ff838f2877dcd5ec7db0745a2652a048a697991 Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Sat, 26 Nov 2022 08:13:13 +0100 Subject: hwmon: (aquacomputer_d5next) Add support for Quadro flow sensor pulses Add support for reading and writing flow sensor pulses value on the Aquacomputer Quadro. Implemented by Leonard Anderweit [1]. [1] https://github.com/aleksamagicka/aquacomputer_d5next-hwmon/pull/45 Originally-from: Leonard Anderweit Signed-off-by: Aleksa Savic Link: https://lore.kernel.org/r/20221126071313.34356-1-savicaleksa83@gmail.com Signed-off-by: Guenter Roeck --- Documentation/hwmon/aquacomputer_d5next.rst | 3 +- drivers/hwmon/aquacomputer_d5next.c | 66 +++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 15226346434dd1..637bdbc8fcad43 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -39,7 +39,7 @@ current. The Quadro exposes four physical and sixteen virtual temperature sensors, a flow sensor and four PWM controllable fans, along with their speed (in RPM), power, -voltage and current. +voltage and current. Flow sensor pulses are also available. The Farbwerk and Farbwerk 360 expose four temperature sensors. Additionally, sixteen virtual temperature sensors of the Farbwerk 360 are exposed. @@ -64,6 +64,7 @@ Sysfs entries temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius) temp[1-4]_offset Temperature sensor correction offset (in millidegrees Celsius) fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h) +fan5_pulses Quadro flow sensor pulses power[1-8]_input Pump/fan power (in micro Watts) in[0-7]_input Pump/fan voltage (in milli Volts) curr[1-8]_input Pump/fan current (in milli Amperes) diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 49d3f9876fe80b..9cc10080160b00 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -136,6 +136,7 @@ static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 }; /* Control report offsets for the Quadro */ #define QUADRO_TEMP_CTRL_OFFSET 0xA +#define QUADRO_FLOW_PULSES_CTRL_OFFSET 0x6 static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed offsets (0-100%) */ /* Specs of High Flow Next flow sensor */ @@ -303,6 +304,7 @@ struct aqc_data { u16 temp_ctrl_offset; u16 power_cycle_count_offset; u8 flow_sensor_offset; + u8 flow_pulses_ctrl_offset; /* General info, same across all devices */ u32 serial_number[2]; @@ -461,20 +463,34 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 } break; case hwmon_fan: - switch (priv->kind) { - case highflownext: - /* Special case to support flow sensor, water quality and conductivity */ - if (channel < 3) - return 0444; + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_label: + switch (priv->kind) { + case highflownext: + /* Special case to support flow sensor, water quality + * and conductivity + */ + if (channel < 3) + return 0444; + break; + case quadro: + /* Special case to support flow sensor */ + if (channel < priv->num_fans + 1) + return 0444; + break; + default: + if (channel < priv->num_fans) + return 0444; + break; + } break; - case quadro: - /* Special case to support flow sensor */ - if (channel < priv->num_fans + 1) - return 0444; + case hwmon_fan_pulses: + /* Special case for Quadro flow sensor */ + if (priv->kind == quadro && channel == priv->num_fans) + return 0644; break; default: - if (channel < priv->num_fans) - return 0444; break; } break; @@ -552,7 +568,18 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, } break; case hwmon_fan: - *val = priv->speed_input[channel]; + switch (attr) { + case hwmon_fan_input: + *val = priv->speed_input[channel]; + break; + case hwmon_fan_pulses: + ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val); + if (ret < 0) + return ret; + break; + default: + break; + } break; case hwmon_power: *val = priv->power_input[channel]; @@ -632,6 +659,18 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, return -EOPNOTSUPP; } break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_pulses: + val = clamp_val(val, 10, 1000); + ret = aqc_set_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val); + if (ret < 0) + return ret; + break; + default: + break; + } + break; case hwmon_pwm: switch (attr) { case hwmon_pwm_input: @@ -691,7 +730,7 @@ static const struct hwmon_channel_info *aqc_info[] = { HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, - HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_PULSES, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL), @@ -1000,6 +1039,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) 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; priv->temp_label = label_temp_sensors; -- cgit 1.2.3-korg From 0cd3ba682ae27cbe17c41f85b8e6db6da38296b2 Mon Sep 17 00:00:00 2001 From: Joaquín Ignacio Aramendía Date: Mon, 28 Nov 2022 15:52:06 -0300 Subject: hwmon: (oxp-sensors) Fix pwm reading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PWM reading is only 1 register long. Signed-off-by: Joaquín Ignacio Aramendía Link: https://lore.kernel.org/r/20221128185206.212022-1-samsagax@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/oxp-sensors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index c04277676b7271..f84ec8f8eda918 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -158,7 +158,7 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_pwm: switch (attr) { case hwmon_pwm_input: - ret = read_from_ec(OXP_SENSOR_PWM_REG, 2, val); + ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); if (ret) return ret; if (board == oxp_mini_amd) -- cgit 1.2.3-korg From 4e6104b1e70020ad500f0fab7238898dd2ea2a38 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Thu, 1 Dec 2022 11:30:31 +0800 Subject: hwmon: use sysfs_emit() to instead of scnprintf() Replace the open-code with sysfs_emit() to simplify the code. Signed-off-by: ye xingchen Link: https://lore.kernel.org/r/202212011130317080061@zte.com.cn Signed-off-by: Guenter Roeck --- drivers/hwmon/ds1621.c | 2 +- drivers/hwmon/lm73.c | 6 +++--- drivers/hwmon/sht3x.c | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 0886abf6ebab14..e803d6393b9e50 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -269,7 +269,7 @@ static ssize_t update_interval_show(struct device *dev, struct device_attribute *da, char *buf) { struct ds1621_data *data = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval); + return sysfs_emit(buf, "%hu\n", data->update_interval); } static ssize_t update_interval_store(struct device *dev, diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index 1346b3b3f4635a..b6433ae2d75c3b 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -92,7 +92,7 @@ static ssize_t temp_show(struct device *dev, struct device_attribute *da, /* use integer division instead of equivalent right shift to guarantee arithmetic shift and preserve the sign */ temp = (((s16) err) * 250) / 32; - return scnprintf(buf, PAGE_SIZE, "%d\n", temp); + return sysfs_emit(buf, "%d\n", temp); } static ssize_t convrate_store(struct device *dev, struct device_attribute *da, @@ -137,7 +137,7 @@ static ssize_t convrate_show(struct device *dev, struct device_attribute *da, int res; res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT; - return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]); + return sysfs_emit(buf, "%hu\n", lm73_convrates[res]); } static ssize_t maxmin_alarm_show(struct device *dev, @@ -154,7 +154,7 @@ static ssize_t maxmin_alarm_show(struct device *dev, data->ctrl = ctrl; mutex_unlock(&data->lock); - return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1); + return sysfs_emit(buf, "%d\n", (ctrl >> attr->index) & 1); abort: mutex_unlock(&data->lock); diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 3f279aa1cee5ed..8305e44d9ab207 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -320,7 +320,7 @@ static ssize_t temp1_limit_show(struct device *dev, u8 index = to_sensor_dev_attr(attr)->index; int temperature_limit = data->temperature_limits[index]; - return scnprintf(buf, PAGE_SIZE, "%d\n", temperature_limit); + return sysfs_emit(buf, "%d\n", temperature_limit); } static ssize_t humidity1_limit_show(struct device *dev, @@ -331,7 +331,7 @@ static ssize_t humidity1_limit_show(struct device *dev, u8 index = to_sensor_dev_attr(attr)->index; u32 humidity_limit = data->humidity_limits[index]; - return scnprintf(buf, PAGE_SIZE, "%u\n", humidity_limit); + return sysfs_emit(buf, "%u\n", humidity_limit); } /* @@ -483,7 +483,7 @@ static ssize_t temp1_alarm_show(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x04)); + return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x04)); } static ssize_t humidity1_alarm_show(struct device *dev, @@ -498,7 +498,7 @@ static ssize_t humidity1_alarm_show(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x08)); + return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x08)); } static ssize_t heater_enable_show(struct device *dev, @@ -513,7 +513,7 @@ static ssize_t heater_enable_show(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x20)); + return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x20)); } static ssize_t heater_enable_store(struct device *dev, @@ -550,7 +550,7 @@ static ssize_t update_interval_show(struct device *dev, { struct sht3x_data *data = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%u\n", + return sysfs_emit(buf, "%u\n", mode_to_update_interval[data->mode]); } -- cgit 1.2.3-korg From 688fcd047ef0f0aeee16d0fefaff065fa69eb642 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 30 Nov 2022 19:34:18 +0100 Subject: hwmon: (dell-smm) Move error message to make probing silent If dell-smm-hwmon loads on unsupported hardware like the Dell XPS 17 9710, an error message is printed. This might confuse users, as drivers are expected to be silent if no supported hardware is found. Reorder the error message so its only printed when the driver is loaded with the "force" option being set. Also reword the error message slightly. Tested on a Dell Inspiron 3505. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20221130183418.357246-1-W_Armin@gmx.de Signed-off-by: Guenter Roeck --- drivers/hwmon/dell-smm-hwmon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 1572b54160158f..7ac778aedc68d1 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -1447,9 +1447,10 @@ static int __init i8k_init(void) */ if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { - pr_err("unable to get SMM Dell signature\n"); if (!force) return -ENODEV; + + pr_err("Unable to get Dell SMM signature\n"); } dell_smm_device = platform_create_bundle(&dell_smm_driver, dell_smm_probe, NULL, 0, NULL, -- cgit 1.2.3-korg From 4d50591ebf60ccf79380fff3a4c23659c61c482f Mon Sep 17 00:00:00 2001 From: Xingjiang Qiao Date: Tue, 6 Dec 2022 13:53:30 +0800 Subject: hwmon: (emc2305) fix unable to probe emc2301/2/3 The definitions of 'EMC2305_REG_PRODUCT_ID' and 'EMC2305_REG_DEVICE' are both '0xfd', they actually return the same value, but the values returned by emc2301/2/3/5 are different, so probe emc2301/2/3 will fail, This patch fixes that. Signed-off-by: Xingjiang Qiao Link: https://lore.kernel.org/r/20221206055331.170459-1-nanpuyue@gmail.com Fixes: 0d8400c5a2ce1 ("hwmon: (emc2305) add support for EMC2301/2/3/5 RPM-based PWM Fan Speed Controller.") Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2305.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index f222fcf3b6aa1c..232238e3231b01 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -16,7 +16,6 @@ static const unsigned short emc2305_normal_i2c[] = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_END }; #define EMC2305_REG_DRIVE_FAIL_STATUS 0x27 -#define EMC2305_REG_DEVICE 0xfd #define EMC2305_REG_VENDOR 0xfe #define EMC2305_FAN_MAX 0xff #define EMC2305_FAN_MIN 0x00 @@ -524,7 +523,7 @@ static int emc2305_probe(struct i2c_client *client) struct device *dev = &client->dev; struct emc2305_data *data; struct emc2305_platform_data *pdata; - int vendor, device; + int vendor; int ret; int i; @@ -535,10 +534,6 @@ static int emc2305_probe(struct i2c_client *client) if (vendor != EMC2305_VENDOR) return -ENODEV; - device = i2c_smbus_read_byte_data(client, EMC2305_REG_DEVICE); - if (device != EMC2305_DEVICE) - return -ENODEV; - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; -- cgit 1.2.3-korg From 364ffd2537c44cb6914ff5669153f4a86fffad29 Mon Sep 17 00:00:00 2001 From: Xingjiang Qiao Date: Tue, 6 Dec 2022 13:53:31 +0800 Subject: hwmon: (emc2305) fix pwm never being able to set lower There are fields 'last_hwmon_state' and 'last_thermal_state' in the structure 'emc2305_cdev_data', which respectively store the cooling state set by the 'hwmon' and 'thermal' subsystem, and the driver author hopes that if the state set by 'hwmon' is lower than the value set by 'thermal', the driver will just save it without actually setting the pwm. Currently, the 'last_thermal_state' also be updated by 'hwmon', which will cause the cooling state to never be set to a lower value. This patch fixes that. Signed-off-by: Xingjiang Qiao Link: https://lore.kernel.org/r/20221206055331.170459-2-nanpuyue@gmail.com Fixes: 0d8400c5a2ce1 ("hwmon: (emc2305) add support for EMC2301/2/3/5 RPM-based PWM Fan Speed Controller.") [groeck: renamed emc2305_set_cur_state_shim -> __emc2305_set_cur_state] Signed-off-by: Guenter Roeck --- drivers/hwmon/emc2305.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 232238e3231b01..6ad055e5868e6c 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -171,22 +171,12 @@ static int emc2305_get_max_state(struct thermal_cooling_device *cdev, unsigned l return 0; } -static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) +static int __emc2305_set_cur_state(struct emc2305_data *data, int cdev_idx, unsigned long state) { - int cdev_idx, ret; - struct emc2305_data *data = cdev->devdata; + int ret; struct i2c_client *client = data->client; u8 val, i; - if (state > data->max_state) - return -EINVAL; - - cdev_idx = emc2305_get_cdev_idx(cdev); - if (cdev_idx < 0) - return cdev_idx; - - /* Save thermal state. */ - data->cdev_data[cdev_idx].last_thermal_state = state; state = max_t(unsigned long, state, data->cdev_data[cdev_idx].last_hwmon_state); val = EMC2305_PWM_STATE2DUTY(state, data->max_state, EMC2305_FAN_MAX); @@ -211,6 +201,27 @@ static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned l return 0; } +static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) +{ + int cdev_idx, ret; + struct emc2305_data *data = cdev->devdata; + + if (state > data->max_state) + return -EINVAL; + + cdev_idx = emc2305_get_cdev_idx(cdev); + if (cdev_idx < 0) + return cdev_idx; + + /* Save thermal state. */ + data->cdev_data[cdev_idx].last_thermal_state = state; + ret = __emc2305_set_cur_state(data, cdev_idx, state); + if (ret < 0) + return ret; + + return 0; +} + static const struct thermal_cooling_device_ops emc2305_cooling_ops = { .get_max_state = emc2305_get_max_state, .get_cur_state = emc2305_get_cur_state, @@ -401,7 +412,7 @@ emc2305_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int ch */ if (data->cdev_data[cdev_idx].last_hwmon_state >= data->cdev_data[cdev_idx].last_thermal_state) - return emc2305_set_cur_state(data->cdev_data[cdev_idx].cdev, + return __emc2305_set_cur_state(data, cdev_idx, data->cdev_data[cdev_idx].last_hwmon_state); return 0; } -- cgit 1.2.3-korg