summaryrefslogtreecommitdiff
path: root/drivers/hwmon
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig36
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/adm1026.c16
-rw-r--r--drivers/hwmon/adm1029.c3
-rw-r--r--drivers/hwmon/adm9240.c17
-rw-r--r--drivers/hwmon/adt7410.c11
-rw-r--r--drivers/hwmon/adt7411.c59
-rw-r--r--drivers/hwmon/adt7x10.c27
-rw-r--r--drivers/hwmon/aht10.c43
-rw-r--r--drivers/hwmon/aquacomputer_d5next.c37
-rw-r--r--drivers/hwmon/aspeed-g6-pwm-tach.c3
-rw-r--r--drivers/hwmon/asus-ec-sensors.c67
-rw-r--r--drivers/hwmon/asus_rog_ryujin.c48
-rw-r--r--drivers/hwmon/cgbc-hwmon.c3
-rw-r--r--drivers/hwmon/chipcap2.c7
-rw-r--r--drivers/hwmon/corsair-cpro.c8
-rw-r--r--drivers/hwmon/corsair-psu.c13
-rw-r--r--drivers/hwmon/dell-smm-hwmon.c9
-rw-r--r--drivers/hwmon/drivetemp.c5
-rw-r--r--drivers/hwmon/emc1403.c46
-rw-r--r--drivers/hwmon/emc2103.c4
-rw-r--r--drivers/hwmon/ftsteutates.c84
-rw-r--r--drivers/hwmon/gpd-fan.c120
-rw-r--r--drivers/hwmon/hs3001.c10
-rw-r--r--drivers/hwmon/i5500_temp.c3
-rw-r--r--drivers/hwmon/ina238.c26
-rw-r--r--drivers/hwmon/ina2xx.c28
-rw-r--r--drivers/hwmon/ina3221.c19
-rw-r--r--drivers/hwmon/jc42.c11
-rw-r--r--drivers/hwmon/k10temp.c12
-rw-r--r--drivers/hwmon/lm78.c5
-rw-r--r--drivers/hwmon/lm87.c16
-rw-r--r--drivers/hwmon/lm90.c25
-rw-r--r--drivers/hwmon/lm92.c11
-rw-r--r--drivers/hwmon/lm95234.c12
-rw-r--r--drivers/hwmon/lm95241.c16
-rw-r--r--drivers/hwmon/lm95245.c16
-rw-r--r--drivers/hwmon/lochnagar-hwmon.c18
-rw-r--r--drivers/hwmon/ltc2947-core.c92
-rw-r--r--drivers/hwmon/ltc4245.c8
-rw-r--r--drivers/hwmon/ltc4282.c68
-rw-r--r--drivers/hwmon/macsmc-hwmon.c851
-rw-r--r--drivers/hwmon/max127.c23
-rw-r--r--drivers/hwmon/max16065.c7
-rw-r--r--drivers/hwmon/max31790.c48
-rw-r--r--drivers/hwmon/max31827.c60
-rw-r--r--drivers/hwmon/max6620.c43
-rw-r--r--drivers/hwmon/max6639.c23
-rw-r--r--drivers/hwmon/max6697.c11
-rw-r--r--drivers/hwmon/mr75203.c1
-rw-r--r--drivers/hwmon/nct6775-platform.c1
-rw-r--r--drivers/hwmon/nct7363.c2
-rw-r--r--drivers/hwmon/nct7904.c63
-rw-r--r--drivers/hwmon/npcm750-pwm-fan.c11
-rw-r--r--drivers/hwmon/ntc_thermistor.c43
-rw-r--r--drivers/hwmon/peci/common.h3
-rw-r--r--drivers/hwmon/peci/cputemp.c90
-rw-r--r--drivers/hwmon/peci/dimmtemp.c36
-rw-r--r--drivers/hwmon/pmbus/Kconfig28
-rw-r--r--drivers/hwmon/pmbus/Makefile3
-rw-r--r--drivers/hwmon/pmbus/isl68137.c17
-rw-r--r--drivers/hwmon/pmbus/max17616.c73
-rw-r--r--drivers/hwmon/pmbus/max34440.c56
-rw-r--r--drivers/hwmon/pmbus/mp2925.c316
-rw-r--r--drivers/hwmon/pmbus/mp9945.c243
-rw-r--r--drivers/hwmon/powr1220.c17
-rw-r--r--drivers/hwmon/sbtsi_temp.c17
-rw-r--r--drivers/hwmon/scmi-hwmon.c9
-rw-r--r--drivers/hwmon/sfctemp.c36
-rw-r--r--drivers/hwmon/sht3x.c27
-rw-r--r--drivers/hwmon/sht4x.c40
-rw-r--r--drivers/hwmon/sy7636a-hwmon.c7
-rw-r--r--drivers/hwmon/tmp102.c2
-rw-r--r--drivers/hwmon/tmp103.c3
-rw-r--r--drivers/hwmon/tmp108.c1
-rw-r--r--drivers/hwmon/tmp401.c8
-rw-r--r--drivers/hwmon/tmp421.c28
-rw-r--r--drivers/hwmon/tmp464.c13
-rw-r--r--drivers/hwmon/tsc1641.c748
-rw-r--r--drivers/hwmon/vt1211.c53
-rw-r--r--drivers/hwmon/vt8231.c18
-rw-r--r--drivers/hwmon/w83781d.c5
-rw-r--r--drivers/hwmon/w83l786ng.c26
83 files changed, 3011 insertions, 1163 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), &regval);
- 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], &regval);
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, &regval);
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/cgbc-hwmon.c b/drivers/hwmon/cgbc-hwmon.c
index 772f44d56ccf..3aff4e092132 100644
--- a/drivers/hwmon/cgbc-hwmon.c
+++ b/drivers/hwmon/cgbc-hwmon.c
@@ -107,6 +107,9 @@ static int cgbc_hwmon_probe_sensors(struct device *dev, struct cgbc_hwmon_data *
nb_sensors = data[0];
hwmon->sensors = devm_kzalloc(dev, sizeof(*hwmon->sensors) * nb_sensors, GFP_KERNEL);
+ if (!hwmon->sensors)
+ return -ENOMEM;
+
sensor = hwmon->sensors;
for (i = 0; i < nb_sensors; i++) {
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 644dc3ca9df7..237f496c4862 100644
--- a/drivers/hwmon/gpd-fan.c
+++ b/drivers/hwmon/gpd-fan.c
@@ -12,9 +12,9 @@
* Copyright (c) 2024 Cryolitia PukNgae
*/
-#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/hwmon.h>
+#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -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,
@@ -276,31 +273,6 @@ static int gpd_generic_read_rpm(void)
return (u16)high << 8 | low;
}
-static void gpd_win4_init_ec(void)
-{
- u8 chip_id, chip_ver;
-
- gpd_ecram_read(0x2000, &chip_id);
-
- if (chip_id == 0x55) {
- gpd_ecram_read(0x1060, &chip_ver);
- gpd_ecram_write(0x1060, chip_ver | 0x80);
- }
-}
-
-static int gpd_win4_read_rpm(void)
-{
- int ret;
-
- ret = gpd_generic_read_rpm();
-
- if (ret == 0)
- // Re-init EC when speed is 0
- gpd_win4_init_ec();
-
- return ret;
-}
-
static int gpd_wm2_read_rpm(void)
{
for (u16 pwm_ctr_offset = GPD_PWM_CTR_OFFSET;
@@ -320,11 +292,10 @@ static int gpd_wm2_read_rpm(void)
static int gpd_read_rpm(void)
{
switch (gpd_driver_priv.drvdata->board) {
+ case win4_6800u:
case win_mini:
case duo:
return gpd_generic_read_rpm();
- case win4_6800u:
- return gpd_win4_read_rpm();
case win_max_2:
return gpd_wm2_read_rpm();
}
@@ -507,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 = {
@@ -607,6 +551,28 @@ static struct hwmon_chip_info gpd_fan_chip_info = {
.info = gpd_fan_hwmon_channel_info
};
+static void gpd_win4_init_ec(void)
+{
+ u8 chip_id, chip_ver;
+
+ gpd_ecram_read(0x2000, &chip_id);
+
+ if (chip_id == 0x55) {
+ gpd_ecram_read(0x1060, &chip_ver);
+ gpd_ecram_write(0x1060, chip_ver | 0x80);
+ }
+}
+
+static void gpd_init_ec(void)
+{
+ // The buggy firmware won't initialize EC properly on boot.
+ // Before its initialization, reading RPM will always return 0,
+ // and writing PWM will have no effect.
+ // Initialize it manually on driver load.
+ if (gpd_driver_priv.drvdata->board == win4_6800u)
+ gpd_win4_init_ec();
+}
+
static int gpd_fan_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -615,14 +581,14 @@ static int gpd_fan_probe(struct platform_device *pdev)
const struct device *hwdev;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (IS_ERR(res))
- return dev_err_probe(dev, PTR_ERR(res),
+ if (!res)
+ return dev_err_probe(dev, -EINVAL,
"Failed to get platform resource\n");
region = devm_request_region(dev, res->start,
resource_size(res), DRIVER_NAME);
- if (IS_ERR(region))
- return dev_err_probe(dev, PTR_ERR(region),
+ if (!region)
+ return dev_err_probe(dev, -EBUSY,
"Failed to request region\n");
hwdev = devm_hwmon_device_register_with_info(dev,
@@ -631,9 +597,11 @@ static int gpd_fan_probe(struct platform_device *pdev)
&gpd_fan_chip_info,
NULL);
if (IS_ERR(hwdev))
- return dev_err_probe(dev, PTR_ERR(region),
+ return dev_err_probe(dev, PTR_ERR(hwdev),
"Failed to register hwmon device\n");
+ gpd_init_ec();
+
return 0;
}
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, &regval);
if (ret)
- goto abort;
+ return ret;
if (regval & mask) {
ret = regmap_read(regmap, INA226_ALERT_LIMIT, &regval);
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, &regval);
@@ -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,
&regval);
- 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,
- &ltc2947_chip_info,
- ltc2947_groups);
+ &ltc2947_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,
- &ltc4282_chip_info,
- ltc4282_groups);
+ &ltc4282_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 52cf62e45a86..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,
};
@@ -336,10 +338,9 @@ static int isl68137_probe_from_dt(struct device *dev,
struct isl68137_data *data)
{
const struct device_node *np = dev->of_node;
- struct device_node *child;
int err;
- for_each_child_of_node(np, child) {
+ for_each_child_of_node_scoped(np, child) {
if (strcmp(child->name, "channel"))
continue;
@@ -400,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;
@@ -470,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 56834d26f8ef..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);
@@ -336,18 +337,18 @@ static struct pmbus_driver_info max34440_info[] = {
.format[PSC_CURRENT_IN] = direct,
.format[PSC_CURRENT_OUT] = direct,
.format[PSC_TEMPERATURE] = direct,
- .m[PSC_VOLTAGE_IN] = 1,
+ .m[PSC_VOLTAGE_IN] = 125,
.b[PSC_VOLTAGE_IN] = 0,
.R[PSC_VOLTAGE_IN] = 0,
- .m[PSC_VOLTAGE_OUT] = 1,
+ .m[PSC_VOLTAGE_OUT] = 125,
.b[PSC_VOLTAGE_OUT] = 0,
.R[PSC_VOLTAGE_OUT] = 0,
- .m[PSC_CURRENT_IN] = 1,
+ .m[PSC_CURRENT_IN] = 250,
.b[PSC_CURRENT_IN] = 0,
- .R[PSC_CURRENT_IN] = 2,
- .m[PSC_CURRENT_OUT] = 1,
+ .R[PSC_CURRENT_IN] = -1,
+ .m[PSC_CURRENT_OUT] = 250,
.b[PSC_CURRENT_OUT] = 0,
- .R[PSC_CURRENT_OUT] = 2,
+ .R[PSC_CURRENT_OUT] = -1,
.m[PSC_TEMPERATURE] = 1,
.b[PSC_TEMPERATURE] = 0,
.R[PSC_TEMPERATURE] = 2,
@@ -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/sht3x.c b/drivers/hwmon/sht3x.c
index 557ad3e7752a..f36c0229328f 100644
--- a/drivers/hwmon/sht3x.c
+++ b/drivers/hwmon/sht3x.c
@@ -291,24 +291,26 @@ out:
return data;
}
-static int temp1_input_read(struct device *dev)
+static int temp1_input_read(struct device *dev, long *temp)
{
struct sht3x_data *data = sht3x_update_client(dev);
if (IS_ERR(data))
return PTR_ERR(data);
- return data->temperature;
+ *temp = data->temperature;
+ return 0;
}
-static int humidity1_input_read(struct device *dev)
+static int humidity1_input_read(struct device *dev, long *humidity)
{
struct sht3x_data *data = sht3x_update_client(dev);
if (IS_ERR(data))
return PTR_ERR(data);
- return data->humidity;
+ *humidity = data->humidity;
+ return 0;
}
/*
@@ -706,6 +708,7 @@ static int sht3x_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
enum sht3x_limits index;
+ int ret;
switch (type) {
case hwmon_chip:
@@ -720,10 +723,12 @@ static int sht3x_read(struct device *dev, enum hwmon_sensor_types type,
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
- *val = temp1_input_read(dev);
- break;
+ return temp1_input_read(dev, val);
case hwmon_temp_alarm:
- *val = temp1_alarm_read(dev);
+ ret = temp1_alarm_read(dev);
+ if (ret < 0)
+ return ret;
+ *val = ret;
break;
case hwmon_temp_max:
index = limit_max;
@@ -748,10 +753,12 @@ static int sht3x_read(struct device *dev, enum hwmon_sensor_types type,
case hwmon_humidity:
switch (attr) {
case hwmon_humidity_input:
- *val = humidity1_input_read(dev);
- break;
+ return humidity1_input_read(dev, val);
case hwmon_humidity_alarm:
- *val = humidity1_alarm_read(dev);
+ ret = humidity1_alarm_read(dev);
+ if (ret < 0)
+ return ret;
+ *val = ret;
break;
case hwmon_humidity_max:
index = limit_max;
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, &regval);
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, &regval);
+ 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, &regval);
+ 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, &regval);
+ 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, &regval);
+ 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, &regval);
+ 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, &regval);
+ 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, &regval);
+ 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