diff options
Diffstat (limited to 'drivers/hwmon')
81 files changed, 2953 insertions, 1112 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 2760feb9f83b..157678b821fc 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -175,7 +175,7 @@ config SENSORS_ADT7X10 select REGMAP help This module contains common code shared by the ADT7310/ADT7320 and - ADT7410/ADT7420 temperature monitoring chip drivers. + ADT7410/ADT7420/ADT7422 temperature monitoring chip drivers. If built as a module, the module will be called adt7x10. @@ -191,12 +191,12 @@ config SENSORS_ADT7310 will be called adt7310. config SENSORS_ADT7410 - tristate "Analog Devices ADT7410/ADT7420" + tristate "Analog Devices ADT7410/ADT7420/ADT7422" depends on I2C select SENSORS_ADT7X10 help If you say yes here you get support for the Analog Devices - ADT7410 and ADT7420 temperature monitoring chips. + ADT7410, ADT7420 and ADT7422 temperature monitoring chips. This driver can also be built as a module. If so, the module will be called adt7410. @@ -245,12 +245,12 @@ config SENSORS_ADT7475 will be called adt7475. config SENSORS_AHT10 - tristate "Aosong AHT10, AHT20" + tristate "Aosong AHT10, AHT20, DHT20" depends on I2C select CRC8 help - If you say yes here, you get support for the Aosong AHT10 and AHT20 - temperature and humidity sensors + If you say yes here, you get support for the Aosong AHT10, AHT20 and + DHT20 temperature and humidity sensors This driver can also be built as a module. If so, the module will be called aht10. @@ -1174,6 +1174,18 @@ config SENSORS_LTQ_CPUTEMP If you say yes here you get support for the temperature sensor inside your CPU. +config SENSORS_MACSMC_HWMON + tristate "Apple SMC (Apple Silicon)" + depends on MFD_MACSMC && OF + help + This driver enables hwmon support for current, power, temperature, + and voltage sensors, as well as fan speed reporting and control + on Apple Silicon devices. Say Y here if you have an Apple Silicon + device. + + This driver can also be built as a module. If so, the module will + be called macsmc-hwmon. + config SENSORS_MAX1111 tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles" depends on SPI_MASTER @@ -2434,6 +2446,18 @@ config SENSORS_TMP513 This driver can also be built as a module. If so, the module will be called tmp513. +config SENSORS_TSC1641 + tristate "ST Microelectronics TSC1641 Power Monitor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for TSC1641 power monitor chip. + The TSC1641 driver is configured for the default configuration of + the part except temperature is enabled by default. + + This driver can also be built as a module. If so, the module + will be called tsc1641. + config SENSORS_VEXPRESS tristate "Versatile Express" depends on VEXPRESS_CONFIG diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 73b2abdcc6dd..eade8e3b1bde 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -148,6 +148,7 @@ obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o obj-$(CONFIG_SENSORS_LTC4282) += ltc4282.o obj-$(CONFIG_SENSORS_LTQ_CPUTEMP) += ltq-cputemp.o +obj-$(CONFIG_SENSORS_MACSMC_HWMON) += macsmc-hwmon.o obj-$(CONFIG_SENSORS_MAX1111) += max1111.o obj-$(CONFIG_SENSORS_MAX127) += max127.o obj-$(CONFIG_SENSORS_MAX16065) += max16065.o @@ -233,6 +234,7 @@ obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_TMP464) += tmp464.o obj-$(CONFIG_SENSORS_TMP513) += tmp513.o +obj-$(CONFIG_SENSORS_TSC1641) += tsc1641.o obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 80d09b017d3b..c38c932e5d2a 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -197,8 +197,16 @@ static int adm1026_scaling[] = { /* .001 Volts */ #define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \ clamp_val(1350000 / ((val) * (div)), \ 1, 254)) -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \ - 1350000 / ((val) * (div))) + +static int fan_from_reg(int val, int div) +{ + if (val == 0) + return -1; + if (val == 0xff) + return 0; + return 1350000 / (val * div); +} + #define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0) @@ -656,7 +664,7 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr], data->fan_div[nr])); } static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr, @@ -665,7 +673,7 @@ static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct adm1026_data *data = adm1026_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + return sprintf(buf, "%d\n", fan_from_reg(data->fan_min[nr], data->fan_div[nr])); } static ssize_t fan_min_store(struct device *dev, diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index 761c13092488..71eea8ae51b9 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -171,14 +171,17 @@ fan_show(struct device *dev, struct device_attribute *devattr, char *buf) struct adm1029_data *data = adm1029_update_device(dev); u16 val; + mutex_lock(&data->update_lock); if (data->fan[attr->index] == 0 || (data->fan_div[attr->index] & 0xC0) == 0 || data->fan[attr->index] == 255) { + mutex_unlock(&data->update_lock); return sprintf(buf, "0\n"); } val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index]) / data->fan[attr->index]; + mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", val); } diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 6dfbeb6acf00..86f6044b5bd0 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -37,7 +37,6 @@ #include <linux/hwmon.h> #include <linux/hwmon-vid.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/regmap.h> /* Addresses to scan */ @@ -125,7 +124,6 @@ static inline unsigned int AOUT_FROM_REG(u8 reg) struct adm9240_data { struct device *dev; struct regmap *regmap; - struct mutex update_lock; u8 fan_div[2]; /* rw fan1_div, read-only accessor */ u8 vrm; /* -- vrm set on startup, no accessor */ @@ -170,8 +168,6 @@ static int adm9240_fan_min_write(struct adm9240_data *data, int channel, long va u8 fan_min; int err; - mutex_lock(&data->update_lock); - if (!val) { fan_min = 255; new_div = data->fan_div[channel]; @@ -206,8 +202,6 @@ static int adm9240_fan_min_write(struct adm9240_data *data, int channel, long va } err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(channel), fan_min); - mutex_unlock(&data->update_lock); - return err; } @@ -501,23 +495,17 @@ static int adm9240_fan_read(struct device *dev, u32 attr, int channel, long *val switch (attr) { case hwmon_fan_input: - mutex_lock(&data->update_lock); err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), ®val); - if (err < 0) { - mutex_unlock(&data->update_lock); + if (err < 0) return err; - } if (regval == 255 && data->fan_div[channel] < 3) { /* adjust fan clock divider on overflow */ err = adm9240_write_fan_div(data, channel, ++data->fan_div[channel]); - if (err) { - mutex_unlock(&data->update_lock); + if (err) return err; - } } *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel])); - mutex_unlock(&data->update_lock); break; case hwmon_fan_div: *val = BIT(data->fan_div[channel]); @@ -791,7 +779,6 @@ static int adm9240_probe(struct i2c_client *client) return -ENOMEM; data->dev = dev; - mutex_init(&data->update_lock); data->regmap = devm_regmap_init_i2c(client, &adm9240_regmap_config); if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 3bf0e0a0882c..73b196a78f3a 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -7,6 +7,7 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/init.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -90,14 +91,24 @@ static int adt7410_i2c_probe(struct i2c_client *client) static const struct i2c_device_id adt7410_ids[] = { { "adt7410" }, { "adt7420" }, + { "adt7422" }, {} }; MODULE_DEVICE_TABLE(i2c, adt7410_ids); +static const struct of_device_id adt7410_of_match[] = { + { .compatible = "adi,adt7410" }, + { .compatible = "adi,adt7420" }, + { .compatible = "adi,adt7422" }, + { } +}; +MODULE_DEVICE_TABLE(of, adt7410_of_match); + static struct i2c_driver adt7410_driver = { .driver = { .name = "adt7410", .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops), + .of_match_table = adt7410_of_match, }, .probe = adt7410_i2c_probe, .id_table = adt7410_ids, diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 08d0effd97f7..b9991a69e6c6 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -11,7 +11,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> @@ -99,8 +98,6 @@ static const u8 adt7411_in_alarm_bits[] = { }; struct adt7411_data { - struct mutex device_lock; /* for "atomic" device accesses */ - struct mutex update_lock; unsigned long next_update; long vref_cached; struct i2c_client *client; @@ -110,55 +107,41 @@ struct adt7411_data { /* * When reading a register containing (up to 4) lsb, all associated * msb-registers get locked by the hardware. After _one_ of those msb is read, - * _all_ are unlocked. In order to use this locking correctly, reading lsb/msb - * is protected here with a mutex, too. + * _all_ are unlocked. */ static int adt7411_read_10_bit(struct i2c_client *client, u8 lsb_reg, - u8 msb_reg, u8 lsb_shift) + u8 msb_reg, u8 lsb_shift) { - struct adt7411_data *data = i2c_get_clientdata(client); int val, tmp; - mutex_lock(&data->device_lock); - val = i2c_smbus_read_byte_data(client, lsb_reg); if (val < 0) - goto exit_unlock; + return val; tmp = (val >> lsb_shift) & 3; val = i2c_smbus_read_byte_data(client, msb_reg); + if (val < 0) + return val; - if (val >= 0) - val = (val << 2) | tmp; - - exit_unlock: - mutex_unlock(&data->device_lock); - + val = (val << 2) | tmp; return val; } static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit, - bool flag) + bool flag) { - struct adt7411_data *data = i2c_get_clientdata(client); int ret, val; - mutex_lock(&data->device_lock); - ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) - goto exit_unlock; + return ret; if (flag) val = ret | bit; else val = ret & ~bit; - ret = i2c_smbus_write_byte_data(client, reg, val); - - exit_unlock: - mutex_unlock(&data->device_lock); - return ret; + return i2c_smbus_write_byte_data(client, reg, val); } static ssize_t adt7411_show_bit(struct device *dev, @@ -186,12 +169,11 @@ static ssize_t adt7411_set_bit(struct device *dev, if (ret || flag > 1) return -EINVAL; + hwmon_lock(dev); ret = adt7411_modify_bit(client, s_attr2->index, s_attr2->nr, flag); - /* force update */ - mutex_lock(&data->update_lock); data->next_update = jiffies; - mutex_unlock(&data->update_lock); + hwmon_unlock(dev); return ret < 0 ? ret : count; } @@ -294,10 +276,9 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, int reg, lsb_reg, lsb_shift; int nr = channel - 1; - mutex_lock(&data->update_lock); ret = adt7411_update_vref(dev); if (ret < 0) - goto exit_unlock; + return ret; switch (attr) { case hwmon_in_input: @@ -307,7 +288,7 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, ADT7411_REG_EXT_TEMP_AIN1_MSB + nr, lsb_shift); if (ret < 0) - goto exit_unlock; + return ret; *val = ret * data->vref_cached / 1024; ret = 0; break; @@ -318,7 +299,7 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, : ADT7411_REG_IN_HIGH(channel); ret = i2c_smbus_read_byte_data(client, reg); if (ret < 0) - goto exit_unlock; + return ret; *val = ret * data->vref_cached / 256; ret = 0; break; @@ -329,8 +310,6 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, ret = -EOPNOTSUPP; break; } - exit_unlock: - mutex_unlock(&data->update_lock); return ret; } @@ -457,10 +436,9 @@ static int adt7411_write_in_chan(struct device *dev, u32 attr, int channel, struct i2c_client *client = data->client; int ret, reg; - mutex_lock(&data->update_lock); ret = adt7411_update_vref(dev); if (ret < 0) - goto exit_unlock; + return ret; val = clamp_val(val, 0, 255 * data->vref_cached / 256); val = DIV_ROUND_CLOSEST(val * 256, data->vref_cached); @@ -472,13 +450,10 @@ static int adt7411_write_in_chan(struct device *dev, u32 attr, int channel, reg = ADT7411_REG_IN_HIGH(channel); break; default: - ret = -EOPNOTSUPP; - goto exit_unlock; + return -EOPNOTSUPP; } ret = i2c_smbus_write_byte_data(client, reg, val); - exit_unlock: - mutex_unlock(&data->update_lock); return ret; } @@ -679,8 +654,6 @@ static int adt7411_probe(struct i2c_client *client) i2c_set_clientdata(client, data); data->client = client; - mutex_init(&data->device_lock); - mutex_init(&data->update_lock); ret = adt7411_init_device(data); if (ret < 0) diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index 2d329391ed3f..d003ee3ebf06 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -15,7 +15,6 @@ #include <linux/jiffies.h> #include <linux/hwmon.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/regmap.h> @@ -55,7 +54,6 @@ /* Each client has this additional data */ struct adt7x10_data { struct regmap *regmap; - struct mutex update_lock; u8 config; u8 oldconfig; bool valid; /* true if temperature valid */ @@ -137,17 +135,13 @@ static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val) unsigned int regval; int ret; - mutex_lock(&data->update_lock); if (index == adt7x10_temperature && !data->valid) { /* wait for valid temperature */ ret = adt7x10_temp_ready(data->regmap); - if (ret) { - mutex_unlock(&data->update_lock); + if (ret) return ret; - } data->valid = true; } - mutex_unlock(&data->update_lock); ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], ®val); if (ret) @@ -159,13 +153,8 @@ static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val) static int adt7x10_temp_write(struct adt7x10_data *data, int index, long temp) { - int ret; - - mutex_lock(&data->update_lock); - ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[index], - ADT7X10_TEMP_TO_REG(temp)); - mutex_unlock(&data->update_lock); - return ret; + return regmap_write(data->regmap, ADT7X10_REG_TEMP[index], + ADT7X10_TEMP_TO_REG(temp)); } static int adt7x10_hyst_read(struct adt7x10_data *data, int index, long *val) @@ -197,22 +186,17 @@ static int adt7x10_hyst_write(struct adt7x10_data *data, long hyst) unsigned int regval; int limit, ret; - mutex_lock(&data->update_lock); - /* convert absolute hysteresis value to a 4 bit delta value */ ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, ®val); if (ret < 0) - goto abort; + return ret; limit = ADT7X10_REG_TO_TEMP(data, regval); hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX); regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0, ADT7X10_T_HYST_MASK); - ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval); -abort: - mutex_unlock(&data->update_lock); - return ret; + return regmap_write(data->regmap, ADT7X10_T_HYST, regval); } static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val) @@ -344,7 +328,6 @@ int adt7x10_probe(struct device *dev, const char *name, int irq, data->regmap = regmap; dev_set_drvdata(dev, data); - mutex_init(&data->update_lock); /* configure as specified */ ret = regmap_read(regmap, ADT7X10_CONFIG, &config); diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index d1c55e2eb479..007befdba977 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -37,6 +37,8 @@ #define AHT10_CMD_MEAS 0b10101100 #define AHT10_CMD_RST 0b10111010 +#define DHT20_CMD_INIT 0x71 + /* * Flags in the answer byte/command */ @@ -48,11 +50,12 @@ #define AHT10_MAX_POLL_INTERVAL_LEN 30 -enum aht10_variant { aht10, aht20 }; +enum aht10_variant { aht10, aht20, dht20}; static const struct i2c_device_id aht10_id[] = { { "aht10", aht10 }, { "aht20", aht20 }, + { "dht20", dht20 }, { }, }; MODULE_DEVICE_TABLE(i2c, aht10_id); @@ -60,8 +63,6 @@ MODULE_DEVICE_TABLE(i2c, aht10_id); /** * struct aht10_data - All the data required to operate an AHT10/AHT20 chip * @client: the i2c client associated with the AHT10/AHT20 - * @lock: a mutex that is used to prevent parallel access to the - * i2c client * @min_poll_interval: the minimum poll interval * While the poll rate limit is not 100% necessary, * the datasheet recommends that a measurement @@ -77,21 +78,18 @@ MODULE_DEVICE_TABLE(i2c, aht10_id); * AHT10/AHT20 * @crc8: crc8 support flag * @meas_size: measurements data size + * @init_cmd: Initialization command */ struct aht10_data { struct i2c_client *client; - /* - * Prevent simultaneous access to the i2c - * client and previous_poll_time - */ - struct mutex lock; ktime_t min_poll_interval; ktime_t previous_poll_time; int temperature; int humidity; bool crc8; unsigned int meas_size; + u8 init_cmd; }; /* @@ -101,13 +99,13 @@ struct aht10_data { */ static int aht10_init(struct aht10_data *data) { - const u8 cmd_init[] = {AHT10_CMD_INIT, AHT10_CAL_ENABLED | AHT10_MODE_CYC, + const u8 cmd_init[] = {data->init_cmd, AHT10_CAL_ENABLED | AHT10_MODE_CYC, 0x00}; int res; u8 status; struct i2c_client *client = data->client; - res = i2c_master_send(client, cmd_init, 3); + res = i2c_master_send(client, cmd_init, sizeof(cmd_init)); if (res < 0) return res; @@ -168,32 +166,24 @@ static int aht10_read_values(struct aht10_data *data) u8 raw_data[AHT20_MEAS_SIZE]; struct i2c_client *client = data->client; - mutex_lock(&data->lock); - if (!aht10_polltime_expired(data)) { - mutex_unlock(&data->lock); + if (!aht10_polltime_expired(data)) return 0; - } res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas)); - if (res < 0) { - mutex_unlock(&data->lock); + if (res < 0) return res; - } usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA); res = i2c_master_recv(client, raw_data, data->meas_size); if (res != data->meas_size) { - mutex_unlock(&data->lock); if (res >= 0) return -ENODATA; return res; } - if (data->crc8 && crc8_check(raw_data, data->meas_size)) { - mutex_unlock(&data->lock); + if (data->crc8 && crc8_check(raw_data, data->meas_size)) return -EIO; - } hum = ((u32)raw_data[1] << 12u) | ((u32)raw_data[2] << 4u) | @@ -210,7 +200,6 @@ static int aht10_read_values(struct aht10_data *data) data->humidity = hum; data->previous_poll_time = ktime_get_boottime(); - mutex_unlock(&data->lock); return 0; } @@ -352,14 +341,20 @@ static int aht10_probe(struct i2c_client *client) data->meas_size = AHT20_MEAS_SIZE; data->crc8 = true; crc8_populate_msb(crc8_table, AHT20_CRC8_POLY); + data->init_cmd = AHT10_CMD_INIT; + break; + case dht20: + data->meas_size = AHT20_MEAS_SIZE; + data->crc8 = true; + crc8_populate_msb(crc8_table, AHT20_CRC8_POLY); + data->init_cmd = DHT20_CMD_INIT; break; default: data->meas_size = AHT10_MEAS_SIZE; + data->init_cmd = AHT10_CMD_INIT; break; } - mutex_init(&data->lock); - res = aht10_init(data); if (res < 0) return res; diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 0dcb8a3a691d..1ca70e726298 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -20,7 +20,6 @@ #include <linux/jiffies.h> #include <linux/ktime.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/seq_file.h> #include <linux/unaligned.h> @@ -551,7 +550,6 @@ struct aqc_data { struct hid_device *hdev; struct device *hwmon_dev; struct dentry *debugfs; - struct mutex mutex; /* Used for locking access when reading and writing PWM values */ enum kinds kind; const char *name; @@ -662,7 +660,6 @@ static void aqc_delay_ctrl_report(struct aqc_data *priv) } } -/* Expects the mutex to be locked */ static int aqc_get_ctrl_data(struct aqc_data *priv) { int ret; @@ -680,7 +677,6 @@ static int aqc_get_ctrl_data(struct aqc_data *priv) return ret; } -/* Expects the mutex to be locked */ static int aqc_send_ctrl_data(struct aqc_data *priv) { int ret; @@ -721,11 +717,9 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int ty { int ret; - mutex_lock(&priv->mutex); - ret = aqc_get_ctrl_data(priv); if (ret < 0) - goto unlock_and_return; + return ret; switch (type) { case AQC_BE16: @@ -737,9 +731,6 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int ty default: ret = -EINVAL; } - -unlock_and_return: - mutex_unlock(&priv->mutex); return ret; } @@ -747,11 +738,9 @@ static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, in { int ret, i; - mutex_lock(&priv->mutex); - ret = aqc_get_ctrl_data(priv); if (ret < 0) - goto unlock_and_return; + return ret; for (i = 0; i < len; i++) { switch (types[i]) { @@ -762,18 +751,11 @@ static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, in priv->buffer[offsets[i]] = (u8)vals[i]; break; default: - ret = -EINVAL; + return -EINVAL; } } - if (ret < 0) - goto unlock_and_return; - - ret = aqc_send_ctrl_data(priv); - -unlock_and_return: - mutex_unlock(&priv->mutex); - return ret; + return aqc_send_ctrl_data(priv); } static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val, int type) @@ -953,13 +935,11 @@ static int aqc_legacy_read(struct aqc_data *priv) { int ret, i, sensor_value; - mutex_lock(&priv->mutex); - memset(priv->buffer, 0x00, priv->buffer_size); ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer, priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); if (ret < 0) - goto unlock_and_return; + return ret; /* Temperature sensor readings */ for (i = 0; i < priv->num_temp_sensors; i++) { @@ -1020,10 +1000,7 @@ static int aqc_legacy_read(struct aqc_data *priv) } priv->updated = jiffies; - -unlock_and_return: - mutex_unlock(&priv->mutex); - return ret; + return 0; } static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, @@ -1870,8 +1847,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) goto fail_and_close; } - mutex_init(&priv->mutex); - priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, priv->name, priv, &aqc_chip_info, NULL); diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c index 4174b129d1fc..44e1ecba205d 100644 --- a/drivers/hwmon/aspeed-g6-pwm-tach.c +++ b/drivers/hwmon/aspeed-g6-pwm-tach.c @@ -528,6 +528,9 @@ static const struct of_device_id aspeed_pwm_tach_match[] = { { .compatible = "aspeed,ast2600-pwm-tach", }, + { + .compatible = "aspeed,ast2700-pwm-tach", + }, {}, }; MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index 34a8f6b834c9..61b18b88ee8f 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -113,15 +113,19 @@ enum ec_sensors { ec_sensor_temp_t_sensor, /* VRM temperature [℃] */ ec_sensor_temp_vrm, + /* VRM east (right) temperature [℃] */ + ec_sensor_temp_vrme, + /* VRM west (left) temperature [℃] */ + ec_sensor_temp_vrmw, /* CPU Core voltage [mV] */ ec_sensor_in_cpu_core, /* CPU_Opt fan [RPM] */ ec_sensor_fan_cpu_opt, /* VRM heat sink fan [RPM] */ ec_sensor_fan_vrm_hs, - /* VRM east heat sink fan [RPM] */ + /* VRM east (right) heat sink fan [RPM] */ ec_sensor_fan_vrme_hs, - /* VRM west heat sink fan [RPM] */ + /* VRM west (left) heat sink fan [RPM] */ ec_sensor_fan_vrmw_hs, /* Chipset fan [RPM] */ ec_sensor_fan_chipset, @@ -157,6 +161,8 @@ enum ec_sensors { #define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb) #define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor) #define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm) +#define SENSOR_TEMP_VRME BIT(ec_sensor_temp_vrme) +#define SENSOR_TEMP_VRMW BIT(ec_sensor_temp_vrmw) #define SENSOR_IN_CPU_CORE BIT(ec_sensor_in_cpu_core) #define SENSOR_FAN_CPU_OPT BIT(ec_sensor_fan_cpu_opt) #define SENSOR_FAN_VRM_HS BIT(ec_sensor_fan_vrm_hs) @@ -182,6 +188,7 @@ enum board_family { family_amd_500_series, family_amd_600_series, family_amd_800_series, + family_amd_trx_50, family_amd_wrx_90, family_intel_200_series, family_intel_300_series, @@ -294,6 +301,19 @@ static const struct ec_sensor_info sensors_family_amd_800[] = { EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), }; +static const struct ec_sensor_info sensors_family_amd_trx_50[] = { + [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x30), + [ec_sensor_temp_cpu_package] = + EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31), + [ec_sensor_temp_vrme] = EC_SENSOR("VRM_E", hwmon_temp, 1, 0x00, 0x33), + [ec_sensor_temp_vrmw] = EC_SENSOR("VRM_W", hwmon_temp, 1, 0x00, 0x34), + [ec_sensor_fan_cpu_opt] = EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), + [ec_sensor_fan_vrmw_hs] = EC_SENSOR("VRM_E HS", hwmon_fan, 2, 0x00, 0xb4), + [ec_sensor_fan_vrme_hs] = EC_SENSOR("VRM_W HS", hwmon_fan, 2, 0x00, 0xbc), + [ec_sensor_temp_t_sensor] = + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x01, 0x04), +}; + static const struct ec_sensor_info sensors_family_amd_wrx_90[] = { [ec_sensor_temp_cpu_package] = EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31), @@ -533,6 +553,15 @@ static const struct ec_board_info board_info_pro_art_x870E_creator_wifi = { .family = family_amd_800_series, }; +static const struct ec_board_info board_info_pro_ws_trx50_sage_wifi = { + /* Board also has a nct6798 */ + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_VRME | + SENSOR_TEMP_VRMW | SENSOR_FAN_CPU_OPT | SENSOR_FAN_VRME_HS | + SENSOR_FAN_VRMW_HS | SENSOR_TEMP_T_SENSOR, + .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, + .family = family_amd_trx_50, +}; + static const struct ec_board_info board_info_pro_ws_wrx90e_sage_se = { /* Board also has a nct6798 with 7 more fans and temperatures */ .sensors = SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_T_SENSOR | @@ -581,6 +610,14 @@ static const struct ec_board_info board_info_strix_b850_i_gaming_wifi = { .family = family_amd_800_series, }; +static const struct ec_board_info board_info_strix_x470_i_gaming = { + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | + SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | + SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE, + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, + .family = family_amd_400_series, +}; + static const struct ec_board_info board_info_strix_x570_e_gaming = { .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR | @@ -628,6 +665,13 @@ static const struct ec_board_info board_info_strix_x670e_i_gaming_wifi = { .family = family_amd_600_series, }; +static const struct ec_board_info board_info_strix_x870_f_gaming_wifi = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR, + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, + .family = family_amd_800_series, +}; + static const struct ec_board_info board_info_strix_x870_i_gaming_wifi = { .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_MB | SENSOR_TEMP_VRM, @@ -643,6 +687,14 @@ static const struct ec_board_info board_info_strix_x870e_e_gaming_wifi = { .family = family_amd_800_series, }; +static const struct ec_board_info board_info_strix_x870e_h_gaming_wifi7 = { + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR | + SENSOR_FAN_CPU_OPT, + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, + .family = family_amd_800_series, +}; + static const struct ec_board_info board_info_strix_z390_f_gaming = { .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR | @@ -739,6 +791,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_pro_art_x670E_creator_wifi), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI", &board_info_pro_art_x870E_creator_wifi), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS TRX50-SAGE WIFI", + &board_info_pro_ws_trx50_sage_wifi), DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS WRX90E-SAGE SE", &board_info_pro_ws_wrx90e_sage_se), DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE", @@ -771,6 +825,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_strix_b650e_i_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B850-I GAMING WIFI", &board_info_strix_b850_i_gaming_wifi), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X470-I GAMING", + &board_info_strix_x470_i_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING", &board_info_strix_x570_e_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING WIFI II", @@ -783,10 +839,14 @@ static const struct dmi_system_id dmi_table[] = { &board_info_strix_x670e_e_gaming_wifi), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X670E-I GAMING WIFI", &board_info_strix_x670e_i_gaming_wifi), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870-F GAMING WIFI", + &board_info_strix_x870_f_gaming_wifi), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870-I GAMING WIFI", &board_info_strix_x870_i_gaming_wifi), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-E GAMING WIFI", &board_info_strix_x870e_e_gaming_wifi), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-H GAMING WIFI7", + &board_info_strix_x870e_h_gaming_wifi7), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING", &board_info_strix_z390_f_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z490-F GAMING", @@ -1274,6 +1334,9 @@ static int asus_ec_probe(struct platform_device *pdev) case family_amd_800_series: ec_data->sensors_info = sensors_family_amd_800; break; + case family_amd_trx_50: + ec_data->sensors_info = sensors_family_amd_trx_50; + break; case family_amd_wrx_90: ec_data->sensors_info = sensors_family_amd_wrx_90; break; diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c index e5e93a20723c..10a1f5aca988 100644 --- a/drivers/hwmon/asus_rog_ryujin.c +++ b/drivers/hwmon/asus_rog_ryujin.c @@ -81,10 +81,6 @@ static const char *const rog_ryujin_speed_label[] = { struct rog_ryujin_data { struct hid_device *hdev; struct device *hwmon_dev; - /* For locking access to buffer */ - struct mutex buffer_lock; - /* For queueing multiple readers */ - struct mutex status_report_request_mutex; /* For reinitializing the completions below */ spinlock_t status_report_request_lock; struct completion cooler_status_received; @@ -153,18 +149,10 @@ static umode_t rog_ryujin_is_visible(const void *data, /* Writes the command to the device with the rest of the report filled with zeroes */ static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length) { - int ret; - - mutex_lock(&priv->buffer_lock); - memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00); - ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH); - - mutex_unlock(&priv->buffer_lock); - return ret; + return hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH); } -/* Assumes priv->status_report_request_mutex is locked */ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length, struct completion *status_completion) { @@ -196,14 +184,11 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i static int rog_ryujin_get_status(struct rog_ryujin_data *priv) { - int ret = mutex_lock_interruptible(&priv->status_report_request_mutex); - - if (ret < 0) - return ret; + int ret; if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) { /* Data is up to date */ - goto unlock_and_return; + return 0; } /* Retrieve cooler status */ @@ -211,36 +196,30 @@ static int rog_ryujin_get_status(struct rog_ryujin_data *priv) rog_ryujin_execute_cmd(priv, get_cooler_status_cmd, GET_CMD_LENGTH, &priv->cooler_status_received); if (ret < 0) - goto unlock_and_return; + return ret; /* Retrieve controller status (speeds) */ ret = rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH, &priv->controller_status_received); if (ret < 0) - goto unlock_and_return; + return ret; /* Retrieve cooler duty */ ret = rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH, &priv->cooler_duty_received); if (ret < 0) - goto unlock_and_return; + return ret; /* Retrieve controller duty */ ret = rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH, &priv->controller_duty_received); if (ret < 0) - goto unlock_and_return; - - priv->updated = jiffies; - -unlock_and_return: - mutex_unlock(&priv->status_report_request_mutex); - if (ret < 0) return ret; + priv->updated = jiffies; return 0; } @@ -303,14 +282,11 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel * Retrieve cooler duty since both pump and internal fan are set * together, then write back with one of them modified. */ - ret = mutex_lock_interruptible(&priv->status_report_request_mutex); - if (ret < 0) - return ret; ret = rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH, &priv->cooler_duty_received); if (ret < 0) - goto unlock_and_return; + return ret; memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH); @@ -329,11 +305,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val; } - ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set); -unlock_and_return: - mutex_unlock(&priv->status_report_request_mutex); - if (ret < 0) - return ret; + return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set); } else { /* * Controller fan duty (channel == 2). No need to retrieve current @@ -538,8 +510,6 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id goto fail_and_close; } - mutex_init(&priv->status_report_request_mutex); - mutex_init(&priv->buffer_lock); spin_lock_init(&priv->status_report_request_lock); init_completion(&priv->cooler_status_received); init_completion(&priv->controller_status_received); diff --git a/drivers/hwmon/chipcap2.c b/drivers/hwmon/chipcap2.c index 9d071f7ca9d2..645b8c2e704e 100644 --- a/drivers/hwmon/chipcap2.c +++ b/drivers/hwmon/chipcap2.c @@ -81,7 +81,6 @@ struct cc2_data { struct completion complete; struct device *hwmon; struct i2c_client *client; - struct mutex dev_access_lock; /* device access lock */ struct regulator *regulator; const char *name; int irq_ready; @@ -558,8 +557,6 @@ static int cc2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, { struct cc2_data *data = dev_get_drvdata(dev); - guard(mutex)(&data->dev_access_lock); - switch (type) { case hwmon_temp: return cc2_measurement(data, type, val); @@ -600,8 +597,6 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, if (val < 0 || val > CC2_RH_MAX) return -EINVAL; - guard(mutex)(&data->dev_access_lock); - switch (attr) { case hwmon_humidity_min: cmd = CC2_W_ALARM_L_ON; @@ -708,8 +703,6 @@ static int cc2_probe(struct i2c_client *client) i2c_set_clientdata(client, data); - mutex_init(&data->dev_access_lock); - data->client = client; data->regulator = devm_regulator_get_exclusive(dev, "vdd"); diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c index b7b911f8359c..b6e508e43fa1 100644 --- a/drivers/hwmon/corsair-cpro.c +++ b/drivers/hwmon/corsair-cpro.c @@ -40,7 +40,7 @@ #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 + * in bytes 1 and 2 as a two's complement value * returns 0x11 in byte 0 if no sensor is connected */ #define CTL_GET_VOLT 0x12 /* @@ -90,10 +90,10 @@ struct ccp_device { u8 *cmd_buffer; u8 *buffer; int buffer_recv_size; /* number of received bytes in buffer */ - int target[6]; + int target[NUM_FANS]; DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS); DECLARE_BITMAP(fan_cnct, NUM_FANS); - char fan_label[6][LABEL_LENGTH]; + char fan_label[NUM_FANS][LABEL_LENGTH]; u8 firmware_ver[3]; u8 bootloader_ver[2]; }; @@ -258,7 +258,7 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type, ret = get_data(ccp, CTL_GET_TMP, channel, true); if (ret < 0) return ret; - *val = ret * 10; + *val = (s16)ret * 10; return 0; default: break; diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index 6b5c8f200780..dddbd2463f8d 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -9,11 +9,9 @@ #include <linux/errno.h> #include <linux/hid.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/slab.h> #include <linux/types.h> @@ -124,7 +122,6 @@ struct corsairpsu_data { struct device *hwmon_dev; struct dentry *debugfs; struct completion wait_completion; - struct mutex lock; /* for locking access to cmd_buffer */ u8 *cmd_buffer; char vendor[REPLY_SIZE]; char product[REPLY_SIZE]; @@ -220,7 +217,6 @@ static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, voi { int ret; - mutex_lock(&priv->lock); switch (cmd) { case PSU_CMD_RAIL_VOLTS_HCRIT: case PSU_CMD_RAIL_VOLTS_LCRIT: @@ -230,17 +226,13 @@ static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, voi case PSU_CMD_RAIL_WATTS: ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL); if (ret < 0) - goto cmd_fail; + return ret; break; default: break; } - ret = corsairpsu_usb_cmd(priv, 3, cmd, 0, data); - -cmd_fail: - mutex_unlock(&priv->lock); - return ret; + return corsairpsu_usb_cmd(priv, 3, cmd, 0, data); } static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, long *val) @@ -797,7 +789,6 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id priv->hdev = hdev; hid_set_drvdata(hdev, priv); - mutex_init(&priv->lock); init_completion(&priv->wait_completion); hid_device_io_start(hdev); diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index cbe1a74a3dee..683baf361c4c 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -1534,6 +1534,15 @@ static const struct i8k_fan_control_data i8k_fan_control_data[] __initconst = { static const struct dmi_system_id i8k_whitelist_fan_control[] __initconst = { { + .ident = "Dell G5 5505", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G5 5505"), + + }, + .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3], + }, + { .ident = "Dell Latitude 5480", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), diff --git a/drivers/hwmon/drivetemp.c b/drivers/hwmon/drivetemp.c index 291d91f68646..9c5b021aab86 100644 --- a/drivers/hwmon/drivetemp.c +++ b/drivers/hwmon/drivetemp.c @@ -102,7 +102,6 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> -#include <linux/mutex.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_driver.h> @@ -110,7 +109,6 @@ struct drivetemp_data { struct list_head list; /* list of instantiated devices */ - struct mutex lock; /* protect data buffer accesses */ struct scsi_device *sdev; /* SCSI device */ struct device *dev; /* instantiating device */ struct device *hwdev; /* hardware monitoring device */ @@ -462,9 +460,7 @@ static int drivetemp_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_temp_input: case hwmon_temp_lowest: case hwmon_temp_highest: - mutex_lock(&st->lock); err = st->get_temp(st, attr, val); - mutex_unlock(&st->lock); break; case hwmon_temp_lcrit: *val = st->temp_lcrit; @@ -566,7 +562,6 @@ static int drivetemp_add(struct device *dev) st->sdev = sdev; st->dev = dev; - mutex_init(&st->lock); if (drivetemp_identify(st)) { err = -ENODEV; diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index eca33220d34a..ccce948a4306 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -17,7 +17,6 @@ #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/sysfs.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/util_macros.h> @@ -30,7 +29,6 @@ enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 }; struct thermal_data { enum emc1403_chip chip; struct regmap *regmap; - struct mutex mutex; }; static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -268,8 +266,8 @@ static s8 emc1403_temp_regs_low[][4] = { }, }; -static int __emc1403_get_temp(struct thermal_data *data, int channel, - enum emc1403_reg_map map, long *val) +static int emc1403_get_temp(struct thermal_data *data, int channel, + enum emc1403_reg_map map, long *val) { unsigned int regvalh; unsigned int regvall = 0; @@ -295,38 +293,23 @@ static int __emc1403_get_temp(struct thermal_data *data, int channel, return 0; } -static int emc1403_get_temp(struct thermal_data *data, int channel, - enum emc1403_reg_map map, long *val) -{ - int ret; - - mutex_lock(&data->mutex); - ret = __emc1403_get_temp(data, channel, map, val); - mutex_unlock(&data->mutex); - - return ret; -} - static int emc1403_get_hyst(struct thermal_data *data, int channel, enum emc1403_reg_map map, long *val) { int hyst, ret; long limit; - mutex_lock(&data->mutex); - ret = __emc1403_get_temp(data, channel, map, &limit); + ret = emc1403_get_temp(data, channel, map, &limit); if (ret < 0) - goto unlock; + return ret; ret = regmap_read(data->regmap, 0x21, &hyst); if (ret < 0) - goto unlock; + return ret; if (map == temp_min) *val = limit + hyst * 1000; else *val = limit - hyst * 1000; -unlock: - mutex_unlock(&data->mutex); - return ret; + return 0; } static int emc1403_temp_read(struct thermal_data *data, u32 attr, int channel, long *val) @@ -451,20 +434,16 @@ static int emc1403_set_hyst(struct thermal_data *data, long val) else val = clamp_val(val, 0, 255000); - mutex_lock(&data->mutex); - ret = __emc1403_get_temp(data, 0, temp_crit, &limit); + ret = emc1403_get_temp(data, 0, temp_crit, &limit); if (ret < 0) - goto unlock; + return ret; hyst = limit - val; if (data->chip == emc1428) hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 127); else hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255); - ret = regmap_write(data->regmap, 0x21, hyst); -unlock: - mutex_unlock(&data->mutex); - return ret; + return regmap_write(data->regmap, 0x21, hyst); } static int emc1403_set_temp(struct thermal_data *data, int channel, @@ -478,7 +457,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regh = emc1403_temp_regs[channel][map]; regl = emc1403_temp_regs_low[channel][map]; - mutex_lock(&data->mutex); if (regl >= 0) { if (data->chip == emc1428) val = clamp_val(val, -128000, 127875); @@ -487,7 +465,7 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval = DIV_ROUND_CLOSEST(val, 125); ret = regmap_write(data->regmap, regh, (regval >> 3) & 0xff); if (ret < 0) - goto unlock; + return ret; ret = regmap_write(data->regmap, regl, (regval & 0x07) << 5); } else { if (data->chip == emc1428) @@ -497,8 +475,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel, regval = DIV_ROUND_CLOSEST(val, 1000); ret = regmap_write(data->regmap, regh, regval); } -unlock: - mutex_unlock(&data->mutex); return ret; } @@ -695,8 +671,6 @@ static int emc1403_probe(struct i2c_client *client) if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); - mutex_init(&data->mutex); - hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, client->name, data, &emc1403_chip_info, diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 60eddc7b0270..9b8e925af030 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -277,8 +277,10 @@ fan1_input_show(struct device *dev, struct device_attribute *da, char *buf) { struct emc2103_data *data = emc2103_update_device(dev); int rpm = 0; + mutex_lock(&data->update_lock); if (data->fan_tach != 0) rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_tach; + mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", rpm); } @@ -363,10 +365,12 @@ fan1_target_show(struct device *dev, struct device_attribute *da, char *buf) struct emc2103_data *data = emc2103_update_device(dev); int rpm = 0; + mutex_lock(&data->update_lock); /* high byte of 0xff indicates disabled so return 0 */ if ((data->fan_target != 0) && ((data->fan_target & 0x1fe0) != 0x1fe0)) rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_target; + mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", rpm); } diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index 8aeec16a7a90..08dcc6a7fb62 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -12,7 +12,6 @@ #include <linux/jiffies.h> #include <linux/math.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/slab.h> #include <linux/watchdog.h> @@ -62,10 +61,6 @@ enum WATCHDOG_RESOLUTION { struct fts_data { struct i2c_client *client; - /* update sensor data lock */ - struct mutex update_lock; - /* read/write register lock */ - struct mutex access_lock; unsigned long last_updated; /* in jiffies */ struct watchdog_device wdd; enum WATCHDOG_RESOLUTION resolution; @@ -98,21 +93,15 @@ static int fts_read_byte(struct i2c_client *client, unsigned short reg) { int ret; unsigned char page = reg >> 8; - struct fts_data *data = dev_get_drvdata(&client->dev); - - mutex_lock(&data->access_lock); dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page); ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page); if (ret < 0) - goto error; + return ret; reg &= 0xFF; ret = i2c_smbus_read_byte_data(client, reg); dev_dbg(&client->dev, "read - reg: 0x%.02x: val: 0x%.02x\n", reg, ret); - -error: - mutex_unlock(&data->access_lock); return ret; } @@ -121,22 +110,16 @@ static int fts_write_byte(struct i2c_client *client, unsigned short reg, { int ret; unsigned char page = reg >> 8; - struct fts_data *data = dev_get_drvdata(&client->dev); - - mutex_lock(&data->access_lock); dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page); ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page); if (ret < 0) - goto error; + return ret; reg &= 0xFF; dev_dbg(&client->dev, "write - reg: 0x%.02x: val: 0x%.02x\n", reg, value); ret = i2c_smbus_write_byte_data(client, reg, value); - -error: - mutex_unlock(&data->access_lock); return ret; } @@ -145,44 +128,40 @@ error: /*****************************************************************************/ static int fts_update_device(struct fts_data *data) { - int i; - int err = 0; + int i, err; - mutex_lock(&data->update_lock); if (!time_after(jiffies, data->last_updated + 2 * HZ) && data->valid) - goto exit; + return 0; err = fts_read_byte(data->client, FTS_DEVICE_STATUS_REG); if (err < 0) - goto exit; + return err; data->valid = !!(err & 0x02); /* Data not ready yet */ - if (unlikely(!data->valid)) { - err = -EAGAIN; - goto exit; - } + if (unlikely(!data->valid)) + return -EAGAIN; err = fts_read_byte(data->client, FTS_FAN_PRESENT_REG); if (err < 0) - goto exit; + return err; data->fan_present = err; err = fts_read_byte(data->client, FTS_FAN_EVENT_REG); if (err < 0) - goto exit; + return err; data->fan_alarm = err; for (i = 0; i < FTS_NO_FAN_SENSORS; i++) { if (data->fan_present & BIT(i)) { err = fts_read_byte(data->client, FTS_REG_FAN_INPUT(i)); if (err < 0) - goto exit; + return err; data->fan_input[i] = err; err = fts_read_byte(data->client, FTS_REG_FAN_SOURCE(i)); if (err < 0) - goto exit; + return err; data->fan_source[i] = err; } else { data->fan_input[i] = 0; @@ -192,27 +171,24 @@ static int fts_update_device(struct fts_data *data) err = fts_read_byte(data->client, FTS_SENSOR_EVENT_REG); if (err < 0) - goto exit; + return err; data->temp_alarm = err; for (i = 0; i < FTS_NO_TEMP_SENSORS; i++) { err = fts_read_byte(data->client, FTS_REG_TEMP_INPUT(i)); if (err < 0) - goto exit; + return err; data->temp_input[i] = err; } for (i = 0; i < FTS_NO_VOLT_SENSORS; i++) { err = fts_read_byte(data->client, FTS_REG_VOLT(i)); if (err < 0) - goto exit; + return err; data->volt[i] = err; } data->last_updated = jiffies; - err = 0; -exit: - mutex_unlock(&data->update_lock); - return err; + return 0; } /*****************************************************************************/ @@ -470,18 +446,14 @@ static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, if (val) return -EINVAL; - mutex_lock(&data->update_lock); ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(channel)); - if (ret >= 0) - ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel), - ret | 0x1); - if (ret >= 0) - data->valid = false; - - mutex_unlock(&data->update_lock); if (ret < 0) return ret; - + ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel), + ret | 0x1); + if (ret < 0) + return ret; + data->valid = false; return 0; default: break; @@ -493,18 +465,14 @@ static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, if (val) return -EINVAL; - mutex_lock(&data->update_lock); ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(channel)); - if (ret >= 0) - ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel), - ret | 0x1); - if (ret >= 0) - data->valid = false; - - mutex_unlock(&data->update_lock); if (ret < 0) return ret; - + ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel), + ret | 0x1); + if (ret < 0) + return ret; + data->valid = false; return 0; default: break; @@ -648,8 +616,6 @@ static int fts_probe(struct i2c_client *client) if (!data) return -ENOMEM; - mutex_init(&data->update_lock); - mutex_init(&data->access_lock); data->client = client; dev_set_drvdata(&client->dev, data); diff --git a/drivers/hwmon/gpd-fan.c b/drivers/hwmon/gpd-fan.c index f81c3bc422f4..237f496c4862 100644 --- a/drivers/hwmon/gpd-fan.c +++ b/drivers/hwmon/gpd-fan.c @@ -26,9 +26,6 @@ static char *gpd_fan_board = ""; module_param(gpd_fan_board, charp, 0444); -// EC read/write locker, protecting a sequence of EC operations -static DEFINE_MUTEX(gpd_fan_sequence_lock); - enum gpd_board { win_mini, win4_6800u, @@ -481,87 +478,60 @@ static int gpd_fan_hwmon_read(__always_unused struct device *dev, { int ret; - ret = mutex_lock_interruptible(&gpd_fan_sequence_lock); - if (ret) - return ret; - if (type == hwmon_fan) { if (attr == hwmon_fan_input) { ret = gpd_read_rpm(); if (ret < 0) - goto OUT; + return ret; *val = ret; - ret = 0; - goto OUT; + return 0; } } else if (type == hwmon_pwm) { switch (attr) { case hwmon_pwm_enable: *val = gpd_driver_priv.pwm_enable; - ret = 0; - goto OUT; + return 0; case hwmon_pwm_input: ret = gpd_read_pwm(); if (ret < 0) - goto OUT; + return ret; *val = ret; - ret = 0; - goto OUT; + return 0; } } - ret = -EOPNOTSUPP; - -OUT: - mutex_unlock(&gpd_fan_sequence_lock); - return ret; + return -EOPNOTSUPP; } static int gpd_fan_hwmon_write(__always_unused struct device *dev, enum hwmon_sensor_types type, u32 attr, __always_unused int channel, long val) { - int ret; - - ret = mutex_lock_interruptible(&gpd_fan_sequence_lock); - if (ret) - return ret; - if (type == hwmon_pwm) { switch (attr) { case hwmon_pwm_enable: - if (!in_range(val, 0, 3)) { - ret = -EINVAL; - goto OUT; - } + if (!in_range(val, 0, 3)) + return -EINVAL; gpd_driver_priv.pwm_enable = val; gpd_set_pwm_enable(gpd_driver_priv.pwm_enable); - ret = 0; - goto OUT; + return 0; case hwmon_pwm_input: - if (!in_range(val, 0, 256)) { - ret = -ERANGE; - goto OUT; - } + if (!in_range(val, 0, 256)) + return -EINVAL; gpd_driver_priv.pwm_value = val; - ret = gpd_write_pwm(val); - goto OUT; + return gpd_write_pwm(val); } } - ret = -EOPNOTSUPP; - -OUT: - mutex_unlock(&gpd_fan_sequence_lock); - return ret; + return -EOPNOTSUPP; } static const struct hwmon_ops gpd_fan_ops = { diff --git a/drivers/hwmon/hs3001.c b/drivers/hwmon/hs3001.c index 24ed3fb9a43a..50c6c15f8b18 100644 --- a/drivers/hwmon/hs3001.c +++ b/drivers/hwmon/hs3001.c @@ -42,7 +42,6 @@ struct hs3001_data { struct i2c_client *client; - struct mutex i2c_lock; /* lock for sending i2c commands */ u32 wait_time; /* in us */ int temperature; /* in milli degree */ u32 humidity; /* in milli % */ @@ -112,12 +111,9 @@ static int hs3001_read(struct device *dev, enum hwmon_sensor_types type, struct i2c_client *client = data->client; int ret; - mutex_lock(&data->i2c_lock); ret = i2c_master_send(client, NULL, 0); - if (ret < 0) { - mutex_unlock(&data->i2c_lock); + if (ret < 0) return ret; - } /* * Sensor needs some time to process measurement depending on @@ -126,8 +122,6 @@ static int hs3001_read(struct device *dev, enum hwmon_sensor_types type, fsleep(data->wait_time); ret = hs3001_data_fetch_command(client, data); - mutex_unlock(&data->i2c_lock); - if (ret < 0) return ret; @@ -211,8 +205,6 @@ static int hs3001_probe(struct i2c_client *client) data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION + HS3001_14BIT_RESOLUTION); - mutex_init(&data->i2c_lock); - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c index 2a530da21949..bf006cb272b1 100644 --- a/drivers/hwmon/i5500_temp.c +++ b/drivers/hwmon/i5500_temp.c @@ -8,13 +8,10 @@ #include <linux/bitops.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/slab.h> -#include <linux/jiffies.h> #include <linux/device.h> #include <linux/pci.h> #include <linux/hwmon.h> #include <linux/err.h> -#include <linux/mutex.h> /* Register definitions from datasheet */ #define REG_TSTHRCATA 0xE2 diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 356d19b7675c..ff67b03189f7 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -117,7 +117,6 @@ struct ina238_config { struct ina238_data { const struct ina238_config *config; struct i2c_client *client; - struct mutex config_lock; struct regmap *regmap; u32 rshunt; int gain; @@ -607,31 +606,18 @@ static int ina238_read(struct device *dev, enum hwmon_sensor_types type, static int ina238_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { - struct ina238_data *data = dev_get_drvdata(dev); - int err; - - mutex_lock(&data->config_lock); - switch (type) { case hwmon_in: - err = ina238_write_in(dev, attr, channel, val); - break; + return ina238_write_in(dev, attr, channel, val); case hwmon_curr: - err = ina238_write_curr(dev, attr, val); - break; + return ina238_write_curr(dev, attr, val); case hwmon_power: - err = ina238_write_power_max(dev, val); - break; + return ina238_write_power_max(dev, val); case hwmon_temp: - err = ina238_write_temp_max(dev, val); - break; + return ina238_write_temp_max(dev, val); default: - err = -EOPNOTSUPP; - break; + return -EOPNOTSUPP; } - - mutex_unlock(&data->config_lock); - return err; } static umode_t ina238_is_visible(const void *drvdata, @@ -757,8 +743,6 @@ static int ina238_probe(struct i2c_client *client) /* set the device type */ data->config = &ina238_config[chip]; - mutex_init(&data->config_lock); - data->regmap = devm_regmap_init_i2c(client, &ina238_regmap_config); if (IS_ERR(data->regmap)) { dev_err(dev, "failed to allocate register map\n"); diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index bc3c1f7314b3..69ac0468dee4 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -156,7 +156,6 @@ struct ina2xx_data { long rshunt; long current_lsb_uA; long power_lsb_uW; - struct mutex config_lock; struct regmap *regmap; struct i2c_client *client; }; @@ -390,22 +389,19 @@ static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg, int regval; int ret; - mutex_lock(&data->config_lock); ret = regmap_read(regmap, INA226_MASK_ENABLE, ®val); if (ret) - goto abort; + return ret; if (regval & mask) { ret = regmap_read(regmap, INA226_ALERT_LIMIT, ®val); if (ret) - goto abort; + return ret; *val = ina2xx_get_value(data, reg, regval); } else { *val = 0; } -abort: - mutex_unlock(&data->config_lock); - return ret; + return 0; } static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, long val) @@ -421,23 +417,20 @@ static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, * due to register write sequence. Then, only enable the alert * if the value is non-zero. */ - mutex_lock(&data->config_lock); ret = regmap_update_bits(regmap, INA226_MASK_ENABLE, INA226_ALERT_CONFIG_MASK, 0); if (ret < 0) - goto abort; + return ret; ret = regmap_write(regmap, INA226_ALERT_LIMIT, ina226_alert_to_reg(data, reg, val)); if (ret < 0) - goto abort; + return ret; if (val) - ret = regmap_update_bits(regmap, INA226_MASK_ENABLE, - INA226_ALERT_CONFIG_MASK, mask); -abort: - mutex_unlock(&data->config_lock); - return ret; + return regmap_update_bits(regmap, INA226_MASK_ENABLE, + INA226_ALERT_CONFIG_MASK, mask); + return 0; } static int ina2xx_chip_read(struct device *dev, u32 attr, long *val) @@ -859,9 +852,9 @@ static ssize_t shunt_resistor_store(struct device *dev, if (status < 0) return status; - mutex_lock(&data->config_lock); + hwmon_lock(dev); status = ina2xx_set_shunt(data, val); - mutex_unlock(&data->config_lock); + hwmon_unlock(dev); if (status < 0) return status; return count; @@ -951,7 +944,6 @@ static int ina2xx_probe(struct i2c_client *client) data->client = client; data->config = &ina2xx_config[chip]; data->chip = chip; - mutex_init(&data->config_lock); data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config); if (IS_ERR(data->regmap)) { diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index ce0e3f214f5b..5ecc68dcf169 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -11,7 +11,6 @@ #include <linux/hwmon-sysfs.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -115,7 +114,6 @@ struct ina3221_input { * @regmap: Register map of the device * @fields: Register fields of the device * @inputs: Array of channel input source specific structures - * @lock: mutex lock to serialize sysfs attribute accesses * @reg_config: Register value of INA3221_CONFIG * @summation_shunt_resistor: equivalent shunt resistor value for summation * @summation_channel_control: Value written to SCC field in INA3221_MASK_ENABLE @@ -126,7 +124,6 @@ struct ina3221_data { struct regmap *regmap; struct regmap_field *fields[F_MAX_FIELDS]; struct ina3221_input inputs[INA3221_NUM_CHANNELS]; - struct mutex lock; u32 reg_config; int summation_shunt_resistor; u32 summation_channel_control; @@ -530,11 +527,8 @@ fail: static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { - struct ina3221_data *ina = dev_get_drvdata(dev); int ret; - mutex_lock(&ina->lock); - switch (type) { case hwmon_chip: ret = ina3221_read_chip(dev, attr, val); @@ -550,20 +544,14 @@ static int ina3221_read(struct device *dev, enum hwmon_sensor_types type, ret = -EOPNOTSUPP; break; } - - mutex_unlock(&ina->lock); - return ret; } static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val) { - struct ina3221_data *ina = dev_get_drvdata(dev); int ret; - mutex_lock(&ina->lock); - switch (type) { case hwmon_chip: ret = ina3221_write_chip(dev, attr, val); @@ -579,9 +567,6 @@ static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, ret = -EOPNOTSUPP; break; } - - mutex_unlock(&ina->lock); - return ret; } @@ -886,7 +871,6 @@ static int ina3221_probe(struct i2c_client *client) } ina->pm_dev = dev; - mutex_init(&ina->lock); dev_set_drvdata(dev, ina); /* Enable PM runtime -- status is suspended by default */ @@ -925,7 +909,6 @@ fail: /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ for (i = 0; i < INA3221_NUM_CHANNELS; i++) pm_runtime_put_noidle(ina->pm_dev); - mutex_destroy(&ina->lock); return ret; } @@ -941,8 +924,6 @@ static void ina3221_remove(struct i2c_client *client) /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */ for (i = 0; i < INA3221_NUM_CHANNELS; i++) pm_runtime_put_noidle(ina->pm_dev); - - mutex_destroy(&ina->lock); } static int ina3221_suspend(struct device *dev) diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 06f0ab2f52fa..6549dc543781 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -19,7 +19,6 @@ #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/regmap.h> /* Addresses to scan */ @@ -179,7 +178,6 @@ static struct jc42_chips jc42_chips[] = { /* Each client has this additional data */ struct jc42_data { - struct mutex update_lock; /* protect register access */ struct regmap *regmap; bool extended; /* true if extended range supported */ bool valid; @@ -216,8 +214,6 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type, unsigned int regval; int ret, temp, hyst; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_temp_input: ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); @@ -295,8 +291,6 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type, break; } - mutex_unlock(&data->update_lock); - return ret; } @@ -308,8 +302,6 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type, int diff, hyst; int ret; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_temp_min: ret = regmap_write(data->regmap, JC42_REG_TEMP_LOWER, @@ -356,8 +348,6 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type, break; } - mutex_unlock(&data->update_lock); - return ret; } @@ -498,7 +488,6 @@ static int jc42_probe(struct i2c_client *client) return PTR_ERR(data->regmap); i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); ret = regmap_read(data->regmap, JC42_REG_CAP, &cap); if (ret) diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index b98d5ec72c4f..a5d8f45b7881 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -31,9 +31,6 @@ static bool force; module_param(force, bool, 0444); MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); -/* Provide lock for writing to NB_SMU_IND_ADDR */ -static DEFINE_MUTEX(nb_smu_ind_mutex); - #ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 #define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3 #endif @@ -85,6 +82,12 @@ static DEFINE_MUTEX(nb_smu_ind_mutex); #define AMD_I3255_STR "3255" /* + * PCI Device IDs for AMD's Family 17h-based SOCs. + * Defining locally as IDs are not shared. + */ +#define PCI_DEVICE_ID_AMD_17H_M90H_DF_F3 0x1663 + +/* * PCI Device IDs for AMD's Family 1Ah-based SOCs. * Defining locally as IDs are not shared. */ @@ -137,12 +140,10 @@ static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval) static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn, unsigned int base, int offset, u32 *val) { - mutex_lock(&nb_smu_ind_mutex); pci_bus_write_config_dword(pdev->bus, devfn, base, offset); pci_bus_read_config_dword(pdev->bus, devfn, base + 4, val); - mutex_unlock(&nb_smu_ind_mutex); } static void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval) @@ -553,6 +554,7 @@ static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M40H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M90H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_MA0H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) }, diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 8b53bb312069..9378a47bf5af 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -843,17 +843,18 @@ static int __init lm78_isa_found(unsigned short address) } } -#define REALLY_SLOW_IO /* * We need the timeouts for at least some LM78-like * chips. But only if we read 'undefined' registers. + * There used to be a "#define REALLY_SLOW_IO" to enforce that, but + * this has been without any effect since more than a decade, so it + * has been dropped. */ val = inb_p(address + 1); if (inb_p(address + 2) != val || inb_p(address + 3) != val || inb_p(address + 7) != val) goto release; -#undef REALLY_SLOW_IO /* * We should be able to change the 7 LSB of the address port. The diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index d2d970e73c61..37bf2d1d3d09 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -116,8 +116,14 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; (((val) < 0 ? (val) - 500 : \ (val) + 500) / 1000)) -#define FAN_FROM_REG(reg, div) ((reg) == 255 || (reg) == 0 ? 0 : \ - (1350000 + (reg)*(div) / 2) / ((reg) * (div))) +static int fan_from_reg(int reg, int div) +{ + if (reg == 255 || reg == 0) + return 0; + + return (1350000 + reg * div / 2) / (reg * div); +} + #define FAN_TO_REG(val, div) ((val) * (div) * 255 <= 1350000 ? 255 : \ (1350000 + (val)*(div) / 2) / ((val) * (div))) @@ -465,7 +471,7 @@ static ssize_t fan_input_show(struct device *dev, struct lm87_data *data = lm87_update_device(dev); int nr = to_sensor_dev_attr(attr)->index; - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr], FAN_DIV_FROM_REG(data->fan_div[nr]))); } @@ -475,7 +481,7 @@ static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr, struct lm87_data *data = lm87_update_device(dev); int nr = to_sensor_dev_attr(attr)->index; - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + return sprintf(buf, "%d\n", fan_from_reg(data->fan_min[nr], FAN_DIV_FROM_REG(data->fan_div[nr]))); } @@ -534,7 +540,7 @@ static ssize_t fan_div_store(struct device *dev, return err; mutex_lock(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], + min = fan_from_reg(data->fan_min[nr], FAN_DIV_FROM_REG(data->fan_div[nr])); switch (val) { diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index c1f528e292f3..3c10a5066b53 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -108,7 +108,6 @@ #include <linux/hwmon.h> #include <linux/kstrtox.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -735,7 +734,6 @@ struct lm90_data { struct hwmon_channel_info temp_info; const struct hwmon_channel_info *info[3]; struct hwmon_chip_info chip; - struct mutex update_lock; struct delayed_work alert_work; struct work_struct report_work; bool valid; /* true if register values are valid */ @@ -1226,9 +1224,9 @@ static int lm90_update_alarms(struct lm90_data *data, bool force) { int err; - mutex_lock(&data->update_lock); + hwmon_lock(data->hwmon_dev); err = lm90_update_alarms_locked(data, force); - mutex_unlock(&data->update_lock); + hwmon_unlock(data->hwmon_dev); return err; } @@ -1519,9 +1517,7 @@ static int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val) int err; u16 bit; - mutex_lock(&data->update_lock); err = lm90_update_device(dev); - mutex_unlock(&data->update_lock); if (err) return err; @@ -1590,11 +1586,9 @@ static int lm90_temp_write(struct device *dev, u32 attr, int channel, long val) struct lm90_data *data = dev_get_drvdata(dev); int err; - mutex_lock(&data->update_lock); - err = lm90_update_device(dev); if (err) - goto error; + return err; switch (attr) { case hwmon_temp_min: @@ -1624,9 +1618,6 @@ static int lm90_temp_write(struct device *dev, u32 attr, int channel, long val) err = -EOPNOTSUPP; break; } -error: - mutex_unlock(&data->update_lock); - return err; } @@ -1662,9 +1653,7 @@ static int lm90_chip_read(struct device *dev, u32 attr, int channel, long *val) struct lm90_data *data = dev_get_drvdata(dev); int err; - mutex_lock(&data->update_lock); err = lm90_update_device(dev); - mutex_unlock(&data->update_lock); if (err) return err; @@ -1710,11 +1699,9 @@ static int lm90_chip_write(struct device *dev, u32 attr, int channel, long val) struct i2c_client *client = data->client; int err; - mutex_lock(&data->update_lock); - err = lm90_update_device(dev); if (err) - goto error; + return err; switch (attr) { case hwmon_chip_update_interval: @@ -1728,9 +1715,6 @@ static int lm90_chip_write(struct device *dev, u32 attr, int channel, long val) err = -EOPNOTSUPP; break; } -error: - mutex_unlock(&data->update_lock); - return err; } @@ -2793,7 +2777,6 @@ static int lm90_probe(struct i2c_client *client) data->client = client; i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); INIT_DELAYED_WORK(&data->alert_work, lm90_alert_work); INIT_WORK(&data->report_work, lm90_report_alarms); diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 0be439b38ee1..91a6b7525bb6 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -32,7 +32,6 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -78,7 +77,6 @@ static inline u8 ALARMS_FROM_REG(s16 reg) /* Client data (each client gets its own) */ struct lm92_data { struct regmap *regmap; - struct mutex update_lock; int resolution; }; @@ -199,15 +197,11 @@ static int lm92_temp_write(struct lm92_data *data, u32 attr, long val) break; case hwmon_temp_crit_hyst: val = clamp_val(val, -120000, 220000); - mutex_lock(&data->update_lock); err = regmap_read(regmap, LM92_REG_TEMP_CRIT, &temp); if (err) - goto unlock; + return err; val = TEMP_TO_REG(TEMP_FROM_REG(temp) - val, data->resolution); - err = regmap_write(regmap, LM92_REG_TEMP_HYST, val); -unlock: - mutex_unlock(&data->update_lock); - return err; + return regmap_write(regmap, LM92_REG_TEMP_HYST, val); default: return -EOPNOTSUPP; } @@ -396,7 +390,6 @@ static int lm92_probe(struct i2c_client *client) data->regmap = regmap; data->resolution = (unsigned long)i2c_get_match_data(client); - mutex_init(&data->update_lock); /* Initialize the chipset */ err = lm92_init_client(regmap); diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index 7da6c8f07332..387b3ba81dbf 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -14,7 +14,6 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/util_macros.h> @@ -54,7 +53,6 @@ static const unsigned short normal_i2c[] = { /* Client data (each client gets its own) */ struct lm95234_data { struct regmap *regmap; - struct mutex update_lock; enum chips type; }; @@ -107,19 +105,14 @@ static ssize_t lm95234_hyst_set(struct lm95234_data *data, long val) u32 tcrit; int ret; - mutex_lock(&data->update_lock); - ret = regmap_read(data->regmap, LM95234_REG_TCRIT1(0), &tcrit); if (ret) - goto unlock; + return ret; val = DIV_ROUND_CLOSEST(clamp_val(val, -255000, 255000), 1000); val = clamp_val((int)tcrit - val, 0, 31); - ret = regmap_write(data->regmap, LM95234_REG_TCRIT_HYST, val); -unlock: - mutex_unlock(&data->update_lock); - return ret; + return regmap_write(data->regmap, LM95234_REG_TCRIT_HYST, val); } static int lm95234_crit_reg(int channel) @@ -526,7 +519,6 @@ static int lm95234_probe(struct i2c_client *client) return PTR_ERR(regmap); data->regmap = regmap; - mutex_init(&data->update_lock); /* Initialize the LM95234 chip */ err = lm95234_init_client(dev, regmap); diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index cad0a0ff8416..456381b0938e 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -15,7 +15,6 @@ #include <linux/jiffies.h> #include <linux/hwmon.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/slab.h> #define DEVNAME "lm95241" @@ -75,7 +74,6 @@ static const u8 lm95241_reg_address[] = { /* Client data (each client gets its own) */ struct lm95241_data { struct i2c_client *client; - struct mutex update_lock; unsigned long last_updated; /* in jiffies */ unsigned long interval; /* in milli-seconds */ bool valid; /* false until following fields are valid */ @@ -102,8 +100,6 @@ static struct lm95241_data *lm95241_update_device(struct device *dev) struct lm95241_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; - mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + msecs_to_jiffies(data->interval)) || !data->valid) { @@ -120,9 +116,6 @@ static struct lm95241_data *lm95241_update_device(struct device *dev) data->last_updated = jiffies; data->valid = true; } - - mutex_unlock(&data->update_lock); - return data; } @@ -204,8 +197,6 @@ static int lm95241_write_chip(struct device *dev, u32 attr, int channel, u8 config; int ret; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_chip_update_interval: config = data->config & ~CFG_CRMASK; @@ -231,7 +222,6 @@ static int lm95241_write_chip(struct device *dev, u32 attr, int channel, ret = -EOPNOTSUPP; break; } - mutex_unlock(&data->update_lock); return ret; } @@ -242,8 +232,6 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel, struct i2c_client *client = data->client; int ret; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_temp_min: if (channel == 1) { @@ -313,9 +301,6 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel, ret = -EOPNOTSUPP; break; } - - mutex_unlock(&data->update_lock); - return ret; } @@ -443,7 +428,6 @@ static int lm95241_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->update_lock); /* Initialize the LM95241 chip */ lm95241_init_client(client, data); diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 3bdc30530847..9ed300c6b5f7 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -13,7 +13,6 @@ #include <linux/hwmon.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -86,7 +85,6 @@ static const unsigned short normal_i2c[] = { /* Client data (each client gets its own) */ struct lm95245_data { struct regmap *regmap; - struct mutex update_lock; int interval; /* in msecs */ }; @@ -279,20 +277,16 @@ static int lm95245_write_temp(struct device *dev, u32 attr, int channel, ret = regmap_write(regmap, reg, val); return ret; case hwmon_temp_crit_hyst: - mutex_lock(&data->update_lock); ret = regmap_read(regmap, LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT, ®val); - if (ret < 0) { - mutex_unlock(&data->update_lock); + if (ret < 0) return ret; - } /* Clamp to reasonable range to prevent overflow */ val = clamp_val(val, -1000000, 1000000); val = regval - val / 1000; val = clamp_val(val, 0, 31); ret = regmap_write(regmap, LM95245_REG_RW_COMMON_HYSTERESIS, val); - mutex_unlock(&data->update_lock); return ret; case hwmon_temp_offset: val = clamp_val(val, -128000, 127875); @@ -332,14 +326,10 @@ static int lm95245_write_chip(struct device *dev, u32 attr, int channel, long val) { struct lm95245_data *data = dev_get_drvdata(dev); - int ret; switch (attr) { case hwmon_chip_update_interval: - mutex_lock(&data->update_lock); - ret = lm95245_set_conversion_rate(data, val); - mutex_unlock(&data->update_lock); - return ret; + return lm95245_set_conversion_rate(data, val); default: return -EOPNOTSUPP; } @@ -542,8 +532,6 @@ static int lm95245_probe(struct i2c_client *client) if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); - mutex_init(&data->update_lock); - /* Initialize the LM95245 chip */ ret = lm95245_init_client(data); if (ret < 0) diff --git a/drivers/hwmon/lochnagar-hwmon.c b/drivers/hwmon/lochnagar-hwmon.c index 5202dddfd61e..c1ba72f6132e 100644 --- a/drivers/hwmon/lochnagar-hwmon.c +++ b/drivers/hwmon/lochnagar-hwmon.c @@ -10,7 +10,6 @@ #include <linux/delay.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/math64.h> #include <linux/mfd/lochnagar.h> #include <linux/mfd/lochnagar2_regs.h> @@ -42,9 +41,6 @@ struct lochnagar_hwmon { struct regmap *regmap; long power_nsamples[ARRAY_SIZE(lochnagar_chan_names)]; - - /* Lock to ensure only a single sensor is read at a time */ - struct mutex sensor_lock; }; enum lochnagar_measure_mode { @@ -178,26 +174,20 @@ static int read_sensor(struct device *dev, int chan, u32 data; int ret; - mutex_lock(&priv->sensor_lock); - ret = do_measurement(regmap, chan, mode, nsamples); if (ret < 0) { dev_err(dev, "Failed to perform measurement: %d\n", ret); - goto error; + return ret; } ret = request_data(regmap, chan, &data); if (ret < 0) { dev_err(dev, "Failed to read measurement: %d\n", ret); - goto error; + return ret; } *val = float_to_long(data, precision); - -error: - mutex_unlock(&priv->sensor_lock); - - return ret; + return 0; } static int read_power(struct device *dev, int chan, long *val) @@ -378,8 +368,6 @@ static int lochnagar_hwmon_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - mutex_init(&priv->sensor_lock); - priv->regmap = dev_get_regmap(dev->parent, NULL); if (!priv->regmap) { dev_err(dev, "No register map found\n"); diff --git a/drivers/hwmon/ltc2947-core.c b/drivers/hwmon/ltc2947-core.c index 244839167e51..ad7120d1e469 100644 --- a/drivers/hwmon/ltc2947-core.c +++ b/drivers/hwmon/ltc2947-core.c @@ -9,8 +9,8 @@ #include <linux/clk.h> #include <linux/device.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/module.h> +#include <linux/math64.h> #include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/regmap.h> @@ -120,12 +120,6 @@ struct ltc2947_data { struct regmap *map; struct device *dev; - /* - * The mutex is needed because the device has 2 memory pages. When - * reading/writing the correct page needs to be set so that, the - * complete sequence select_page->read/write needs to be protected. - */ - struct mutex lock; u32 lsb_energy; bool gpio_out; }; @@ -181,13 +175,9 @@ static int ltc2947_val_read(struct ltc2947_data *st, const u8 reg, int ret; u64 __val = 0; - mutex_lock(&st->lock); - ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page); - if (ret) { - mutex_unlock(&st->lock); + if (ret) return ret; - } dev_dbg(st->dev, "Read val, reg:%02X, p:%d sz:%zu\n", reg, page, size); @@ -207,8 +197,6 @@ static int ltc2947_val_read(struct ltc2947_data *st, const u8 reg, break; } - mutex_unlock(&st->lock); - if (ret) return ret; @@ -242,13 +230,10 @@ static int ltc2947_val_write(struct ltc2947_data *st, const u8 reg, { int ret; - mutex_lock(&st->lock); /* set device on correct page */ ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page); - if (ret) { - mutex_unlock(&st->lock); + if (ret) return ret; - } dev_dbg(st->dev, "Write val, r:%02X, p:%d, sz:%zu, val:%016llX\n", reg, page, size, val); @@ -265,8 +250,6 @@ static int ltc2947_val_write(struct ltc2947_data *st, const u8 reg, break; } - mutex_unlock(&st->lock); - return ret; } @@ -295,11 +278,9 @@ static int ltc2947_alarm_read(struct ltc2947_data *st, const u8 reg, memset(alarms, 0, sizeof(alarms)); - mutex_lock(&st->lock); - ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, LTC2947_PAGE0); if (ret) - goto unlock; + return ret; dev_dbg(st->dev, "Read alarm, reg:%02X, mask:%02X\n", reg, mask); /* @@ -310,31 +291,11 @@ static int ltc2947_alarm_read(struct ltc2947_data *st, const u8 reg, ret = regmap_bulk_read(st->map, LTC2947_REG_STATUS, alarms, sizeof(alarms)); if (ret) - goto unlock; + return ret; /* get the alarm */ *val = !!(alarms[offset] & mask); -unlock: - mutex_unlock(&st->lock); - return ret; -} - -static ssize_t ltc2947_show_value(struct device *dev, - struct device_attribute *da, char *buf) -{ - struct ltc2947_data *st = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - int ret; - s64 val = 0; - - ret = ltc2947_val_read(st, attr->index, LTC2947_PAGE0, 6, &val); - if (ret) - return ret; - - /* value in microJoule. st->lsb_energy was multiplied by 10E9 */ - val = div_s64(val * st->lsb_energy, 1000); - - return sprintf(buf, "%lld\n", val); + return 0; } static int ltc2947_read_temp(struct device *dev, const u32 attr, long *val, @@ -588,6 +549,23 @@ static int ltc2947_read_in(struct device *dev, const u32 attr, long *val, return 0; } +static int ltc2947_read_energy(struct device *dev, s64 *val, const int channel) +{ + int reg = channel ? LTC2947_REG_ENERGY2 : LTC2947_REG_ENERGY1; + struct ltc2947_data *st = dev_get_drvdata(dev); + s64 __val = 0; + int ret; + + ret = ltc2947_val_read(st, reg, LTC2947_PAGE0, 6, &__val); + if (ret) + return ret; + + /* value in microJoule. st->lsb_energy was multiplied by 10E9 */ + *val = DIV_S64_ROUND_CLOSEST(__val * st->lsb_energy, 1000); + + return 0; +} + static int ltc2947_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -600,6 +578,8 @@ static int ltc2947_read(struct device *dev, enum hwmon_sensor_types type, return ltc2947_read_power(dev, attr, val); case hwmon_temp: return ltc2947_read_temp(dev, attr, val, channel); + case hwmon_energy64: + return ltc2947_read_energy(dev, (s64 *)val, channel); default: return -ENOTSUPP; } @@ -897,6 +877,8 @@ static umode_t ltc2947_is_visible(const void *data, return ltc2947_power_is_visible(attr); case hwmon_temp: return ltc2947_temp_is_visible(attr); + case hwmon_energy64: + return 0444; default: return 0; } @@ -929,6 +911,9 @@ static const struct hwmon_channel_info * const ltc2947_info[] = { HWMON_T_LABEL, HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(energy64, + HWMON_E_INPUT, + HWMON_E_INPUT), NULL }; @@ -944,19 +929,6 @@ static const struct hwmon_chip_info ltc2947_chip_info = { .info = ltc2947_info, }; -/* energy attributes are 6bytes wide so we need u64 */ -static SENSOR_DEVICE_ATTR(energy1_input, 0444, ltc2947_show_value, NULL, - LTC2947_REG_ENERGY1); -static SENSOR_DEVICE_ATTR(energy2_input, 0444, ltc2947_show_value, NULL, - LTC2947_REG_ENERGY2); - -static struct attribute *ltc2947_attrs[] = { - &sensor_dev_attr_energy1_input.dev_attr.attr, - &sensor_dev_attr_energy2_input.dev_attr.attr, - NULL, -}; -ATTRIBUTE_GROUPS(ltc2947); - static int ltc2947_setup(struct ltc2947_data *st) { int ret; @@ -1107,15 +1079,13 @@ int ltc2947_core_probe(struct regmap *map, const char *name) st->map = map; st->dev = dev; dev_set_drvdata(dev, st); - mutex_init(&st->lock); ret = ltc2947_setup(st); if (ret) return ret; hwmon = devm_hwmon_device_register_with_info(dev, name, st, - <c2947_chip_info, - ltc2947_groups); + <c2947_chip_info, NULL); return PTR_ERR_OR_ZERO(hwmon); } EXPORT_SYMBOL_GPL(ltc2947_core_probe); diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index 14593bc81e85..e8131a48bda7 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -18,7 +18,6 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/jiffies.h> #include <linux/platform_data/ltc4245.h> @@ -51,7 +50,6 @@ enum ltc4245_cmd { struct ltc4245_data { struct i2c_client *client; - struct mutex update_lock; bool valid; unsigned long last_updated; /* in jiffies */ @@ -132,10 +130,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev) s32 val; int i; - mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - /* Read control registers -- 0x00 to 0x07 */ for (i = 0; i < ARRAY_SIZE(data->cregs); i++) { val = i2c_smbus_read_byte_data(client, i); @@ -161,8 +156,6 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev) data->valid = true; } - mutex_unlock(&data->update_lock); - return data; } @@ -454,7 +447,6 @@ static int ltc4245_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->update_lock); data->use_extra_gpios = ltc4245_use_extra_gpios(client); /* Initialize the LTC4245 chip */ diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c index 1d664a2d7b3c..b9cad89f2cd9 100644 --- a/drivers/hwmon/ltc4282.c +++ b/drivers/hwmon/ltc4282.c @@ -12,13 +12,11 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/i2c.h> #include <linux/math.h> #include <linux/minmax.h> #include <linux/module.h> #include <linux/mod_devicetable.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/property.h> #include <linux/string.h> @@ -132,8 +130,6 @@ struct ltc4282_cache { struct ltc4282_state { struct regmap *map; - /* Protect against multiple accesses to the device registers */ - struct mutex lock; struct clk_hw clk_hw; /* * Used to cache values for VDD/VSOURCE depending which will be used @@ -282,14 +278,12 @@ static int __ltc4282_read_alarm(struct ltc4282_state *st, u32 reg, u32 mask, static int ltc4282_read_alarm(struct ltc4282_state *st, u32 reg, u32 mask, long *val) { - guard(mutex)(&st->lock); return __ltc4282_read_alarm(st, reg, mask, val); } static int ltc4282_vdd_source_read_in(struct ltc4282_state *st, u32 channel, long *val) { - guard(mutex)(&st->lock); if (!st->in0_1_cache[channel].en) return -ENODATA; @@ -301,7 +295,6 @@ static int ltc4282_vdd_source_read_hist(struct ltc4282_state *st, u32 reg, { int ret; - guard(mutex)(&st->lock); if (!st->in0_1_cache[channel].en) { *val = *cached; return 0; @@ -318,7 +311,6 @@ static int ltc4282_vdd_source_read_hist(struct ltc4282_state *st, u32 reg, static int ltc4282_vdd_source_read_lim(struct ltc4282_state *st, u32 reg, u32 channel, u32 *cached, long *val) { - guard(mutex)(&st->lock); if (!st->in0_1_cache[channel].en) return ltc4282_read_voltage_byte_cached(st, reg, st->vfs_out, val, cached); @@ -329,7 +321,6 @@ static int ltc4282_vdd_source_read_lim(struct ltc4282_state *st, u32 reg, static int ltc4282_vdd_source_read_alm(struct ltc4282_state *st, u32 mask, u32 channel, long *val) { - guard(mutex)(&st->lock); if (!st->in0_1_cache[channel].en) { /* * Do this otherwise alarms can get confused because we clear @@ -413,9 +404,7 @@ static int ltc4282_read_in(struct ltc4282_state *st, u32 attr, long *val, channel, &st->in0_1_cache[channel].in_min_raw, val); case hwmon_in_enable: - scoped_guard(mutex, &st->lock) { - *val = st->in0_1_cache[channel].en; - } + *val = st->in0_1_cache[channel].en; return 0; case hwmon_in_fault: /* @@ -541,7 +530,7 @@ static int ltc4282_read_power_byte(const struct ltc4282_state *st, u32 reg, return 0; } -static int ltc4282_read_energy(const struct ltc4282_state *st, u64 *val) +static int ltc4282_read_energy(const struct ltc4282_state *st, s64 *val) { u64 temp, energy; __be64 raw; @@ -613,10 +602,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type, case hwmon_power: return ltc4282_read_power(st, attr, val); case hwmon_energy: - scoped_guard(mutex, &st->lock) { - *val = st->energy_en; - } + *val = st->energy_en; return 0; + case hwmon_energy64: + if (st->energy_en) + return ltc4282_read_energy(st, (s64 *)val); + return -ENODATA; default: return -EOPNOTSUPP; } @@ -683,7 +674,6 @@ static int __ltc4282_in_write_history(const struct ltc4282_state *st, u32 reg, static int ltc4282_in_write_history(struct ltc4282_state *st, u32 reg, long lowest, long highest, u32 fs) { - guard(mutex)(&st->lock); return __ltc4282_in_write_history(st, reg, lowest, highest, fs); } @@ -691,8 +681,6 @@ static int ltc4282_power_reset_hist(struct ltc4282_state *st) { int ret; - guard(mutex)(&st->lock); - ret = ltc4282_write_power_word(st, LTC4282_POWER_LOWEST, st->power_max); if (ret) @@ -798,7 +786,6 @@ static int ltc4282_vdd_source_write_lim(struct ltc4282_state *st, u32 reg, { int ret; - guard(mutex)(&st->lock); if (st->in0_1_cache[channel].en) ret = ltc4282_write_voltage_byte(st, reg, st->vfs_out, val); else @@ -816,7 +803,6 @@ static int ltc4282_vdd_source_reset_hist(struct ltc4282_state *st, int channel) if (channel == LTC4282_CHAN_VDD) lowest = st->vdd; - guard(mutex)(&st->lock); if (st->in0_1_cache[channel].en) { ret = __ltc4282_in_write_history(st, LTC4282_VSOURCE_LOWEST, lowest, 0, st->vfs_out); @@ -856,7 +842,6 @@ static int ltc4282_vdd_source_enable(struct ltc4282_state *st, int channel, int ret, other_chan = ~channel & 0x1; u8 __val = val; - guard(mutex)(&st->lock); if (st->in0_1_cache[channel].en == !!val) return 0; @@ -933,8 +918,6 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st) { int ret; - guard(mutex)(&st->lock); - ret = __ltc4282_in_write_history(st, LTC4282_VSENSE_LOWEST, st->vsense_max, 0, 40 * MILLI); if (ret) @@ -969,7 +952,6 @@ static int ltc4282_energy_enable_set(struct ltc4282_state *st, long val) { int ret; - guard(mutex)(&st->lock); /* setting the bit halts the meter */ ret = regmap_update_bits(st->map, LTC4282_ADC_CTRL, LTC4282_METER_HALT_MASK, @@ -1078,6 +1060,9 @@ static umode_t ltc4282_is_visible(const void *data, case hwmon_energy: /* hwmon_energy_enable */ return 0644; + case hwmon_energy64: + /* hwmon_energy_input */ + return 0444; default: return 0; } @@ -1106,24 +1091,6 @@ static int ltc4282_read_labels(struct device *dev, } } -static ssize_t ltc4282_energy_show(struct device *dev, - struct device_attribute *da, char *buf) -{ - struct ltc4282_state *st = dev_get_drvdata(dev); - u64 energy; - int ret; - - guard(mutex)(&st->lock); - if (!st->energy_en) - return -ENODATA; - - ret = ltc4282_read_energy(st, &energy); - if (ret < 0) - return ret; - - return sysfs_emit(buf, "%llu\n", energy); -} - static const struct clk_ops ltc4282_ops = { .recalc_rate = ltc4282_recalc_rate, .determine_rate = ltc4282_determine_rate, @@ -1588,6 +1555,8 @@ static const struct hwmon_channel_info * const ltc4282_info[] = { HWMON_P_RESET_HISTORY | HWMON_P_LABEL), HWMON_CHANNEL_INFO(energy, HWMON_E_ENABLE), + HWMON_CHANNEL_INFO(energy64, + HWMON_E_INPUT), NULL }; @@ -1603,15 +1572,6 @@ static const struct hwmon_chip_info ltc4282_chip_info = { .info = ltc4282_info, }; -/* energy attributes are 6bytes wide so we need u64 */ -static SENSOR_DEVICE_ATTR_RO(energy1_input, ltc4282_energy, 0); - -static struct attribute *ltc4282_attrs[] = { - &sensor_dev_attr_energy1_input.dev_attr.attr, - NULL -}; -ATTRIBUTE_GROUPS(ltc4282); - static int ltc4282_show_fault_log(void *arg, u64 *val, u32 mask) { struct ltc4282_state *st = arg; @@ -1716,10 +1676,8 @@ static int ltc4282_probe(struct i2c_client *i2c) if (ret) return ret; - mutex_init(&st->lock); hwmon = devm_hwmon_device_register_with_info(dev, "ltc4282", st, - <c4282_chip_info, - ltc4282_groups); + <c4282_chip_info, NULL); if (IS_ERR(hwmon)) return PTR_ERR(hwmon); diff --git a/drivers/hwmon/macsmc-hwmon.c b/drivers/hwmon/macsmc-hwmon.c new file mode 100644 index 000000000000..1c0bbec7e8eb --- /dev/null +++ b/drivers/hwmon/macsmc-hwmon.c @@ -0,0 +1,851 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SMC hwmon driver for Apple Silicon platforms + * + * The System Management Controller on Apple Silicon devices is responsible for + * measuring data from sensors across the SoC and machine. These include power, + * temperature, voltage and current sensors. Some "sensors" actually expose + * derived values. An example of this is the key PHPC, which is an estimate + * of the heat energy being dissipated by the SoC. + * + * While each SoC only has one SMC variant, each platform exposes a different + * set of sensors. For example, M1 MacBooks expose battery telemetry sensors + * which are not present on the M1 Mac mini. For this reason, the available + * sensors for a given platform are described in the device tree in a child + * node of the SMC device. We must walk this list of available sensors and + * populate the required hwmon data structures at runtime. + * + * Originally based on a concept by Jean-Francois Bortolotti <jeff@borto.fr> + * + * Copyright The Asahi Linux Contributors + */ + +#include <linux/bitfield.h> +#include <linux/hwmon.h> +#include <linux/mfd/macsmc.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define MAX_LABEL_LENGTH 32 + +/* Temperature, voltage, current, power, fan(s) */ +#define NUM_SENSOR_TYPES 5 + +#define FLT_EXP_BIAS 127 +#define FLT_EXP_MASK GENMASK(30, 23) +#define FLT_MANT_BIAS 23 +#define FLT_MANT_MASK GENMASK(22, 0) +#define FLT_SIGN_MASK BIT(31) + +static bool fan_control; +module_param_unsafe(fan_control, bool, 0644); +MODULE_PARM_DESC(fan_control, + "Override the SMC to set your own fan speeds on supported machines"); + +struct macsmc_hwmon_sensor { + struct apple_smc_key_info info; + smc_key macsmc_key; + char label[MAX_LABEL_LENGTH]; + u32 attrs; +}; + +struct macsmc_hwmon_fan { + struct macsmc_hwmon_sensor now; + struct macsmc_hwmon_sensor min; + struct macsmc_hwmon_sensor max; + struct macsmc_hwmon_sensor set; + struct macsmc_hwmon_sensor mode; + char label[MAX_LABEL_LENGTH]; + u32 attrs; + bool manual; +}; + +struct macsmc_hwmon_sensors { + struct hwmon_channel_info channel_info; + struct macsmc_hwmon_sensor *sensors; + u32 count; +}; + +struct macsmc_hwmon_fans { + struct hwmon_channel_info channel_info; + struct macsmc_hwmon_fan *fans; + u32 count; +}; + +struct macsmc_hwmon { + struct device *dev; + struct apple_smc *smc; + struct device *hwmon_dev; + struct hwmon_chip_info chip_info; + /* Chip + sensor types + NULL */ + const struct hwmon_channel_info *channel_infos[1 + NUM_SENSOR_TYPES + 1]; + struct macsmc_hwmon_sensors temp; + struct macsmc_hwmon_sensors volt; + struct macsmc_hwmon_sensors curr; + struct macsmc_hwmon_sensors power; + struct macsmc_hwmon_fans fan; +}; + +static int macsmc_hwmon_read_label(struct device *dev, + enum hwmon_sensor_types type, u32 attr, + int channel, const char **str) +{ + struct macsmc_hwmon *hwmon = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + *str = hwmon->temp.sensors[channel].label; + break; + case hwmon_in: + *str = hwmon->volt.sensors[channel].label; + break; + case hwmon_curr: + *str = hwmon->curr.sensors[channel].label; + break; + case hwmon_power: + *str = hwmon->power.sensors[channel].label; + break; + case hwmon_fan: + *str = hwmon->fan.fans[channel].label; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/* + * A number of sensors report data in a 48.16 fixed-point decimal format that is + * not used by any other function of the SMC. + */ +static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key, + u64 *p, int scale) +{ + u64 val; + int ret; + + ret = apple_smc_read_u64(smc, key, &val); + if (ret < 0) + return ret; + + *p = mult_frac(val, scale, 65536); + + return 0; +} + +/* + * Many sensors report their data as IEEE-754 floats. No other SMC function uses + * them. + */ +static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key, + int *p, int scale) +{ + u32 fval; + u64 val; + int ret, exp; + + ret = apple_smc_read_u32(smc, key, &fval); + if (ret < 0) + return ret; + + val = ((u64)((fval & FLT_MANT_MASK) | BIT(23))); + exp = ((fval >> 23) & 0xff) - FLT_EXP_BIAS - FLT_MANT_BIAS; + + /* We never have negatively scaled SMC floats */ + val *= scale; + + if (exp > 63) + val = U64_MAX; + else if (exp < -63) + val = 0; + else if (exp < 0) + val >>= -exp; + else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */ + val = U64_MAX; + else + val <<= exp; + + if (fval & FLT_SIGN_MASK) { + if (val > (-(s64)INT_MIN)) + *p = INT_MIN; + else + *p = -val; + } else { + if (val > INT_MAX) + *p = INT_MAX; + else + *p = val; + } + + return 0; +} + +/* + * The SMC has keys of multiple types, denoted by a FourCC of the same format + * as the key ID. We don't know what data type a key encodes until we poke at it. + */ +static int macsmc_hwmon_read_key(struct apple_smc *smc, + struct macsmc_hwmon_sensor *sensor, int scale, + long *val) +{ + int ret; + + switch (sensor->info.type_code) { + /* 32-bit IEEE 754 float */ + case __SMC_KEY('f', 'l', 't', ' '): { + u32 flt_ = 0; + + ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key, + &flt_, scale); + if (ret) + return ret; + + *val = flt_; + break; + } + /* 48.16 fixed point decimal */ + case __SMC_KEY('i', 'o', 'f', 't'): { + u64 ioft = 0; + + ret = macsmc_hwmon_read_ioft_scaled(smc, sensor->macsmc_key, + &ioft, scale); + if (ret) + return ret; + + *val = (long)ioft; + break; + } + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value) +{ + u64 val; + u32 fval = 0; + int exp = 0, neg; + + val = abs(value); + neg = val != value; + + if (val) { + int msb = __fls(val) - exp; + + if (msb > 23) { + val >>= msb - FLT_MANT_BIAS; + exp -= msb - FLT_MANT_BIAS; + } else if (msb < 23) { + val <<= FLT_MANT_BIAS - msb; + exp += msb; + } + + fval = FIELD_PREP(FLT_SIGN_MASK, neg) | + FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) | + FIELD_PREP(FLT_MANT_MASK, val); + } + + return apple_smc_write_u32(smc, key, fval); +} + +static int macsmc_hwmon_write_key(struct apple_smc *smc, + struct macsmc_hwmon_sensor *sensor, long val) +{ + switch (sensor->info.type_code) { + /* 32-bit IEEE 754 float */ + case __SMC_KEY('f', 'l', 't', ' '): + return macsmc_hwmon_write_f32(smc, sensor->macsmc_key, val); + /* unsigned 8-bit integer */ + case __SMC_KEY('u', 'i', '8', ' '): + return apple_smc_write_u8(smc, sensor->macsmc_key, val); + default: + return -EOPNOTSUPP; + } +} + +static int macsmc_hwmon_read_fan(struct macsmc_hwmon *hwmon, u32 attr, int chan, + long *val) +{ + switch (attr) { + case hwmon_fan_input: + return macsmc_hwmon_read_key(hwmon->smc, + &hwmon->fan.fans[chan].now, 1, val); + case hwmon_fan_min: + return macsmc_hwmon_read_key(hwmon->smc, + &hwmon->fan.fans[chan].min, 1, val); + case hwmon_fan_max: + return macsmc_hwmon_read_key(hwmon->smc, + &hwmon->fan.fans[chan].max, 1, val); + case hwmon_fan_target: + return macsmc_hwmon_read_key(hwmon->smc, + &hwmon->fan.fans[chan].set, 1, val); + default: + return -EOPNOTSUPP; + } +} + +static int macsmc_hwmon_write_fan(struct device *dev, u32 attr, int channel, + long val) +{ + struct macsmc_hwmon *hwmon = dev_get_drvdata(dev); + long min, max; + int ret; + + if (!fan_control || hwmon->fan.fans[channel].mode.macsmc_key == 0) + return -EOPNOTSUPP; + + /* + * The SMC does no sanity checks on requested fan speeds, so we need to. + */ + ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].min, + 1, &min); + if (ret) + return ret; + + ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].max, + 1, &max); + if (ret) + return ret; + + if (val >= min && val <= max) { + if (!hwmon->fan.fans[channel].manual) { + /* Write 1 to mode key for manual control */ + ret = macsmc_hwmon_write_key(hwmon->smc, + &hwmon->fan.fans[channel].mode, 1); + if (ret < 0) + return ret; + + hwmon->fan.fans[channel].manual = true; + } + return macsmc_hwmon_write_key(hwmon->smc, + &hwmon->fan.fans[channel].set, val); + } else if (!val) { + if (hwmon->fan.fans[channel].manual) { + ret = macsmc_hwmon_write_key(hwmon->smc, + &hwmon->fan.fans[channel].mode, 0); + if (ret < 0) + return ret; + + hwmon->fan.fans[channel].manual = false; + } + } else { + return -EINVAL; + } + + return 0; +} + +static int macsmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct macsmc_hwmon *hwmon = dev_get_drvdata(dev); + int ret = 0; + + switch (type) { + case hwmon_temp: + ret = macsmc_hwmon_read_key(hwmon->smc, + &hwmon->temp.sensors[channel], 1000, val); + break; + case hwmon_in: + ret = macsmc_hwmon_read_key(hwmon->smc, + &hwmon->volt.sensors[channel], 1000, val); + break; + case hwmon_curr: + ret = macsmc_hwmon_read_key(hwmon->smc, + &hwmon->curr.sensors[channel], 1000, val); + break; + case hwmon_power: + /* SMC returns power in Watts with acceptable precision to scale to uW */ + ret = macsmc_hwmon_read_key(hwmon->smc, + &hwmon->power.sensors[channel], + 1000000, val); + break; + case hwmon_fan: + ret = macsmc_hwmon_read_fan(hwmon, attr, channel, val); + break; + default: + return -EOPNOTSUPP; + } + + return ret; +} + +static int macsmc_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_fan: + return macsmc_hwmon_write_fan(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static umode_t macsmc_hwmon_fan_is_visible(const struct macsmc_hwmon_fan *fan, + u32 attr) +{ + if (fan->attrs & BIT(attr)) { + if (attr == hwmon_fan_target && fan_control && fan->mode.macsmc_key) + return 0644; + + return 0444; + } + + return 0; +} + +static umode_t macsmc_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, u32 attr, + int channel) +{ + const struct macsmc_hwmon *hwmon = data; + struct macsmc_hwmon_sensor *sensor; + + switch (type) { + case hwmon_in: + sensor = &hwmon->volt.sensors[channel]; + break; + case hwmon_curr: + sensor = &hwmon->curr.sensors[channel]; + break; + case hwmon_power: + sensor = &hwmon->power.sensors[channel]; + break; + case hwmon_temp: + sensor = &hwmon->temp.sensors[channel]; + break; + case hwmon_fan: + return macsmc_hwmon_fan_is_visible(&hwmon->fan.fans[channel], attr); + default: + return 0; + } + + /* Sensors only register ro attributes */ + if (sensor->attrs & BIT(attr)) + return 0444; + + return 0; +} + +static const struct hwmon_ops macsmc_hwmon_ops = { + .is_visible = macsmc_hwmon_is_visible, + .read = macsmc_hwmon_read, + .read_string = macsmc_hwmon_read_label, + .write = macsmc_hwmon_write, +}; + +/* + * Get the key metadata, including key data type, from the SMC. + */ +static int macsmc_hwmon_parse_key(struct device *dev, struct apple_smc *smc, + struct macsmc_hwmon_sensor *sensor, + const char *key) +{ + int ret; + + ret = apple_smc_get_key_info(smc, _SMC_KEY(key), &sensor->info); + if (ret) { + dev_dbg(dev, "Failed to retrieve key info for %s\n", key); + return ret; + } + + sensor->macsmc_key = _SMC_KEY(key); + + return 0; +} + +/* + * A sensor is a single key-value pair as made available by the SMC. + * The devicetree gives us the SMC key ID and a friendly name where the + * purpose of the sensor is known. + */ +static int macsmc_hwmon_create_sensor(struct device *dev, struct apple_smc *smc, + struct device_node *sensor_node, + struct macsmc_hwmon_sensor *sensor) +{ + const char *key, *label; + int ret; + + ret = of_property_read_string(sensor_node, "apple,key-id", &key); + if (ret) { + dev_dbg(dev, "Could not find apple,key-id in sensor node\n"); + return ret; + } + + ret = macsmc_hwmon_parse_key(dev, smc, sensor, key); + if (ret) + return ret; + + ret = of_property_read_string(sensor_node, "label", &label); + if (ret) + dev_dbg(dev, "No label found for sensor %s\n", key); + else + strscpy_pad(sensor->label, label, sizeof(sensor->label)); + + return 0; +} + +/* + * Fan data is exposed by the SMC as multiple sensors. + * + * The devicetree schema reuses apple,key-id for the actual fan speed sensor. + * Min, max and target keys do not need labels, so we can reuse label + * for naming the entire fan. + */ +static int macsmc_hwmon_create_fan(struct device *dev, struct apple_smc *smc, + struct device_node *fan_node, + struct macsmc_hwmon_fan *fan) +{ + const char *label, *now, *min, *max, *set, *mode; + int ret; + + ret = of_property_read_string(fan_node, "apple,key-id", &now); + if (ret) { + dev_err(dev, "apple,key-id not found in fan node!\n"); + return ret; + } + + ret = macsmc_hwmon_parse_key(dev, smc, &fan->now, now); + if (ret) + return ret; + + fan->attrs = HWMON_F_INPUT; + + ret = of_property_read_string(fan_node, "label", &label); + if (ret) { + dev_dbg(dev, "No label found for fan %s\n", now); + } else { + strscpy_pad(fan->label, label, sizeof(fan->label)); + fan->attrs |= HWMON_F_LABEL; + } + + /* The following keys are not required to simply monitor fan speed */ + if (!of_property_read_string(fan_node, "apple,fan-minimum", &min)) { + ret = macsmc_hwmon_parse_key(dev, smc, &fan->min, min); + if (ret) + return ret; + + fan->attrs |= HWMON_F_MIN; + } + + if (!of_property_read_string(fan_node, "apple,fan-maximum", &max)) { + ret = macsmc_hwmon_parse_key(dev, smc, &fan->max, max); + if (ret) + return ret; + + fan->attrs |= HWMON_F_MAX; + } + + if (!of_property_read_string(fan_node, "apple,fan-target", &set)) { + ret = macsmc_hwmon_parse_key(dev, smc, &fan->set, set); + if (ret) + return ret; + + fan->attrs |= HWMON_F_TARGET; + } + + if (!of_property_read_string(fan_node, "apple,fan-mode", &mode)) { + ret = macsmc_hwmon_parse_key(dev, smc, &fan->mode, mode); + if (ret) + return ret; + } + + /* Initialise fan control mode to automatic */ + fan->manual = false; + + return 0; +} + +static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon, + struct device_node *hwmon_node) +{ + struct device_node *key_node __maybe_unused; + struct macsmc_hwmon_sensor *sensor; + u32 n_current = 0, n_fan = 0, n_power = 0, n_temperature = 0, n_voltage = 0; + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") { + n_current++; + } + + if (n_current) { + hwmon->curr.sensors = devm_kcalloc(hwmon->dev, n_current, + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); + if (!hwmon->curr.sensors) + return -ENOMEM; + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") { + sensor = &hwmon->curr.sensors[hwmon->curr.count]; + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) { + sensor->attrs = HWMON_C_INPUT; + + if (*sensor->label) + sensor->attrs |= HWMON_C_LABEL; + + hwmon->curr.count++; + } + } + } + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") { + n_fan++; + } + + if (n_fan) { + hwmon->fan.fans = devm_kcalloc(hwmon->dev, n_fan, + sizeof(struct macsmc_hwmon_fan), GFP_KERNEL); + if (!hwmon->fan.fans) + return -ENOMEM; + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") { + if (!macsmc_hwmon_create_fan(hwmon->dev, hwmon->smc, key_node, + &hwmon->fan.fans[hwmon->fan.count])) + hwmon->fan.count++; + } + } + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") { + n_power++; + } + + if (n_power) { + hwmon->power.sensors = devm_kcalloc(hwmon->dev, n_power, + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); + if (!hwmon->power.sensors) + return -ENOMEM; + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") { + sensor = &hwmon->power.sensors[hwmon->power.count]; + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) { + sensor->attrs = HWMON_P_INPUT; + + if (*sensor->label) + sensor->attrs |= HWMON_P_LABEL; + + hwmon->power.count++; + } + } + } + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") { + n_temperature++; + } + + if (n_temperature) { + hwmon->temp.sensors = devm_kcalloc(hwmon->dev, n_temperature, + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); + if (!hwmon->temp.sensors) + return -ENOMEM; + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") { + sensor = &hwmon->temp.sensors[hwmon->temp.count]; + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) { + sensor->attrs = HWMON_T_INPUT; + + if (*sensor->label) + sensor->attrs |= HWMON_T_LABEL; + + hwmon->temp.count++; + } + } + } + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") { + n_voltage++; + } + + if (n_voltage) { + hwmon->volt.sensors = devm_kcalloc(hwmon->dev, n_voltage, + sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL); + if (!hwmon->volt.sensors) + return -ENOMEM; + + for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-") { + sensor = &hwmon->temp.sensors[hwmon->temp.count]; + if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) { + sensor->attrs = HWMON_I_INPUT; + + if (*sensor->label) + sensor->attrs |= HWMON_I_LABEL; + + hwmon->volt.count++; + } + } + } + + return 0; +} + +/* Create NULL-terminated config arrays */ +static void macsmc_hwmon_populate_configs(u32 *configs, const struct macsmc_hwmon_sensors *sensors) +{ + int idx; + + for (idx = 0; idx < sensors->count; idx++) + configs[idx] = sensors->sensors[idx].attrs; +} + +static void macsmc_hwmon_populate_fan_configs(u32 *configs, const struct macsmc_hwmon_fans *fans) +{ + int idx; + + for (idx = 0; idx < fans->count; idx++) + configs[idx] = fans->fans[idx].attrs; +} + +static const struct hwmon_channel_info *const macsmc_chip_channel_info = + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ); + +static int macsmc_hwmon_create_infos(struct macsmc_hwmon *hwmon) +{ + struct hwmon_channel_info *channel_info; + int i = 0; + + /* chip */ + hwmon->channel_infos[i++] = macsmc_chip_channel_info; + + if (hwmon->curr.count) { + channel_info = &hwmon->curr.channel_info; + channel_info->type = hwmon_curr; + channel_info->config = devm_kcalloc(hwmon->dev, hwmon->curr.count + 1, + sizeof(u32), GFP_KERNEL); + if (!channel_info->config) + return -ENOMEM; + + macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->curr); + hwmon->channel_infos[i++] = channel_info; + } + + if (hwmon->fan.count) { + channel_info = &hwmon->fan.channel_info; + channel_info->type = hwmon_fan; + channel_info->config = devm_kcalloc(hwmon->dev, hwmon->fan.count + 1, + sizeof(u32), GFP_KERNEL); + if (!channel_info->config) + return -ENOMEM; + + macsmc_hwmon_populate_fan_configs((u32 *)channel_info->config, &hwmon->fan); + hwmon->channel_infos[i++] = channel_info; + } + + if (hwmon->power.count) { + channel_info = &hwmon->power.channel_info; + channel_info->type = hwmon_power; + channel_info->config = devm_kcalloc(hwmon->dev, hwmon->power.count + 1, + sizeof(u32), GFP_KERNEL); + if (!channel_info->config) + return -ENOMEM; + + macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->power); + hwmon->channel_infos[i++] = channel_info; + } + + if (hwmon->temp.count) { + channel_info = &hwmon->temp.channel_info; + channel_info->type = hwmon_temp; + channel_info->config = devm_kcalloc(hwmon->dev, hwmon->temp.count + 1, + sizeof(u32), GFP_KERNEL); + if (!channel_info->config) + return -ENOMEM; + + macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->temp); + hwmon->channel_infos[i++] = channel_info; + } + + if (hwmon->volt.count) { + channel_info = &hwmon->volt.channel_info; + channel_info->type = hwmon_in; + channel_info->config = devm_kcalloc(hwmon->dev, hwmon->volt.count + 1, + sizeof(u32), GFP_KERNEL); + if (!channel_info->config) + return -ENOMEM; + + macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->volt); + hwmon->channel_infos[i++] = channel_info; + } + + return 0; +} + +static int macsmc_hwmon_probe(struct platform_device *pdev) +{ + struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent); + struct macsmc_hwmon *hwmon; + int ret; + + /* + * The MFD driver will try to probe us unconditionally. Some devices + * with the SMC do not have hwmon capabilities. Only probe if we have + * a hwmon node. + */ + if (!pdev->dev.of_node) + return -ENODEV; + + hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), + GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + hwmon->dev = &pdev->dev; + hwmon->smc = smc; + + ret = macsmc_hwmon_populate_sensors(hwmon, hwmon->dev->of_node); + if (ret) { + dev_err(hwmon->dev, "Could not parse sensors\n"); + return ret; + } + + if (!hwmon->curr.count && !hwmon->fan.count && + !hwmon->power.count && !hwmon->temp.count && + !hwmon->volt.count) { + dev_err(hwmon->dev, + "No valid sensors found of any supported type\n"); + return -ENODEV; + } + + ret = macsmc_hwmon_create_infos(hwmon); + if (ret) + return ret; + + hwmon->chip_info.ops = &macsmc_hwmon_ops; + hwmon->chip_info.info = + (const struct hwmon_channel_info *const *)&hwmon->channel_infos; + + hwmon->hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, + "macsmc_hwmon", hwmon, + &hwmon->chip_info, NULL); + if (IS_ERR(hwmon->hwmon_dev)) + return dev_err_probe(hwmon->dev, PTR_ERR(hwmon->hwmon_dev), + "Probing SMC hwmon device failed\n"); + + dev_dbg(hwmon->dev, "Registered SMC hwmon device. Sensors:\n"); + dev_dbg(hwmon->dev, + "Current: %d, Fans: %d, Power: %d, Temperature: %d, Voltage: %d", + hwmon->curr.count, hwmon->fan.count, + hwmon->power.count, hwmon->temp.count, + hwmon->volt.count); + + return 0; +} + +static const struct of_device_id macsmc_hwmon_of_table[] = { + { .compatible = "apple,smc-hwmon" }, + {} +}; +MODULE_DEVICE_TABLE(of, macsmc_hwmon_of_table); + +static struct platform_driver macsmc_hwmon_driver = { + .probe = macsmc_hwmon_probe, + .driver = { + .name = "macsmc-hwmon", + .of_match_table = macsmc_hwmon_of_table, + }, +}; +module_platform_driver(macsmc_hwmon_driver); + +MODULE_DESCRIPTION("Apple Silicon SMC hwmon driver"); +MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/hwmon/max127.c b/drivers/hwmon/max127.c index a9aab8862f5e..5102d86d2619 100644 --- a/drivers/hwmon/max127.c +++ b/drivers/hwmon/max127.c @@ -45,7 +45,6 @@ #define MAX127_SIGN_BIT BIT(11) struct max127_data { - struct mutex lock; struct i2c_client *client; u8 ctrl_byte[MAX127_NUM_CHANNELS]; }; @@ -121,21 +120,16 @@ static int max127_read_input(struct max127_data *data, int channel, long *val) struct i2c_client *client = data->client; u8 ctrl_byte = data->ctrl_byte[channel]; - mutex_lock(&data->lock); - status = max127_select_channel(client, ctrl_byte); if (status) - goto exit; + return status; status = max127_read_channel(client, &raw); if (status) - goto exit; + return status; *val = max127_process_raw(ctrl_byte, raw); - -exit: - mutex_unlock(&data->lock); - return status; + return 0; } static int max127_read_min(struct max127_data *data, int channel, long *val) @@ -170,8 +164,6 @@ static int max127_write_min(struct max127_data *data, int channel, long val) { u8 ctrl; - mutex_lock(&data->lock); - ctrl = data->ctrl_byte[channel]; if (val <= -MAX127_FULL_RANGE) { ctrl |= (MAX127_CTRL_RNG | MAX127_CTRL_BIP); @@ -182,23 +174,15 @@ static int max127_write_min(struct max127_data *data, int channel, long val) ctrl &= ~MAX127_CTRL_BIP; } data->ctrl_byte[channel] = ctrl; - - mutex_unlock(&data->lock); - return 0; } static int max127_write_max(struct max127_data *data, int channel, long val) { - mutex_lock(&data->lock); - if (val >= MAX127_FULL_RANGE) data->ctrl_byte[channel] |= MAX127_CTRL_RNG; else data->ctrl_byte[channel] &= ~MAX127_CTRL_RNG; - - mutex_unlock(&data->lock); - return 0; } @@ -315,7 +299,6 @@ static int max127_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->lock); for (i = 0; i < ARRAY_SIZE(data->ctrl_byte); i++) data->ctrl_byte[i] = (MAX127_CTRL_START | MAX127_SET_CHANNEL(i)); diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index 0ccb5eb596fc..4c9e7892a73c 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -216,12 +216,13 @@ static ssize_t max16065_current_show(struct device *dev, struct device_attribute *da, char *buf) { struct max16065_data *data = max16065_update_device(dev); + int curr_sense = data->curr_sense; - if (unlikely(data->curr_sense < 0)) - return data->curr_sense; + if (unlikely(curr_sense < 0)) + return curr_sense; return sysfs_emit(buf, "%d\n", - ADC_TO_CURR(data->curr_sense, data->curr_gain)); + ADC_TO_CURR(curr_sense, data->curr_gain)); } static ssize_t max16065_limit_store(struct device *dev, diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index f56913327004..4f6171a17d9f 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -57,7 +57,6 @@ */ struct max31790_data { struct i2c_client *client; - struct mutex update_lock; bool valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -74,30 +73,27 @@ static struct max31790_data *max31790_update_device(struct device *dev) { struct max31790_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; - struct max31790_data *ret = data; - int i; - int rv; - - mutex_lock(&data->update_lock); + int i, rv; if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->valid = false; rv = i2c_smbus_read_byte_data(client, MAX31790_REG_FAN_FAULT_STATUS1); if (rv < 0) - goto abort; + return ERR_PTR(rv); data->fault_status |= rv & 0x3F; rv = i2c_smbus_read_byte_data(client, MAX31790_REG_FAN_FAULT_STATUS2); if (rv < 0) - goto abort; + return ERR_PTR(rv); data->fault_status |= (rv & 0x3F) << 6; for (i = 0; i < NR_CHANNEL; i++) { rv = i2c_smbus_read_word_swapped(client, MAX31790_REG_TACH_COUNT(i)); if (rv < 0) - goto abort; + return ERR_PTR(rv); data->tach[i] = rv; if (data->fan_config[i] @@ -106,19 +102,19 @@ static struct max31790_data *max31790_update_device(struct device *dev) MAX31790_REG_TACH_COUNT(NR_CHANNEL + i)); if (rv < 0) - goto abort; + return ERR_PTR(rv); data->tach[NR_CHANNEL + i] = rv; } else { rv = i2c_smbus_read_word_swapped(client, MAX31790_REG_PWM_DUTY_CYCLE(i)); if (rv < 0) - goto abort; + return ERR_PTR(rv); data->pwm[i] = rv; rv = i2c_smbus_read_word_swapped(client, MAX31790_REG_TARGET_COUNT(i)); if (rv < 0) - goto abort; + return ERR_PTR(rv); data->target_count[i] = rv; } } @@ -126,16 +122,7 @@ static struct max31790_data *max31790_update_device(struct device *dev) data->last_updated = jiffies; data->valid = true; } - goto done; - -abort: - data->valid = false; - ret = ERR_PTR(rv); - -done: - mutex_unlock(&data->update_lock); - - return ret; + return data; } static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; @@ -189,7 +176,6 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, *val = rpm; return 0; case hwmon_fan_fault: - mutex_lock(&data->update_lock); *val = !!(data->fault_status & (1 << channel)); data->fault_status &= ~(1 << channel); /* @@ -200,10 +186,9 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel, if (*val) { int reg = MAX31790_REG_TARGET_COUNT(channel % NR_CHANNEL); - i2c_smbus_write_byte_data(data->client, reg, - data->target_count[channel % NR_CHANNEL] >> 8); + return i2c_smbus_write_byte_data(data->client, reg, + data->target_count[channel % NR_CHANNEL] >> 8); } - mutex_unlock(&data->update_lock); return 0; case hwmon_fan_enable: *val = !!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN); @@ -223,8 +208,6 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, u8 bits, fan_config; int sr; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_fan_target: val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX); @@ -270,9 +253,6 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel, err = -EOPNOTSUPP; break; } - - mutex_unlock(&data->update_lock); - return err; } @@ -338,8 +318,6 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, u8 fan_config; int err = 0; - mutex_lock(&data->update_lock); - switch (attr) { case hwmon_pwm_input: if (val < 0 || val > 255) { @@ -389,9 +367,6 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel, err = -EOPNOTSUPP; break; } - - mutex_unlock(&data->update_lock); - return err; } @@ -525,7 +500,6 @@ static int max31790_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->update_lock); /* * Initialize the max31790 chip diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c index a31c7b655da1..9b2e56c040df 100644 --- a/drivers/hwmon/max31827.c +++ b/drivers/hwmon/max31827.c @@ -10,7 +10,6 @@ #include <linux/delay.h> #include <linux/hwmon.h> #include <linux/i2c.h> -#include <linux/mutex.h> #include <linux/of_device.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -99,7 +98,6 @@ struct max31827_state { /* * Prevent simultaneous access to the i2c client. */ - struct mutex lock; struct regmap *regmap; bool enable; unsigned int resolution; @@ -123,30 +121,23 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg, * Before the Temperature Threshold Alarm, Alarm Hysteresis Threshold * and Resolution bits from Configuration register are changed over I2C, * the part must be in shutdown mode. - * - * Mutex is used to ensure, that some other process doesn't change the - * configuration register. */ - mutex_lock(&st->lock); - if (!st->enable) { if (!mask) - ret = regmap_write(st->regmap, reg, val); - else - ret = regmap_update_bits(st->regmap, reg, mask, val); - goto unlock; + return regmap_write(st->regmap, reg, val); + return regmap_update_bits(st->regmap, reg, mask, val); } ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg); if (ret) - goto unlock; + return ret; cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg; cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | MAX31827_CONFIGURATION_CNV_RATE_MASK); ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); if (ret) - goto unlock; + return ret; if (!mask) ret = regmap_write(st->regmap, reg, val); @@ -154,15 +145,11 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg, ret = regmap_update_bits(st->regmap, reg, mask, val); if (ret) - goto unlock; - - ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_CNV_RATE_MASK, - cnv_rate); + return ret; -unlock: - mutex_unlock(&st->lock); - return ret; + return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_CNV_RATE_MASK, + cnv_rate); } static int write_alarm_val(struct max31827_state *st, unsigned int reg, @@ -223,23 +210,13 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, break; case hwmon_temp_input: - mutex_lock(&st->lock); - if (!st->enable) { - /* - * This operation requires mutex protection, - * because the chip configuration should not - * be changed during the conversion process. - */ - ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, MAX31827_CONFIGURATION_1SHOT_MASK, 1); - if (ret) { - mutex_unlock(&st->lock); + if (ret) return ret; - } msleep(max31827_conv_times[st->resolution]); } @@ -254,8 +231,6 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type, ret = regmap_read(st->regmap, MAX31827_T_REG, &uval); - mutex_unlock(&st->lock); - if (ret) break; @@ -352,7 +327,6 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, if (val >> 1) return -EINVAL; - mutex_lock(&st->lock); /** * The chip should not be enabled while a conversion is * performed. Neither should the chip be enabled when @@ -361,15 +335,11 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type, st->enable = val; - ret = regmap_update_bits(st->regmap, - MAX31827_CONFIGURATION_REG, - MAX31827_CONFIGURATION_1SHOT_MASK | - MAX31827_CONFIGURATION_CNV_RATE_MASK, - MAX31827_DEVICE_ENABLE(val)); - - mutex_unlock(&st->lock); - - return ret; + return regmap_update_bits(st->regmap, + MAX31827_CONFIGURATION_REG, + MAX31827_CONFIGURATION_1SHOT_MASK | + MAX31827_CONFIGURATION_CNV_RATE_MASK, + MAX31827_DEVICE_ENABLE(val)); case hwmon_temp_max: return write_alarm_val(st, MAX31827_TH_REG, val); @@ -623,8 +593,6 @@ static int max31827_probe(struct i2c_client *client) if (!st) return -ENOMEM; - mutex_init(&st->lock); - st->regmap = devm_regmap_init_i2c(client, &max31827_regmap); if (IS_ERR(st->regmap)) return dev_err_probe(dev, PTR_ERR(st->regmap), diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c index 13201fb755c9..4316dcdd03fc 100644 --- a/drivers/hwmon/max6620.c +++ b/drivers/hwmon/max6620.c @@ -130,7 +130,6 @@ static const u8 target_reg[] = { struct max6620_data { struct i2c_client *client; - struct mutex update_lock; bool valid; /* false until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -161,39 +160,36 @@ static int max6620_update_device(struct device *dev) { struct max6620_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; - int i; - int ret = 0; - - mutex_lock(&data->update_lock); + int i, ret; if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { for (i = 0; i < 4; i++) { ret = i2c_smbus_read_byte_data(client, config_reg[i]); if (ret < 0) - goto error; + return ret; data->fancfg[i] = ret; ret = i2c_smbus_read_byte_data(client, dyn_reg[i]); if (ret < 0) - goto error; + return ret; data->fandyn[i] = ret; ret = i2c_smbus_read_byte_data(client, tach_reg[i]); if (ret < 0) - goto error; + return ret; data->tach[i] = (ret << 3) & 0x7f8; ret = i2c_smbus_read_byte_data(client, tach_reg[i] + 1); if (ret < 0) - goto error; + return ret; data->tach[i] |= (ret >> 5) & 0x7; ret = i2c_smbus_read_byte_data(client, target_reg[i]); if (ret < 0) - goto error; + return ret; data->target[i] = (ret << 3) & 0x7f8; ret = i2c_smbus_read_byte_data(client, target_reg[i] + 1); if (ret < 0) - goto error; + return ret; data->target[i] |= (ret >> 5) & 0x7; } @@ -204,16 +200,13 @@ static int max6620_update_device(struct device *dev) */ ret = i2c_smbus_read_byte_data(client, MAX6620_REG_FAULT); if (ret < 0) - goto error; + return ret; data->fault |= (ret >> 4) & (ret & 0x0F); data->last_updated = jiffies; data->valid = true; } - -error: - mutex_unlock(&data->update_lock); - return ret; + return 0; } static umode_t @@ -261,7 +254,6 @@ max6620_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_fan: switch (attr) { case hwmon_fan_alarm: - mutex_lock(&data->update_lock); *val = !!(data->fault & BIT(channel)); /* Setting TACH count to re-enable fan fault detection */ @@ -270,21 +262,15 @@ max6620_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, val2 = (data->target[channel] << 5) & 0xe0; ret = i2c_smbus_write_byte_data(client, target_reg[channel], val1); - if (ret < 0) { - mutex_unlock(&data->update_lock); + if (ret < 0) return ret; - } ret = i2c_smbus_write_byte_data(client, target_reg[channel] + 1, val2); - if (ret < 0) { - mutex_unlock(&data->update_lock); + if (ret < 0) return ret; - } data->fault &= ~BIT(channel); } - mutex_unlock(&data->update_lock); - break; case hwmon_fan_div: *val = max6620_fan_div_from_reg(data->fandyn[channel]); @@ -334,7 +320,6 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, return ret; data = dev_get_drvdata(dev); client = data->client; - mutex_lock(&data->update_lock); switch (type) { case hwmon_fan: @@ -360,8 +345,7 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, div = 5; break; default: - ret = -EINVAL; - goto error; + return -EINVAL; } data->fandyn[channel] &= 0x1F; data->fandyn[channel] |= div << 5; @@ -396,8 +380,6 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, break; } -error: - mutex_unlock(&data->update_lock); return ret; } @@ -478,7 +460,6 @@ static int max6620_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->update_lock); err = max6620_init_client(data); if (err) diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index a06346496e1d..99140a2ca995 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -16,9 +16,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/util_macros.h> @@ -75,7 +73,6 @@ static const unsigned int freq_table[] = { 20, 33, 50, 100, 5000, 8333, 12500, */ struct max6639_data { struct regmap *regmap; - struct mutex update_lock; /* Register values initialized only once */ u8 ppr[MAX6639_NUM_CHANNELS]; /* Pulses per rotation 0..3 for 1..4 ppr */ @@ -249,16 +246,11 @@ static int max6639_write_fan(struct device *dev, u32 attr, int channel, if (val <= 0 || val > 4) return -EINVAL; - mutex_lock(&data->update_lock); /* Set Fan pulse per revolution */ err = max6639_set_ppr(data, channel, val); - if (err < 0) { - mutex_unlock(&data->update_lock); + if (err < 0) return err; - } data->ppr[channel] = val; - - mutex_unlock(&data->update_lock); return 0; default: return -EOPNOTSUPP; @@ -320,21 +312,17 @@ static int max6639_write_pwm(struct device *dev, u32 attr, int channel, case hwmon_pwm_input: if (val < 0 || val > 255) return -EINVAL; - err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel), - val * 120 / 255); - return err; + return regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel), + val * 120 / 255); case hwmon_pwm_freq: val = clamp_val(val, 0, 25000); i = find_closest(val, freq_table, ARRAY_SIZE(freq_table)); - mutex_lock(&data->update_lock); err = regmap_update_bits(data->regmap, MAX6639_REG_FAN_CONFIG3(channel), MAX6639_FAN_CONFIG3_FREQ_MASK, i); - if (err < 0) { - mutex_unlock(&data->update_lock); + if (err < 0) return err; - } if (i >> 2) err = regmap_set_bits(data->regmap, MAX6639_REG_GCONFIG, @@ -343,7 +331,6 @@ static int max6639_write_pwm(struct device *dev, u32 attr, int channel, err = regmap_clear_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_PWM_FREQ_HI); - mutex_unlock(&data->update_lock); return err; default: return -EOPNOTSUPP; @@ -753,8 +740,6 @@ static int max6639_probe(struct i2c_client *client) } } - mutex_init(&data->update_lock); - /* Initialize the max6639 chip */ err = max6639_init_client(client, data); if (err < 0) diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 0735a1d2c20f..dd906cf491ca 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -13,7 +13,6 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -91,8 +90,6 @@ struct max6697_data { int temp_offset; /* in degrees C */ - struct mutex update_lock; - #define MAX6697_TEMP_INPUT 0 #define MAX6697_TEMP_EXT 1 #define MAX6697_TEMP_MAX 2 @@ -302,7 +299,6 @@ static int max6697_write(struct device *dev, enum hwmon_sensor_types type, val = clamp_val(val, 0, 255); return regmap_write(regmap, MAX6697_REG_MIN, val); case hwmon_temp_offset: - mutex_lock(&data->update_lock); val = clamp_val(val, MAX6581_OFFSET_MIN, MAX6581_OFFSET_MAX); val = DIV_ROUND_CLOSEST(val, 250); if (!val) { /* disable this (and only this) channel */ @@ -313,11 +309,9 @@ static int max6697_write(struct device *dev, enum hwmon_sensor_types type, ret = regmap_set_bits(regmap, MAX6581_REG_OFFSET_SELECT, BIT(channel - 1)); if (ret) - goto unlock; + return ret; ret = regmap_write(regmap, MAX6581_REG_OFFSET, val); } -unlock: - mutex_unlock(&data->update_lock); return ret; default: return -EOPNOTSUPP; @@ -548,7 +542,7 @@ static int max6697_probe(struct i2c_client *client) struct regmap *regmap; int err; - regmap = regmap_init_i2c(client, &max6697_regmap_config); + regmap = devm_regmap_init_i2c(client, &max6697_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -559,7 +553,6 @@ static int max6697_probe(struct i2c_client *client) data->regmap = regmap; data->type = (uintptr_t)i2c_get_match_data(client); data->chip = &max6697_chip_data[data->type]; - mutex_init(&data->update_lock); err = max6697_init_chip(client->dev.of_node, data); if (err) diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 7848198f8996..32c1e42e1278 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -14,7 +14,6 @@ #include <linux/kstrtox.h> #include <linux/module.h> #include <linux/mod_devicetable.h> -#include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 407945d2cd6a..c3a719aef1ac 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -1403,6 +1403,7 @@ static const char * const asus_msi_boards[] = { "ROG STRIX X670E-E GAMING WIFI", "ROG STRIX X670E-F GAMING WIFI", "ROG STRIX X670E-I GAMING WIFI", + "ROG STRIX X870E-H GAMING WIFI7", "ROG STRIX Z590-A GAMING WIFI", "ROG STRIX Z590-A GAMING WIFI II", "ROG STRIX Z590-E GAMING WIFI", diff --git a/drivers/hwmon/nct7363.c b/drivers/hwmon/nct7363.c index e13ab918b1ab..71cef794835d 100644 --- a/drivers/hwmon/nct7363.c +++ b/drivers/hwmon/nct7363.c @@ -7,10 +7,8 @@ #include <linux/bits.h> #include <linux/err.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/slab.h> diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index f1e6eda949ba..2fa091720c79 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -21,7 +21,6 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/i2c.h> -#include <linux/mutex.h> #include <linux/hwmon.h> #include <linux/watchdog.h> @@ -128,7 +127,6 @@ static const unsigned short normal_i2c[] = { struct nct7904_data { struct i2c_client *client; struct watchdog_device wdt; - struct mutex bank_lock; int bank_sel; u32 fanin_mask; u32 vsen_mask; @@ -142,24 +140,19 @@ struct nct7904_data { }; /* Access functions */ -static int nct7904_bank_lock(struct nct7904_data *data, unsigned int bank) +static int nct7904_bank_select(struct nct7904_data *data, unsigned int bank) { int ret; - mutex_lock(&data->bank_lock); if (data->bank_sel == bank) return 0; ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank); - if (ret == 0) - data->bank_sel = bank; - else + if (ret < 0) { data->bank_sel = -1; - return ret; -} - -static inline void nct7904_bank_release(struct nct7904_data *data) -{ - mutex_unlock(&data->bank_lock); + return ret; + } + data->bank_sel = bank; + return 0; } /* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */ @@ -169,12 +162,10 @@ static int nct7904_read_reg(struct nct7904_data *data, struct i2c_client *client = data->client; int ret; - ret = nct7904_bank_lock(data, bank); - if (ret == 0) - ret = i2c_smbus_read_byte_data(client, reg); - - nct7904_bank_release(data); - return ret; + ret = nct7904_bank_select(data, bank); + if (ret < 0) + return ret; + return i2c_smbus_read_byte_data(client, reg); } /* @@ -187,19 +178,16 @@ static int nct7904_read_reg16(struct nct7904_data *data, struct i2c_client *client = data->client; int ret, hi; - ret = nct7904_bank_lock(data, bank); - if (ret == 0) { - ret = i2c_smbus_read_byte_data(client, reg); - if (ret >= 0) { - hi = ret; - ret = i2c_smbus_read_byte_data(client, reg + 1); - if (ret >= 0) - ret |= hi << 8; - } - } - - nct7904_bank_release(data); - return ret; + ret = nct7904_bank_select(data, bank); + if (ret < 0) + return ret; + hi = i2c_smbus_read_byte_data(client, reg); + if (hi < 0) + return hi; + ret = i2c_smbus_read_byte_data(client, reg + 1); + if (ret < 0) + return ret; + return ret | (hi << 8); } /* Write 1-byte register. Returns 0 or -ERRNO on error. */ @@ -209,12 +197,10 @@ static int nct7904_write_reg(struct nct7904_data *data, struct i2c_client *client = data->client; int ret; - ret = nct7904_bank_lock(data, bank); - if (ret == 0) - ret = i2c_smbus_write_byte_data(client, reg, val); - - nct7904_bank_release(data); - return ret; + ret = nct7904_bank_select(data, bank); + if (ret < 0) + return ret; + return i2c_smbus_write_byte_data(client, reg, val); } static int nct7904_read_fan(struct device *dev, u32 attr, int channel, @@ -1023,7 +1009,6 @@ static int nct7904_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->bank_lock); data->bank_sel = -1; /* Setup sensor groups. */ diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c index 802c73def428..c8f5e695fb6d 100644 --- a/drivers/hwmon/npcm750-pwm-fan.c +++ b/drivers/hwmon/npcm750-pwm-fan.c @@ -4,7 +4,6 @@ #include <linux/clk.h> #include <linux/device.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> @@ -198,7 +197,6 @@ struct npcm7xx_pwm_fan_data { int pwm_modules; struct clk *pwm_clk; struct clk *fan_clk; - struct mutex pwm_lock[NPCM7XX_PWM_MAX_MODULES]; spinlock_t fan_lock[NPCM7XX_FAN_MAX_MODULE]; int fan_irq[NPCM7XX_FAN_MAX_MODULE]; bool pwm_present[NPCM7XX_PWM_MAX_CHN_NUM]; @@ -221,7 +219,6 @@ static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_fan_data *data, /* * Config PWM Comparator register for setting duty cycle */ - mutex_lock(&data->pwm_lock[module]); /* write new CMR value */ iowrite32(val, NPCM7XX_PWM_REG_CMRx(data->pwm_base, module, pwm_ch)); @@ -245,7 +242,6 @@ static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_fan_data *data, env_bit = NPCM7XX_PWM_CTRL_CH3_INV_BIT; break; default: - mutex_unlock(&data->pwm_lock[module]); return -ENODEV; } @@ -260,8 +256,6 @@ static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_fan_data *data, } iowrite32(tmp_buf, NPCM7XX_PWM_REG_CR(data->pwm_base, module)); - mutex_unlock(&data->pwm_lock[module]); - return 0; } @@ -932,8 +926,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev) struct resource *res; struct device *hwmon; char name[20]; - int ret, cnt; u32 output_freq; + int ret; u32 i; np = dev->of_node; @@ -985,9 +979,6 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev) output_freq = npcm7xx_pwm_init(data); npcm7xx_fan_init(data); - for (cnt = 0; cnt < data->pwm_modules; cnt++) - mutex_init(&data->pwm_lock[cnt]); - for (i = 0; i < NPCM7XX_FAN_MAX_MODULE; i++) { spin_lock_init(&data->fan_lock[i]); diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index d21f7266c411..d6b48178343d 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -24,6 +24,7 @@ enum ntc_thermistor_type { TYPE_NCPXXWF104, TYPE_NCPXXWL333, TYPE_NCPXXXH103, + TYPE_NCPXXWM474, }; struct ntc_compensation { @@ -46,6 +47,7 @@ enum { NTC_NCP18WB473, NTC_NCP21WB473, NTC_SSG1404001221, + NTC_NCP18WM474, NTC_LAST, }; @@ -60,6 +62,7 @@ static const struct platform_device_id ntc_thermistor_id[] = { [NTC_NCP18WB473] = { "ncp18wb473", TYPE_NCPXXWB473 }, [NTC_NCP21WB473] = { "ncp21wb473", TYPE_NCPXXWB473 }, [NTC_SSG1404001221] = { "ssg1404_001221", TYPE_NCPXXWB473 }, + [NTC_NCP18WM474] = { "ncp18wm474", TYPE_NCPXXWM474 }, [NTC_LAST] = { }, }; MODULE_DEVICE_TABLE(platform, ntc_thermistor_id); @@ -217,6 +220,43 @@ static const struct ntc_compensation ncpXXxh103[] = { { .temp_c = 125, .ohm = 531 }, }; +static const struct ntc_compensation ncpXXwm474[] = { + { .temp_c = -40, .ohm = 10900000 }, + { .temp_c = -35, .ohm = 9600000 }, + { .temp_c = -30, .ohm = 8300000 }, + { .temp_c = -25, .ohm = 7000000 }, + { .temp_c = -20, .ohm = 5980000 }, + { .temp_c = -15, .ohm = 4960000 }, + { .temp_c = -10, .ohm = 3940000 }, + { .temp_c = -5, .ohm = 2920000 }, + { .temp_c = 0, .ohm = 1900000 }, + { .temp_c = 5, .ohm = 1614000 }, + { .temp_c = 10, .ohm = 1328000 }, + { .temp_c = 15, .ohm = 1042000 }, + { .temp_c = 20, .ohm = 756000 }, + { .temp_c = 25, .ohm = 470000 }, + { .temp_c = 30, .ohm = 404000 }, + { .temp_c = 35, .ohm = 338000 }, + { .temp_c = 40, .ohm = 272000 }, + { .temp_c = 45, .ohm = 206000 }, + { .temp_c = 50, .ohm = 140000 }, + { .temp_c = 55, .ohm = 122000 }, + { .temp_c = 60, .ohm = 104000 }, + { .temp_c = 65, .ohm = 86000 }, + { .temp_c = 70, .ohm = 68000 }, + { .temp_c = 75, .ohm = 50000 }, + { .temp_c = 80, .ohm = 44200 }, + { .temp_c = 85, .ohm = 38400 }, + { .temp_c = 90, .ohm = 32600 }, + { .temp_c = 95, .ohm = 26800 }, + { .temp_c = 100, .ohm = 21000 }, + { .temp_c = 105, .ohm = 18600 }, + { .temp_c = 110, .ohm = 16200 }, + { .temp_c = 115, .ohm = 13800 }, + { .temp_c = 120, .ohm = 11400 }, + { .temp_c = 125, .ohm = 9000 }, +}; + /* * The following compensation tables are from the specifications in EPCOS NTC * Thermistors Datasheets @@ -319,6 +359,7 @@ static const struct ntc_type ntc_type[] = { NTC_TYPE(TYPE_NCPXXWF104, ncpXXwf104), NTC_TYPE(TYPE_NCPXXWL333, ncpXXwl333), NTC_TYPE(TYPE_NCPXXXH103, ncpXXxh103), + NTC_TYPE(TYPE_NCPXXWM474, ncpXXwm474), }; /* @@ -675,6 +716,8 @@ static const struct of_device_id ntc_match[] = { .data = &ntc_thermistor_id[NTC_NCP21WB473] }, { .compatible = "samsung,1404-001221", .data = &ntc_thermistor_id[NTC_SSG1404001221] }, + { .compatible = "murata,ncp18wm474", + .data = &ntc_thermistor_id[NTC_NCP18WM474] }, /* Usage of vendor name "ntc" is deprecated */ { .compatible = "ntc,ncp03wb473", diff --git a/drivers/hwmon/peci/common.h b/drivers/hwmon/peci/common.h index 734506b0eca2..92a7ee1925bc 100644 --- a/drivers/hwmon/peci/common.h +++ b/drivers/hwmon/peci/common.h @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2021 Intel Corporation */ -#include <linux/mutex.h> #include <linux/types.h> #ifndef __PECI_HWMON_COMMON_H @@ -13,12 +12,10 @@ * struct peci_sensor_state - PECI state information * @valid: flag to indicate the sensor value is valid * @last_updated: time of the last update in jiffies - * @lock: mutex to protect sensor access */ struct peci_sensor_state { bool valid; unsigned long last_updated; - struct mutex lock; /* protect sensor access */ }; /** diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c index c7112dbf008b..b2fc936851e1 100644 --- a/drivers/hwmon/peci/cputemp.c +++ b/drivers/hwmon/peci/cputemp.c @@ -116,11 +116,9 @@ static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type { int ret; - mutex_lock(&priv->temp.target.state.lock); - ret = update_temp_target(priv); if (ret) - goto unlock; + return ret; switch (type) { case tcontrol_type: @@ -139,9 +137,6 @@ static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type ret = -EOPNOTSUPP; break; } -unlock: - mutex_unlock(&priv->temp.target.state.lock); - return ret; } @@ -177,26 +172,23 @@ static s32 dts_eight_dot_eight_to_millidegree(u16 val) static int get_die_temp(struct peci_cputemp *priv, long *val) { - int ret = 0; long tjmax; u16 temp; + int ret; - mutex_lock(&priv->temp.die.state.lock); if (!peci_sensor_need_update(&priv->temp.die.state)) goto skip_update; ret = peci_temp_read(priv->peci_dev, &temp); if (ret) - goto err_unlock; + return ret; - if (!dts_valid(temp)) { - ret = -EIO; - goto err_unlock; - } + if (!dts_valid(temp)) + return -EIO; ret = get_temp_target(priv, tjmax_type, &tjmax); if (ret) - goto err_unlock; + return ret; priv->temp.die.value = (s32)tjmax + dts_ten_dot_six_to_millidegree(temp); @@ -204,35 +196,30 @@ static int get_die_temp(struct peci_cputemp *priv, long *val) skip_update: *val = priv->temp.die.value; -err_unlock: - mutex_unlock(&priv->temp.die.state.lock); - return ret; + return 0; } static int get_dts(struct peci_cputemp *priv, long *val) { - int ret = 0; u16 thermal_margin; long tcontrol; u32 pcs; + int ret; - mutex_lock(&priv->temp.dts.state.lock); if (!peci_sensor_need_update(&priv->temp.dts.state)) goto skip_update; ret = peci_pcs_read(priv->peci_dev, PECI_PCS_THERMAL_MARGIN, 0, &pcs); if (ret) - goto err_unlock; + return ret; thermal_margin = FIELD_GET(DTS_MARGIN_MASK, pcs); - if (!dts_valid(thermal_margin)) { - ret = -EIO; - goto err_unlock; - } + if (!dts_valid(thermal_margin)) + return -EIO; ret = get_temp_target(priv, tcontrol_type, &tcontrol); if (ret) - goto err_unlock; + return ret; /* Note that the tcontrol should be available before calling it */ priv->temp.dts.value = @@ -242,35 +229,30 @@ static int get_dts(struct peci_cputemp *priv, long *val) skip_update: *val = priv->temp.dts.value; -err_unlock: - mutex_unlock(&priv->temp.dts.state.lock); - return ret; + return 0; } static int get_core_temp(struct peci_cputemp *priv, int core_index, long *val) { - int ret = 0; u16 core_dts_margin; long tjmax; u32 pcs; + int ret; - mutex_lock(&priv->temp.core[core_index].state.lock); if (!peci_sensor_need_update(&priv->temp.core[core_index].state)) goto skip_update; ret = peci_pcs_read(priv->peci_dev, PECI_PCS_MODULE_TEMP, core_index, &pcs); if (ret) - goto err_unlock; + return ret; core_dts_margin = FIELD_GET(PCS_MODULE_TEMP_MASK, pcs); - if (!dts_valid(core_dts_margin)) { - ret = -EIO; - goto err_unlock; - } + if (!dts_valid(core_dts_margin)) + return -EIO; ret = get_temp_target(priv, tjmax_type, &tjmax); if (ret) - goto err_unlock; + return ret; /* Note that the tjmax should be available before calling it */ priv->temp.core[core_index].value = @@ -280,9 +262,7 @@ static int get_core_temp(struct peci_cputemp *priv, int core_index, long *val) skip_update: *val = priv->temp.core[core_index].value; -err_unlock: - mutex_unlock(&priv->temp.core[core_index].state.lock); - return ret; + return 0; } static int cputemp_read_string(struct device *dev, enum hwmon_sensor_types type, @@ -364,6 +344,7 @@ static int init_core_mask(struct peci_cputemp *priv) case INTEL_ICELAKE_X: case INTEL_ICELAKE_D: case INTEL_SAPPHIRERAPIDS_X: + case INTEL_EMERALDRAPIDS_X: ret = peci_ep_pci_local_read(peci_dev, 0, reg->bus, reg->dev, reg->func, reg->offset + 4, &data); if (ret) @@ -430,18 +411,6 @@ static void check_resolved_cores(struct peci_cputemp *priv) bitmap_zero(priv->core_mask, CORE_NUMS_MAX); } -static void sensor_init(struct peci_cputemp *priv) -{ - int i; - - mutex_init(&priv->temp.target.state.lock); - mutex_init(&priv->temp.die.state.lock); - mutex_init(&priv->temp.dts.state.lock); - - for_each_set_bit(i, priv->core_mask, CORE_NUMS_MAX) - mutex_init(&priv->temp.core[i].state.lock); -} - static const struct hwmon_ops peci_cputemp_ops = { .is_visible = cputemp_is_visible, .read_string = cputemp_read_string, @@ -506,8 +475,6 @@ static int peci_cputemp_probe(struct auxiliary_device *adev, check_resolved_cores(priv); - sensor_init(priv); - hwmon_dev = devm_hwmon_device_register_with_info(priv->dev, priv->name, priv, &peci_cputemp_chip_info, NULL); @@ -539,6 +506,13 @@ static struct resolved_cores_reg resolved_cores_reg_spr = { .offset = 0x80, }; +static struct resolved_cores_reg resolved_cores_reg_emr = { + .bus = 31, + .dev = 30, + .func = 6, + .offset = 0x80, +}; + static const struct cpu_info cpu_hsx = { .reg = &resolved_cores_reg_hsx, .min_peci_revision = 0x33, @@ -563,6 +537,12 @@ static const struct cpu_info cpu_spr = { .thermal_margin_to_millidegree = &dts_ten_dot_six_to_millidegree, }; +static const struct cpu_info cpu_emr = { + .reg = &resolved_cores_reg_emr, + .min_peci_revision = 0x40, + .thermal_margin_to_millidegree = &dts_ten_dot_six_to_millidegree, +}; + static const struct auxiliary_device_id peci_cputemp_ids[] = { { .name = "peci_cpu.cputemp.hsx", @@ -592,6 +572,10 @@ static const struct auxiliary_device_id peci_cputemp_ids[] = { .name = "peci_cpu.cputemp.spr", .driver_data = (kernel_ulong_t)&cpu_spr, }, + { + .name = "peci_cpu.cputemp.emr", + .driver_data = (kernel_ulong_t)&cpu_emr, + }, { } }; MODULE_DEVICE_TABLE(auxiliary, peci_cputemp_ids); diff --git a/drivers/hwmon/peci/dimmtemp.c b/drivers/hwmon/peci/dimmtemp.c index fbe82d9852e0..bd3e8715dfec 100644 --- a/drivers/hwmon/peci/dimmtemp.c +++ b/drivers/hwmon/peci/dimmtemp.c @@ -32,6 +32,8 @@ #define DIMM_IDX_MAX_ON_ICXD 2 #define CHAN_RANK_MAX_ON_SPR 8 #define DIMM_IDX_MAX_ON_SPR 2 +#define CHAN_RANK_MAX_ON_EMR 8 +#define DIMM_IDX_MAX_ON_EMR 2 #define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX #define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX @@ -94,16 +96,15 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no, long *val) { int dimm_order = dimm_no % priv->gen_info->dimm_idx_max; int chan_rank = dimm_no / priv->gen_info->dimm_idx_max; - int ret = 0; u32 data; + int ret; - mutex_lock(&priv->dimm[dimm_no].temp.state.lock); if (!peci_sensor_need_update(&priv->dimm[dimm_no].temp.state)) goto skip_update; ret = peci_pcs_read(priv->peci_dev, PECI_PCS_DDR_DIMM_TEMP, chan_rank, &data); if (ret) - goto unlock; + return ret; priv->dimm[dimm_no].temp.value = __dimm_temp(data, dimm_order) * MILLIDEGREE_PER_DEGREE; @@ -111,9 +112,7 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no, long *val) skip_update: *val = priv->dimm[dimm_no].temp.value; -unlock: - mutex_unlock(&priv->dimm[dimm_no].temp.state.lock); - return ret; + return 0; } static int update_thresholds(struct peci_dimmtemp *priv, int dimm_no) @@ -143,10 +142,9 @@ static int get_dimm_thresholds(struct peci_dimmtemp *priv, enum peci_dimm_thresh { int ret; - mutex_lock(&priv->dimm[dimm_no].thresholds.state.lock); ret = update_thresholds(priv, dimm_no); if (ret) - goto unlock; + return ret; switch (type) { case temp_max_type: @@ -159,9 +157,6 @@ static int get_dimm_thresholds(struct peci_dimmtemp *priv, enum peci_dimm_thresh ret = -EOPNOTSUPP; break; } -unlock: - mutex_unlock(&priv->dimm[dimm_no].thresholds.state.lock); - return ret; } @@ -347,8 +342,6 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv) ret = create_dimm_temp_label(priv, i); if (ret) return ret; - mutex_init(&priv->dimm[i].thresholds.state.lock); - mutex_init(&priv->dimm[i].temp.state.lock); } dev = devm_hwmon_device_register_with_info(priv->dev, priv->name, priv, @@ -571,6 +564,12 @@ read_thresholds_spr(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u return 0; } +static int read_thresholds_emr(struct peci_dimmtemp *priv, int dimm_order, + int chan_rank, u32 *data) +{ + return read_thresholds_spr(priv, dimm_order, chan_rank, data); +} + static const struct dimm_info dimm_hsx = { .chan_rank_max = CHAN_RANK_MAX_ON_HSX, .dimm_idx_max = DIMM_IDX_MAX_ON_HSX, @@ -620,6 +619,13 @@ static const struct dimm_info dimm_spr = { .read_thresholds = &read_thresholds_spr, }; +static const struct dimm_info dimm_emr = { + .chan_rank_max = CHAN_RANK_MAX_ON_EMR, + .dimm_idx_max = DIMM_IDX_MAX_ON_EMR, + .min_peci_revision = 0x40, + .read_thresholds = &read_thresholds_emr, +}; + static const struct auxiliary_device_id peci_dimmtemp_ids[] = { { .name = "peci_cpu.dimmtemp.hsx", @@ -649,6 +655,10 @@ static const struct auxiliary_device_id peci_dimmtemp_ids[] = { .name = "peci_cpu.dimmtemp.spr", .driver_data = (kernel_ulong_t)&dimm_spr, }, + { + .name = "peci_cpu.dimmtemp.emr", + .driver_data = (kernel_ulong_t)&dimm_emr, + }, { } }; MODULE_DEVICE_TABLE(auxiliary, peci_dimmtemp_ids); diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index da04ff6df28b..f3fb94cebf1a 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -320,6 +320,15 @@ config SENSORS_MAX16601 This driver can also be built as a module. If so, the module will be called max16601. +config SENSORS_MAX17616 + tristate "Analog Devices MAX17616/MAX17616A" + help + If you say yes here you get hardware monitoring support for Analog + Devices MAX17616/MAX17616A. + + This driver can also be built as a module. If so, the module will + be called max17616. + config SENSORS_MAX20730 tristate "Maxim MAX20710, MAX20730, MAX20734, MAX20743" help @@ -352,6 +361,7 @@ config SENSORS_MAX34440 help If you say yes here you get hardware monitoring support for Maxim MAX34440, MAX34441, MAX34446, MAX34451, MAX34460, and MAX34461. + Other compatible are ADPM12160, and ADPM12200. This driver can also be built as a module. If so, the module will be called max34440. @@ -401,6 +411,15 @@ config SENSORS_MP2891 This driver can also be built as a module. If so, the module will be called mp2891. +config SENSORS_MP2925 + tristate "MPS MP2925" + help + If you say yes here you get hardware monitoring support for MPS + MP2925 Dual Loop Digital Multi-Phase Controller. + + This driver can also be built as a module. If so, the module will + be called mp2925. + config SENSORS_MP29502 tristate "MPS MP29502" help @@ -471,6 +490,15 @@ config SENSORS_MP9941 This driver can also be built as a module. If so, the module will be called mp9941. +config SENSORS_MP9945 + tristate "MPS MP9945" + help + If you say yes here you get hardware monitoring support for MPS + MP9945. + + This driver can also be built as a module. If so, the module will + be called mp9945. + config SENSORS_MPQ7932_REGULATOR bool "Regulator support for MPQ7932" depends on SENSORS_MPQ7932 && REGULATOR diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 4c5ff3f32c5e..349a89b6d92e 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_SENSORS_LTC4286) += ltc4286.o obj-$(CONFIG_SENSORS_MAX15301) += max15301.o obj-$(CONFIG_SENSORS_MAX16064) += max16064.o obj-$(CONFIG_SENSORS_MAX16601) += max16601.o +obj-$(CONFIG_SENSORS_MAX17616) += max17616.o obj-$(CONFIG_SENSORS_MAX20730) += max20730.o obj-$(CONFIG_SENSORS_MAX20751) += max20751.o obj-$(CONFIG_SENSORS_MAX31785) += max31785.o @@ -40,6 +41,7 @@ obj-$(CONFIG_SENSORS_MP2856) += mp2856.o obj-$(CONFIG_SENSORS_MP2869) += mp2869.o obj-$(CONFIG_SENSORS_MP2888) += mp2888.o obj-$(CONFIG_SENSORS_MP2891) += mp2891.o +obj-$(CONFIG_SENSORS_MP2925) += mp2925.o obj-$(CONFIG_SENSORS_MP29502) += mp29502.o obj-$(CONFIG_SENSORS_MP2975) += mp2975.o obj-$(CONFIG_SENSORS_MP2993) += mp2993.o @@ -47,6 +49,7 @@ obj-$(CONFIG_SENSORS_MP5023) += mp5023.o obj-$(CONFIG_SENSORS_MP5920) += mp5920.o obj-$(CONFIG_SENSORS_MP5990) += mp5990.o obj-$(CONFIG_SENSORS_MP9941) += mp9941.o +obj-$(CONFIG_SENSORS_MP9945) += mp9945.o obj-$(CONFIG_SENSORS_MPQ7932) += mpq7932.o obj-$(CONFIG_SENSORS_MPQ8785) += mpq8785.o obj-$(CONFIG_SENSORS_PLI1209BC) += pli1209bc.o diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 6bba9b50c51b..97b61836f53a 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -65,6 +65,7 @@ enum chips { raa228246, raa229001, raa229004, + raa229141, raa229621, }; @@ -73,6 +74,7 @@ enum variants { raa_dmpvr2_1rail, raa_dmpvr2_2rail, raa_dmpvr2_2rail_nontc, + raa_dmpvr2_2rail_pmbus, raa_dmpvr2_3rail, raa_dmpvr2_hv, }; @@ -399,6 +401,17 @@ static int isl68137_probe(struct i2c_client *client) info->read_word_data = raa_dmpvr2_read_word_data; info->write_word_data = raa_dmpvr2_write_word_data; break; + case raa_dmpvr2_2rail_pmbus: + info->format[PSC_VOLTAGE_IN] = linear, + info->format[PSC_VOLTAGE_OUT] = linear, + info->format[PSC_CURRENT_IN] = linear; + info->format[PSC_CURRENT_OUT] = linear; + info->format[PSC_POWER] = linear; + info->format[PSC_TEMPERATURE] = linear; + info->pages = 2; + info->read_word_data = raa_dmpvr2_read_word_data; + info->write_word_data = raa_dmpvr2_write_word_data; + break; case raa_dmpvr2_3rail: info->read_word_data = raa_dmpvr2_read_word_data; info->write_word_data = raa_dmpvr2_write_word_data; @@ -469,6 +482,7 @@ static const struct i2c_device_id raa_dmpvr_id[] = { {"raa228246", raa_dmpvr2_2rail_nontc}, {"raa229001", raa_dmpvr2_2rail}, {"raa229004", raa_dmpvr2_2rail}, + {"raa229141", raa_dmpvr2_2rail_pmbus}, {"raa229621", raa_dmpvr2_2rail}, {} }; diff --git a/drivers/hwmon/pmbus/max17616.c b/drivers/hwmon/pmbus/max17616.c new file mode 100644 index 000000000000..1d4a0ddb95bb --- /dev/null +++ b/drivers/hwmon/pmbus/max17616.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hardware monitoring driver for Analog Devices MAX17616/MAX17616A + * + * Copyright (C) 2025 Analog Devices, Inc. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> + +#include "pmbus.h" + +static struct pmbus_driver_info max17616_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = direct, + .m[PSC_VOLTAGE_IN] = 512, + .b[PSC_VOLTAGE_IN] = -18, + .R[PSC_VOLTAGE_IN] = -1, + + .format[PSC_VOLTAGE_OUT] = direct, + .m[PSC_VOLTAGE_OUT] = 512, + .b[PSC_VOLTAGE_OUT] = -18, + .R[PSC_VOLTAGE_OUT] = -1, + + .format[PSC_CURRENT_OUT] = direct, + .m[PSC_CURRENT_OUT] = 5845, + .b[PSC_CURRENT_OUT] = 80, + .R[PSC_CURRENT_OUT] = -1, + + .format[PSC_TEMPERATURE] = direct, + .m[PSC_TEMPERATURE] = 71, + .b[PSC_TEMPERATURE] = 19653, + .R[PSC_TEMPERATURE] = -1, + + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_STATUS_TEMP, +}; + +static int max17616_probe(struct i2c_client *client) +{ + return pmbus_do_probe(client, &max17616_info); +} + +static const struct i2c_device_id max17616_id[] = { + { "max17616" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max17616_id); + +static const struct of_device_id max17616_of_match[] = { + { .compatible = "adi,max17616" }, + { } +}; +MODULE_DEVICE_TABLE(of, max17616_of_match); + +static struct i2c_driver max17616_driver = { + .driver = { + .name = "max17616", + .of_match_table = max17616_of_match, + }, + .probe = max17616_probe, + .id_table = max17616_id, +}; +module_i2c_driver(max17616_driver); + +MODULE_AUTHOR("Kim Seer Paller <kimseer.paller@analog.com>"); +MODULE_DESCRIPTION("PMBus driver for Analog Devices MAX17616/MAX17616A"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index ef981ed97da8..8ea4e68d4e9d 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -17,6 +17,7 @@ enum chips { adpm12160, + adpm12200, max34440, max34441, max34446, @@ -98,7 +99,7 @@ static int max34440_read_word_data(struct i2c_client *client, int page, break; case PMBUS_VIRT_READ_IOUT_AVG: if (data->id != max34446 && data->id != max34451 && - data->id != adpm12160) + data->id != adpm12160 && data->id != adpm12200) return -ENXIO; ret = pmbus_read_word_data(client, page, phase, MAX34446_MFR_IOUT_AVG); @@ -183,7 +184,7 @@ static int max34440_write_word_data(struct i2c_client *client, int page, ret = pmbus_write_word_data(client, page, MAX34440_MFR_IOUT_PEAK, 0); if (!ret && (data->id == max34446 || data->id == max34451 || - data->id == adpm12160)) + data->id == adpm12160 || data->id == adpm12200)) ret = pmbus_write_word_data(client, page, MAX34446_MFR_IOUT_AVG, 0); @@ -364,6 +365,42 @@ static struct pmbus_driver_info max34440_info[] = { .read_word_data = max34440_read_word_data, .write_word_data = max34440_write_word_data, }, + [adpm12200] = { + .pages = 19, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_CURRENT_IN] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_VOLTAGE_IN] = 125, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = 0, + .m[PSC_VOLTAGE_OUT] = 125, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = 0, + .m[PSC_CURRENT_IN] = 250, + .b[PSC_CURRENT_IN] = 0, + .R[PSC_CURRENT_IN] = -1, + .m[PSC_CURRENT_OUT] = 250, + .b[PSC_CURRENT_OUT] = 0, + .R[PSC_CURRENT_OUT] = -1, + .m[PSC_TEMPERATURE] = 1, + .b[PSC_TEMPERATURE] = 0, + .R[PSC_TEMPERATURE] = 2, + /* absent func below [18] are not for monitoring */ + .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, + .func[4] = PMBUS_HAVE_STATUS_IOUT, + .func[5] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[6] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[7] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[8] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, + .func[9] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT, + .func[10] = PMBUS_HAVE_IIN | PMBUS_HAVE_STATUS_INPUT, + .func[14] = PMBUS_HAVE_IOUT, + .func[18] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, + .read_word_data = max34440_read_word_data, + .write_word_data = max34440_write_word_data, + }, [max34440] = { .pages = 14, .format[PSC_VOLTAGE_IN] = direct, @@ -600,7 +637,7 @@ static int max34440_probe(struct i2c_client *client) rv = max34451_set_supported_funcs(client, data); if (rv) return rv; - } else if (data->id == adpm12160) { + } else if (data->id == adpm12160 || data->id == adpm12200) { data->iout_oc_fault_limit = PMBUS_IOUT_OC_FAULT_LIMIT; data->iout_oc_warn_limit = PMBUS_IOUT_OC_WARN_LIMIT; } @@ -610,6 +647,7 @@ static int max34440_probe(struct i2c_client *client) static const struct i2c_device_id max34440_id[] = { {"adpm12160", adpm12160}, + {"adpm12200", adpm12200}, {"max34440", max34440}, {"max34441", max34441}, {"max34446", max34446}, diff --git a/drivers/hwmon/pmbus/mp2925.c b/drivers/hwmon/pmbus/mp2925.c new file mode 100644 index 000000000000..6bebd6023021 --- /dev/null +++ b/drivers/hwmon/pmbus/mp2925.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP2925) + */ + +#include <linux/bitfield.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include "pmbus.h" + +/* + * Vender specific register MFR_VR_MULTI_CONFIG(0x08). + * This register is used to obtain vid scale. + */ +#define MFR_VR_MULTI_CONFIG 0x08 + +#define MP2925_VOUT_DIV 512 +#define MP2925_VOUT_OVUV_UINT 195 +#define MP2925_VOUT_OVUV_DIV 100 + +#define MP2925_PAGE_NUM 2 + +#define MP2925_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | \ + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | \ + PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | \ + PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_HAVE_STATUS_TEMP | \ + PMBUS_HAVE_STATUS_INPUT) + +#define MP2925_RAIL2_FUNC (PMBUS_HAVE_PIN | PMBUS_HAVE_VOUT | \ + PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | \ + PMBUS_HAVE_TEMP | PMBUS_HAVE_IIN | \ + PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_HAVE_STATUS_TEMP | \ + PMBUS_HAVE_STATUS_INPUT) + +struct mp2925_data { + struct pmbus_driver_info info; + int vout_scale[MP2925_PAGE_NUM]; +}; + +#define to_mp2925_data(x) container_of(x, struct mp2925_data, info) + +static u16 mp2925_linear_exp_transfer(u16 word, u16 expect_exponent) +{ + s16 exponent, mantissa, target_exponent; + + exponent = ((s16)word) >> 11; + mantissa = ((s16)((word & 0x7ff) << 5)) >> 5; + target_exponent = (s16)((expect_exponent & 0x1f) << 11) >> 11; + + if (exponent > target_exponent) + mantissa = mantissa << (exponent - target_exponent); + else + mantissa = mantissa >> (target_exponent - exponent); + + return (mantissa & 0x7ff) | ((expect_exponent << 11) & 0xf800); +} + +static int mp2925_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + switch (reg) { + case PMBUS_VOUT_MODE: + /* + * The MP2925 does not follow standard PMBus protocol completely, + * and the calculation of vout in this driver is based on direct + * format. As a result, the format of vout is enforced to direct. + */ + ret = PB_VOUT_MODE_DIRECT; + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int mp2925_read_word_data(struct i2c_client *client, int page, int phase, + int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp2925_data *data = to_mp2925_data(info); + int ret; + + switch (reg) { + case PMBUS_READ_VOUT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * data->vout_scale[page], + MP2925_VOUT_DIV); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = pmbus_read_word_data(client, page, phase, reg); + if (ret < 0) + return ret; + + ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * MP2925_VOUT_OVUV_UINT, + MP2925_VOUT_OVUV_DIV); + break; + case PMBUS_STATUS_WORD: + case PMBUS_READ_VIN: + case PMBUS_READ_IOUT: + case PMBUS_READ_POUT: + case PMBUS_READ_PIN: + case PMBUS_READ_IIN: + case PMBUS_READ_TEMPERATURE_1: + case PMBUS_VIN_OV_FAULT_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_OT_WARN_LIMIT: + ret = -ENODATA; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int mp2925_write_word_data(struct i2c_client *client, int page, int reg, + u16 word) +{ + int ret; + + switch (reg) { + case PMBUS_VIN_OV_FAULT_LIMIT: + case PMBUS_VIN_OV_WARN_LIMIT: + case PMBUS_VIN_UV_WARN_LIMIT: + case PMBUS_VIN_UV_FAULT_LIMIT: + /* + * The PMBUS_VIN_OV_FAULT_LIMIT, PMBUS_VIN_OV_WARN_LIMIT, + * PMBUS_VIN_UV_WARN_LIMIT and PMBUS_VIN_UV_FAULT_LIMIT + * of MP2925 is linear11 format, and the exponent is a + * constant value(5'b11100), so the exponent of word + * parameter should be converted to 5'b11100(0x1C). + */ + ret = pmbus_write_word_data(client, page, reg, + mp2925_linear_exp_transfer(word, 0x1C)); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + /* + * The bit0-bit11 is the limit value, and bit12-bit15 + * should not be changed. + */ + ret = pmbus_read_word_data(client, page, 0xff, reg); + if (ret < 0) + return ret; + + ret = pmbus_write_word_data(client, page, reg, + (ret & ~GENMASK(11, 0)) | + FIELD_PREP(GENMASK(11, 0), + DIV_ROUND_CLOSEST(word * MP2925_VOUT_OVUV_DIV, + MP2925_VOUT_OVUV_UINT))); + break; + case PMBUS_OT_FAULT_LIMIT: + case PMBUS_OT_WARN_LIMIT: + /* + * The PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT of + * MP2925 is linear11 format, and the exponent is a + * constant value(5'b00000), so the exponent of word + * parameter should be converted to 5'b00000. + */ + ret = pmbus_write_word_data(client, page, reg, + mp2925_linear_exp_transfer(word, 0x00)); + break; + case PMBUS_IOUT_OC_FAULT_LIMIT: + case PMBUS_IOUT_OC_WARN_LIMIT: + /* + * The PMBUS_IOUT_OC_FAULT_LIMIT and PMBUS_IOUT_OC_WARN_LIMIT + * of MP2925 is linear11 format, and the exponent can not be + * changed. + */ + ret = pmbus_read_word_data(client, page, 0xff, reg); + if (ret < 0) + return ret; + + ret = pmbus_write_word_data(client, page, reg, + mp2925_linear_exp_transfer(word, + FIELD_GET(GENMASK(15, 11), + ret))); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int +mp2925_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info, + int page) +{ + struct mp2925_data *data = to_mp2925_data(info); + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + if (FIELD_GET(GENMASK(5, 5), ret)) { + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, + page == 0 ? 3 : 4); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_word_data(client, MFR_VR_MULTI_CONFIG); + if (ret < 0) + return ret; + + if (FIELD_GET(GENMASK(5, 5), ret)) + data->vout_scale[page] = 2560; + else + data->vout_scale[page] = 5120; + } else if (FIELD_GET(GENMASK(4, 4), ret)) { + data->vout_scale[page] = 1; + } else { + data->vout_scale[page] = 512; + } + + return 0; +} + +static int mp2925_identify(struct i2c_client *client, struct pmbus_driver_info *info) +{ + int ret; + + ret = mp2925_identify_vout_scale(client, info, 0); + if (ret < 0) + return ret; + + return mp2925_identify_vout_scale(client, info, 1); +} + +static const struct pmbus_driver_info mp2925_info = { + .pages = MP2925_PAGE_NUM, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + + .m[PSC_VOLTAGE_OUT] = 1, + .R[PSC_VOLTAGE_OUT] = 3, + .b[PSC_VOLTAGE_OUT] = 0, + + .func[0] = MP2925_RAIL1_FUNC, + .func[1] = MP2925_RAIL2_FUNC, + .read_word_data = mp2925_read_word_data, + .read_byte_data = mp2925_read_byte_data, + .write_word_data = mp2925_write_word_data, + .identify = mp2925_identify, +}; + +static int mp2925_probe(struct i2c_client *client) +{ + struct mp2925_data *data; + + data = devm_kzalloc(&client->dev, sizeof(struct mp2925_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + memcpy(&data->info, &mp2925_info, sizeof(mp2925_info)); + + return pmbus_do_probe(client, &data->info); +} + +static const struct i2c_device_id mp2925_id[] = { + {"mp2925"}, + {"mp2929"}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mp2925_id); + +static const struct of_device_id __maybe_unused mp2925_of_match[] = { + {.compatible = "mps,mp2925"}, + {.compatible = "mps,mp2929"}, + {} +}; +MODULE_DEVICE_TABLE(of, mp2925_of_match); + +static struct i2c_driver mp2925_driver = { + .driver = { + .name = "mp2925", + .of_match_table = mp2925_of_match, + }, + .probe = mp2925_probe, + .id_table = mp2925_id, +}; + +module_i2c_driver(mp2925_driver); + +MODULE_AUTHOR("Wensheng Wang <wenswang@yeah.net>"); +MODULE_DESCRIPTION("PMBus driver for MPS MP2925"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/mp9945.c b/drivers/hwmon/pmbus/mp9945.c new file mode 100644 index 000000000000..34822e0de812 --- /dev/null +++ b/drivers/hwmon/pmbus/mp9945.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hardware monitoring driver for MPS Single-phase Digital VR Controllers(MP9945) + */ + +#include <linux/bitfield.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include "pmbus.h" + +#define MFR_VR_MULTI_CONFIG_R1 0x08 +#define MFR_SVID_CFG_R1 0xBD + +/* VOUT_MODE register values */ +#define VOUT_MODE_LINEAR16 0x17 +#define VOUT_MODE_VID 0x21 +#define VOUT_MODE_DIRECT 0x40 + +#define MP9945_PAGE_NUM 1 + +#define MP9945_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \ + PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | \ + PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | \ + PMBUS_HAVE_TEMP | \ + PMBUS_HAVE_STATUS_VOUT | \ + PMBUS_HAVE_STATUS_IOUT | \ + PMBUS_HAVE_STATUS_TEMP | \ + PMBUS_HAVE_STATUS_INPUT) + +enum mp9945_vout_mode { + MP9945_VOUT_MODE_VID, + MP9945_VOUT_MODE_DIRECT, + MP9945_VOUT_MODE_LINEAR16, +}; + +struct mp9945_data { + struct pmbus_driver_info info; + enum mp9945_vout_mode vout_mode; + int vid_resolution; + int vid_offset; +}; + +#define to_mp9945_data(x) container_of(x, struct mp9945_data, info) + +static int mp9945_read_vout(struct i2c_client *client, struct mp9945_data *data) +{ + int ret; + + ret = i2c_smbus_read_word_data(client, PMBUS_READ_VOUT); + if (ret < 0) + return ret; + + ret &= GENMASK(11, 0); + + switch (data->vout_mode) { + case MP9945_VOUT_MODE_VID: + if (ret > 0) + ret = (ret + data->vid_offset) * data->vid_resolution; + break; + case MP9945_VOUT_MODE_DIRECT: + break; + case MP9945_VOUT_MODE_LINEAR16: + /* LSB: 1000 * 2^-9 (mV) */ + ret = DIV_ROUND_CLOSEST(ret * 125, 64); + break; + default: + return -ENODEV; + } + + return ret; +} + +static int mp9945_read_byte_data(struct i2c_client *client, int page, int reg) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; + + switch (reg) { + case PMBUS_VOUT_MODE: + /* + * Override VOUT_MODE to DIRECT as the driver handles custom + * VOUT format conversions internally. + */ + return PB_VOUT_MODE_DIRECT; + default: + return -ENODATA; + } +} + +static int mp9945_read_word_data(struct i2c_client *client, int page, int phase, + int reg) +{ + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); + struct mp9945_data *data = to_mp9945_data(info); + int ret; + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; + + switch (reg) { + case PMBUS_READ_VOUT: + ret = mp9945_read_vout(client, data); + break; + case PMBUS_VOUT_OV_FAULT_LIMIT: + case PMBUS_VOUT_UV_FAULT_LIMIT: + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + /* LSB: 1.95 (mV) */ + ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * 39, 20); + break; + case PMBUS_VOUT_UV_WARN_LIMIT: + ret = i2c_smbus_read_word_data(client, reg); + if (ret < 0) + return ret; + + ret &= GENMASK(9, 0); + if (ret > 0) + ret = (ret + data->vid_offset) * data->vid_resolution; + break; + default: + ret = -ENODATA; + break; + } + + return ret; +} + +static int mp9945_identify(struct i2c_client *client, + struct pmbus_driver_info *info) +{ + struct mp9945_data *data = to_mp9945_data(info); + int ret; + + ret = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE); + if (ret < 0) + return ret; + + switch (ret) { + case VOUT_MODE_LINEAR16: + data->vout_mode = MP9945_VOUT_MODE_LINEAR16; + break; + case VOUT_MODE_VID: + data->vout_mode = MP9945_VOUT_MODE_VID; + break; + case VOUT_MODE_DIRECT: + data->vout_mode = MP9945_VOUT_MODE_DIRECT; + break; + default: + return -ENODEV; + } + + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 3); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_word_data(client, MFR_VR_MULTI_CONFIG_R1); + if (ret < 0) + return ret; + + data->vid_resolution = (FIELD_GET(BIT(2), ret)) ? 5 : 10; + + ret = i2c_smbus_read_word_data(client, MFR_SVID_CFG_R1); + if (ret < 0) + return ret; + + data->vid_offset = (FIELD_GET(BIT(15), ret)) ? 19 : 49; + + return i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); +} + +static struct pmbus_driver_info mp9945_info = { + .pages = MP9945_PAGE_NUM, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_CURRENT_OUT] = linear, + .format[PSC_POWER] = linear, + .format[PSC_TEMPERATURE] = linear, + .m[PSC_VOLTAGE_OUT] = 1, + .R[PSC_VOLTAGE_OUT] = 3, + .b[PSC_VOLTAGE_OUT] = 0, + .func[0] = MP9945_RAIL1_FUNC, + .read_word_data = mp9945_read_word_data, + .read_byte_data = mp9945_read_byte_data, + .identify = mp9945_identify, +}; + +static int mp9945_probe(struct i2c_client *client) +{ + struct mp9945_data *data; + int ret; + + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + memcpy(&data->info, &mp9945_info, sizeof(mp9945_info)); + + /* + * Set page 0 before probe. The core reads paged registers which are + * only on page 0 for this device. + */ + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; + + return pmbus_do_probe(client, &data->info); +} + +static const struct i2c_device_id mp9945_id[] = { + {"mp9945"}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mp9945_id); + +static const struct of_device_id __maybe_unused mp9945_of_match[] = { + {.compatible = "mps,mp9945"}, + {} +}; +MODULE_DEVICE_TABLE(of, mp9945_of_match); + +static struct i2c_driver mp9945_driver = { + .driver = { + .name = "mp9945", + .of_match_table = of_match_ptr(mp9945_of_match), + }, + .probe = mp9945_probe, + .id_table = mp9945_id, +}; + +module_i2c_driver(mp9945_driver); + +MODULE_AUTHOR("Cosmo Chou <chou.cosmo@gmail.com>"); +MODULE_DESCRIPTION("PMBus driver for MPS MP9945"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index 5f9ca6543530..06a2c56016d1 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c @@ -16,7 +16,6 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/delay.h> #define ADC_STEP_MV 2 @@ -75,7 +74,6 @@ enum powr1220_adc_values { struct powr1220_data { struct i2c_client *client; - struct mutex update_lock; u8 max_channels; bool adc_valid[MAX_POWR1220_ADC_VALUES]; /* the next value is in jiffies */ @@ -111,8 +109,6 @@ static int powr1220_read_adc(struct device *dev, int ch_num) int result; int adc_range = 0; - mutex_lock(&data->update_lock); - if (time_after(jiffies, data->adc_last_updated[ch_num] + HZ) || !data->adc_valid[ch_num]) { /* @@ -128,8 +124,8 @@ static int powr1220_read_adc(struct device *dev, int ch_num) /* set the attenuator and mux */ result = i2c_smbus_write_byte_data(data->client, ADC_MUX, adc_range | ch_num); - if (result) - goto exit; + if (result < 0) + return result; /* * wait at least Tconvert time (200 us) for the @@ -140,14 +136,14 @@ static int powr1220_read_adc(struct device *dev, int ch_num) /* get the ADC reading */ result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_LOW); if (result < 0) - goto exit; + return result; reading = result >> 4; /* get the upper half of the reading */ result = i2c_smbus_read_byte_data(data->client, ADC_VALUE_HIGH); if (result < 0) - goto exit; + return result; reading |= result << 4; @@ -163,10 +159,6 @@ static int powr1220_read_adc(struct device *dev, int ch_num) } else { result = data->adc_values[ch_num]; } - -exit: - mutex_unlock(&data->update_lock); - return result; } @@ -302,7 +294,6 @@ static int powr1220_probe(struct i2c_client *client) break; } - mutex_init(&data->update_lock); data->client = client; hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c index a6c439e376ff..c5b2488c4c7f 100644 --- a/drivers/hwmon/sbtsi_temp.c +++ b/drivers/hwmon/sbtsi_temp.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/hwmon.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/bitfield.h> @@ -52,7 +51,6 @@ /* Each client has this additional data */ struct sbtsi_data { struct i2c_client *client; - struct mutex lock; bool ext_range_mode; bool read_order; }; @@ -94,7 +92,6 @@ static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type, switch (attr) { case hwmon_temp_input: - mutex_lock(&data->lock); if (data->read_order) { temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC); temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT); @@ -102,19 +99,14 @@ static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type, temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT); temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC); } - mutex_unlock(&data->lock); break; case hwmon_temp_max: - mutex_lock(&data->lock); temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_INT); temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_DEC); - mutex_unlock(&data->lock); break; case hwmon_temp_min: - mutex_lock(&data->lock); temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_INT); temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_DEC); - mutex_unlock(&data->lock); break; default: return -EINVAL; @@ -158,15 +150,11 @@ static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type, val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX); sbtsi_mc_to_reg(val, &temp_int, &temp_dec); - mutex_lock(&data->lock); err = i2c_smbus_write_byte_data(data->client, reg_int, temp_int); if (err) - goto exit; + return err; - err = i2c_smbus_write_byte_data(data->client, reg_dec, temp_dec); -exit: - mutex_unlock(&data->lock); - return err; + return i2c_smbus_write_byte_data(data->client, reg_dec, temp_dec); } static umode_t sbtsi_is_visible(const void *data, @@ -219,7 +207,6 @@ static int sbtsi_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->lock); err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG); if (err < 0) diff --git a/drivers/hwmon/scmi-hwmon.c b/drivers/hwmon/scmi-hwmon.c index 364199b332c0..eec223d174c0 100644 --- a/drivers/hwmon/scmi-hwmon.c +++ b/drivers/hwmon/scmi-hwmon.c @@ -240,6 +240,8 @@ static int scmi_hwmon_probe(struct scmi_device *sdev) const struct hwmon_channel_info **ptr_scmi_ci; const struct scmi_handle *handle = sdev->handle; struct scmi_protocol_handle *ph; + u32 sensor_config = FIELD_PREP(SCMI_SENS_CFG_SENSOR_ENABLED_MASK, + SCMI_SENS_CFG_SENSOR_ENABLE); if (!handle) return -ENODEV; @@ -339,6 +341,13 @@ static int scmi_hwmon_probe(struct scmi_device *sdev) if (!sensor) continue; + ret = sensor_ops->config_set(ph, i, sensor_config); + if (ret) { + dev_err(dev, "Error enabling sensor %s. err=%d\n", + sensor->name, ret); + continue; + } + /* * Warn on any misconfiguration related to thermal zones but * bail out of probing only on memory errors. diff --git a/drivers/hwmon/sfctemp.c b/drivers/hwmon/sfctemp.c index fb1da93383d7..b78b2c099a12 100644 --- a/drivers/hwmon/sfctemp.c +++ b/drivers/hwmon/sfctemp.c @@ -10,7 +10,6 @@ #include <linux/hwmon.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/reset.h> @@ -49,8 +48,6 @@ #define SFCTEMP_K1000 81100L struct sfctemp { - /* serialize access to hardware register and enabled below */ - struct mutex lock; void __iomem *regs; struct clk *clk_sense; struct clk *clk_bus; @@ -92,15 +89,14 @@ static void sfctemp_stop(struct sfctemp *sfctemp) static int sfctemp_enable(struct sfctemp *sfctemp) { - int ret = 0; + int ret; - mutex_lock(&sfctemp->lock); if (sfctemp->enabled) - goto done; + return 0; ret = clk_prepare_enable(sfctemp->clk_bus); if (ret) - goto err; + return ret; ret = reset_control_deassert(sfctemp->rst_bus); if (ret) goto err_disable_bus; @@ -115,9 +111,7 @@ static int sfctemp_enable(struct sfctemp *sfctemp) sfctemp_power_up(sfctemp); sfctemp_run(sfctemp); sfctemp->enabled = true; -done: - mutex_unlock(&sfctemp->lock); - return ret; + return 0; err_disable_sense: clk_disable_unprepare(sfctemp->clk_sense); @@ -125,16 +119,13 @@ err_assert_bus: reset_control_assert(sfctemp->rst_bus); err_disable_bus: clk_disable_unprepare(sfctemp->clk_bus); -err: - mutex_unlock(&sfctemp->lock); return ret; } static int sfctemp_disable(struct sfctemp *sfctemp) { - mutex_lock(&sfctemp->lock); if (!sfctemp->enabled) - goto done; + return 0; sfctemp_stop(sfctemp); sfctemp_power_down(sfctemp); @@ -143,8 +134,6 @@ static int sfctemp_disable(struct sfctemp *sfctemp) reset_control_assert(sfctemp->rst_bus); clk_disable_unprepare(sfctemp->clk_bus); sfctemp->enabled = false; -done: - mutex_unlock(&sfctemp->lock); return 0; } @@ -155,22 +144,14 @@ static void sfctemp_disable_action(void *data) static int sfctemp_convert(struct sfctemp *sfctemp, long *val) { - int ret; - - mutex_lock(&sfctemp->lock); - if (!sfctemp->enabled) { - ret = -ENODATA; - goto out; - } + if (!sfctemp->enabled) + return -ENODATA; /* calculate temperature in milli Celcius */ *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS) * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000; - ret = 0; -out: - mutex_unlock(&sfctemp->lock); - return ret; + return 0; } static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type, @@ -263,7 +244,6 @@ static int sfctemp_probe(struct platform_device *pdev) return -ENOMEM; dev_set_drvdata(dev, sfctemp); - mutex_init(&sfctemp->lock); sfctemp->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(sfctemp->regs)) diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 6c9b776237c2..5abe1227e109 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -55,7 +55,6 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table); /** * struct sht4x_data - All the data required to operate an SHT4X chip * @client: the i2c client associated with the SHT4X - * @lock: a mutex that is used to prevent parallel access to the i2c client * @heating_complete: the time that the last heating finished * @data_pending: true if and only if there are measurements to retrieve after heating * @heater_power: the power at which the heater will be started @@ -68,7 +67,6 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table); */ struct sht4x_data { struct i2c_client *client; - struct mutex lock; /* atomic read data updates */ unsigned long heating_complete; /* in jiffies */ bool data_pending; u32 heater_power; /* in milli-watts */ @@ -87,7 +85,7 @@ struct sht4x_data { */ static int sht4x_read_values(struct sht4x_data *data) { - int ret = 0; + int ret; u16 t_ticks, rh_ticks; unsigned long next_update; struct i2c_client *client = data->client; @@ -96,8 +94,6 @@ static int sht4x_read_values(struct sht4x_data *data) u8 raw_data[SHT4X_RESPONSE_LENGTH]; unsigned long curr_jiffies; - mutex_lock(&data->lock); - curr_jiffies = jiffies; if (time_before(curr_jiffies, data->heating_complete)) msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies)); @@ -110,11 +106,11 @@ static int sht4x_read_values(struct sht4x_data *data) msecs_to_jiffies(data->update_interval); if (data->valid && time_before_eq(jiffies, next_update)) - goto unlock; + return 0; ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); if (ret < 0) - goto unlock; + return ret; usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA); } @@ -123,7 +119,7 @@ static int sht4x_read_values(struct sht4x_data *data) if (ret != SHT4X_RESPONSE_LENGTH) { if (ret >= 0) ret = -ENODATA; - goto unlock; + return ret; } t_ticks = raw_data[0] << 8 | raw_data[1]; @@ -132,26 +128,20 @@ static int sht4x_read_values(struct sht4x_data *data) crc = crc8(sht4x_crc8_table, &raw_data[0], SHT4X_WORD_LEN, CRC8_INIT_VALUE); if (crc != raw_data[2]) { dev_err(&client->dev, "data integrity check failed\n"); - ret = -EIO; - goto unlock; + return -EIO; } crc = crc8(sht4x_crc8_table, &raw_data[3], SHT4X_WORD_LEN, CRC8_INIT_VALUE); if (crc != raw_data[5]) { dev_err(&client->dev, "data integrity check failed\n"); - ret = -EIO; - goto unlock; + return -EIO; } data->temperature = ((21875 * (int32_t)t_ticks) >> 13) - 45000; data->humidity = ((15625 * (int32_t)rh_ticks) >> 13) - 6000; data->last_updated = jiffies; data->valid = true; - ret = 0; - -unlock: - mutex_unlock(&data->lock); - return ret; + return 0; } static ssize_t sht4x_interval_write(struct sht4x_data *data, long val) @@ -287,22 +277,16 @@ static ssize_t heater_enable_store(struct device *dev, heating_time_bound = 1100; } - mutex_lock(&data->lock); - - if (time_before(jiffies, data->heating_complete)) { - ret = -EBUSY; - goto unlock; - } + if (time_before(jiffies, data->heating_complete)) + return -EBUSY; ret = i2c_master_send(data->client, &cmd, SHT4X_CMD_LEN); if (ret < 0) - goto unlock; + return ret; data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound); data->data_pending = true; -unlock: - mutex_unlock(&data->lock); - return ret; + return 0; } static ssize_t heater_power_show(struct device *dev, @@ -422,8 +406,6 @@ static int sht4x_probe(struct i2c_client *client) data->heater_time = 1000; data->heating_complete = jiffies; - mutex_init(&data->lock); - crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL); ret = i2c_master_send(client, cmd, SHT4X_CMD_LEN); diff --git a/drivers/hwmon/sy7636a-hwmon.c b/drivers/hwmon/sy7636a-hwmon.c index a12fc0ce70e7..d51daaf63d63 100644 --- a/drivers/hwmon/sy7636a-hwmon.c +++ b/drivers/hwmon/sy7636a-hwmon.c @@ -66,18 +66,13 @@ static const struct hwmon_chip_info sy7636a_chip_info = { static int sy7636a_sensor_probe(struct platform_device *pdev) { struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL); - struct regulator *regulator; struct device *hwmon_dev; int err; if (!regmap) return -EPROBE_DEFER; - regulator = devm_regulator_get(&pdev->dev, "vcom"); - if (IS_ERR(regulator)) - return PTR_ERR(regulator); - - err = regulator_enable(regulator); + err = devm_regulator_get_enable(&pdev->dev, "vcom"); if (err) return err; diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 376e0eac8cc1..5b10c395a84d 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -10,9 +10,7 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/device.h> #include <linux/jiffies.h> #include <linux/regmap.h> diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c index f271a03e05ae..221bba8a215d 100644 --- a/drivers/hwmon/tmp103.c +++ b/drivers/hwmon/tmp103.c @@ -14,11 +14,8 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/hwmon.h> -#include <linux/hwmon-sysfs.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/device.h> -#include <linux/jiffies.h> #include <linux/regmap.h> #define TMP103_TEMP_REG 0x00 diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index a971ff628435..60a237cbedbc 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -10,7 +10,6 @@ #include <linux/hwmon.h> #include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/i2c.h> #include <linux/i3c/device.h> #include <linux/init.h> diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index 02c5a3bb1071..fbaa34973694 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -24,7 +24,6 @@ #include <linux/hwmon.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -107,7 +106,6 @@ MODULE_DEVICE_TABLE(i2c, tmp401_id); struct tmp401_data { struct i2c_client *client; struct regmap *regmap; - struct mutex update_lock; enum chips kind; bool extended_range; @@ -357,7 +355,6 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, unsigned int regval; int reg, ret, temp; - mutex_lock(&data->update_lock); switch (attr) { case hwmon_temp_min: case hwmon_temp_max: @@ -386,7 +383,6 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, ret = -EOPNOTSUPP; break; } - mutex_unlock(&data->update_lock); return ret; } @@ -436,7 +432,6 @@ static int tmp401_chip_write(struct device *dev, u32 attr, int channel, long val struct regmap *regmap = data->regmap; int err; - mutex_lock(&data->update_lock); switch (attr) { case hwmon_chip_update_interval: err = tmp401_set_convrate(regmap, val); @@ -456,8 +451,6 @@ static int tmp401_chip_write(struct device *dev, u32 attr, int channel, long val err = -EOPNOTSUPP; break; } - mutex_unlock(&data->update_lock); - return err; } @@ -685,7 +678,6 @@ static int tmp401_probe(struct i2c_client *client) return -ENOMEM; data->client = client; - mutex_init(&data->update_lock); data->kind = (uintptr_t)i2c_get_match_data(client); data->regmap = devm_regmap_init(dev, NULL, data, &tmp401_regmap_config); diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 9537727aad9a..2ea9d3e9553d 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -19,7 +19,6 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/err.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/sysfs.h> @@ -99,7 +98,6 @@ struct tmp421_channel { struct tmp421_data { struct i2c_client *client; - struct mutex update_lock; u32 temp_config[MAX_CHANNELS + 1]; struct hwmon_channel_info temp_info; const struct hwmon_channel_info *info[2]; @@ -130,38 +128,28 @@ static int tmp421_update_device(struct tmp421_data *data) int ret = 0; int i; - mutex_lock(&data->update_lock); - if (time_after(jiffies, data->last_updated + (HZ / 2)) || !data->valid) { + data->valid = false; ret = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1); if (ret < 0) - goto exit; + return ret; data->config = ret; for (i = 0; i < data->channels; i++) { ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_MSB[i]); if (ret < 0) - goto exit; + return ret; data->channel[i].temp = ret << 8; ret = i2c_smbus_read_byte_data(client, TMP421_TEMP_LSB[i]); if (ret < 0) - goto exit; + return ret; data->channel[i].temp |= ret; } data->last_updated = jiffies; data->valid = true; } - -exit: - mutex_unlock(&data->update_lock); - - if (ret < 0) { - data->valid = false; - return ret; - } - return 0; } @@ -262,7 +250,6 @@ static umode_t tmp421_is_visible(const void *data, enum hwmon_sensor_types type, switch (attr) { case hwmon_temp_fault: case hwmon_temp_input: - return 0444; case hwmon_temp_label: return 0444; case hwmon_temp_enable: @@ -381,7 +368,11 @@ static int tmp421_probe_child_from_dt(struct i2c_client *client, return -EINVAL; } - of_property_read_string(child, "label", &data->channel[i].label); + err = of_property_read_string(child, "label", &data->channel[i].label); + if (err == -ENODATA || err == -EILSEQ) { + dev_err(dev, "invalid label property in %pOFn\n", child); + return err; + } if (data->channel[i].label) data->temp_config[i] |= HWMON_T_LABEL; @@ -442,7 +433,6 @@ static int tmp421_probe(struct i2c_client *client) if (!data) return -ENOMEM; - mutex_init(&data->update_lock); data->channels = (unsigned long)i2c_get_match_data(client); data->client = client; diff --git a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c index 0f629c6d7695..98f2576d94c6 100644 --- a/drivers/hwmon/tmp464.c +++ b/drivers/hwmon/tmp464.c @@ -13,7 +13,6 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -92,7 +91,6 @@ struct tmp464_channel { struct tmp464_data { struct regmap *regmap; - struct mutex update_lock; int channels; s16 config_orig; u16 open_reg; @@ -172,19 +170,16 @@ static int tmp464_temp_read(struct device *dev, u32 attr, int channel, long *val * complete. That means we have to cache the value internally * for one measurement cycle and report the cached value. */ - mutex_lock(&data->update_lock); if (!data->valid || time_after(jiffies, data->last_updated + msecs_to_jiffies(data->update_interval))) { err = regmap_read(regmap, TMP464_REMOTE_OPEN_REG, ®val); if (err < 0) - goto unlock; + break; data->open_reg = regval; data->last_updated = jiffies; data->valid = true; } *val = !!(data->open_reg & BIT(channel + 7)); -unlock: - mutex_unlock(&data->update_lock); break; case hwmon_temp_max_hyst: regs[0] = TMP464_THERM_LIMIT[channel]; @@ -345,8 +340,6 @@ static int tmp464_write(struct device *dev, enum hwmon_sensor_types type, struct tmp464_data *data = dev_get_drvdata(dev); int err; - mutex_lock(&data->update_lock); - switch (type) { case hwmon_chip: err = tmp464_chip_write(data, attr, channel, val); @@ -359,8 +352,6 @@ static int tmp464_write(struct device *dev, enum hwmon_sensor_types type, break; } - mutex_unlock(&data->update_lock); - return err; } @@ -658,8 +649,6 @@ static int tmp464_probe(struct i2c_client *client) if (!data) return -ENOMEM; - mutex_init(&data->update_lock); - data->channels = (int)(unsigned long)i2c_get_match_data(client); data->regmap = devm_regmap_init_i2c(client, &tmp464_regmap_config); diff --git a/drivers/hwmon/tsc1641.c b/drivers/hwmon/tsc1641.c new file mode 100644 index 000000000000..2b5d34bab146 --- /dev/null +++ b/drivers/hwmon/tsc1641.c @@ -0,0 +1,748 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for ST Microelectronics TSC1641 I2C power monitor + * + * 60 V, 16-bit high-precision power monitor with I2C and MIPI I3C interface + * Datasheet: https://www.st.com/resource/en/datasheet/tsc1641.pdf + * + * Copyright (C) 2025 Igor Reznichenko <igor@reznichenko.net> + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/sysfs.h> +#include <linux/util_macros.h> + +/* I2C registers */ +#define TSC1641_CONFIG 0x00 +#define TSC1641_SHUNT_VOLTAGE 0x01 +#define TSC1641_LOAD_VOLTAGE 0x02 +#define TSC1641_POWER 0x03 +#define TSC1641_CURRENT 0x04 +#define TSC1641_TEMP 0x05 +#define TSC1641_MASK 0x06 +#define TSC1641_FLAG 0x07 +#define TSC1641_RSHUNT 0x08 /* Shunt resistance */ +#define TSC1641_SOL 0x09 +#define TSC1641_SUL 0x0A +#define TSC1641_LOL 0x0B +#define TSC1641_LUL 0x0C +#define TSC1641_POL 0x0D +#define TSC1641_TOL 0x0E +#define TSC1641_MANUF_ID 0xFE /* 0x0006 */ +#define TSC1641_DIE_ID 0xFF /* 0x1000 */ +#define TSC1641_MAX_REG 0xFF + +#define TSC1641_RSHUNT_DEFAULT 1000 /* 1mOhm */ +#define TSC1641_CONFIG_DEFAULT 0x003F /* Default mode and temperature sensor */ +#define TSC1641_MASK_DEFAULT 0xFC00 /* Unmask all alerts */ + +/* Bit mask for conversion time in the configuration register */ +#define TSC1641_CONV_TIME_MASK GENMASK(7, 4) + +#define TSC1641_CONV_TIME_DEFAULT 1024 +#define TSC1641_MIN_UPDATE_INTERVAL 1024 + +/* LSB value of different registers */ +#define TSC1641_VLOAD_LSB_MVOLT 2 +#define TSC1641_POWER_LSB_UWATT 25000 +#define TSC1641_VSHUNT_LSB_NVOLT 2500 /* Use nanovolts to make it integer */ +#define TSC1641_RSHUNT_LSB_UOHM 10 +#define TSC1641_TEMP_LSB_MDEGC 500 + +/* Limits based on datasheet */ +#define TSC1641_RSHUNT_MIN_UOHM 100 +#define TSC1641_RSHUNT_MAX_UOHM 655350 +#define TSC1641_CURR_ABS_MAX_MAMP 819200 /* Max current at 100uOhm*/ + +#define TSC1641_ALERT_POL_MASK BIT(1) +#define TSC1641_ALERT_LATCH_EN_MASK BIT(0) + +/* Flags indicating alerts in TSC1641_FLAG register*/ +#define TSC1641_SAT_FLAG BIT(13) +#define TSC1641_SHUNT_OV_FLAG BIT(6) +#define TSC1641_SHUNT_UV_FLAG BIT(5) +#define TSC1641_LOAD_OV_FLAG BIT(4) +#define TSC1641_LOAD_UV_FLAG BIT(3) +#define TSC1641_POWER_OVER_FLAG BIT(2) +#define TSC1641_TEMP_OVER_FLAG BIT(1) + +static bool tsc1641_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TSC1641_CONFIG: + case TSC1641_MASK: + case TSC1641_RSHUNT: + case TSC1641_SOL: + case TSC1641_SUL: + case TSC1641_LOL: + case TSC1641_LUL: + case TSC1641_POL: + case TSC1641_TOL: + return true; + default: + return false; + } +} + +static bool tsc1641_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TSC1641_SHUNT_VOLTAGE: + case TSC1641_LOAD_VOLTAGE: + case TSC1641_POWER: + case TSC1641_CURRENT: + case TSC1641_TEMP: + case TSC1641_FLAG: + case TSC1641_MANUF_ID: + case TSC1641_DIE_ID: + return true; + default: + return false; + } +} + +static const struct regmap_config tsc1641_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .use_single_write = true, + .use_single_read = true, + .max_register = TSC1641_MAX_REG, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = tsc1641_volatile_reg, + .writeable_reg = tsc1641_writeable_reg, +}; + +struct tsc1641_data { + long rshunt_uohm; + long current_lsb_ua; + struct regmap *regmap; +}; + +/* + * Upper limit due to chip 16-bit shunt register, lower limit to + * prevent current and power registers overflow + */ +static inline int tsc1641_validate_shunt(u32 val) +{ + if (val < TSC1641_RSHUNT_MIN_UOHM || val > TSC1641_RSHUNT_MAX_UOHM) + return -EINVAL; + return 0; +} + +static int tsc1641_set_shunt(struct tsc1641_data *data, u32 val) +{ + struct regmap *regmap = data->regmap; + long rshunt_reg; + + /* RSHUNT register LSB is 10uOhm so need to divide further */ + rshunt_reg = DIV_ROUND_CLOSEST(val, TSC1641_RSHUNT_LSB_UOHM); + /* + * Clamp value to the nearest multiple of TSC1641_RSHUNT_LSB_UOHM + * in case shunt value provided was not a multiple + */ + data->rshunt_uohm = rshunt_reg * TSC1641_RSHUNT_LSB_UOHM; + data->current_lsb_ua = DIV_ROUND_CLOSEST(TSC1641_VSHUNT_LSB_NVOLT * 1000, + data->rshunt_uohm); + + return regmap_write(regmap, TSC1641_RSHUNT, rshunt_reg); +} + +/* + * Conversion times in uS, value in CONFIG[CT3:CT0] corresponds to index in this array + * See "Table 14. CT3 to CT0: conversion time" in: + * https://www.st.com/resource/en/datasheet/tsc1641.pdf + */ +static const int tsc1641_conv_times[] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 }; + +static int tsc1641_reg_to_upd_interval(u16 config) +{ + int idx = FIELD_GET(TSC1641_CONV_TIME_MASK, config); + + idx = clamp_val(idx, 0, ARRAY_SIZE(tsc1641_conv_times) - 1); + int conv_time = tsc1641_conv_times[idx]; + + /* Don't support sub-millisecond update interval as it's not supported in hwmon */ + conv_time = max(conv_time, TSC1641_MIN_UPDATE_INTERVAL); + /* Return nearest value in milliseconds */ + return DIV_ROUND_CLOSEST(conv_time, 1000); +} + +static u16 tsc1641_upd_interval_to_reg(long interval) +{ + /* Supported interval is 1ms - 33ms */ + interval = clamp_val(interval, 1, 33); + + int conv = interval * 1000; + int conv_bits = find_closest(conv, tsc1641_conv_times, + ARRAY_SIZE(tsc1641_conv_times)); + + return FIELD_PREP(TSC1641_CONV_TIME_MASK, conv_bits); +} + +static int tsc1641_chip_write(struct device *dev, u32 attr, long val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + + switch (attr) { + case hwmon_chip_update_interval: + return regmap_update_bits(data->regmap, TSC1641_CONFIG, + TSC1641_CONV_TIME_MASK, + tsc1641_upd_interval_to_reg(val)); + default: + return -EOPNOTSUPP; + } +} + +static int tsc1641_chip_read(struct device *dev, u32 attr, long *val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + u32 regval; + int ret; + + switch (attr) { + case hwmon_chip_update_interval: + ret = regmap_read(data->regmap, TSC1641_CONFIG, ®val); + if (ret) + return ret; + + *val = tsc1641_reg_to_upd_interval(regval); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int tsc1641_flag_read(struct regmap *regmap, u32 flag, long *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read_bypassed(regmap, TSC1641_FLAG, ®val); + if (ret) + return ret; + + *val = !!(regval & flag); + return 0; +} + +static int tsc1641_in_read(struct device *dev, u32 attr, long *val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + unsigned int regval; + int ret, reg; + long sat_flag; + + switch (attr) { + case hwmon_in_input: + reg = TSC1641_LOAD_VOLTAGE; + break; + case hwmon_in_min: + reg = TSC1641_LUL; + break; + case hwmon_in_max: + reg = TSC1641_LOL; + break; + case hwmon_in_min_alarm: + return tsc1641_flag_read(regmap, TSC1641_LOAD_UV_FLAG, val); + case hwmon_in_max_alarm: + return tsc1641_flag_read(regmap, TSC1641_LOAD_OV_FLAG, val); + default: + return -EOPNOTSUPP; + } + + ret = regmap_read(regmap, reg, ®val); + if (ret) + return ret; + + /* Check if load voltage is out of range */ + if (reg == TSC1641_LOAD_VOLTAGE) { + /* Register is 15-bit max */ + if (regval & 0x8000) + return -ENODATA; + + ret = tsc1641_flag_read(regmap, TSC1641_SAT_FLAG, &sat_flag); + if (ret) + return ret; + /* Out of range conditions per datasheet */ + if (sat_flag && (regval == 0x7FFF || !regval)) + return -ENODATA; + } + + *val = regval * TSC1641_VLOAD_LSB_MVOLT; + return 0; +} + +/* Chip supports bidirectional (positive or negative) current */ +static int tsc1641_curr_read(struct device *dev, u32 attr, long *val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + int regval; + int ret, reg; + long sat_flag; + + /* Current limits are the shunt under/over voltage limits */ + switch (attr) { + case hwmon_curr_input: + reg = TSC1641_CURRENT; + break; + case hwmon_curr_min: + reg = TSC1641_SUL; + break; + case hwmon_curr_max: + reg = TSC1641_SOL; + break; + case hwmon_curr_min_alarm: + return tsc1641_flag_read(regmap, TSC1641_SHUNT_UV_FLAG, val); + case hwmon_curr_max_alarm: + return tsc1641_flag_read(regmap, TSC1641_SHUNT_OV_FLAG, val); + default: + return -EOPNOTSUPP; + } + /* + * Current uses shunt voltage, so check if it's out of range. + * We report current register in sysfs to stay consistent with internal + * power calculations which use current register values + */ + if (reg == TSC1641_CURRENT) { + ret = regmap_read(regmap, TSC1641_SHUNT_VOLTAGE, ®val); + if (ret) + return ret; + + ret = tsc1641_flag_read(regmap, TSC1641_SAT_FLAG, &sat_flag); + if (ret) + return ret; + + if (sat_flag && (regval == 0x7FFF || regval == 0x8000)) + return -ENODATA; + } + + ret = regmap_read(regmap, reg, ®val); + if (ret) + return ret; + + /* Current in milliamps, signed */ + *val = DIV_ROUND_CLOSEST((s16)regval * data->current_lsb_ua, 1000); + return 0; +} + +static int tsc1641_power_read(struct device *dev, u32 attr, long *val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + unsigned int regval; + int ret, reg; + + switch (attr) { + case hwmon_power_input: + reg = TSC1641_POWER; + break; + case hwmon_power_max: + reg = TSC1641_POL; + break; + case hwmon_power_max_alarm: + return tsc1641_flag_read(regmap, TSC1641_POWER_OVER_FLAG, val); + default: + return -EOPNOTSUPP; + } + + ret = regmap_read(regmap, reg, ®val); + if (ret) + return ret; + + *val = regval * TSC1641_POWER_LSB_UWATT; + return 0; +} + +static int tsc1641_temp_read(struct device *dev, u32 attr, long *val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + unsigned int regval; + int ret, reg; + + switch (attr) { + case hwmon_temp_input: + reg = TSC1641_TEMP; + break; + case hwmon_temp_max: + reg = TSC1641_TOL; + break; + case hwmon_temp_max_alarm: + return tsc1641_flag_read(regmap, TSC1641_TEMP_OVER_FLAG, val); + default: + return -EOPNOTSUPP; + } + + ret = regmap_read(regmap, reg, ®val); + if (ret) + return ret; + + /* 0x8000 means that TEMP measurement not enabled */ + if (reg == TSC1641_TEMP && regval == 0x8000) + return -ENODATA; + + /* Both temperature and limit registers are signed */ + *val = (s16)regval * TSC1641_TEMP_LSB_MDEGC; + return 0; +} + +static int tsc1641_in_write(struct device *dev, u32 attr, long val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + unsigned int regval; + int reg; + + switch (attr) { + case hwmon_in_min: + reg = TSC1641_LUL; + break; + case hwmon_in_max: + reg = TSC1641_LOL; + break; + default: + return -EOPNOTSUPP; + } + /* Clamp to full register range */ + val = clamp_val(val, 0, TSC1641_VLOAD_LSB_MVOLT * USHRT_MAX); + regval = DIV_ROUND_CLOSEST(val, TSC1641_VLOAD_LSB_MVOLT); + + return regmap_write(regmap, reg, regval); +} + +static int tsc1641_curr_write(struct device *dev, u32 attr, long val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + int reg, regval; + + switch (attr) { + case hwmon_curr_min: + reg = TSC1641_SUL; + break; + case hwmon_curr_max: + reg = TSC1641_SOL; + break; + default: + return -EOPNOTSUPP; + } + + /* Clamp to prevent over/underflow below */ + val = clamp_val(val, -TSC1641_CURR_ABS_MAX_MAMP, TSC1641_CURR_ABS_MAX_MAMP); + /* Convert val in milliamps to register */ + regval = DIV_ROUND_CLOSEST(val * 1000, data->current_lsb_ua); + /* + * Prevent signed 16-bit overflow. + * Integer arithmetic and shunt scaling can quantize values near 0x7FFF/0x8000, + * so reading and writing back may not preserve the exact original register value. + */ + regval = clamp_val(regval, SHRT_MIN, SHRT_MAX); + /* SUL and SOL registers are signed */ + return regmap_write(regmap, reg, regval & 0xFFFF); +} + +static int tsc1641_power_write(struct device *dev, u32 attr, long val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + unsigned int regval; + + switch (attr) { + case hwmon_power_max: + /* Clamp to full register range */ + val = clamp_val(val, 0, TSC1641_POWER_LSB_UWATT * USHRT_MAX); + regval = DIV_ROUND_CLOSEST(val, TSC1641_POWER_LSB_UWATT); + return regmap_write(regmap, TSC1641_POL, regval); + default: + return -EOPNOTSUPP; + } +} + +static int tsc1641_temp_write(struct device *dev, u32 attr, long val) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + int regval; + + switch (attr) { + case hwmon_temp_max: + /* Clamp to full register range */ + val = clamp_val(val, TSC1641_TEMP_LSB_MDEGC * SHRT_MIN, + TSC1641_TEMP_LSB_MDEGC * SHRT_MAX); + regval = DIV_ROUND_CLOSEST(val, TSC1641_TEMP_LSB_MDEGC); + /* TOL register is signed */ + return regmap_write(regmap, TSC1641_TOL, regval & 0xFFFF); + default: + return -EOPNOTSUPP; + } +} + +static umode_t tsc1641_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_chip: + switch (attr) { + case hwmon_chip_update_interval: + return 0644; + default: + break; + } + break; + case hwmon_in: + switch (attr) { + case hwmon_in_input: + return 0444; + case hwmon_in_min: + case hwmon_in_max: + return 0644; + case hwmon_in_min_alarm: + case hwmon_in_max_alarm: + return 0444; + default: + break; + } + break; + case hwmon_curr: + switch (attr) { + case hwmon_curr_input: + return 0444; + case hwmon_curr_min: + case hwmon_curr_max: + return 0644; + case hwmon_curr_min_alarm: + case hwmon_curr_max_alarm: + return 0444; + default: + break; + } + break; + case hwmon_power: + switch (attr) { + case hwmon_power_input: + return 0444; + case hwmon_power_max: + return 0644; + case hwmon_power_max_alarm: + return 0444; + default: + break; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + return 0444; + case hwmon_temp_max: + return 0644; + case hwmon_temp_max_alarm: + return 0444; + default: + break; + } + break; + default: + break; + } + return 0; +} + +static int tsc1641_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_chip: + return tsc1641_chip_read(dev, attr, val); + case hwmon_in: + return tsc1641_in_read(dev, attr, val); + case hwmon_curr: + return tsc1641_curr_read(dev, attr, val); + case hwmon_power: + return tsc1641_power_read(dev, attr, val); + case hwmon_temp: + return tsc1641_temp_read(dev, attr, val); + default: + return -EOPNOTSUPP; + } +} + +static int tsc1641_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_chip: + return tsc1641_chip_write(dev, attr, val); + case hwmon_in: + return tsc1641_in_write(dev, attr, val); + case hwmon_curr: + return tsc1641_curr_write(dev, attr, val); + case hwmon_power: + return tsc1641_power_write(dev, attr, val); + case hwmon_temp: + return tsc1641_temp_write(dev, attr, val); + default: + return -EOPNOTSUPP; + } +} + +static const struct hwmon_channel_info * const tsc1641_info[] = { + HWMON_CHANNEL_INFO(chip, + HWMON_C_UPDATE_INTERVAL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MAX_ALARM | + HWMON_I_MIN | HWMON_I_MIN_ALARM), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_MAX_ALARM | + HWMON_C_MIN | HWMON_C_MIN_ALARM), + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT | HWMON_P_MAX | HWMON_P_MAX_ALARM), + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_ALARM), + NULL +}; + +static ssize_t shunt_resistor_show(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%li\n", data->rshunt_uohm); +} + +static ssize_t shunt_resistor_store(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) +{ + struct tsc1641_data *data = dev_get_drvdata(dev); + unsigned int val; + int ret; + + ret = kstrtouint(buf, 10, &val); + if (ret < 0) + return ret; + + ret = tsc1641_validate_shunt(val); + if (ret < 0) + return ret; + + ret = tsc1641_set_shunt(data, val); + if (ret < 0) + return ret; + return count; +} + +static const struct hwmon_ops tsc1641_hwmon_ops = { + .is_visible = tsc1641_is_visible, + .read = tsc1641_read, + .write = tsc1641_write, +}; + +static const struct hwmon_chip_info tsc1641_chip_info = { + .ops = &tsc1641_hwmon_ops, + .info = tsc1641_info, +}; + +static DEVICE_ATTR_RW(shunt_resistor); + +/* Shunt resistor value is exposed via sysfs attribute */ +static struct attribute *tsc1641_attrs[] = { + &dev_attr_shunt_resistor.attr, + NULL, +}; +ATTRIBUTE_GROUPS(tsc1641); + +static int tsc1641_init(struct device *dev, struct tsc1641_data *data) +{ + struct regmap *regmap = data->regmap; + bool active_high; + u32 shunt; + int ret; + + if (device_property_read_u32(dev, "shunt-resistor-micro-ohms", &shunt) < 0) + shunt = TSC1641_RSHUNT_DEFAULT; + + if (tsc1641_validate_shunt(shunt) < 0) { + dev_err(dev, "invalid shunt resistor value %u\n", shunt); + return -EINVAL; + } + + ret = tsc1641_set_shunt(data, shunt); + if (ret < 0) + return ret; + + ret = regmap_write(regmap, TSC1641_CONFIG, TSC1641_CONFIG_DEFAULT); + if (ret < 0) + return ret; + + active_high = device_property_read_bool(dev, "st,alert-polarity-active-high"); + + return regmap_write(regmap, TSC1641_MASK, TSC1641_MASK_DEFAULT | + FIELD_PREP(TSC1641_ALERT_POL_MASK, active_high)); +} + +static int tsc1641_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct tsc1641_data *data; + struct device *hwmon_dev; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->regmap = devm_regmap_init_i2c(client, &tsc1641_regmap_config); + if (IS_ERR(data->regmap)) + return dev_err_probe(dev, PTR_ERR(data->regmap), + "failed to allocate register map\n"); + + ret = tsc1641_init(dev, data); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to configure device\n"); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + data, &tsc1641_chip_info, tsc1641_groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n", + client->name, data->rshunt_uohm); + + return 0; +} + +static const struct i2c_device_id tsc1641_id[] = { + { "tsc1641", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tsc1641_id); + +static const struct of_device_id __maybe_unused tsc1641_of_match[] = { + { .compatible = "st,tsc1641" }, + { }, +}; +MODULE_DEVICE_TABLE(of, tsc1641_of_match); + +static struct i2c_driver tsc1641_driver = { + .driver = { + .name = "tsc1641", + .of_match_table = of_match_ptr(tsc1641_of_match), + }, + .probe = tsc1641_probe, + .id_table = tsc1641_id, +}; + +module_i2c_driver(tsc1641_driver); + +MODULE_AUTHOR("Igor Reznichenko <igor@reznichenko.net>"); +MODULE_DESCRIPTION("tsc1641 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 386edea6b69e..1e52cabd6e24 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -142,9 +142,15 @@ struct vt1211_data { * in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the * driver according to the VT1211 BIOS porting guide */ -#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \ - (((reg) - 3) * 15882 + 479) / 958 : \ - (((reg) - 3) * 10000 + 479) / 958) +static int in_from_reg(int ix, int reg) +{ + if (reg < 3) + return 0; + if (ix == 5) + return ((reg - 3) * 15882 + 479) / 958; + return ((reg - 3) * 10000 + 479) / 958; +} + #define IN_TO_REG(ix, val) (clamp_val((ix) == 5 ? \ ((val) * 958 + 7941) / 15882 + 3 : \ ((val) * 958 + 5000) / 10000 + 3, 0, 255)) @@ -156,10 +162,15 @@ struct vt1211_data { * temp3-7 are thermistor based so the driver returns the voltage measured at * the pin (range 0V - 2.2V). */ -#define TEMP_FROM_REG(ix, reg) ((ix) == 0 ? (reg) * 1000 : \ - (ix) == 1 ? (reg) < 51 ? 0 : \ - ((reg) - 51) * 1000 : \ - ((253 - (reg)) * 2200 + 105) / 210) +static int temp_from_reg(int ix, int reg) +{ + if (ix == 0) + return reg * 1000; + if (ix == 1) + return reg < 51 ? 0 : (reg - 51) * 1000; + return ((253 - reg) * 2200 + 105) / 210; +} + #define TEMP_TO_REG(ix, val) clamp_val( \ ((ix) == 0 ? ((val) + 500) / 1000 : \ (ix) == 1 ? ((val) + 500) / 1000 + 51 : \ @@ -167,8 +178,14 @@ struct vt1211_data { #define DIV_FROM_REG(reg) (1 << (reg)) -#define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \ - 1310720 / (reg) / DIV_FROM_REG(div)) +static int rpm_from_reg(int reg, int div) +{ + if (reg == 0 || reg == 255) + return 0; + + return 1310720 / reg / DIV_FROM_REG(div); +} + #define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \ clamp_val((1310720 / (val) / \ DIV_FROM_REG(div)), 1, 254)) @@ -343,13 +360,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, switch (fn) { case SHOW_IN_INPUT: - res = IN_FROM_REG(ix, data->in[ix]); + res = in_from_reg(ix, data->in[ix]); break; case SHOW_SET_IN_MIN: - res = IN_FROM_REG(ix, data->in_min[ix]); + res = in_from_reg(ix, data->in_min[ix]); break; case SHOW_SET_IN_MAX: - res = IN_FROM_REG(ix, data->in_max[ix]); + res = in_from_reg(ix, data->in_max[ix]); break; case SHOW_IN_ALARM: res = (data->alarms >> bitalarmin[ix]) & 1; @@ -417,13 +434,13 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, switch (fn) { case SHOW_TEMP_INPUT: - res = TEMP_FROM_REG(ix, data->temp[ix]); + res = temp_from_reg(ix, data->temp[ix]); break; case SHOW_SET_TEMP_MAX: - res = TEMP_FROM_REG(ix, data->temp_max[ix]); + res = temp_from_reg(ix, data->temp_max[ix]); break; case SHOW_SET_TEMP_MAX_HYST: - res = TEMP_FROM_REG(ix, data->temp_hyst[ix]); + res = temp_from_reg(ix, data->temp_hyst[ix]); break; case SHOW_TEMP_ALARM: res = (data->alarms >> bitalarmtemp[ix]) & 1; @@ -493,10 +510,10 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, switch (fn) { case SHOW_FAN_INPUT: - res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]); + res = rpm_from_reg(data->fan[ix], data->fan_div[ix]); break; case SHOW_SET_FAN_MIN: - res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]); + res = rpm_from_reg(data->fan_min[ix], data->fan_div[ix]); break; case SHOW_SET_FAN_DIV: res = DIV_FROM_REG(data->fan_div[ix]); @@ -751,7 +768,7 @@ static ssize_t show_pwm_auto_point_temp(struct device *dev, int ix = sensor_attr_2->index; int ap = sensor_attr_2->nr; - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7, + return sprintf(buf, "%d\n", temp_from_reg(data->pwm_ctl[ix] & 7, data->pwm_auto_temp[ap])); } diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 3bf27c21845b..5757a0979f3f 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -138,7 +138,12 @@ static inline u8 FAN_TO_REG(long rpm, int div) return clamp_val(1310720 / (rpm * div), 1, 255); } -#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div))) +static int fan_from_reg(int val, int div) +{ + if (val == 0) + return 0; + return 1310720 / (val * div); +} struct vt8231_data { unsigned short addr; @@ -561,7 +566,7 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct vt8231_data *data = vt8231_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], + return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr], DIV_FROM_REG(data->fan_div[nr]))); } @@ -571,7 +576,7 @@ static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct vt8231_data *data = vt8231_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + return sprintf(buf, "%d\n", fan_from_reg(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]))); } @@ -613,9 +618,8 @@ static ssize_t fan_div_store(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); unsigned long val; int nr = sensor_attr->index; - int old = vt8231_read_value(data, VT8231_REG_FANDIV); - long min = FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr])); + int old; + long min; int err; err = kstrtoul(buf, 10, &val); @@ -623,6 +627,8 @@ static ssize_t fan_div_store(struct device *dev, return err; mutex_lock(&data->update_lock); + old = vt8231_read_value(data, VT8231_REG_FANDIV); + min = fan_from_reg(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); switch (val) { case 1: data->fan_div[nr] = 0; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 076200ed2ec9..f664c2152a6d 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1850,10 +1850,12 @@ w83781d_isa_found(unsigned short address) } } -#define REALLY_SLOW_IO /* * We need the timeouts for at least some W83781D-like * chips. But only if we read 'undefined' registers. + * There used to be a "#define REALLY_SLOW_IO" to enforce that, but + * this has been without any effect since more than a decade, so it + * has been dropped. */ val = inb_p(address + 1); if (inb_p(address + 2) != val @@ -1862,7 +1864,6 @@ w83781d_isa_found(unsigned short address) pr_debug("Detection failed at step %d\n", 1); goto release; } -#undef REALLY_SLOW_IO /* * We should be able to change the 7 LSB of the address port. The diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 9b81bd406e05..1d9109ca1585 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -76,15 +76,25 @@ FAN_TO_REG(long rpm, int div) return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } -#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ - ((val) == 255 ? 0 : \ - 1350000 / ((val) * (div)))) +static int fan_from_reg(int val, int div) +{ + if (val == 0) + return -1; + if (val == 255) + return 0; + return 1350000 / (val * div); +} /* for temp */ #define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (val) + 0x100 * 1000 \ : (val)) / 1000, 0, 0xff)) -#define TEMP_FROM_REG(val) (((val) & 0x80 ? \ - (val) - 0x100 : (val)) * 1000) + +static int temp_from_reg(int val) +{ + if (val & 0x80) + return (val - 0x100) * 1000; + return val * 1000; +} /* * The analog voltage inputs have 8mV LSB. Since the sysfs output is @@ -280,7 +290,7 @@ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ int nr = to_sensor_dev_attr(attr)->index; \ struct w83l786ng_data *data = w83l786ng_update_device(dev); \ return sprintf(buf, "%d\n", \ - FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ + fan_from_reg(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } show_fan_reg(fan); @@ -347,7 +357,7 @@ store_fan_div(struct device *dev, struct device_attribute *attr, /* Save fan_min */ mutex_lock(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + min = fan_from_reg(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); data->fan_div[nr] = DIV_TO_REG(val); @@ -409,7 +419,7 @@ show_temp(struct device *dev, struct device_attribute *attr, char *buf) int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83l786ng_data *data = w83l786ng_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); + return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr][index])); } static ssize_t |
