diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-29 11:20:45 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-01-29 11:20:45 -0800 |
| commit | 47d5cc5be396eca67cc89572957ff16f10fd768e (patch) | |
| tree | 1f7cc53be5c3d857a3a1724a8dd773997d20620b /drivers | |
| parent | 0fc7e74663447682c904fe375bb680b004ddaa14 (diff) | |
| parent | 6fbc4232a5ac944531bda397f3644d1cf66bdd13 (diff) | |
| download | linux-47d5cc5be396eca67cc89572957ff16f10fd768e.tar.gz linux-47d5cc5be396eca67cc89572957ff16f10fd768e.tar.bz2 linux-47d5cc5be396eca67cc89572957ff16f10fd768e.zip | |
Merge tag 'hwmon-for-linus-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
- New driver for W83773G
- Fan control support for PMBus drivers
- Improvements and minor fixes in several drivers
* tag 'hwmon-for-linus-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (32 commits)
hwmon: (dell-smm) Disable fan support for Dell Vostro 3360
hwmon: (dell-smm) Disable fan support for Dell Inspiron 7720
hwmon: (dell-smm) Enable broken functionality via "force" module param
hwmon: (k10temp) Add temperature offset for Ryzen 1900X
hwmon: (lm75) Fix trailing semicolon
hwmon: (ina2xx) Fix access to uninitialized mutex
hwmon: (pmbus/ir35221) Remove unnecessary scaling
hwmon: (sht3x) wait predefined limits loading complete before access
hwmon: (pmbus/ibm-cffps) Add dependency on LEDS_CLASS
hwmon: (pmbus/cffps) Add led class device for power supply fault led
hwmon: (pmbus) cffps: Add PMBUS_SKIP_STATUS_CHECK
hwmon: (aspeed-pwm-tacho) Deassert reset in probe
dt-bindings: hwmon: aspeed-pwm-tacho: Add reset node
hwmon: (pmbus) cffps: Add debugfs entries
hwmon: (pmbus) Export pmbus device debugfs directory entry
hwmon: (w83773g) Fix fault detection and reporting
hwmon: (hih6130) Fix documentation of struct hih6130
hwmon: (iio_hwmon) Fix documentation of struct iio_hwmon_state
hwmon: (sht15) Fix parameter documentation of sht15_crc8()
hwmon: (sht21) Fix documentation of struct sht21
...
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/hwmon/Kconfig | 26 | ||||
| -rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
| -rw-r--r-- | drivers/hwmon/aspeed-pwm-tacho.c | 22 | ||||
| -rw-r--r-- | drivers/hwmon/coretemp.c | 3 | ||||
| -rw-r--r-- | drivers/hwmon/dell-smm-hwmon.c | 54 | ||||
| -rw-r--r-- | drivers/hwmon/hih6130.c | 2 | ||||
| -rw-r--r-- | drivers/hwmon/hwmon.c | 12 | ||||
| -rw-r--r-- | drivers/hwmon/iio_hwmon.c | 3 | ||||
| -rw-r--r-- | drivers/hwmon/ina2xx.c | 90 | ||||
| -rw-r--r-- | drivers/hwmon/k10temp.c | 1 | ||||
| -rw-r--r-- | drivers/hwmon/lm75.c | 2 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/ibm-cffps.c | 288 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/ir35221.c | 189 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/lm25066.c | 67 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/max31785.c | 294 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/pmbus.h | 41 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 273 | ||||
| -rw-r--r-- | drivers/hwmon/sht15.c | 1 | ||||
| -rw-r--r-- | drivers/hwmon/sht21.c | 2 | ||||
| -rw-r--r-- | drivers/hwmon/sht3x.c | 7 | ||||
| -rw-r--r-- | drivers/hwmon/w83773g.c | 329 |
22 files changed, 1357 insertions, 351 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7ad017690e3a..ef23553ff5cb 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -26,11 +26,9 @@ if HWMON config HWMON_VID tristate - default n config HWMON_DEBUG_CHIP bool "Hardware Monitoring Chip debugging messages" - default n help Say Y here if you want the I2C chip drivers to produce a bunch of debug messages to the system log. Select this if you are having @@ -42,7 +40,6 @@ comment "Native drivers" config SENSORS_AB8500 tristate "AB8500 thermal monitoring" depends on AB8500_GPADC && AB8500_BM - default n help If you say yes here you get support for the thermal sensor part of the AB8500 chip. The driver includes thermal management for @@ -302,7 +299,6 @@ config SENSORS_APPLESMC select NEW_LEDS select LEDS_CLASS select INPUT_POLLDEV - default n help This driver provides support for the Apple System Management Controller, which provides an accelerometer (Apple Sudden Motion @@ -678,7 +674,6 @@ config SENSORS_JC42 config SENSORS_POWR1220 tristate "Lattice POWR1220 Power Monitoring" depends on I2C - default n help If you say yes here you get access to the hardware monitoring functions of the Lattice POWR1220 isp Power Supply Monitoring, @@ -702,7 +697,6 @@ config SENSORS_LTC2945 tristate "Linear Technology LTC2945" depends on I2C select REGMAP_I2C - default n help If you say yes here you get support for Linear Technology LTC2945 I2C System Monitor. @@ -727,7 +721,6 @@ config SENSORS_LTC2990 config SENSORS_LTC4151 tristate "Linear Technology LTC4151" depends on I2C - default n help If you say yes here you get support for Linear Technology LTC4151 High Voltage I2C Current and Voltage Monitor interface. @@ -738,7 +731,6 @@ config SENSORS_LTC4151 config SENSORS_LTC4215 tristate "Linear Technology LTC4215" depends on I2C - default n help If you say yes here you get support for Linear Technology LTC4215 Hot Swap Controller I2C interface. @@ -750,7 +742,6 @@ config SENSORS_LTC4222 tristate "Linear Technology LTC4222" depends on I2C select REGMAP_I2C - default n help If you say yes here you get support for Linear Technology LTC4222 Dual Hot Swap Controller I2C interface. @@ -761,7 +752,6 @@ config SENSORS_LTC4222 config SENSORS_LTC4245 tristate "Linear Technology LTC4245" depends on I2C - default n help If you say yes here you get support for Linear Technology LTC4245 Multiple Supply Hot Swap Controller I2C interface. @@ -773,7 +763,6 @@ config SENSORS_LTC4260 tristate "Linear Technology LTC4260" depends on I2C select REGMAP_I2C - default n help If you say yes here you get support for Linear Technology LTC4260 Positive Voltage Hot Swap Controller I2C interface. @@ -784,7 +773,6 @@ config SENSORS_LTC4260 config SENSORS_LTC4261 tristate "Linear Technology LTC4261" depends on I2C - default n help If you say yes here you get support for Linear Technology LTC4261 Negative Voltage Hot Swap Controller I2C interface. @@ -1276,7 +1264,6 @@ config SENSORS_NSA320 config SENSORS_PCF8591 tristate "Philips PCF8591 ADC/DAC" depends on I2C - default n help If you say yes here you get support for Philips PCF8591 4-channel ADC, 1-channel DAC chips. @@ -1459,7 +1446,6 @@ config SENSORS_SMSC47B397 config SENSORS_SCH56XX_COMMON tristate - default n config SENSORS_SCH5627 tristate "SMSC SCH5627" @@ -1505,7 +1491,6 @@ config SENSORS_STTS751 config SENSORS_SMM665 tristate "Summit Microelectronics SMM665" depends on I2C - default n help If you say yes here you get support for the hardware monitoring features of the Summit Microelectronics SMM665/SMM665B Six-Channel @@ -1725,6 +1710,16 @@ config SENSORS_VT8231 This driver can also be built as a module. If so, the module will be called vt8231. +config SENSORS_W83773G + tristate "Nuvoton W83773G" + depends on I2C + help + If you say yes here you get support for the Nuvoton W83773G hardware + monitoring chip. + + This driver can also be built as a module. If so, the module + will be called w83773g. + config SENSORS_W83781D tristate "Winbond W83781D, W83782D, W83783S, Asus AS99127F" depends on I2C @@ -1782,7 +1777,6 @@ config SENSORS_W83795 config SENSORS_W83795_FANCTRL bool "Include automatic fan control support (DANGEROUS)" depends on SENSORS_W83795 - default n help If you say yes here, support for automatic fan speed control will be included in the driver. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 0fe489fab663..f814b4ace138 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o # asb100, then w83781d go first, as they can override other drivers' addresses. obj-$(CONFIG_SENSORS_ASB100) += asb100.o obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o +obj-$(CONFIG_SENSORS_W83773G) += w83773g.o obj-$(CONFIG_SENSORS_W83792D) += w83792d.o obj-$(CONFIG_SENSORS_W83793) += w83793.o obj-$(CONFIG_SENSORS_W83795) += w83795.o diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c index 63a95e23ca81..693a3d53cab5 100644 --- a/drivers/hwmon/aspeed-pwm-tacho.c +++ b/drivers/hwmon/aspeed-pwm-tacho.c @@ -19,6 +19,7 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/reset.h> #include <linux/sysfs.h> #include <linux/thermal.h> @@ -181,6 +182,7 @@ struct aspeed_cooling_device { struct aspeed_pwm_tacho_data { struct regmap *regmap; + struct reset_control *rst; unsigned long clk_freq; bool pwm_present[8]; bool fan_tach_present[16]; @@ -905,6 +907,13 @@ static int aspeed_create_fan(struct device *dev, return 0; } +static void aspeed_pwm_tacho_remove(void *data) +{ + struct aspeed_pwm_tacho_data *priv = data; + + reset_control_assert(priv->rst); +} + static int aspeed_pwm_tacho_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -931,6 +940,19 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev) &aspeed_pwm_tacho_regmap_config); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); + + priv->rst = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(priv->rst)) { + dev_err(dev, + "missing or invalid reset controller device tree entry"); + return PTR_ERR(priv->rst); + } + reset_control_deassert(priv->rst); + + ret = devm_add_action_or_reset(dev, aspeed_pwm_tacho_remove, priv); + if (ret) + return ret; + regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE, 0); regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 0); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index c13a4fd86b3c..4bdbf77f7197 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -246,7 +246,8 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) int err; u32 eax, edx; int i; - struct pci_dev *host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); + u16 devfn = PCI_DEVFN(0, 0); + struct pci_dev *host_bridge = pci_get_domain_bus_and_slot(0, 0, devfn); /* * Explicit tjmax table entries override heuristics. diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index c7c9e95e58a8..bf3bb7e1adab 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -76,6 +76,7 @@ static uint i8k_fan_mult = I8K_FAN_MULT; static uint i8k_pwm_mult; static uint i8k_fan_max = I8K_FAN_HIGH; static bool disallow_fan_type_call; +static bool disallow_fan_support; #define I8K_HWMON_HAVE_TEMP1 (1 << 0) #define I8K_HWMON_HAVE_TEMP2 (1 << 1) @@ -242,6 +243,9 @@ static int i8k_get_fan_status(int fan) { struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; + if (disallow_fan_support) + return -EINVAL; + regs.ebx = fan & 0xff; return i8k_smm(®s) ? : regs.eax & 0xff; } @@ -253,6 +257,9 @@ static int i8k_get_fan_speed(int fan) { struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; + if (disallow_fan_support) + return -EINVAL; + regs.ebx = fan & 0xff; return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; } @@ -264,7 +271,7 @@ static int _i8k_get_fan_type(int fan) { struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, }; - if (disallow_fan_type_call) + if (disallow_fan_support || disallow_fan_type_call) return -EINVAL; regs.ebx = fan & 0xff; @@ -289,6 +296,9 @@ static int i8k_get_fan_nominal_speed(int fan, int speed) { struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, }; + if (disallow_fan_support) + return -EINVAL; + regs.ebx = (fan & 0xff) | (speed << 8); return i8k_smm(®s) ? : (regs.eax & 0xffff) * i8k_fan_mult; } @@ -300,6 +310,9 @@ static int i8k_set_fan(int fan, int speed) { struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; + if (disallow_fan_support) + return -EINVAL; + speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed); regs.ebx = (fan & 0xff) | (speed << 8); @@ -772,6 +785,8 @@ static struct attribute *i8k_attrs[] = { static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, int index) { + if (disallow_fan_support && index >= 8) + return 0; if (disallow_fan_type_call && (index == 9 || index == 12 || index == 15)) return 0; @@ -1039,6 +1054,30 @@ static const struct dmi_system_id i8k_blacklist_fan_type_dmi_table[] __initconst }; /* + * On some machines all fan related SMM functions implemented by Dell BIOS + * firmware freeze kernel for about 500ms. Until Dell fixes these problems fan + * support for affected blacklisted Dell machines stay disabled. + * See bug: https://bugzilla.kernel.org/show_bug.cgi?id=195751 + */ +static struct dmi_system_id i8k_blacklist_fan_support_dmi_table[] __initdata = { + { + .ident = "Dell Inspiron 7720", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 7720"), + }, + }, + { + .ident = "Dell Vostro 3360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Vostro 3360"), + }, + }, + { } +}; + +/* * Probe for the presence of a supported laptop. */ static int __init i8k_probe(void) @@ -1060,8 +1099,17 @@ static int __init i8k_probe(void) i8k_get_dmi_data(DMI_BIOS_VERSION)); } - if (dmi_check_system(i8k_blacklist_fan_type_dmi_table)) - disallow_fan_type_call = true; + if (dmi_check_system(i8k_blacklist_fan_support_dmi_table)) { + pr_warn("broken Dell BIOS detected, disallow fan support\n"); + if (!force) + disallow_fan_support = true; + } + + if (dmi_check_system(i8k_blacklist_fan_type_dmi_table)) { + pr_warn("broken Dell BIOS detected, disallow fan type call\n"); + if (!force) + disallow_fan_type_call = true; + } strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version)); diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index 7b73d2002d3e..0ae1ee1dbf76 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -37,7 +37,7 @@ /** * struct hih6130 - HIH-6130 device specific data - * @hwmon_dev: device registered with hwmon + * @client: pointer to I2C client device * @lock: mutex to protect measurement values * @valid: only false before first measurement is taken * @last_update: time of last update (jiffies) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index af5123042990..32083e452cde 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -678,7 +678,7 @@ EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); * @dev: the parent device * @name: hwmon name attribute * @drvdata: driver data to attach to created device - * @info: pointer to hwmon chip information + * @chip: pointer to hwmon chip information * @extra_groups: pointer to list of additional non-standard attribute groups * * hwmon_device_unregister() must be called when the device is no @@ -785,11 +785,11 @@ EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); /** * devm_hwmon_device_register_with_info - register w/ hwmon - * @dev: the parent device - * @name: hwmon name attribute - * @drvdata: driver data to attach to created device - * @info: Pointer to hwmon chip information - * @groups - pointer to list of driver specific attribute groups + * @dev: the parent device + * @name: hwmon name attribute + * @drvdata: driver data to attach to created device + * @chip: pointer to hwmon chip information + * @groups: pointer to list of driver specific attribute groups * * Returns the pointer to the new device. The new device is automatically * unregistered with the parent device. diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index f6a76679c650..5e5b32a1ec4b 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -23,7 +23,8 @@ * @channels: filled with array of channels from iio * @num_channels: number of channels in channels (saves counting twice) * @hwmon_dev: associated hwmon device - * @attr_group: the group of attributes + * @attr_group: the group of attributes + * @groups: null terminated array of attribute groups * @attrs: null terminated array of attribute pointers. */ struct iio_hwmon_state { diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 62e38fa8cda2..e9e6aeabbf84 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -95,18 +95,20 @@ enum ina2xx_ids { ina219, ina226 }; struct ina2xx_config { u16 config_default; - int calibration_factor; + int calibration_value; int registers; int shunt_div; int bus_voltage_shift; int bus_voltage_lsb; /* uV */ - int power_lsb; /* uW */ + int power_lsb_factor; }; struct ina2xx_data { const struct ina2xx_config *config; long rshunt; + long current_lsb_uA; + long power_lsb_uW; struct mutex config_lock; struct regmap *regmap; @@ -116,21 +118,21 @@ struct ina2xx_data { static const struct ina2xx_config ina2xx_config[] = { [ina219] = { .config_default = INA219_CONFIG_DEFAULT, - .calibration_factor = 40960000, + .calibration_value = 4096, .registers = INA219_REGISTERS, .shunt_div = 100, .bus_voltage_shift = 3, .bus_voltage_lsb = 4000, - .power_lsb = 20000, + .power_lsb_factor = 20, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, - .calibration_factor = 5120000, + .calibration_value = 2048, .registers = INA226_REGISTERS, .shunt_div = 400, .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, - .power_lsb = 25000, + .power_lsb_factor = 25, }, }; @@ -169,12 +171,16 @@ static u16 ina226_interval_to_reg(int interval) return INA226_SHIFT_AVG(avg_bits); } +/* + * Calibration register is set to the best value, which eliminates + * truncation errors on calculating current register in hardware. + * According to datasheet (eq. 3) the best values are 2048 for + * ina226 and 4096 for ina219. They are hardcoded as calibration_value. + */ static int ina2xx_calibrate(struct ina2xx_data *data) { - u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor, - data->rshunt); - - return regmap_write(data->regmap, INA2XX_CALIBRATION, val); + return regmap_write(data->regmap, INA2XX_CALIBRATION, + data->config->calibration_value); } /* @@ -187,10 +193,6 @@ static int ina2xx_init(struct ina2xx_data *data) if (ret < 0) return ret; - /* - * Set current LSB to 1mA, shunt is in uOhms - * (equation 13 in datasheet). - */ return ina2xx_calibrate(data); } @@ -268,15 +270,15 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg, val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_POWER: - val = regval * data->config->power_lsb; + val = regval * data->power_lsb_uW; break; case INA2XX_CURRENT: - /* signed register, LSB=1mA (selected), in mA */ - val = (s16)regval; + /* signed register, result in mA */ + val = regval * data->current_lsb_uA; + val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_CALIBRATION: - val = DIV_ROUND_CLOSEST(data->config->calibration_factor, - regval); + val = regval; break; default: /* programmer goofed */ @@ -304,9 +306,32 @@ static ssize_t ina2xx_show_value(struct device *dev, ina2xx_get_value(data, attr->index, regval)); } -static ssize_t ina2xx_set_shunt(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +/* + * In order to keep calibration register value fixed, the product + * of current_lsb and shunt_resistor should also be fixed and equal + * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order + * to keep the scale. + */ +static int ina2xx_set_shunt(struct ina2xx_data *data, long val) +{ + unsigned int dividend = DIV_ROUND_CLOSEST(1000000000, + data->config->shunt_div); + if (val <= 0 || val > dividend) + return -EINVAL; + + mutex_lock(&data->config_lock); + data->rshunt = val; + data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val); + data->power_lsb_uW = data->config->power_lsb_factor * + data->current_lsb_uA; + mutex_unlock(&data->config_lock); + + return 0; +} + +static ssize_t ina2xx_store_shunt(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) { unsigned long val; int status; @@ -316,18 +341,9 @@ static ssize_t ina2xx_set_shunt(struct device *dev, if (status < 0) return status; - if (val == 0 || - /* Values greater than the calibration factor make no sense. */ - val > data->config->calibration_factor) - return -EINVAL; - - mutex_lock(&data->config_lock); - data->rshunt = val; - status = ina2xx_calibrate(data); - mutex_unlock(&data->config_lock); + status = ina2xx_set_shunt(data, val); if (status < 0) return status; - return count; } @@ -387,7 +403,7 @@ static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL, /* shunt resistance */ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR, - ina2xx_show_value, ina2xx_set_shunt, + ina2xx_show_value, ina2xx_store_shunt, INA2XX_CALIBRATION); /* update interval (ina226 only) */ @@ -438,6 +454,7 @@ static int ina2xx_probe(struct i2c_client *client, /* set the device type */ data->config = &ina2xx_config[chip]; + mutex_init(&data->config_lock); if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) { struct ina2xx_platform_data *pdata = dev_get_platdata(dev); @@ -448,10 +465,7 @@ static int ina2xx_probe(struct i2c_client *client, val = INA2XX_RSHUNT_DEFAULT; } - if (val <= 0 || val > data->config->calibration_factor) - return -ENODEV; - - data->rshunt = val; + ina2xx_set_shunt(data, val); ina2xx_regmap_config.max_register = data->config->registers; @@ -467,8 +481,6 @@ static int ina2xx_probe(struct i2c_client *client, return -ENODEV; } - mutex_init(&data->config_lock); - data->groups[group++] = &ina2xx_group; if (id->driver_data == ina226) data->groups[group++] = &ina226_group; diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 0721e175664a..06b4e1c78bd8 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -86,6 +86,7 @@ static const struct tctl_offset tctl_offset_table[] = { { 0x17, "AMD Ryzen 7 1800X", 20000 }, { 0x17, "AMD Ryzen Threadripper 1950X", 27000 }, { 0x17, "AMD Ryzen Threadripper 1920X", 27000 }, + { 0x17, "AMD Ryzen Threadripper 1900X", 27000 }, { 0x17, "AMD Ryzen Threadripper 1950", 10000 }, { 0x17, "AMD Ryzen Threadripper 1920", 10000 }, { 0x17, "AMD Ryzen Threadripper 1910", 10000 }, diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 005ffb5ffa92..49f4b33a5685 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -100,7 +100,7 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type, switch (attr) { case hwmon_chip_update_interval: *val = data->sample_time; - break;; + break; default: return -EINVAL; } diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 08479006c7f9..6e4298e99222 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -39,6 +39,7 @@ config SENSORS_ADM1275 config SENSORS_IBM_CFFPS tristate "IBM Common Form Factor Power Supply" + depends on LEDS_CLASS help If you say yes here you get hardware monitoring support for the IBM Common Form Factor power supply. diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index cb56da6834e5..93d9a9ea112b 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -8,12 +8,29 @@ */ #include <linux/bitops.h> +#include <linux/debugfs.h> #include <linux/device.h> +#include <linux/fs.h> #include <linux/i2c.h> +#include <linux/jiffies.h> +#include <linux/leds.h> #include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pmbus.h> #include "pmbus.h" +#define CFFPS_FRU_CMD 0x9A +#define CFFPS_PN_CMD 0x9B +#define CFFPS_SN_CMD 0x9E +#define CFFPS_CCIN_CMD 0xBD +#define CFFPS_FW_CMD_START 0xFA +#define CFFPS_FW_NUM_BYTES 4 +#define CFFPS_SYS_CONFIG_CMD 0xDA + +#define CFFPS_INPUT_HISTORY_CMD 0xD6 +#define CFFPS_INPUT_HISTORY_SIZE 100 + /* STATUS_MFR_SPECIFIC bits */ #define CFFPS_MFR_FAN_FAULT BIT(0) #define CFFPS_MFR_THERMAL_FAULT BIT(1) @@ -24,6 +41,153 @@ #define CFFPS_MFR_VAUX_FAULT BIT(6) #define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7) +#define CFFPS_LED_BLINK BIT(0) +#define CFFPS_LED_ON BIT(1) +#define CFFPS_LED_OFF BIT(2) +#define CFFPS_BLINK_RATE_MS 250 + +enum { + CFFPS_DEBUGFS_INPUT_HISTORY = 0, + CFFPS_DEBUGFS_FRU, + CFFPS_DEBUGFS_PN, + CFFPS_DEBUGFS_SN, + CFFPS_DEBUGFS_CCIN, + CFFPS_DEBUGFS_FW, + CFFPS_DEBUGFS_NUM_ENTRIES +}; + +struct ibm_cffps_input_history { + struct mutex update_lock; + unsigned long last_update; + + u8 byte_count; + u8 data[CFFPS_INPUT_HISTORY_SIZE]; +}; + +struct ibm_cffps { + struct i2c_client *client; + + struct ibm_cffps_input_history input_history; + + int debugfs_entries[CFFPS_DEBUGFS_NUM_ENTRIES]; + + char led_name[32]; + u8 led_state; + struct led_classdev led; +}; + +#define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)]) + +static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu, + char __user *buf, size_t count, + loff_t *ppos) +{ + int rc; + u8 msgbuf0[1] = { CFFPS_INPUT_HISTORY_CMD }; + u8 msgbuf1[CFFPS_INPUT_HISTORY_SIZE + 1] = { 0 }; + struct i2c_msg msg[2] = { + { + .addr = psu->client->addr, + .flags = psu->client->flags, + .len = 1, + .buf = msgbuf0, + }, { + .addr = psu->client->addr, + .flags = psu->client->flags | I2C_M_RD, + .len = CFFPS_INPUT_HISTORY_SIZE + 1, + .buf = msgbuf1, + }, + }; + + if (!*ppos) { + mutex_lock(&psu->input_history.update_lock); + if (time_after(jiffies, psu->input_history.last_update + HZ)) { + /* + * Use a raw i2c transfer, since we need more bytes + * than Linux I2C supports through smbus xfr (only 32). + */ + rc = i2c_transfer(psu->client->adapter, msg, 2); + if (rc < 0) { + mutex_unlock(&psu->input_history.update_lock); + return rc; + } + + psu->input_history.byte_count = msgbuf1[0]; + memcpy(psu->input_history.data, &msgbuf1[1], + CFFPS_INPUT_HISTORY_SIZE); + psu->input_history.last_update = jiffies; + } + + mutex_unlock(&psu->input_history.update_lock); + } + + return simple_read_from_buffer(buf, count, ppos, + psu->input_history.data, + psu->input_history.byte_count); +} + +static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + u8 cmd; + int i, rc; + int *idxp = file->private_data; + int idx = *idxp; + struct ibm_cffps *psu = to_psu(idxp, idx); + char data[I2C_SMBUS_BLOCK_MAX] = { 0 }; + + switch (idx) { + case CFFPS_DEBUGFS_INPUT_HISTORY: + return ibm_cffps_read_input_history(psu, buf, count, ppos); + case CFFPS_DEBUGFS_FRU: + cmd = CFFPS_FRU_CMD; + break; + case CFFPS_DEBUGFS_PN: + cmd = CFFPS_PN_CMD; + break; + case CFFPS_DEBUGFS_SN: + cmd = CFFPS_SN_CMD; + break; + case CFFPS_DEBUGFS_CCIN: + rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD); + if (rc < 0) + return rc; + + rc = snprintf(data, 5, "%04X", rc); + goto done; + case CFFPS_DEBUGFS_FW: + for (i = 0; i < CFFPS_FW_NUM_BYTES; ++i) { + rc = i2c_smbus_read_byte_data(psu->client, + CFFPS_FW_CMD_START + i); + if (rc < 0) + return rc; + + snprintf(&data[i * 2], 3, "%02X", rc); + } + + rc = i * 2; + goto done; + default: + return -EINVAL; + } + + rc = i2c_smbus_read_block_data(psu->client, cmd, data); + if (rc < 0) + return rc; + +done: + data[rc] = '\n'; + rc += 2; + + return simple_read_from_buffer(buf, count, ppos, data, rc); +} + +static const struct file_operations ibm_cffps_fops = { + .llseek = noop_llseek, + .read = ibm_cffps_debugfs_op, + .open = simple_open, +}; + static int ibm_cffps_read_byte_data(struct i2c_client *client, int page, int reg) { @@ -105,6 +269,69 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page, return rc; } +static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int rc; + struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led); + + if (brightness == LED_OFF) { + psu->led_state = CFFPS_LED_OFF; + } else { + brightness = LED_FULL; + if (psu->led_state != CFFPS_LED_BLINK) + psu->led_state = CFFPS_LED_ON; + } + + rc |
