From 9e444234b6d8de48e9032f47997773cd98d863a5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 10 Jun 2020 13:36:38 +0100 Subject: hwmon: (i5k_amb) remove redundant assignment to variable res The variable res is being initialized with a value that is never read and it is being updated later with a new value. The initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20200610123638.1133428-1-colin.king@canonical.com Signed-off-by: Guenter Roeck --- drivers/hwmon/i5k_amb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index eeac4b04df27..cd5b62905eee 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -396,7 +396,7 @@ exit_remove: static int i5k_amb_add(void) { - int res = -ENODEV; + int res; /* only ever going to be one of these */ amb_pdev = platform_device_alloc(DRVNAME, 0); -- cgit v1.2.3 From 23fd63a44460cda2e09703b625fa2fbcf2a27000 Mon Sep 17 00:00:00 2001 From: Wang Qing Date: Sat, 13 Jun 2020 16:06:44 +0800 Subject: hwmon: (nct6683) Replace container_of() with kobj_to_dev() Use kobj_to_dev() instead of container_of(). Signed-off-by: Wang Qing Link: https://lore.kernel.org/r/1592035604-22336-1-git-send-email-wangqing@vivo.com Signed-off-by: Guenter Roeck --- drivers/hwmon/nct6683.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index c0229152296f..2d299149f4d2 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -674,7 +674,7 @@ show_in_reg(struct device *dev, struct device_attribute *attr, char *buf) static umode_t nct6683_in_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct nct6683_data *data = dev_get_drvdata(dev); int nr = index % 4; /* attribute */ @@ -739,7 +739,7 @@ show_fan_pulses(struct device *dev, struct device_attribute *attr, char *buf) static umode_t nct6683_fan_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct nct6683_data *data = dev_get_drvdata(dev); int fan = index / 3; /* fan index */ int nr = index % 3; /* attribute index */ @@ -857,7 +857,7 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) static umode_t nct6683_temp_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct nct6683_data *data = dev_get_drvdata(dev); int temp = index / 7; /* temp index */ int nr = index % 7; /* attribute index */ @@ -944,7 +944,7 @@ SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, store_pwm, 0); static umode_t nct6683_pwm_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct nct6683_data *data = dev_get_drvdata(dev); int pwm = index; /* pwm index */ -- cgit v1.2.3 From 0ca8bb2cc9606beec6833e5e4742c882e2196bda Mon Sep 17 00:00:00 2001 From: Jeffrey Lin Date: Sun, 21 Jun 2020 00:52:48 -0400 Subject: hwmon: (dell-smm) Add Latitude 5480 to fan control whitelist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows manual PWM control without the BIOS fighting back on Dell Latitude 5480. Signed-off-by: Jeffrey Lin Acked-by: Pali Rohár Link: https://lore.kernel.org/r/20200621045246.929649-1-jeffrey@icurse.nl Signed-off-by: Guenter Roeck --- drivers/hwmon/dell-smm-hwmon.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 16be012a95ed..ec448f5f2dc3 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -1187,6 +1187,14 @@ static struct dmi_system_id i8k_whitelist_fan_control[] __initdata = { }, .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], }, + { + .ident = "Dell Latitude 5480", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude 5480"), + }, + .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], + }, { .ident = "Dell Latitude E6440", .matches = { -- cgit v1.2.3 From a37881dead2503614b837c005efde05e614d3b69 Mon Sep 17 00:00:00 2001 From: Manikandan Elumalai Date: Mon, 22 Jun 2020 21:07:27 +0530 Subject: hwmon: (adm1275) Enable adm1278 ADM1278_TEMP1_EN The adm1278 temp attribute need it for openbmc platform . This feature not enabled by default, so PMON_CONFIG needs to enable it. Signed-off-by: Manikandan Elumalai Link: https://lore.kernel.org/r/20200622153727.GA9347@cnn [groeck: Split long line] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/adm1275.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 19317575d1c6..651846650a9c 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -683,11 +683,13 @@ static int adm1275_probe(struct i2c_client *client, tindex = 3; info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | - PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; - /* Enable VOUT if not enabled (it is disabled by default) */ - if (!(config & ADM1278_VOUT_EN)) { - config |= ADM1278_VOUT_EN; + /* Enable VOUT & TEMP1 if not enabled (disabled by default) */ + if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) != + (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) { + config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN; ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG, config); @@ -698,9 +700,6 @@ static int adm1275_probe(struct i2c_client *client, } } - if (config & ADM1278_TEMP1_EN) - info->func[0] |= - PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; if (config & ADM1278_VIN_EN) info->func[0] |= PMBUS_HAVE_VIN; break; -- cgit v1.2.3 From a4872f7a4bc16d6ed831833b4f1ec16df642c367 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 9 Jun 2020 07:57:20 -0700 Subject: hwmon: (gsc) add 16bit pre-scaled voltage mode add a 16-bit pre-scaled voltage mode to adc and clarify that existing pre-scaled mode is 24bit. Signed-off-by: Tim Harvey Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/1591714640-10332-3-git-send-email-tharvey@gateworks.com Signed-off-by: Guenter Roeck --- drivers/hwmon/gsc-hwmon.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index 2137bc65829d..3dfe2ca2f8c8 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -159,7 +159,7 @@ gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, return -EOPNOTSUPP; } - sz = (ch->mode == mode_voltage) ? 3 : 2; + sz = (ch->mode == mode_voltage_24bit) ? 3 : 2; ret = regmap_bulk_read(hwmon->regmap, ch->reg, buf, sz); if (ret) return ret; @@ -186,7 +186,8 @@ gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, /* adjust by uV offset */ tmp += ch->mvoffset; break; - case mode_voltage: + case mode_voltage_24bit: + case mode_voltage_16bit: /* no adjustment needed */ break; } @@ -336,7 +337,8 @@ static int gsc_hwmon_probe(struct platform_device *pdev) HWMON_T_LABEL; i_temp++; break; - case mode_voltage: + case mode_voltage_24bit: + case mode_voltage_16bit: case mode_voltage_raw: if (i_in == GSC_HWMON_MAX_IN_CH) { dev_err(gsc->dev, "too many input channels\n"); -- cgit v1.2.3 From 5c9353f5f81340f350320b5fcfc4c09756ba6da4 Mon Sep 17 00:00:00 2001 From: Ugur Usug Date: Mon, 15 Jun 2020 23:49:14 +0000 Subject: hwmon: (pmbus/max20730) Add max20710 support Add support for max20710 into the existing max20730 driver. Signed-off-by: Ugur Usug Link: https://lore.kernel.org/r/BYAPR11MB317423C13909AE6F1913BBD7FD9C0@BYAPR11MB3174.namprd11.prod.outlook.com [groeck: Fixed various whitespace errors] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/Kconfig | 4 ++-- drivers/hwmon/pmbus/max20730.c | 49 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index ea516cec1d35..e35db489b76f 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -156,10 +156,10 @@ config SENSORS_MAX16601 be called max16601. config SENSORS_MAX20730 - tristate "Maxim MAX20730, MAX20734, MAX20743" + tristate "Maxim MAX20710, MAX20730, MAX20734, MAX20743" help If you say yes here you get hardware monitoring support for Maxim - MAX20730, MAX20734, and MAX20743. + MAX20710, MAX20730, MAX20734, and MAX20743. This driver can also be built as a module. If so, the module will be called max20730. diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index c0bb05487e0e..a151a2b588a5 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Driver for MAX20730, MAX20734, and MAX20743 Integrated, Step-Down - * Switching Regulators + * Driver for MAX20710, MAX20730, MAX20734, and MAX20743 Integrated, + * Step-Down Switching Regulators * * Copyright 2019 Google LLC. + * Copyright 2020 Maxim Integrated */ #include @@ -19,6 +20,7 @@ #include "pmbus.h" enum chips { + max20710, max20730, max20734, max20743 @@ -80,6 +82,7 @@ static long direct_to_val(u16 w, enum pmbus_sensor_classes class, } static u32 max_current[][5] = { + [max20710] = { 6200, 8000, 9700, 11600 }, [max20730] = { 13000, 16600, 20100, 23600 }, [max20734] = { 21000, 27000, 32000, 38000 }, [max20743] = { 18900, 24100, 29200, 34100 }, @@ -164,6 +167,35 @@ static int max20730_write_word_data(struct i2c_client *client, int page, } static const struct pmbus_driver_info max20730_info[] = { + [max20710] = { + .pages = 1, + .read_word_data = max20730_read_word_data, + .write_word_data = max20730_write_word_data, + + /* Source : Maxim AN6140 and AN6042 */ + .format[PSC_TEMPERATURE] = direct, + .m[PSC_TEMPERATURE] = 21, + .b[PSC_TEMPERATURE] = 5887, + .R[PSC_TEMPERATURE] = -1, + + .format[PSC_VOLTAGE_IN] = direct, + .m[PSC_VOLTAGE_IN] = 3609, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = -2, + + .format[PSC_CURRENT_OUT] = direct, + .m[PSC_CURRENT_OUT] = 153, + .b[PSC_CURRENT_OUT] = 4976, + .R[PSC_CURRENT_OUT] = -1, + + .format[PSC_VOLTAGE_OUT] = linear, + + .func[0] = PMBUS_HAVE_VIN | + PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_INPUT, + }, [max20730] = { .pages = 1, .read_word_data = max20730_read_word_data, @@ -200,7 +232,8 @@ static const struct pmbus_driver_info max20730_info[] = { .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | - PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_INPUT, }, [max20734] = { .pages = 1, @@ -228,7 +261,8 @@ static const struct pmbus_driver_info max20730_info[] = { .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | - PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_INPUT, }, [max20743] = { .pages = 1, @@ -256,7 +290,8 @@ static const struct pmbus_driver_info max20730_info[] = { .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | - PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_INPUT, }, }; @@ -339,6 +374,7 @@ static int max20730_probe(struct i2c_client *client, } static const struct i2c_device_id max20730_id[] = { + { "max20710", max20710 }, { "max20730", max20730 }, { "max20734", max20734 }, { "max20743", max20743 }, @@ -348,6 +384,7 @@ static const struct i2c_device_id max20730_id[] = { MODULE_DEVICE_TABLE(i2c, max20730_id); static const struct of_device_id max20730_of_match[] = { + { .compatible = "maxim,max20710", .data = (void *)max20710 }, { .compatible = "maxim,max20730", .data = (void *)max20730 }, { .compatible = "maxim,max20734", .data = (void *)max20734 }, { .compatible = "maxim,max20743", .data = (void *)max20743 }, @@ -369,5 +406,5 @@ static struct i2c_driver max20730_driver = { module_i2c_driver(max20730_driver); MODULE_AUTHOR("Guenter Roeck "); -MODULE_DESCRIPTION("PMBus driver for Maxim MAX20730 / MAX20734 / MAX20743"); +MODULE_DESCRIPTION("PMBus driver for Maxim MAX20710 / MAX20730 / MAX20734 / MAX20743"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8ba75b2028496777a7d595ed5ba03cc85f86bdbb Mon Sep 17 00:00:00 2001 From: Josh Lehan Date: Thu, 25 Jun 2020 17:13:43 -0700 Subject: hwmon: (pmbus/core) Use s64 instead of long for calculations Using s64 type, instead of long type, for internal calculations and for the sysfs interface. This allows 64-bit values to appear correctly on 32-bit kernels. As wattage is reported in microwatts, monitoring a power supply over 2KW requires this. Although it may seem unlikely to run a 32-bit kernel on such a large machine, enterprise servers often include a BMC, and the BMC might be running a 32-bit kernel. Signed-off-by: Josh Lehan [groeck: Removed Change-Id and other tags, reformatted description] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 66 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 2191575a448b..44535add3a4a 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -628,12 +628,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) * Convert linear sensor values to milli- or micro-units * depending on sensor type. */ -static long pmbus_reg2data_linear(struct pmbus_data *data, - struct pmbus_sensor *sensor) +static s64 pmbus_reg2data_linear(struct pmbus_data *data, + struct pmbus_sensor *sensor) { s16 exponent; s32 mantissa; - long val; + s64 val; if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ exponent = data->exponent[sensor->page]; @@ -647,11 +647,11 @@ static long pmbus_reg2data_linear(struct pmbus_data *data, /* scale result to milli-units for all sensors except fans */ if (sensor->class != PSC_FAN) - val = val * 1000L; + val = val * 1000LL; /* scale result to micro-units for power sensors */ if (sensor->class == PSC_POWER) - val = val * 1000L; + val = val * 1000LL; if (exponent >= 0) val <<= exponent; @@ -665,8 +665,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data, * Convert direct sensor values to milli- or micro-units * depending on sensor type. */ -static long pmbus_reg2data_direct(struct pmbus_data *data, - struct pmbus_sensor *sensor) +static s64 pmbus_reg2data_direct(struct pmbus_data *data, + struct pmbus_sensor *sensor) { s64 b, val = (s16)sensor->data; s32 m, R; @@ -702,15 +702,15 @@ static long pmbus_reg2data_direct(struct pmbus_data *data, } val = div_s64(val - b, m); - return clamp_val(val, LONG_MIN, LONG_MAX); + return val; } /* * Convert VID sensor values to milli- or micro-units * depending on sensor type. */ -static long pmbus_reg2data_vid(struct pmbus_data *data, - struct pmbus_sensor *sensor) +static s64 pmbus_reg2data_vid(struct pmbus_data *data, + struct pmbus_sensor *sensor) { long val = sensor->data; long rv = 0; @@ -740,9 +740,9 @@ static long pmbus_reg2data_vid(struct pmbus_data *data, return rv; } -static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) +static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) { - long val; + s64 val; if (!sensor->convert) return sensor->data; @@ -766,7 +766,7 @@ static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) #define MIN_MANTISSA (511 * 1000) static u16 pmbus_data2reg_linear(struct pmbus_data *data, - struct pmbus_sensor *sensor, long val) + struct pmbus_sensor *sensor, s64 val) { s16 exponent = 0, mantissa; bool negative = false; @@ -788,8 +788,8 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, val <<= -data->exponent[sensor->page]; else val >>= data->exponent[sensor->page]; - val = DIV_ROUND_CLOSEST(val, 1000); - return val & 0xffff; + val = DIV_ROUND_CLOSEST_ULL(val, 1000); + return clamp_val(val, 0, 0xffff); } if (val < 0) { @@ -799,14 +799,14 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, /* Power is in uW. Convert to mW before converting. */ if (sensor->class == PSC_POWER) - val = DIV_ROUND_CLOSEST(val, 1000L); + val = DIV_ROUND_CLOSEST_ULL(val, 1000); /* * For simplicity, convert fan data to milli-units * before calculating the exponent. */ if (sensor->class == PSC_FAN) - val = val * 1000; + val = val * 1000LL; /* Reduce large mantissa until it fits into 10 bit */ while (val >= MAX_MANTISSA && exponent < 15) { @@ -820,11 +820,7 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, } /* Convert mantissa from milli-units to units */ - mantissa = DIV_ROUND_CLOSEST(val, 1000); - - /* Ensure that resulting number is within range */ - if (mantissa > 0x3ff) - mantissa = 0x3ff; + mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff); /* restore sign */ if (negative) @@ -835,9 +831,9 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, } static u16 pmbus_data2reg_direct(struct pmbus_data *data, - struct pmbus_sensor *sensor, long val) + struct pmbus_sensor *sensor, s64 val) { - s64 b, val64 = val; + s64 b; s32 m, R; m = data->info->m[sensor->class]; @@ -855,30 +851,30 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data, R -= 3; /* Adjust R and b for data in milli-units */ b *= 1000; } - val64 = val64 * m + b; + val = val * m + b; while (R > 0) { - val64 *= 10; + val *= 10; R--; } while (R < 0) { - val64 = div_s64(val64 + 5LL, 10L); /* round closest */ + val = div_s64(val + 5LL, 10L); /* round closest */ R++; } - return (u16)clamp_val(val64, S16_MIN, S16_MAX); + return (u16)clamp_val(val, S16_MIN, S16_MAX); } static u16 pmbus_data2reg_vid(struct pmbus_data *data, - struct pmbus_sensor *sensor, long val) + struct pmbus_sensor *sensor, s64 val) { val = clamp_val(val, 500, 1600); - return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625); + return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); } static u16 pmbus_data2reg(struct pmbus_data *data, - struct pmbus_sensor *sensor, long val) + struct pmbus_sensor *sensor, s64 val) { u16 regval; @@ -944,7 +940,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); return 0; } else { - long v1, v2; + s64 v1, v2; if (s1->data < 0) return s1->data; @@ -981,7 +977,7 @@ static ssize_t pmbus_show_sensor(struct device *dev, if (sensor->data < 0) return sensor->data; - return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor)); + return snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor)); } static ssize_t pmbus_set_sensor(struct device *dev, @@ -992,11 +988,11 @@ static ssize_t pmbus_set_sensor(struct device *dev, struct pmbus_data *data = i2c_get_clientdata(client); struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); ssize_t rv = count; - long val = 0; + s64 val; int ret; u16 regval; - if (kstrtol(buf, 10, &val) < 0) + if (kstrtos64(buf, 10, &val) < 0) return -EINVAL; mutex_lock(&data->update_lock); -- cgit v1.2.3 From e263f2d3c2bc0985025d4996b4f92cb4f18265b7 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Fri, 3 Jul 2020 20:56:57 +0200 Subject: hwmon: (tmmp513) Replace HTTP links with HTTPS links Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Link: https://lore.kernel.org/r/20200703185657.15329-1-grandmaster@al2klimov.de Signed-off-by: Guenter Roeck --- drivers/hwmon/tmp513.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index df66e0bc1253..23908dc5611b 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -5,12 +5,12 @@ * TMP513: * Thermal/Power Management with Triple Remote and * Local Temperature Sensor and Current Shunt Monitor - * Datasheet: http://www.ti.com/lit/gpn/tmp513 + * Datasheet: https://www.ti.com/lit/gpn/tmp513 * * TMP512: * Thermal/Power Management with Dual Remote * and Local Temperature Sensor and Current Shunt Monitor - * Datasheet: http://www.ti.com/lit/gpn/tmp512 + * Datasheet: https://www.ti.com/lit/gpn/tmp512 * * Copyright (C) 2019 Eric Tremblay * -- cgit v1.2.3 From a686024e18bdce5724468c7f1703c35de299dd80 Mon Sep 17 00:00:00 2001 From: Chu Lin Date: Tue, 7 Jul 2020 17:15:28 +0000 Subject: hwmon: (max6697) Allow max6581 to create tempX_offset Add tempX_offset attribute support to max6697 driver. Temperature offsets are only supported for MAX6581. Testing: echo 16250 > temp2_offset cat temp2_offset 16250 echo 17500 > temp3_offset cat temp3_offset 17500 cat temp4_offset 0 cat temp2_offset 17500 echo 0 > temp2_offset cat temp2_offset 0 cat temp3_offset 17500 echo -0 > temp2_offset cat temp2_offset 0 echo -100000 > temp2_offset cat temp2_input 4875 echo 10000 > temp2_offset cat temp2_input 47125 echo -2000 > temp2_offset cat temp2_input 34875 echo -0 > temp2_offset cat temp2_input 37000 Signed-off-by: Chu Lin Link: https://lore.kernel.org/r/20200707171528.2929275-1-linchuyuan@google.com [groeck: Fixed checkpatch warning (unnecessary { })] Signed-off-by: Guenter Roeck --- drivers/hwmon/max6697.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 64122eb38060..58781d999caa 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -57,6 +57,8 @@ static const u8 MAX6697_REG_CRIT[] = { #define MAX6581_REG_IDEALITY_SELECT 0x4c #define MAX6581_REG_OFFSET 0x4d #define MAX6581_REG_OFFSET_SELECT 0x4e +#define MAX6581_OFFSET_MIN -31750 +#define MAX6581_OFFSET_MAX 31750 #define MAX6697_CONV_TIME 156 /* ms per channel, worst case */ @@ -172,6 +174,11 @@ static const struct max6697_chip_data max6697_chip_data[] = { }, }; +static inline int max6581_offset_to_millic(int val) +{ + return sign_extend32(val, 7) * 250; +} + static struct max6697_data *max6697_update_device(struct device *dev) { struct max6697_data *data = dev_get_drvdata(dev); @@ -317,6 +324,70 @@ static ssize_t temp_store(struct device *dev, return ret < 0 ? ret : count; } +static ssize_t offset_store(struct device *dev, struct device_attribute *devattr, const char *buf, + size_t count) +{ + int val, ret, index, select; + struct max6697_data *data; + bool channel_enabled; + long temp; + + index = to_sensor_dev_attr(devattr)->index; + data = dev_get_drvdata(dev); + ret = kstrtol(buf, 10, &temp); + if (ret < 0) + return ret; + + mutex_lock(&data->update_lock); + select = i2c_smbus_read_byte_data(data->client, MAX6581_REG_OFFSET_SELECT); + if (select < 0) { + ret = select; + goto abort; + } + channel_enabled = (select & (1 << (index - 1))); + temp = clamp_val(temp, MAX6581_OFFSET_MIN, MAX6581_OFFSET_MAX); + val = DIV_ROUND_CLOSEST(temp, 250); + /* disable the offset for channel if the new offset is 0 */ + if (val == 0) { + if (channel_enabled) + ret = i2c_smbus_write_byte_data(data->client, MAX6581_REG_OFFSET_SELECT, + select & ~(1 << (index - 1))); + ret = ret < 0 ? ret : count; + goto abort; + } + if (!channel_enabled) { + ret = i2c_smbus_write_byte_data(data->client, MAX6581_REG_OFFSET_SELECT, + select | (1 << (index - 1))); + if (ret < 0) + goto abort; + } + ret = i2c_smbus_write_byte_data(data->client, MAX6581_REG_OFFSET, val); + ret = ret < 0 ? ret : count; + +abort: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t offset_show(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct max6697_data *data; + int select, ret, index; + + index = to_sensor_dev_attr(devattr)->index; + data = dev_get_drvdata(dev); + mutex_lock(&data->update_lock); + select = i2c_smbus_read_byte_data(data->client, MAX6581_REG_OFFSET_SELECT); + if (select < 0) + ret = select; + else if (select & (1 << (index - 1))) + ret = i2c_smbus_read_byte_data(data->client, MAX6581_REG_OFFSET); + else + ret = 0; + mutex_unlock(&data->update_lock); + return ret < 0 ? ret : sprintf(buf, "%d\n", max6581_offset_to_millic(ret)); +} + static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0); static SENSOR_DEVICE_ATTR_2_RW(temp1_max, temp, 0, MAX6697_TEMP_MAX); static SENSOR_DEVICE_ATTR_2_RW(temp1_crit, temp, 0, MAX6697_TEMP_CRIT); @@ -375,6 +446,15 @@ static SENSOR_DEVICE_ATTR_RO(temp6_fault, alarm, 5); static SENSOR_DEVICE_ATTR_RO(temp7_fault, alarm, 6); static SENSOR_DEVICE_ATTR_RO(temp8_fault, alarm, 7); +/* There is no offset for local temperature so starting from temp2 */ +static SENSOR_DEVICE_ATTR_RW(temp2_offset, offset, 1); +static SENSOR_DEVICE_ATTR_RW(temp3_offset, offset, 2); +static SENSOR_DEVICE_ATTR_RW(temp4_offset, offset, 3); +static SENSOR_DEVICE_ATTR_RW(temp5_offset, offset, 4); +static SENSOR_DEVICE_ATTR_RW(temp6_offset, offset, 5); +static SENSOR_DEVICE_ATTR_RW(temp7_offset, offset, 6); +static SENSOR_DEVICE_ATTR_RW(temp8_offset, offset, 7); + static DEVICE_ATTR(dummy, 0, NULL, NULL); static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr, @@ -383,8 +463,8 @@ static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr, struct device *dev = container_of(kobj, struct device, kobj); struct max6697_data *data = dev_get_drvdata(dev); const struct max6697_chip_data *chip = data->chip; - int channel = index / 6; /* channel number */ - int nr = index % 6; /* attribute index within channel */ + int channel = index / 7; /* channel number */ + int nr = index % 7; /* attribute index within channel */ if (channel >= chip->channels) return 0; @@ -393,6 +473,10 @@ static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr, return 0; if (nr == 5 && !(chip->have_fault & (1 << channel))) return 0; + /* offset reg is only supported on max6581 remote channels */ + if (nr == 6) + if (data->type != max6581 || channel == 0) + return 0; return attr->mode; } @@ -409,6 +493,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, &dev_attr_dummy.attr, + &dev_attr_dummy.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, @@ -416,6 +501,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, @@ -423,6 +509,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp3_crit.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, &sensor_dev_attr_temp4_input.dev_attr.attr, &sensor_dev_attr_temp4_max.dev_attr.attr, @@ -430,6 +517,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp4_crit.dev_attr.attr, &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp4_fault.dev_attr.attr, + &sensor_dev_attr_temp4_offset.dev_attr.attr, &sensor_dev_attr_temp5_input.dev_attr.attr, &sensor_dev_attr_temp5_max.dev_attr.attr, @@ -437,6 +525,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp5_crit.dev_attr.attr, &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp5_fault.dev_attr.attr, + &sensor_dev_attr_temp5_offset.dev_attr.attr, &sensor_dev_attr_temp6_input.dev_attr.attr, &sensor_dev_attr_temp6_max.dev_attr.attr, @@ -444,6 +533,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp6_crit.dev_attr.attr, &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp6_fault.dev_attr.attr, + &sensor_dev_attr_temp6_offset.dev_attr.attr, &sensor_dev_attr_temp7_input.dev_attr.attr, &sensor_dev_attr_temp7_max.dev_attr.attr, @@ -451,6 +541,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp7_crit.dev_attr.attr, &sensor_dev_attr_temp7_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp7_fault.dev_attr.attr, + &sensor_dev_attr_temp7_offset.dev_attr.attr, &sensor_dev_attr_temp8_input.dev_attr.attr, &sensor_dev_attr_temp8_max.dev_attr.attr, @@ -458,6 +549,7 @@ static struct attribute *max6697_attributes[] = { &sensor_dev_attr_temp8_crit.dev_attr.attr, &sensor_dev_attr_temp8_crit_alarm.dev_attr.attr, &sensor_dev_attr_temp8_fault.dev_attr.attr, + &sensor_dev_attr_temp8_offset.dev_attr.attr, NULL }; -- cgit v1.2.3 From 40c3a445422579db8ad96c234dbe6c0ab3f6b936 Mon Sep 17 00:00:00 2001 From: Marius Zachmann Date: Fri, 26 Jun 2020 07:59:36 +0200 Subject: hwmon: add Corsair Commander Pro driver This is v7 of a driver for the Corsair Commander Pro. It provides sysfs attributes for: - Reading fan speed - Reading temp sensors - Reading voltage values - Writing pwm and reading last written pwm - Reading fan and temp connection status It is an usb driver, so it needs to be ignored by usbhid. The Corsair Commander Pro is a fan controller and provides no means for user interaction. The two device numbers are there, because there is a slightly different version of the same device. (Only difference seem to be in some presets.) Squashed: hwmon: (corsair-cpro) add fan_target This adds fan_target entries to the corsair-cpro driver. Reading the attribute from the device does not seem possible, so it returns the last set value (same as pwm). send_usb_cmd now has one more argument, which is needed for the fan_target command. hwmon: corsair-cpro: Change to HID driver This changes corsair-cpro to a hid driver using hid reports. Signed-off-by: Marius Zachmann Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200626055936.4441-1-mail@mariuszachmann.de Link: https://lore.kernel.org/r/20200709141413.30790-1-mail@mariuszachmann.de [groeck: Squashed follow-up patches to avoid changes in HID code] Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 10 + drivers/hwmon/Makefile | 1 + drivers/hwmon/corsair-cpro.c | 558 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 569 insertions(+) create mode 100644 drivers/hwmon/corsair-cpro.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 288ae9f63588..7b11d622b82d 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -439,6 +439,16 @@ config SENSORS_BT1_PVT_ALARMS the data conversion will be periodically performed and the data will be saved in the internal driver cache. +config SENSORS_CORSAIR_CPRO + tristate "Corsair Commander Pro controller" + depends on HID + help + If you say yes here you get support for the Corsair Commander Pro + controller. + + This driver can also be built as a module. If so, the module + will be called corsair-cpro. + config SENSORS_DRIVETEMP tristate "Hard disk drives with temperature sensors" depends on SCSI && ATA diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 3e32c21f5efe..18e1ef74ade7 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o obj-$(CONFIG_SENSORS_BT1_PVT) += bt1-pvt.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o +obj-$(CONFIG_SENSORS_CORSAIR_CPRO) += corsair-cpro.o obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c new file mode 100644 index 000000000000..e8504267d0e8 --- /dev/null +++ b/drivers/hwmon/corsair-cpro.c @@ -0,0 +1,558 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * corsair-cpro.c - Linux driver for Corsair Commander Pro + * Copyright (C) 2020 Marius Zachmann + * + * This driver uses hid reports to communicate with the device to allow hidraw userspace drivers + * still being used. The device does not use report ids. When using hidraw and this driver + * simultaniously, reports could be switched. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USB_VENDOR_ID_CORSAIR 0x1b1c +#define USB_PRODUCT_ID_CORSAIR_COMMANDERPRO 0x0c10 +#define USB_PRODUCT_ID_CORSAIR_1000D 0x1d00 + +#define OUT_BUFFER_SIZE 63 +#define IN_BUFFER_SIZE 16 +#define LABEL_LENGTH 11 +#define REQ_TIMEOUT 300 + +#define CTL_GET_TMP_CNCT 0x10 /* + * returns in bytes 1-4 for each temp sensor: + * 0 not connected + * 1 connected + */ +#define CTL_GET_TMP 0x11 /* + * send: byte 1 is channel, rest zero + * rcv: returns temp for channel in centi-degree celsius + * in bytes 1 and 2 + * returns 17 in byte 0 if no sensor is connected + */ +#define CTL_GET_VOLT 0x12 /* + * send: byte 1 is rail number: 0 = 12v, 1 = 5v, 2 = 3.3v + * rcv: returns millivolt in bytes 1,2 + */ +#define CTL_GET_FAN_CNCT 0x20 /* + * returns in bytes 1-6 for each fan: + * 0 not connected + * 1 3pin + * 2 4pin + */ +#define CTL_GET_FAN_RPM 0x21 /* + * send: byte 1 is channel, rest zero + * rcv: returns rpm in bytes 1,2 + */ +#define CTL_SET_FAN_FPWM 0x23 /* + * set fixed pwm + * send: byte 1 is fan number + * send: byte 2 is percentage from 0 - 100 + */ +#define CTL_SET_FAN_TARGET 0x24 /* + * set target rpm + * send: byte 1 is fan number + * send: byte 2-3 is target + * device accepts all values from 0x00 - 0xFFFF + */ + +#define NUM_FANS 6 +#define NUM_TEMP_SENSORS 4 + +struct ccp_device { + struct hid_device *hdev; + struct device *hwmon_dev; + struct completion wait_input_report; + struct mutex mutex; /* whenever buffer is used, lock before send_usb_cmd */ + u8 *buffer; + int pwm[6]; + int target[6]; + DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS); + DECLARE_BITMAP(fan_cnct, NUM_FANS); + char fan_label[6][LABEL_LENGTH]; +}; + +/* send command, check for error in response, response in ccp->buffer */ +static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, u8 byte3) +{ + unsigned long t; + int ret; + + memset(ccp->buffer, 0x00, OUT_BUFFER_SIZE); + ccp->buffer[0] = command; + ccp->buffer[1] = byte1; + ccp->buffer[2] = byte2; + ccp->buffer[3] = byte3; + + reinit_completion(&ccp->wait_input_report); + + ret = hid_hw_output_report(ccp->hdev, ccp->buffer, OUT_BUFFER_SIZE); + if (ret < 0) + return ret; + + t = wait_for_completion_timeout(&ccp->wait_input_report, msecs_to_jiffies(REQ_TIMEOUT)); + if (!t) + return -ETIMEDOUT; + + /* first byte of response is error code */ + if (ccp->buffer[0] != 0x00) { + hid_dbg(ccp->hdev, "device response error: %d", ccp->buffer[0]); + return -EIO; + } + + return 0; +} + +static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) +{ + struct ccp_device *ccp = hid_get_drvdata(hdev); + + /* only copy buffer when requested */ + if (completion_done(&ccp->wait_input_report)) + return 0; + + memcpy(ccp->buffer, data, min(IN_BUFFER_SIZE, size)); + complete(&ccp->wait_input_report); + + return 0; +} + +/* requests and returns single data values depending on channel */ +static int get_data(struct ccp_device *ccp, int command, int channel) +{ + int ret; + + mutex_lock(&ccp->mutex); + + ret = send_usb_cmd(ccp, command, channel, 0, 0); + if (ret) + goto out_unlock; + + ret = (ccp->buffer[1] << 8) + ccp->buffer[2]; + +out_unlock: + mutex_unlock(&ccp->mutex); + return ret; +} + +static int set_pwm(struct ccp_device *ccp, int channel, long val) +{ + int ret; + + if (val < 0 || val > 255) + return -EINVAL; + + ccp->pwm[channel] = val; + + /* The Corsair Commander Pro uses values from 0-100 */ + val = DIV_ROUND_CLOSEST(val * 100, 255); + + mutex_lock(&ccp->mutex); + + ret = send_usb_cmd(ccp, CTL_SET_FAN_FPWM, channel, val, 0); + + mutex_unlock(&ccp->mutex); + return ret; +} + +static int set_target(struct ccp_device *ccp, int channel, long val) +{ + int ret; + + val = clamp_val(val, 0, 0xFFFF); + ccp->target[channel] = val; + + mutex_lock(&ccp->mutex); + + ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val); + + mutex_unlock(&ccp->mutex); + return ret; +} + +static int ccp_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + struct ccp_device *ccp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_label: + *str = ccp->fan_label[channel]; + return 0; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +} + +static int ccp_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct ccp_device *ccp = dev_get_drvdata(dev); + int ret; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + ret = get_data(ccp, CTL_GET_TMP, channel); + if (ret < 0) + return ret; + *val = ret * 10; + return 0; + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + ret = get_data(ccp, CTL_GET_FAN_RPM, channel); + if (ret < 0) + return ret; + *val = ret; + return 0; + case hwmon_fan_target: + /* how to read target values from the device is unknown */ + /* driver returns last set value or 0 */ + *val = ccp->target[channel]; + return 0; + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + /* how to read pwm values from the device is currently unknown */ + /* driver returns last set value or 0 */ + *val = ccp->pwm[channel]; + return 0; + default: + break; + } + break; + case hwmon_in: + switch (attr) { + case hwmon_in_input: + ret = get_data(ccp, CTL_GET_VOLT, channel); + if (ret < 0) + return ret; + *val = ret; + return 0; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +}; + +static int ccp_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct ccp_device *ccp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + return set_pwm(ccp, channel, val); + default: + break; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_target: + return set_target(ccp, channel, val); + default: + break; + } + default: + break; + } + + return -EOPNOTSUPP; +}; + +static umode_t ccp_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct ccp_device *ccp = data; + + switch (type) { + case hwmon_temp: + if (!test_bit(channel, ccp->temp_cnct)) + break; + + switch (attr) { + case hwmon_temp_input: + return 0444; + case hwmon_temp_label: + return 0444; + default: + break; + } + break; + case hwmon_fan: + if (!test_bit(channel, ccp->fan_cnct)) + break; + + switch (attr) { + case hwmon_fan_input: + return 0444; + case hwmon_fan_label: + return 0444; + case hwmon_fan_target: + return 0644; + default: + break; + } + break; + case hwmon_pwm: + if (!test_bit(channel, ccp->fan_cnct)) + break; + + switch (attr) { + case hwmon_pwm_input: + return 0644; + default: + break; + } + break; + case hwmon_in: + switch (attr) { + case hwmon_in_input: + return 0444; + default: + break; + } + break; + default: + break; + } + + return 0; +}; + +static const struct hwmon_ops ccp_hwmon_ops = { + .is_visible = ccp_is_visible, + .read = ccp_read, + .read_string = ccp_read_string, + .write = ccp_write, +}; + +static const struct hwmon_channel_info *ccp_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT, + HWMON_T_INPUT + ), + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_TARGET + ), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT + ), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT, + HWMON_I_INPUT, + HWMON_I_INPUT + ), + NULL +}; + +static const struct hwmon_chip_info ccp_chip_info = { + .ops = &ccp_hwmon_ops, + .info = ccp_info, +}; + +/* read fan connection status and set labels */ +static int get_fan_cnct(struct ccp_device *ccp) +{ + int channel; + int mode; + int ret; + + ret = send_usb_cmd(ccp, CTL_GET_FAN_CNCT, 0, 0, 0); + if (ret) + return ret; + + for (channel = 0; channel < NUM_FANS; channel++) { + mode = ccp->buffer[channel + 1]; + if (mode == 0) + continue; + + set_bit(channel, ccp->fan_cnct); + + switch (mode) { + case 1: + scnprintf(ccp->fan_label[channel], LABEL_LENGTH, + "fan%d 3pin", channel + 1); + break; + case 2: + scnprintf(ccp->fan_label[channel], LABEL_LENGTH, + "fan%d 4pin", channel + 1); + break; + default: + scnprintf(ccp->fan_label[channel], LABEL_LENGTH, + "fan%d other", channel + 1); + break; + } + } + + return 0; +} + +/* read temp sensor connection status */ +static int get_temp_cnct(struct ccp_device *ccp) +{ + int channel; + int mode; + int ret; + + ret = send_usb_cmd(ccp, CTL_GET_TMP_CNCT, 0, 0, 0); + if (ret) + return ret; + + for (channel = 0; channel < NUM_TEMP_SENSORS; channel++) { + mode = ccp->buffer[channel + 1]; + if (mode == 0) + continue; + + set_bit(channel, ccp->temp_cnct); + } + + return 0; +} + +static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + struct ccp_device *ccp; + int ret; + + ccp = devm_kzalloc(&hdev->dev, sizeof(*ccp), GFP_KERNEL); + if (!ccp) + return -ENOMEM; + + ccp->buffer = devm_kmalloc(&hdev->dev, OUT_BUFFER_SIZE, GFP_KERNEL); + if (!ccp->buffer) + return -ENOMEM; + + ret = hid_parse(hdev); + if (ret) + return ret; + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) + return ret; + + ret = hid_hw_open(hdev); + if (ret) + goto out_hw_stop; + + ccp->hdev = hdev; + hid_set_drvdata(hdev, ccp); + mutex_init(&ccp->mutex); + init_completion(&ccp->wait_input_report); + + hid_device_io_start(hdev); + + /* temp and fan connection status only updates when device is powered on */ + ret = get_temp_cnct(ccp); + if (ret) + goto out_hw_close; + + ret = get_fan_cnct(ccp); + if (ret) + goto out_hw_close; + ccp->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsaircpro", + ccp, &ccp_chip_info, 0); + if (IS_ERR(ccp->hwmon_dev)) { + ret = PTR_ERR(ccp->hwmon_dev); + goto out_hw_close; + } + + return 0; + +out_hw_close: + hid_hw_close(hdev); +out_hw_stop: + hid_hw_stop(hdev); + return ret; +} + +static void ccp_remove(struct hid_device *hdev) +{ + struct ccp_device *ccp = hid_get_drvdata(hdev); + + hwmon_device_unregister(ccp->hwmon_dev); + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +static const struct hid_device_id ccp_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_PRODUCT_ID_CORSAIR_COMMANDERPRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_PRODUCT_ID_CORSAIR_1000D) }, + { } +}; + +static struct hid_driver ccp_driver = { + .name = "corsair-cpro", + .id_table = ccp_devices, + .probe = ccp_probe, + .remove = ccp_remove, + .raw_event = ccp_raw_event, +}; + +MODULE_DEVICE_TABLE(hid, ccp_devices); +MODULE_LICENSE("GPL"); + +static int __init ccp_init(void) +{ + return hid_register_driver(&ccp_driver); +} + +static void __exit ccp_exit(void) +{ + hid_unregister_driver(&ccp_driver); +} + +/* + * When compiling this driver as built-in, hwmon initcalls will get called before the + * hid driver and this driver would fail to register. late_initcall solves this. + */ +late_initcall(ccp_init); +module_exit(ccp_exit); -- cgit v1.2.3 From 0303d06315564e113ffa345799ae2bbfbca6716e Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Mon, 13 Jul 2020 16:00:28 +0200 Subject: hwmon: (adm1025) Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Link: https://lore.kernel.org/r/20200713140028.34775-1-grandmaster@al2klimov.de Signed-off-by: Guenter Roeck --- drivers/hwmon/adm1025.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index ae7b96945185..ed15185fa60f 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -13,7 +13,7 @@ * resolution of about 0.5% of the nominal value). Temperature values are * reported with a 1 deg resolution and a 3 deg accuracy. Complete * datasheet can be obtained from Analog's website at: - * http://www.onsemi.com/PowerSolutions/product.do?id=ADM1025 + * https://www.onsemi.com/PowerSolutions/product.do?id=ADM1025 * * This driver also supports the ADM1025A, which differs from the ADM1025 * only in that it has "open-drain VID inputs while the ADM1025 has -- cgit v1.2.3 From ad736c1a4dcc6f0a26483619d7b4b232152c38fc Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 19 Jul 2020 19:55:12 +0200 Subject: hwmon: Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Link: https://lore.kernel.org/r/20200719175512.60745-1-grandmaster@al2klimov.de Signed-off-by: Guenter Roeck --- drivers/hwmon/adm1026.c | 2 +- drivers/hwmon/hwmon-vid.c | 6 +++--- drivers/hwmon/ina3221.c | 2 +- drivers/hwmon/lm87.c | 2 +- drivers/hwmon/powr1220.c | 2 +- drivers/hwmon/sht21.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index e0f630c64152..af77096724fd 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -7,7 +7,7 @@ * * Chip details at: * - * + * */ #include diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 8ae68dfa75b2..eb72e390844e 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -49,15 +49,15 @@ * The 13 specification corresponds to the Intel Pentium M series. There * doesn't seem to be any named specification for these. The conversion * tables are detailed directly in the various Pentium M datasheets: - * http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm + * https://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm * * The 14 specification corresponds to Intel Core series. There * doesn't seem to be any named specification for these. The conversion * tables are detailed directly in the various Pentium Core datasheets: - * http://www.intel.com/design/mobile/datashts/309221.htm + * https://www.intel.com/design/mobile/datashts/309221.htm * * The 110 (VRM 11) specification corresponds to Intel Conroe based series. - * http://www.intel.com/design/processor/applnots/313214.htm + * https://www.intel.com/design/processor/applnots/313214.htm */ /* diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index f335d0cb0c77..7fc5b065ad8b 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -2,7 +2,7 @@ /* * INA3221 Triple Current/Voltage Monitor * - * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis */ diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index ad501ac4a594..c96c4d807e38 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -40,7 +40,7 @@ * This driver also supports the ADM1024, a sensor chip made by Analog * Devices. That chip is fully compatible with the LM87. Complete * datasheet can be obtained from Analog's website at: - * http://www.analog.com/en/prod/0,2877,ADM1024,00.html + * https://www.analog.com/en/prod/0,2877,ADM1024,00.html */ #include diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index 65997421ee3c..a5d1a890d0be 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c @@ -4,7 +4,7 @@ * and monitor. Users can read all ADC inputs along with their labels * using the sysfs nodes. * - * Copyright (c) 2014 Echo360 http://www.echo360.com + * Copyright (c) 2014 Echo360 https://www.echo360.com * Scott Kanowitz */ diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index bc70c8332d9a..8ea5534455f2 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Urs Fleisch * - * Data sheet available at http://www.sensirion.com/file/datasheet_sht21 + * Data sheet available at https://www.sensirion.com/file/datasheet_sht21 */ #include -- cgit v1.2.3 From 009f429f6b0d8636a38b91545f373c752e320e64 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 19 Jul 2020 20:05:21 +0200 Subject: hwmon: (ina209) Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Link: https://lore.kernel.org/r/20200719180521.60811-1-grandmaster@al2klimov.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ina209.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c index 70ad1efcb3de..08ee3a64a026 100644 --- a/drivers/hwmon/ina209.c +++ b/drivers/hwmon/ina209.c @@ -14,7 +14,7 @@ * Thanks to Jan Volkering * * Datasheet: - * http://www.ti.com/lit/gpn/ina209 + * https://www.ti.com/lit/gpn/ina209 */ #include -- cgit v1.2.3 From 49dc2fb0e04679422369f54ff3ed720616ee7eb3 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Sun, 19 Jul 2020 20:15:30 +0200 Subject: hwmon: (ina2xx) Replace HTTP links with HTTPS ones Rationale: Reduces attack surface on kernel devs opening the links for MITM as HTTPS traffic is much harder to manipulate. Deterministic algorithm: For each file: If not .svg: For each line: If doesn't contain `\bxmlns\b`: For each link, `\bhttp://[^# \t\r\n]*(?:\w|/)`: If neither `\bgnu\.org/license`, nor `\bmozilla\.org/MPL\b`: If both the HTTP and HTTPS versions return 200 OK and serve the same content: Replace HTTP with HTTPS. Signed-off-by: Alexander A. Klimov Link: https://lore.kernel.org/r/20200719181530.60878-1-grandmaster@al2klimov.de Signed-off-by: Guenter Roeck --- drivers/hwmon/ina2xx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 55d474ec7c35..0fc6d5857993 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -4,19 +4,19 @@ * * INA219: * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface - * Datasheet: http://www.ti.com/product/ina219 + * Datasheet: https://www.ti.com/product/ina219 * * INA220: * Bi-Directional Current/Power Monitor with I2C Interface - * Datasheet: http://www.ti.com/product/ina220 + * Datasheet: https://www.ti.com/product/ina220 * * INA226: * Bi-Directional Current/Power Monitor with I2C Interface - * Datasheet: http://www.ti.com/product/ina226 + * Datasheet: https://www.ti.com/product/ina226 * * INA230: * Bi-directional Current/Power Monitor with I2C Interface - * Datasheet: http://www.ti.com/product/ina230 + * Datasheet: https://www.ti.com/product/ina230 * * Copyright (C) 2012 Lothar Felten * Thanks to Jan Volkering @@ -148,7 +148,7 @@ static const struct ina2xx_config ina2xx_config[] = { * Available averaging rates for ina226. The indices correspond with * the bit values expected by the chip (according to the ina226 datasheet, * table 3 AVG bit settings, found at - * http://www.ti.com/lit/ds/symlink/ina226.pdf. + * https://www.ti.com/lit/ds/symlink/ina226.pdf. */ static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 }; -- cgit v1.2.3 From e4922176e1669f174e101d321d76fdc1a134f7ac Mon Sep 17 00:00:00 2001 From: Lars Povlsen Date: Thu, 18 Jun 2020 15:59:51 +0200 Subject: hwmon: sparx5: Add Sparx5 SoC temperature driver This patch adds a temperature sensor driver to the Sparx5 SoC. Signed-off-by: Lars Povlsen Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20200618135951.25441-4-lars.povlsen@microchip.com Signed-off-by: Guenter Roeck --- drivers/hwmon/Kconfig | 10 +++ drivers/hwmon/Makefile | 1 + drivers/hwmon/sparx5-temp.c | 168 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 drivers/hwmon/sparx5-temp.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7b11d622b82d..8dc28b26916e 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -525,6 +525,16 @@ config SENSORS_I5K_AMB This driver can also be built as a module. If so, the module will be called i5k_amb. +config SENSORS_SPARX5 + tristate "Sparx5 SoC temperature sensor" + depends on ARCH_SPARX5 || COMPILE_TEST + help + If you say yes here you get support for temperature monitoring + with the Microchip Sparx5 SoC. + + This driver can also be built as a module. If so, the module + will be called sparx5-temp. + config SENSORS_F71805F tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG" depends on !PPC diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 18e1ef74ade7..a8f4b35b136b 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -168,6 +168,7 @@ obj-$(CONFIG_SENSORS_SMM665) += smm665.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o +obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o obj-$(CONFIG_SENSORS_STTS751) += stts751.o obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o obj-$(CONFIG_SENSORS_TC74) += tc74.o diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c new file mode 100644 index 000000000000..7d7a060259a8 --- /dev/null +++ b/drivers/hwmon/sparx5-temp.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Sparx5 SoC temperature sensor driver + * + * Copyright (C) 2020 Lars Povlsen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEMP_CTRL 0 +#define TEMP_CFG 4 +#define TEMP_CFG_CYCLES GENMASK(24, 15) +#define TEMP_CFG_ENA BIT(0) +#define TEMP_STAT 8 +#define TEMP_STAT_VALID BIT(12) +#define TEMP_STAT_TEMP GENMASK(11, 0) + +struct s5_hwmon { + void __iomem *base; + struct clk *clk; +}; + +static void s5_temp_clk_disable(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + +static void s5_temp_enable(struct s5_hwmon *hwmon) +{ + u32 val = readl(hwmon->base + TEMP_CFG); + u32 clk = clk_get_rate(hwmon->clk) / USEC_PER_SEC; + + val &= ~TEMP_CFG_CYCLES; + val |= FIELD_PREP(TEMP_CFG_CYCLES, clk); + val |= TEMP_CFG_ENA; + + writel(val, hwmon->base + TEMP_CFG); +} + +static int s5_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *temp) +{ + struct s5_hwmon *hwmon = dev_get_drvdata(dev); + int rc = 0, value; + u32 stat; + + switch (attr) { + case hwmon_temp_input: + stat = readl_relaxed(hwmon->base + TEMP_STAT); + if (!(stat & TEMP_STAT_VALID)) + return -EIO; + value = stat & TEMP_STAT_TEMP; + /* + * From register documentation: + * Temp(C) = TEMP_SENSOR_STAT.TEMP / 4096 * 352.2 - 109.4 + */ + value = DIV_ROUND_CLOSEST(value * 3522, 4096) - 1094; + /* + * Scale down by 10 from above and multiply by 1000 to + * have millidegrees as specified by the hwmon sysfs + * interface. + */ + value *= 100; + *temp = value; + break; + default: + rc = -EOPNOTSUPP; + break; + } + + return rc; +} + +static umode_t s5_is_visible(const void *_data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + return 0444; + default: + return 0; + } +} + +static const struct hwmon_channel_info *s5_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops s5_hwmon_ops = { + .is_visible = s5_is_visible, + .read = s5_read, +}; + +static const struct hwmon_chip_info s5_chip_info = { + .ops = &s5_hwmon_ops, + .info = s5_info, +}; + +static int s5_temp_probe(struct platform_device *pdev) +{ + struct device *hwmon_dev; + struct s5_hwmon *hwmon; + int ret; + + hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + hwmon->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hwmon->base)) + return PTR_ERR(hwmon->base); + + hwmon->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(hwmon->clk)) + return PTR_ERR(hwmon->clk); + + ret = clk_prepare_enable(hwmon->clk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&pdev->dev, s5_temp_clk_disable, + hwmon->clk); + if (ret) + return ret; + + s5_temp_enable(hwmon); + + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, + "s5_temp", + hwmon, + &s5_chip_info, + NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +const struct of_device_id s5_temp_match[] = { + { .compatible = "microchip,sparx5-temp" }, + {}, +}; +MODULE_DEVICE_TABLE(of, s5_temp_match); + +static struct platform_driver s5_temp_driver = { + .probe = s5_temp_probe, + .driver = { + .name = "sparx5-temp", + .of_match_table = s5_temp_match, + }, +}; + +module_platform_driver(s5_temp_driver); + +MODULE_AUTHOR("Lars Povlsen "); +MODULE_DESCRIPTION("Sparx5 SoC temperature sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From fa4dac3e1bf7fadb4c5e098dcd721eafe3cd80c5 Mon Sep 17 00:00:00 2001 From: Marius Zachmann Date: Tue, 21 Jul 2020 10:54:47 +0200 Subject: hwmon: (corsair-cpro) add reading pwm values This adds the possibility for reading pwm values. These can not be read if the device is controlled via fan_target or a fan curve and will return an error in this case. Since an error is expected, this adds some rudimentary error handling. Changes: - add CTL_GET_FAN_PWM and use it via get_data - pwm returns -ENODATA if the device returns error 0x12 - fan_target now returns -ENODATA when the driver is started or a pwm value is set. - add ccp_get_errno to determine errno from device error. - get_data now has a parameter to determine whether to read one or two bytes of data. - update documentation - fix missing surname in MAINTAINERS Signed-off-by: Marius Zachmann Signed-off-by: Guenter Roeck --- drivers/hwmon/corsair-cpro.c | 64 ++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c index e8504267d0e8..591929ec217a 100644 --- a/drivers/hwmon/corsair-cpro.c +++ b/drivers/hwmon/corsair-cpro.c @@ -36,11 +36,12 @@ * send: byte 1 is channel, rest zero * rcv: returns temp for channel in centi-degree celsius * in bytes 1 and 2 - * returns 17 in byte 0 if no sensor is connected + * returns 0x11 in byte 0 if no sensor is connected */ #define CTL_GET_VOLT 0x12 /* * send: byte 1 is rail number: 0 = 12v, 1 = 5v, 2 = 3.3v * rcv: returns millivolt in bytes 1,2 + * returns error 0x10 if request is invalid */ #define CTL_GET_FAN_CNCT 0x20 /* * returns in bytes 1-6 for each fan: @@ -52,6 +53,12 @@ * send: byte 1 is channel, rest zero * rcv: returns rpm in bytes 1,2 */ +#define CTL_GET_FAN_PWM 0x22 /* + * send: byte 1 is channel, rest zero + * rcv: returns pwm in byte 1 if it was set + * returns error 0x12 if fan is controlled via + * fan_target or fan curve + */ #define CTL_SET_FAN_FPWM 0x23 /* * set fixed pwm * send: byte 1 is fan number @@ -73,13 +80,31 @@ struct ccp_device { struct completion wait_input_report; struct mutex mutex; /* whenever buffer is used, lock before send_usb_cmd */ u8 *buffer; - int pwm[6]; int target[6]; DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS); DECLARE_BITMAP(fan_cnct, NUM_FANS); char fan_label[6][LABEL_LENGTH]; }; +/* converts response error in buffer to errno */ +static int ccp_get_errno(struct ccp_device *ccp) +{ + switch (ccp->buffer[0]) { + case 0x00: /* success */ + return 0; + case 0x01: /* called invalid command */ + return -EOPNOTSUPP; + case 0x10: /* called GET_VOLT / GET_TMP with invalid arguments */ + return -EINVAL; + case 0x11: /* requested temps of disconnected sensors */ + case 0x12: /* requested pwm of not pwm controlled channels */ + return -ENODATA; + default: + hid_dbg(ccp->hdev, "unknown device response error: %d", ccp->buffer[0]); + return -EIO; + } +} + /* send command, check for error in response, response in ccp->buffer */ static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, u8 byte3) { @@ -102,13 +127,7 @@ static int send_usb_cmd(struct ccp_device *ccp, u8 command, u8 byte1, u8 byte2, if (!t) return -ETIMEDOUT; - /* first byte of response is error code */ - if (ccp->buffer[0] != 0x00) { - hid_dbg(ccp->hdev, "device response error: %d", ccp->buffer[0]); - return -EIO; - } - - return 0; + return ccp_get_errno(ccp); } static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) @@ -126,7 +145,7 @@ static int ccp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 } /* requests and returns single data values depending on channel */ -static int get_data(struct ccp_device *ccp, int command, int channel) +static int get_data(struct ccp_device *ccp, int command, int channel, bool two_byte_data) { int ret; @@ -136,7 +155,9 @@ static int get_data(struct ccp_device *ccp, int command, int channel) if (ret) goto out_unlock; - ret = (ccp->buffer[1] << 8) + ccp->buffer[2]; + ret = ccp->buffer[1]; + if (two_byte_data) + ret = (ret << 8) + ccp->buffer[2]; out_unlock: mutex_unlock(&ccp->mutex); @@ -150,14 +171,14 @@ static int set_pwm(struct ccp_device *ccp, int channel, long val) if (val < 0 || val > 255) return -EINVAL; - ccp->pwm[channel] = val; - /* The Corsair Commander Pro uses values from 0-100 */ val = DIV_ROUND_CLOSEST(val * 100, 255); mutex_lock(&ccp->mutex); ret = send_usb_cmd(ccp, CTL_SET_FAN_FPWM, channel, val, 0); + if (!ret) + ccp->target[channel] = -ENODATA; mutex_unlock(&ccp->mutex); return ret; @@ -171,7 +192,6 @@ static int set_target(struct ccp_device *ccp, int channel, long val) ccp->target[channel] = val; mutex_lock(&ccp->mutex); - ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val); mutex_unlock(&ccp->mutex); @@ -210,7 +230,7 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_temp: switch (attr) { case hwmon_temp_input: - ret = get_data(ccp, CTL_GET_TMP, channel); + ret = get_data(ccp, CTL_GET_TMP, channel, true); if (ret < 0) return ret; *val = ret * 10; @@ -222,7 +242,7 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_fan: switch (attr) { case hwmon_fan_input: - ret = get_data(ccp, CTL_GET_FAN_RPM, channel); + ret = get_data(ccp, CTL_GET_FAN_RPM, channel, true); if (ret < 0) return ret; *val = ret; @@ -230,6 +250,8 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_fan_target: /* how to read target values from the device is unknown */ /* driver returns last set value or 0 */ + if (ccp->target[channel] < 0) + return -ENODATA; *val = ccp->target[channel]; return 0; default: @@ -239,9 +261,10 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_pwm: switch (attr) { case hwmon_pwm_input: - /* how to read pwm values from the device is currently unknown */ - /* driver returns last set value or 0 */ - *val = ccp->pwm[channel]; + ret = get_data(ccp, CTL_GET_FAN_PWM, channel, false); + if (ret < 0) + return ret; + *val = DIV_ROUND_CLOSEST(ret * 255, 100); return 0; default: break; @@ -250,7 +273,7 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_in: switch (attr) { case hwmon_in_input: - ret = get_data(ccp, CTL_GET_VOLT, channel); + ret = get_data(ccp, CTL_GET_VOLT, channel, true); if (ret < 0) return ret; *val = ret; @@ -416,6 +439,7 @@ static int get_fan_cnct(struct ccp_device *ccp) continue; set_bit(channel, ccp->fan_cnct); + ccp->target[channel] = -ENODATA; switch (mode) { case 1: -- cgit v1.2.3 From 2fdf8f7f086712bbe296d1d4d4049ca88e7a662d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 21 Jul 2020 21:49:19 +0800 Subject: hwmon: (sparx5) Make symbol 's5_temp_match' static The sparse tool complains as follows: drivers/hwmon/sparx5-temp.c:150:27: warning: symbol 's5_temp_match' was not declared. Should it be static? This variable is not used outside of sparx5-temp.c, this commit marks it static. Fixes: c2cb4b5777e1 ("hwmon: sparx5: Add Sparx5 SoC temperature driver") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Link: https://lore.kernel.org/r/20200721134919.34033-1-weiyongjun1@huawei.com Signed-off-by: Guenter Roeck --- drivers/hwmon/sparx5-temp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c index 7d7a060259a8..1a2b1026b026 100644 --- a/drivers/hwmon/sparx5-temp.c +++ b/drivers/hwmon/sparx5-temp.c @@ -147,7 +147,7 @@ static int s5_temp_probe(struct platform_device *pdev) return PTR_ERR_OR_ZERO(hwmon_dev); } -const struct of_device_id s5_temp_match[] = { +static const struct of_device_id s5_temp_match[] = { { .compatible = "microchip,sparx5-temp" }, {}, }; -- cgit v1.2.3 From 2207515db60a6885e11069251d4f4ca4bf3abb6b Mon Sep 17 00:00:00 2001 From: "Saheed O. Bolarinwa" Date: Sat, 1 Aug 2020 13:24:39 +0200 Subject: hwmon: (i5k_amb, vt8231) Drop uses of pci_read_config_*() return value The return value of pci_read_config_*() may not indicate a device error. However, the value read by these functions is more likely to indicate this kind of error. This presents two overlapping ways of reporting errors and complicates error checking. It is possible to move to one single way of checking for error if the dependency on the return value of these functions is removed, then it can later be made to return void. Remove all uses of the return value of pci_read_config_*(). Check the actual value read for ~0. In this case, ~0 is an invalid value thus it indicates some kind of error. Suggested-by: Bjorn Helgaas Signed-off-by: Saheed O. Bolarinwa Link: https://lore.kernel.org/r/20200801112446.149549-11-refactormyself@gmail.com Signed-off-by: Guenter Roeck --- drivers/hwmon/i5k_amb.c | 12 ++++++++---- drivers/hwmon/vt8231.c | 8 ++++---- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index cd5b62905eee..783fa936e4d1 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -427,11 +427,13 @@ static int i5k_find_amb_registers(struct i5k_amb_data *data, if (!pcidev) return -ENODEV; - if (pci_read_config_dword(pcidev, I5K_REG_AMB_BASE_ADDR, &val32)) + pci_read_config_dword(pcidev, I5K_REG_AMB_BASE_ADDR, &val32); + if (val32 == (u32)~0) goto out; data->amb_base = val32; - if (pci_read_config_dword(pcidev, I5K_REG_AMB_LEN_ADDR, &val32)) + pci_read_config_dword(pcidev, I5K_REG_AMB_LEN_ADDR, &val32); + if (val32 == (u32)~0) goto out; data->amb_len = val32; @@ -458,11 +460,13 @@ static int i5k_channel_probe(u16 *amb_present, unsigned long dev_id) if (!pcidev) return -ENODEV; - if (pci_read_config_word(pcidev, I5K_REG_CHAN0_PRESENCE_ADDR, &val16)) + pci_read_config_word(pcidev, I5K_REG_CHAN0_PRESENCE_ADDR, &val16); + if (val16 == (u16)~0) goto out; amb_present[0] = val16; - if (pci_read_config_word(pcidev, I5K_REG_CHAN1_PRESENCE_ADDR, &val16)) + pci_read_config_word(pcidev, I5K_REG_CHAN1_PRESENCE_ADDR, &val16); + if (val16 == (u16)~0) goto out; amb_present[1] = val16; diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 2335d440f72d..6603727e15a0 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -992,8 +992,8 @@ static int vt8231_pci_probe(struct pci_dev *dev, return -ENODEV; } - if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_BASE_REG, - &val)) + pci_read_config_word(dev, VT8231_BASE_REG, &val); + if (val == (u16)~0) return -ENODEV; address = val & ~(VT8231_EXTENT - 1); @@ -1002,8 +1002,8 @@ static int vt8231_pci_probe(struct pci_dev *dev, return -ENODEV; } - if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_ENABLE_REG, - &val)) + pci_read_config_word(dev, VT8231_ENABLE_REG, &val); + if (val == (u16)~0) return -ENODEV; if (!(val & 0x0001)) { -- cgit v1.2.3 From dfddc57c9971b213214cada1dcf26ef27f419b5c Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 3 Aug 2020 08:43:11 +0300 Subject: hwmon: (axi-fan-control) remove duplicate macros These macros are also present in the "include/linux/fpga/adi-axi-common.h" file which is included in this driver. This patch removes them from the AXI Fan Control driver. No sense in having them in 2 places. Signed-off-by: Alexandru Ardelean Link: https://lore.kernel.org/r/20200803054311.98174-1-alexandru.ardelean@analog.com Signed-off-by: Guenter Roeck --- drivers/hwmon/axi-fan-control.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c index 38d9cdb3db1a..e3f6b03e6764 100644 --- a/drivers/hwmon/axi-fan-control.c +++ b/drivers/hwmon/axi-fan-control.c @@ -15,10 +15,6 @@ #include #include -#define ADI_AXI_PCORE_VER_MAJOR(version) (((version) >> 16) & 0xff) -#define ADI_AXI_PCORE_VER_MINOR(version) (((version) >> 8) & 0xff) -#define ADI_AXI_PCORE_VER_PATCH(version) ((version) & 0xff) - /* register map */ #define ADI_REG_RSTN 0x0080 #define ADI_REG_PWM_WIDTH 0x0084 -- cgit v1.2.3 From e2f75e6b5d766195d2ca584d92995a0dfe467fc7 Mon Sep 17 00:00:00 2001 From: Roy van Doormaal Date: Tue, 28 Jul 2020 17:18:45 +0200 Subject: hwmon: (adc128d818) Fix advanced configuration register init If the operation mode is non-zero and an external reference voltage is set, first the operation mode is written to the advanced configuration register, followed by the externel reference enable bit, resetting the configuration mode to 0. To fix this, first compose the value of the advanced configuration register based on the configuration mode and the external reference voltage. The advanced configuration register is then written to the device, if it is different from the default register value (0x0). Signed-off-by: Roy van Doormaal Link: https://lore.kernel.org/r/20200728151846.231785-1-roy.van.doormaal@prodrive-technologies.com Signed-off-by: Guenter Roeck --- drivers/hwmon/adc128d818.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index f9edec195c35..571d5454c6b2 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -393,6 +393,7 @@ static int adc128_init_client(struct adc128_data *data) { struct i2c_client *client = data->client; int err; + u8 regval = 0x0; /* * Reset chip to defaults. @@ -403,10 +404,17 @@ static int adc128_init_client(struct adc128_data *data) return err; /* Set operation mode, if non-default */ - if (data->mode != 0) { - err = i2c_smbus_write_byte_data(client, - ADC128_REG_CONFIG_ADV, - data->mode << 1); + if (data->mode != 0) + regval |= data->mode << 1; + + /* If external vref is selected, configure the chip to use it */ + if (data->regulator) + regval |= 0x01; + + /* Write advanced configuration register */ + if (regval != 0x0) { + err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG_ADV, + regval); if (err) return err; } @@ -416,14 +424,6 @@ static int adc128_init_client(struct adc128_data *data) if (err) return err; - /* If external vref is selected, configure the chip to use it */ - if (data->regulator) { - err = i2c_smbus_write_byte_data(client, - ADC128_REG_CONFIG_ADV, 0x01); - if (err) - return err; - } - return 0; } -- cgit v1.2.3