summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:39:57 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 17:39:57 +0000
commitdc50eab76b709d68175a358d6e23a5a3890764d3 (patch)
treec754d0390db060af0213ff994f0ac310e4cfd6e9 /drivers/hwmon
parentAdding debian version 6.6.15-2. (diff)
downloadlinux-dc50eab76b709d68175a358d6e23a5a3890764d3.tar.xz
linux-dc50eab76b709d68175a358d6e23a5a3890764d3.zip
Merging upstream version 6.7.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig26
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/abituguru.c6
-rw-r--r--drivers/hwmon/abituguru3.c5
-rw-r--r--drivers/hwmon/acpi_power_meter.c5
-rw-r--r--drivers/hwmon/adt7475.c68
-rw-r--r--drivers/hwmon/aquacomputer_d5next.c72
-rw-r--r--drivers/hwmon/aspeed-pwm-tacho.c7
-rw-r--r--drivers/hwmon/asus-ec-sensors.c12
-rw-r--r--drivers/hwmon/asus_wmi_sensors.c2
-rw-r--r--drivers/hwmon/coretemp.c42
-rw-r--r--drivers/hwmon/da9052-hwmon.c6
-rw-r--r--drivers/hwmon/dme1737.c6
-rw-r--r--drivers/hwmon/f71805f.c6
-rw-r--r--drivers/hwmon/f71882fg.c5
-rw-r--r--drivers/hwmon/fam15h_power.c7
-rw-r--r--drivers/hwmon/hp-wmi-sensors.c127
-rw-r--r--drivers/hwmon/hs3001.c2
-rw-r--r--drivers/hwmon/i5k_amb.c5
-rw-r--r--drivers/hwmon/ibmpowernv.c2
-rw-r--r--drivers/hwmon/ina238.c3
-rw-r--r--drivers/hwmon/ina3221.c33
-rw-r--r--drivers/hwmon/ltc2991.c437
-rw-r--r--drivers/hwmon/ltc2992.c6
-rw-r--r--drivers/hwmon/max197.c6
-rw-r--r--drivers/hwmon/max31827.c130
-rw-r--r--drivers/hwmon/mc13783-adc.c6
-rw-r--r--drivers/hwmon/nct6683.c3
-rw-r--r--drivers/hwmon/nct6775-core.c21
-rw-r--r--drivers/hwmon/nct6775-platform.c4
-rw-r--r--drivers/hwmon/npcm750-pwm-fan.c2
-rw-r--r--drivers/hwmon/occ/p9_sbe.c6
-rw-r--r--drivers/hwmon/pc87360.c6
-rw-r--r--drivers/hwmon/pc87427.c6
-rw-r--r--drivers/hwmon/pmbus/max31785.c188
-rw-r--r--drivers/hwmon/pmbus/mpq7932.c19
-rw-r--r--drivers/hwmon/pmbus/pmbus.h24
-rw-r--r--drivers/hwmon/pmbus/tda38640.c154
-rw-r--r--drivers/hwmon/powerz.c275
-rw-r--r--drivers/hwmon/sch5627.c246
-rw-r--r--drivers/hwmon/sch5636.c6
-rw-r--r--drivers/hwmon/sch56xx-common.c107
-rw-r--r--drivers/hwmon/sch56xx-common.h6
-rw-r--r--drivers/hwmon/sht15.c6
-rw-r--r--drivers/hwmon/sis5595.c6
-rw-r--r--drivers/hwmon/tmp513.c52
-rw-r--r--drivers/hwmon/ultra45_env.c6
-rw-r--r--drivers/hwmon/via-cputemp.c5
-rw-r--r--drivers/hwmon/via686a.c6
-rw-r--r--drivers/hwmon/vt1211.c6
-rw-r--r--drivers/hwmon/vt8231.c6
-rw-r--r--drivers/hwmon/w83627hf.c6
-rw-r--r--drivers/hwmon/w83781d.c7
-rw-r--r--drivers/hwmon/xgene-hwmon.c22
54 files changed, 1871 insertions, 364 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index ec38c88921..cf27523eed 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -40,7 +40,7 @@ comment "Native drivers"
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
- depends on X86 && DMI
+ depends on (X86 && DMI) || COMPILE_TEST
help
If you say yes here you get support for the sensor part of the first
and second revision of the Abit uGuru chip. The voltage and frequency
@@ -55,7 +55,7 @@ config SENSORS_ABITUGURU
config SENSORS_ABITUGURU3
tristate "Abit uGuru (rev 3)"
- depends on X86 && DMI
+ depends on (X86 && DMI) || COMPILE_TEST
help
If you say yes here you get support for the sensor part of the
third revision of the Abit uGuru chip. Only reading the sensors
@@ -839,6 +839,16 @@ config SENSORS_JC42
This driver can also be built as a module. If so, the module
will be called jc42.
+config SENSORS_POWERZ
+ tristate "ChargerLAB POWER-Z USB-C tester"
+ depends on USB
+ help
+ If you say yes here you get support for ChargerLAB POWER-Z series of
+ USB-C charging testers.
+
+ This driver can also be built as a module. If so, the module
+ will be called powerz.
+
config SENSORS_POWR1220
tristate "Lattice POWR1220 Power Monitoring"
depends on I2C
@@ -932,6 +942,17 @@ config SENSORS_LTC2990
This driver can also be built as a module. If so, the module will
be called ltc2990.
+config SENSORS_LTC2991
+ tristate "Analog Devices LTC2991"
+ depends on I2C
+ help
+ If you say yes here you get support for Analog Devices LTC2991
+ Octal I2C Voltage, Current, and Temperature Monitor. The LTC2991
+ supports a combination of voltage, current and temperature monitoring.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc2991.
+
config SENSORS_LTC2992
tristate "Linear Technology LTC2992"
depends on I2C
@@ -1909,6 +1930,7 @@ config SENSORS_SMSC47B397
config SENSORS_SCH56XX_COMMON
tristate
+ select REGMAP
config SENSORS_SCH5627
tristate "SMSC SCH5627"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4ac9452b54..e84bd9685b 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -127,6 +127,7 @@ obj-$(CONFIG_SENSORS_LTC2947) += ltc2947-core.o
obj-$(CONFIG_SENSORS_LTC2947_I2C) += ltc2947-i2c.o
obj-$(CONFIG_SENSORS_LTC2947_SPI) += ltc2947-spi.o
obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o
+obj-$(CONFIG_SENSORS_LTC2991) += ltc2991.o
obj-$(CONFIG_SENSORS_LTC2992) += ltc2992.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
@@ -176,6 +177,7 @@ obj-$(CONFIG_SENSORS_OXP) += oxp-sensors.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_SENSORS_POWERZ) += powerz.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index a7cae65681..93653ea054 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -1428,7 +1428,7 @@ abituguru_probe_error:
return res;
}
-static int abituguru_remove(struct platform_device *pdev)
+static void abituguru_remove(struct platform_device *pdev)
{
int i;
struct abituguru_data *data = platform_get_drvdata(pdev);
@@ -1439,8 +1439,6 @@ static int abituguru_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
-
- return 0;
}
static struct abituguru_data *abituguru_update_device(struct device *dev)
@@ -1533,7 +1531,7 @@ static struct platform_driver abituguru_driver = {
.pm = pm_sleep_ptr(&abituguru_pm),
},
.probe = abituguru_probe,
- .remove = abituguru_remove,
+ .remove_new = abituguru_remove,
};
static int __init abituguru_detect(void)
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index afb21f7303..4501f0e49e 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -1061,7 +1061,7 @@ abituguru3_probe_error:
return res;
}
-static int abituguru3_remove(struct platform_device *pdev)
+static void abituguru3_remove(struct platform_device *pdev)
{
int i;
struct abituguru3_data *data = platform_get_drvdata(pdev);
@@ -1072,7 +1072,6 @@ static int abituguru3_remove(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru3_sysfs_attr[i].dev_attr);
- return 0;
}
static struct abituguru3_data *abituguru3_update_device(struct device *dev)
@@ -1153,7 +1152,7 @@ static struct platform_driver abituguru3_driver = {
.pm = pm_sleep_ptr(&abituguru3_pm),
},
.probe = abituguru3_probe,
- .remove = abituguru3_remove,
+ .remove_new = abituguru3_remove,
};
static int __init abituguru3_dmi_detect(void)
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index b772c076a5..703666b95b 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -800,14 +800,13 @@ static int read_capabilities(struct acpi_power_meter_resource *resource)
goto error;
}
- *str = kcalloc(element->string.length + 1, sizeof(u8),
- GFP_KERNEL);
+ *str = kmemdup_nul(element->string.pointer, element->string.length,
+ GFP_KERNEL);
if (!*str) {
res = -ENOMEM;
goto error;
}
- strncpy(*str, element->string.pointer, element->string.length);
str++;
}
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
index 03acadc3a6..4224ffb304 100644
--- a/drivers/hwmon/adt7475.c
+++ b/drivers/hwmon/adt7475.c
@@ -43,6 +43,7 @@
/* 7475 Common Registers */
#define REG_DEVREV2 0x12 /* ADT7490 only */
+#define REG_IMON 0x1D /* ADT7490 only */
#define REG_VTT 0x1E /* ADT7490 only */
#define REG_EXTEND3 0x1F /* ADT7490 only */
@@ -103,6 +104,9 @@
#define REG_VTT_MIN 0x84 /* ADT7490 only */
#define REG_VTT_MAX 0x86 /* ADT7490 only */
+#define REG_IMON_MIN 0x85 /* ADT7490 only */
+#define REG_IMON_MAX 0x87 /* ADT7490 only */
+
#define VID_VIDSEL 0x80 /* ADT7476 only */
#define CONFIG2_ATTN 0x20
@@ -123,7 +127,7 @@
/* ADT7475 Settings */
-#define ADT7475_VOLTAGE_COUNT 5 /* Not counting Vtt */
+#define ADT7475_VOLTAGE_COUNT 5 /* Not counting Vtt or Imon */
#define ADT7475_TEMP_COUNT 3
#define ADT7475_TACH_COUNT 4
#define ADT7475_PWM_COUNT 3
@@ -204,7 +208,7 @@ struct adt7475_data {
u8 has_fan4:1;
u8 has_vid:1;
u32 alarms;
- u16 voltage[3][6];
+ u16 voltage[3][7];
u16 temp[7][3];
u16 tach[2][4];
u8 pwm[4][3];
@@ -215,7 +219,7 @@ struct adt7475_data {
u8 vid;
u8 vrm;
- const struct attribute_group *groups[9];
+ const struct attribute_group *groups[10];
};
static struct i2c_driver adt7475_driver;
@@ -273,13 +277,14 @@ static inline u16 rpm2tach(unsigned long rpm)
}
/* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */
-static const int adt7473_in_scaling[ADT7475_VOLTAGE_COUNT + 1][2] = {
+static const int adt7473_in_scaling[ADT7475_VOLTAGE_COUNT + 2][2] = {
{ 45, 94 }, /* +2.5V */
{ 175, 525 }, /* Vccp */
{ 68, 71 }, /* Vcc */
{ 93, 47 }, /* +5V */
{ 120, 20 }, /* +12V */
{ 45, 45 }, /* Vtt */
+ { 45, 45 }, /* Imon */
};
static inline int reg2volt(int channel, u16 reg, u8 bypass_attn)
@@ -369,11 +374,16 @@ static ssize_t voltage_store(struct device *dev,
reg = VOLTAGE_MIN_REG(sattr->index);
else
reg = VOLTAGE_MAX_REG(sattr->index);
- } else {
+ } else if (sattr->index == 5) {
if (sattr->nr == MIN)
reg = REG_VTT_MIN;
else
reg = REG_VTT_MAX;
+ } else {
+ if (sattr->nr == MIN)
+ reg = REG_IMON_MIN;
+ else
+ reg = REG_IMON_MAX;
}
i2c_smbus_write_byte_data(client, reg,
@@ -1104,6 +1114,10 @@ static SENSOR_DEVICE_ATTR_2_RO(in5_input, voltage, INPUT, 5);
static SENSOR_DEVICE_ATTR_2_RW(in5_max, voltage, MAX, 5);
static SENSOR_DEVICE_ATTR_2_RW(in5_min, voltage, MIN, 5);
static SENSOR_DEVICE_ATTR_2_RO(in5_alarm, voltage, ALARM, 31);
+static SENSOR_DEVICE_ATTR_2_RO(in6_input, voltage, INPUT, 6);
+static SENSOR_DEVICE_ATTR_2_RW(in6_max, voltage, MAX, 6);
+static SENSOR_DEVICE_ATTR_2_RW(in6_min, voltage, MIN, 6);
+static SENSOR_DEVICE_ATTR_2_RO(in6_alarm, voltage, ALARM, 30);
static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, INPUT, 0);
static SENSOR_DEVICE_ATTR_2_RO(temp1_alarm, temp, ALARM, 0);
static SENSOR_DEVICE_ATTR_2_RO(temp1_fault, temp, FAULT, 0);
@@ -1294,6 +1308,14 @@ static struct attribute *in5_attrs[] = {
NULL
};
+static struct attribute *in6_attrs[] = {
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ NULL
+};
+
static struct attribute *vid_attrs[] = {
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@@ -1307,6 +1329,7 @@ static const struct attribute_group in0_attr_group = { .attrs = in0_attrs };
static const struct attribute_group in3_attr_group = { .attrs = in3_attrs };
static const struct attribute_group in4_attr_group = { .attrs = in4_attrs };
static const struct attribute_group in5_attr_group = { .attrs = in5_attrs };
+static const struct attribute_group in6_attr_group = { .attrs = in6_attrs };
static const struct attribute_group vid_attr_group = { .attrs = vid_attrs };
static int adt7475_detect(struct i2c_client *client,
@@ -1389,6 +1412,18 @@ static int adt7475_update_limits(struct i2c_client *client)
data->voltage[MAX][5] = ret << 2;
}
+ if (data->has_voltage & (1 << 6)) {
+ ret = adt7475_read(REG_IMON_MIN);
+ if (ret < 0)
+ return ret;
+ data->voltage[MIN][6] = ret << 2;
+
+ ret = adt7475_read(REG_IMON_MAX);
+ if (ret < 0)
+ return ret;
+ data->voltage[MAX][6] = ret << 2;
+ }
+
for (i = 0; i < ADT7475_TEMP_COUNT; i++) {
/* Adjust values so they match the input precision */
ret = adt7475_read(TEMP_MIN_REG(i));
@@ -1663,7 +1698,7 @@ static int adt7475_probe(struct i2c_client *client)
revision = adt7475_read(REG_DEVID2) & 0x07;
break;
case adt7490:
- data->has_voltage = 0x3e; /* in1 to in5 */
+ data->has_voltage = 0x7e; /* in1 to in6 */
revision = adt7475_read(REG_DEVID2) & 0x03;
if (revision == 0x03)
revision += adt7475_read(REG_DEVREV2);
@@ -1775,6 +1810,9 @@ static int adt7475_probe(struct i2c_client *client)
if (data->has_voltage & (1 << 5)) {
data->groups[group_num++] = &in5_attr_group;
}
+ if (data->has_voltage & (1 << 6)) {
+ data->groups[group_num++] = &in6_attr_group;
+ }
if (data->has_vid) {
data->vrm = vid_which_vrm();
data->groups[group_num] = &vid_attr_group;
@@ -1960,6 +1998,24 @@ static int adt7475_update_measure(struct device *dev)
((ext >> 4) & 3);
}
+ if (data->has_voltage & (1 << 6)) {
+ ret = adt7475_read(REG_STATUS4);
+ if (ret < 0)
+ return ret;
+ data->alarms |= ret << 24;
+
+ ret = adt7475_read(REG_EXTEND3);
+ if (ret < 0)
+ return ret;
+ ext = ret;
+
+ ret = adt7475_read(REG_IMON);
+ if (ret < 0)
+ return ret;
+ data->voltage[INPUT][6] = ret << 2 |
+ ((ext >> 6) & 3);
+ }
+
for (i = 0; i < ADT7475_TACH_COUNT; i++) {
if (i == 3 && !data->has_fan4)
continue;
diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c
index 023807859b..4fdd2e1242 100644
--- a/drivers/hwmon/aquacomputer_d5next.c
+++ b/drivers/hwmon/aquacomputer_d5next.c
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
- * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield)
+ * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield,
+ * High Flow USB/MPS Flow family)
*
* Aquacomputer devices send HID reports (with ID 0x01) every second to report
* sensor values, except for devices that communicate through the
- * legacy way (currently, Poweradjust 3).
+ * legacy way (currently, Poweradjust 3 and High Flow USB/MPS Flow family).
*
* Copyright 2021 Aleksa Savic <savicaleksa83@gmail.com>
* Copyright 2022 Jack Doan <me@jackdoan.com>
@@ -35,11 +36,12 @@
#define USB_PRODUCT_ID_AQUASTREAMXT 0xf0b6
#define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b
#define USB_PRODUCT_ID_POWERADJUST3 0xf0bd
+#define USB_PRODUCT_ID_HIGHFLOW 0xf003
enum kinds {
d5next, farbwerk, farbwerk360, octo, quadro,
highflownext, aquaero, poweradjust3, aquastreamult,
- aquastreamxt, leakshield
+ aquastreamxt, leakshield, highflow
};
static const char *const aqc_device_names[] = {
@@ -53,7 +55,8 @@ static const char *const aqc_device_names[] = {
[aquastreamxt] = "aquastreamxt",
[aquaero] = "aquaero",
[aquastreamult] = "aquastreamultimate",
- [poweradjust3] = "poweradjust3"
+ [poweradjust3] = "poweradjust3",
+ [highflow] = "highflow" /* Covers MPS Flow devices */
};
#define DRIVER_NAME "aquacomputer_d5next"
@@ -90,6 +93,8 @@ static u8 aquaero_secondary_ctrl_report[] = {
#define POWERADJUST3_STATUS_REPORT_ID 0x03
+#define HIGHFLOW_STATUS_REPORT_ID 0x02
+
/* Data types for reading and writing control reports */
#define AQC_8 0
#define AQC_BE16 1
@@ -282,6 +287,17 @@ static u16 aquastreamxt_sensor_fan_offsets[] = { 0x13, 0x1b };
/* Sensor report offsets for the Poweradjust 3 */
#define POWERADJUST3_SENSOR_START 0x03
+/* Specs of the High Flow USB */
+#define HIGHFLOW_NUM_SENSORS 2
+#define HIGHFLOW_NUM_FLOW_SENSORS 1
+#define HIGHFLOW_SENSOR_REPORT_SIZE 0x76
+
+/* Sensor report offsets for the High Flow USB */
+#define HIGHFLOW_FIRMWARE_VERSION 0x3
+#define HIGHFLOW_SERIAL_START 0x9
+#define HIGHFLOW_FLOW_SENSOR_OFFSET 0x23
+#define HIGHFLOW_SENSOR_START 0x2b
+
/* Labels for D5 Next */
static const char *const label_d5next_temp[] = {
"Coolant temp"
@@ -486,6 +502,16 @@ static const char *const label_poweradjust3_temp_sensors[] = {
"External sensor"
};
+/* Labels for Highflow */
+static const char *const label_highflow_temp[] = {
+ "External temp",
+ "Internal temp"
+};
+
+static const char *const label_highflow_speeds[] = {
+ "Flow speed [dL/h]"
+};
+
struct aqc_fan_structure_offsets {
u8 voltage;
u8 curr;
@@ -819,6 +845,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
break;
case aquaero:
case quadro:
+ case highflow:
/* Special case to support flow sensors */
if (channel < priv->num_fans + priv->num_flow_sensors)
return 0444;
@@ -926,7 +953,10 @@ static int aqc_legacy_read(struct aqc_data *priv)
for (i = 0; i < priv->num_temp_sensors; i++) {
sensor_value = get_unaligned_le16(priv->buffer + priv->temp_sensor_start_offset +
i * AQC_SENSOR_SIZE);
- priv->temp_input[i] = sensor_value * 10;
+ if (sensor_value == AQC_SENSOR_NA)
+ priv->temp_input[i] = -ENODATA;
+ else
+ priv->temp_input[i] = sensor_value * 10;
}
/* Special-case sensor readings */
@@ -962,6 +992,17 @@ static int aqc_legacy_read(struct aqc_data *priv)
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_VOLTAGE_OFFSET);
priv->voltage_input[1] = DIV_ROUND_CLOSEST(sensor_value * 1000, 63);
break;
+ case highflow:
+ /* Info provided with every report */
+ priv->serial_number[0] = get_unaligned_le16(priv->buffer +
+ priv->serial_number_start_offset);
+ priv->firmware_version =
+ get_unaligned_le16(priv->buffer + priv->firmware_version_offset);
+
+ /* Read flow speed */
+ priv->speed_input[0] = get_unaligned_le16(priv->buffer +
+ priv->flow_sensors_start_offset);
+ break;
default:
break;
}
@@ -1747,6 +1788,20 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_label = label_poweradjust3_temp_sensors;
break;
+ case USB_PRODUCT_ID_HIGHFLOW:
+ priv->kind = highflow;
+
+ priv->num_fans = 0;
+
+ priv->num_temp_sensors = HIGHFLOW_NUM_SENSORS;
+ priv->temp_sensor_start_offset = HIGHFLOW_SENSOR_START;
+ priv->num_flow_sensors = HIGHFLOW_NUM_FLOW_SENSORS;
+ priv->flow_sensors_start_offset = HIGHFLOW_FLOW_SENSOR_OFFSET;
+ priv->buffer_size = HIGHFLOW_SENSOR_REPORT_SIZE;
+
+ priv->temp_label = label_highflow_temp;
+ priv->speed_label = label_highflow_speeds;
+ break;
default:
break;
}
@@ -1772,6 +1827,12 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->status_report_id = AQUASTREAMXT_STATUS_REPORT_ID;
break;
+ case highflow:
+ priv->serial_number_start_offset = HIGHFLOW_SERIAL_START;
+ priv->firmware_version_offset = HIGHFLOW_FIRMWARE_VERSION;
+
+ priv->status_report_id = HIGHFLOW_STATUS_REPORT_ID;
+ break;
default:
priv->serial_number_start_offset = AQC_SERIAL_START;
priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
@@ -1846,6 +1907,7 @@ static const struct hid_device_id aqc_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOW) },
{ }
};
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
index 997df4b405..b2ae2176f1 100644
--- a/drivers/hwmon/aspeed-pwm-tacho.c
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -193,6 +193,8 @@ struct aspeed_pwm_tacho_data {
u8 fan_tach_ch_source[16];
struct aspeed_cooling_device *cdev[8];
const struct attribute_group *groups[3];
+ /* protects access to shared ASPEED_PTCR_RESULT */
+ struct mutex tach_lock;
};
enum type { TYPEM, TYPEN, TYPEO };
@@ -527,6 +529,8 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
u8 fan_tach_ch_source, type, mode, both;
int ret;
+ mutex_lock(&priv->tach_lock);
+
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
@@ -544,6 +548,8 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
ASPEED_RPM_STATUS_SLEEP_USEC,
usec);
+ mutex_unlock(&priv->tach_lock);
+
/* return -ETIMEDOUT if we didn't get an answer. */
if (ret)
return ret;
@@ -903,6 +909,7 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ mutex_init(&priv->tach_lock);
priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs,
&aspeed_pwm_tacho_regmap_config);
if (IS_ERR(priv->regmap))
diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index 51f9c2db40..36f9e38000 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -244,6 +244,8 @@ static const struct ec_sensor_info sensors_family_amd_600[] = {
EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x32),
[ec_sensor_temp_vrm] =
EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33),
+ [ec_sensor_temp_t_sensor] =
+ EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x36),
[ec_sensor_temp_water_in] =
EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
[ec_sensor_temp_water_out] =
@@ -344,6 +346,14 @@ static const struct ec_board_info board_info_crosshair_x670e_hero = {
.family = family_amd_600_series,
};
+static const struct ec_board_info board_info_crosshair_x670e_gene = {
+ .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
+ SENSOR_TEMP_T_SENSOR |
+ SENSOR_TEMP_MB | SENSOR_TEMP_VRM,
+ .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
+ .family = family_amd_600_series,
+};
+
static const struct ec_board_info board_info_crosshair_viii_dark_hero = {
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
SENSOR_TEMP_T_SENSOR |
@@ -490,6 +500,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_crosshair_viii_hero),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO",
&board_info_crosshair_x670e_hero),
+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E GENE",
+ &board_info_crosshair_x670e_gene),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO",
&board_info_maximus_xi_hero),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)",
diff --git a/drivers/hwmon/asus_wmi_sensors.c b/drivers/hwmon/asus_wmi_sensors.c
index 6e8a908171..c2dd7ff882 100644
--- a/drivers/hwmon/asus_wmi_sensors.c
+++ b/drivers/hwmon/asus_wmi_sensors.c
@@ -300,7 +300,7 @@ static int asus_wmi_sensor_info(int index, struct asus_wmi_sensor_info *s)
goto out_free_obj;
}
- strncpy(s->name, name_obj.string.pointer, sizeof(s->name) - 1);
+ strscpy(s->name, name_obj.string.pointer, sizeof(s->name));
data_type_obj = obj->package.elements[1];
if (data_type_obj.type != ACPI_TYPE_INTEGER) {
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index ba82d1e79c..b8fc8d1ef2 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius");
#define PKG_SYSFS_ATTR_NO 1 /* Sysfs attribute for package temp */
#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
-#define NUM_REAL_CORES 128 /* Number of Real cores per cpu */
+#define NUM_REAL_CORES 512 /* Number of Real cores per cpu */
#define CORETEMP_NAME_LENGTH 28 /* String Length of attrs */
#define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */
#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1)
@@ -419,7 +419,7 @@ static ssize_t show_temp(struct device *dev,
}
static int create_core_attrs(struct temp_data *tdata, struct device *dev,
- int attr_no)
+ int index)
{
int i;
static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev,
@@ -431,13 +431,20 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev,
};
for (i = 0; i < tdata->attr_size; i++) {
+ /*
+ * We map the attr number to core id of the CPU
+ * The attr number is always core id + 2
+ * The Pkgtemp will always show up as temp1_*, if available
+ */
+ int attr_no = tdata->is_pkg_data ? 1 : tdata->cpu_core_id + 2;
+
snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH,
"temp%d_%s", attr_no, suffixes[i]);
sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
tdata->sd_attrs[i].dev_attr.attr.mode = 0444;
tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
- tdata->sd_attrs[i].index = attr_no;
+ tdata->sd_attrs[i].index = index;
tdata->attrs[i] = &tdata->sd_attrs[i].dev_attr.attr;
}
tdata->attr_group.attrs = tdata->attrs;
@@ -495,30 +502,25 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
struct platform_data *pdata = platform_get_drvdata(pdev);
struct cpuinfo_x86 *c = &cpu_data(cpu);
u32 eax, edx;
- int err, index, attr_no;
+ int err, index;
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
return 0;
/*
- * Find attr number for sysfs:
- * We map the attr number to core id of the CPU
- * The attr number is always core id + 2
- * The Pkgtemp will always show up as temp1_*, if available
+ * Get the index of tdata in pdata->core_data[]
+ * tdata for package: pdata->core_data[1]
+ * tdata for core: pdata->core_data[2] .. pdata->core_data[NUM_REAL_CORES + 1]
*/
if (pkg_flag) {
- attr_no = PKG_SYSFS_ATTR_NO;
+ index = PKG_SYSFS_ATTR_NO;
} else {
- index = ida_alloc(&pdata->ida, GFP_KERNEL);
+ index = ida_alloc_max(&pdata->ida, NUM_REAL_CORES - 1, GFP_KERNEL);
if (index < 0)
return index;
- pdata->cpu_map[index] = topology_core_id(cpu);
- attr_no = index + BASE_SYSFS_ATTR_NO;
- }
- if (attr_no > MAX_CORE_DATA - 1) {
- err = -ERANGE;
- goto ida_free;
+ pdata->cpu_map[index] = topology_core_id(cpu);
+ index += BASE_SYSFS_ATTR_NO;
}
tdata = init_temp_data(cpu, pkg_flag);
@@ -544,20 +546,20 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
if (get_ttarget(tdata, &pdev->dev) >= 0)
tdata->attr_size++;
- pdata->core_data[attr_no] = tdata;
+ pdata->core_data[index] = tdata;
/* Create sysfs interfaces */
- err = create_core_attrs(tdata, pdata->hwmon_dev, attr_no);
+ err = create_core_attrs(tdata, pdata->hwmon_dev, index);
if (err)
goto exit_free;
return 0;
exit_free:
- pdata->core_data[attr_no] = NULL;
+ pdata->core_data[index] = NULL;
kfree(tdata);
ida_free:
if (!pkg_flag)
- ida_free(&pdata->ida, index);
+ ida_free(&pdata->ida, index - BASE_SYSFS_ATTR_NO);
return err;
}
diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c
index ed6c5df94f..2bd7ae8100 100644
--- a/drivers/hwmon/da9052-hwmon.c
+++ b/drivers/hwmon/da9052-hwmon.c
@@ -479,7 +479,7 @@ exit_regulator:
return err;
}
-static int da9052_hwmon_remove(struct platform_device *pdev)
+static void da9052_hwmon_remove(struct platform_device *pdev)
{
struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
@@ -487,13 +487,11 @@ static int da9052_hwmon_remove(struct platform_device *pdev)
da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
regulator_disable(hwmon->tsiref);
}
-
- return 0;
}
static struct platform_driver da9052_hwmon_driver = {
.probe = da9052_hwmon_probe,
- .remove = da9052_hwmon_remove,
+ .remove_new = da9052_hwmon_remove,
.driver = {
.name = "da9052-hwmon",
},
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index cdbf3dff91..3dcef22104 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -2710,14 +2710,12 @@ exit_remove_files:
return err;
}
-static int dme1737_isa_remove(struct platform_device *pdev)
+static void dme1737_isa_remove(struct platform_device *pdev)
{
struct dme1737_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
dme1737_remove_files(&pdev->dev);
-
- return 0;
}
static struct platform_driver dme1737_isa_driver = {
@@ -2725,7 +2723,7 @@ static struct platform_driver dme1737_isa_driver = {
.name = "dme1737",
},
.probe = dme1737_isa_probe,
- .remove = dme1737_isa_remove,
+ .remove_new = dme1737_isa_remove,
};
/* ---------------------------------------------------------------------
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 7f20edb067..243c570dee 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1480,7 +1480,7 @@ exit_remove_files:
return err;
}
-static int f71805f_remove(struct platform_device *pdev)
+static void f71805f_remove(struct platform_device *pdev)
{
struct f71805f_data *data = platform_get_drvdata(pdev);
int i;
@@ -1490,8 +1490,6 @@ static int f71805f_remove(struct platform_device *pdev)
for (i = 0; i < 4; i++)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
-
- return 0;
}
static struct platform_driver f71805f_driver = {
@@ -1499,7 +1497,7 @@ static struct platform_driver f71805f_driver = {
.name = DRVNAME,
},
.probe = f71805f_probe,
- .remove = f71805f_remove,
+ .remove_new = f71805f_remove,
};
static int __init f71805f_device_add(unsigned short address,
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 27207ec6f7..7c941d320a 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -2223,7 +2223,7 @@ static int f71882fg_create_fan_sysfs_files(
return err;
}
-static int f71882fg_remove(struct platform_device *pdev)
+static void f71882fg_remove(struct platform_device *pdev)
{
struct f71882fg_data *data = platform_get_drvdata(pdev);
int nr_fans = f71882fg_nr_fans[data->type];
@@ -2333,7 +2333,6 @@ static int f71882fg_remove(struct platform_device *pdev)
ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
}
}
- return 0;
}
static int f71882fg_probe(struct platform_device *pdev)
@@ -2659,7 +2658,7 @@ static struct platform_driver f71882fg_driver = {
.name = DRVNAME,
},
.probe = f71882fg_probe,
- .remove = f71882fg_remove,
+ .remove_new = f71882fg_remove,
};
static int __init f71882fg_init(void)
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index 521534d5c1..6307112c2c 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -17,6 +17,7 @@
#include <linux/cpumask.h>
#include <linux/time.h>
#include <linux/sched.h>
+#include <linux/topology.h>
#include <asm/processor.h>
#include <asm/msr.h>
@@ -134,15 +135,13 @@ static DEVICE_ATTR_RO(power1_crit);
static void do_read_registers_on_cu(void *_data)
{
struct fam15h_power_data *data = _data;
- int cpu, cu;
-
- cpu = smp_processor_id();
+ int cu;
/*
* With the new x86 topology modelling, cpu core id actually
* is compute unit id.
*/
- cu = cpu_data(cpu).cpu_core_id;
+ cu = topology_core_id(smp_processor_id());
rdmsrl_safe(MSR_F15H_CU_PWR_ACCUMULATOR, &data->cu_acc_power[cu]);
rdmsrl_safe(MSR_F15H_PTSC, &data->cpu_sw_pwr_ptsc[cu]);
diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c
index 17ae62f88b..b5325d0e72 100644
--- a/drivers/hwmon/hp-wmi-sensors.c
+++ b/drivers/hwmon/hp-wmi-sensors.c
@@ -17,6 +17,8 @@
* Available: https://github.com/linuxhw/ACPI
* [4] P. Rohár, "bmfdec - Decompile binary MOF file (BMF) from WMI buffer",
* 2017. [Online]. Available: https://github.com/pali/bmfdec
+ * [5] Microsoft Corporation, "Driver-Defined WMI Data Items", 2017. [Online].
+ * Available: https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/driver-defined-wmi-data-items
*/
#include <linux/acpi.h>
@@ -24,6 +26,7 @@
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
+#include <linux/nls.h>
#include <linux/units.h>
#include <linux/wmi.h>
@@ -395,6 +398,50 @@ struct hp_wmi_sensors {
struct mutex lock; /* Lock polling WMI and driver state changes. */
};
+static bool is_raw_wmi_string(const u8 *pointer, u32 length)
+{
+ const u16 *ptr;
+ u16 len;
+
+ /* WMI strings are length-prefixed UTF-16 [5]. */
+ if (length <= sizeof(*ptr))
+ return false;
+
+ length -= sizeof(*ptr);
+ ptr = (const u16 *)pointer;
+ len = *ptr;
+
+ return len <= length && !(len & 1);
+}
+
+static char *convert_raw_wmi_string(const u8 *buf)
+{
+ const wchar_t *src;
+ unsigned int cps;
+ unsigned int len;
+ char *dst;
+ int i;
+
+ src = (const wchar_t *)buf;
+
+ /* Count UTF-16 code points. Exclude trailing null padding. */
+ cps = *src / sizeof(*src);
+ while (cps && !src[cps])
+ cps--;
+
+ /* Each code point becomes up to 3 UTF-8 characters. */
+ len = min(cps * 3, HP_WMI_MAX_STR_SIZE - 1);
+
+ dst = kmalloc((len + 1) * sizeof(*dst), GFP_KERNEL);
+ if (!dst)
+ return NULL;
+
+ i = utf16s_to_utf8s(++src, cps, UTF16_LITTLE_ENDIAN, dst, len);
+ dst[i] = '\0';
+
+ return dst;
+}
+
/* hp_wmi_strdup - devm_kstrdup, but length-limited */
static char *hp_wmi_strdup(struct device *dev, const char *src)
{
@@ -412,6 +459,23 @@ static char *hp_wmi_strdup(struct device *dev, const char *src)
return dst;
}
+/* hp_wmi_wstrdup - hp_wmi_strdup, but for a raw WMI string */
+static char *hp_wmi_wstrdup(struct device *dev, const u8 *buf)
+{
+ char *src;
+ char *dst;
+
+ src = convert_raw_wmi_string(buf);
+ if (!src)
+ return NULL;
+
+ dst = hp_wmi_strdup(dev, strim(src)); /* Note: Copy is trimmed. */
+
+ kfree(src);
+
+ return dst;
+}
+
/*
* hp_wmi_get_wobj - poll WMI for a WMI object instance
* @guid: WMI object GUID
@@ -462,8 +526,14 @@ static int check_wobj(const union acpi_object *wobj,
for (prop = 0; prop <= last_prop; prop++) {
type = elements[prop].type;
valid_type = property_map[prop];
- if (type != valid_type)
+ if (type != valid_type) {
+ if (type == ACPI_TYPE_BUFFER &&
+ valid_type == ACPI_TYPE_STRING &&
+ is_raw_wmi_string(elements[prop].buffer.pointer,
+ elements[prop].buffer.length))
+ continue;
return -EINVAL;
+ }
}
return 0;
@@ -480,7 +550,9 @@ static int extract_acpi_value(struct device *dev,
break;
case ACPI_TYPE_STRING:
- *out_string = hp_wmi_strdup(dev, strim(element->string.pointer));
+ *out_string = element->type == ACPI_TYPE_BUFFER ?
+ hp_wmi_wstrdup(dev, element->buffer.pointer) :
+ hp_wmi_strdup(dev, strim(element->string.pointer));
if (!*out_string)
return -ENOMEM;
break;
@@ -861,7 +933,9 @@ update_numeric_sensor_from_wobj(struct device *dev,
{
const union acpi_object *elements;
const union acpi_object *element;
- const char *string;
+ const char *new_string;
+ char *trimmed;
+ char *string;
bool is_new;
int offset;
u8 size;
@@ -885,11 +959,21 @@ update_numeric_sensor_from_wobj(struct device *dev,
offset = is_new ? size - 1 : -2;
element = &elements[HP_WMI_PROPERTY_CURRENT_STATE + offset];
- string = strim(element->string.pointer);
-
- if (strcmp(string, nsensor->current_state)) {
- devm_kfree(dev, nsensor->current_state);
- nsensor->current_state = hp_wmi_strdup(dev, string);
+ string = element->type == ACPI_TYPE_BUFFER ?
+ convert_raw_wmi_string(element->buffer.pointer) :
+ element->string.pointer;
+
+ if (string) {
+ trimmed = strim(string);
+ if (strcmp(trimmed, nsensor->current_state)) {
+ new_string = hp_wmi_strdup(dev, trimmed);
+ if (new_string) {
+ devm_kfree(dev, nsensor->current_state);
+ nsensor->current_state = new_string;
+ }
+ }
+ if (element->type == ACPI_TYPE_BUFFER)
+ kfree(string);
}
/* Old variant: -2 (not -1) because it lacks the Size property. */
@@ -996,11 +1080,15 @@ static int check_event_wobj(const union acpi_object *wobj)
HP_WMI_EVENT_PROPERTY_STATUS);
}
-static int populate_event_from_wobj(struct hp_wmi_event *event,
+static int populate_event_from_wobj(struct device *dev,
+ struct hp_wmi_event *event,
union acpi_object *wobj)
{
int prop = HP_WMI_EVENT_PROPERTY_NAME;
union acpi_object *element;
+ acpi_object_type type;
+ char *string;
+ u32 value;
int err;
err = check_event_wobj(wobj);
@@ -1009,20 +1097,24 @@ static int populate_event_from_wobj(struct hp_wmi_event *event,
element = wobj->package.elements;
- /* Extracted strings are NOT device-managed copies. */
-
for (; prop <= HP_WMI_EVENT_PROPERTY_CATEGORY; prop++, element++) {
+ type = hp_wmi_event_property_map[prop];
+
+ err = extract_acpi_value(dev, element, type, &value, &string);
+ if (err)
+ return err;
+
switch (prop) {
case HP_WMI_EVENT_PROPERTY_NAME:
- event->name = strim(element->string.pointer);
+ event->name = string;
break;
case HP_WMI_EVENT_PROPERTY_DESCRIPTION:
- event->description = strim(element->string.pointer);
+ event->description = string;
break;
case HP_WMI_EVENT_PROPERTY_CATEGORY:
- event->category = element->integer.value;
+ event->category = value;
break;
default:
@@ -1511,8 +1603,8 @@ static void hp_wmi_notify(u32 value, void *context)
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
struct hp_wmi_sensors *state = context;
struct device *dev = &state->wdev->dev;
+ struct hp_wmi_event event = {};
struct hp_wmi_info *fan_info;
- struct hp_wmi_event event;
union acpi_object *wobj;
acpi_status err;
int event_type;
@@ -1546,7 +1638,7 @@ static void hp_wmi_notify(u32 value, void *context)
wobj = out.pointer;
- err = populate_event_from_wobj(&event, wobj);
+ err = populate_event_from_wobj(dev, &event, wobj);
if (err) {
dev_warn(dev, "Bad event data (ACPI type %d)\n", wobj->type);
goto out_free_wobj;
@@ -1577,6 +1669,9 @@ static void hp_wmi_notify(u32 value, void *context)
out_free_wobj:
kfree(wobj);
+ devm_kfree(dev, event.name);
+ devm_kfree(dev, event.description);
+
out_unlock:
mutex_unlock(&state->lock);
}
diff --git a/drivers/hwmon/hs3001.c b/drivers/hwmon/hs3001.c
index ac574e46d0..01ea9a3062 100644
--- a/drivers/hwmon/hs3001.c
+++ b/drivers/hwmon/hs3001.c
@@ -62,7 +62,7 @@ static u32 hs3001_extract_humidity(u16 raw)
{
u32 hum = (raw & HS3001_MASK_HUMIDITY_0X3FFF) * HS3001_FIXPOINT_ARITH * 100;
- return hum /= (1 << 14) - 1;
+ return hum / (1 << 14) - 1;
}
static int hs3001_data_fetch_command(struct i2c_client *client,
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index 783fa936e4..ff48913fe6 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -555,7 +555,7 @@ err:
return res;
}
-static int i5k_amb_remove(struct platform_device *pdev)
+static void i5k_amb_remove(struct platform_device *pdev)
{
int i;
struct i5k_amb_data *data = platform_get_drvdata(pdev);
@@ -568,7 +568,6 @@ static int i5k_amb_remove(struct platform_device *pdev)
iounmap(data->amb_mmio);
release_mem_region(data->amb_base, data->amb_len);
kfree(data);
- return 0;
}
static struct platform_driver i5k_amb_driver = {
@@ -576,7 +575,7 @@ static struct platform_driver i5k_amb_driver = {
.name = DRVNAME,
},
.probe = i5k_amb_probe,
- .remove = i5k_amb_remove,
+ .remove_new = i5k_amb_remove,
};
static int __init i5k_amb_init(void)
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
index 594254d6a7..70ca833259 100644
--- a/drivers/hwmon/ibmpowernv.c
+++ b/drivers/hwmon/ibmpowernv.c
@@ -234,7 +234,7 @@ static int get_sensor_index_attr(const char *name, u32 *index, char *attr)
if (copy_len >= sizeof(buf))
return -EINVAL;
- strncpy(buf, hash_pos + 1, copy_len);
+ memcpy(buf, hash_pos + 1, copy_len);
err = kstrtou32(buf, 10, index);
if (err)
diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c
index f519c22d39..ca9f5d2c81 100644
--- a/drivers/hwmon/ina238.c
+++ b/drivers/hwmon/ina238.c
@@ -33,7 +33,7 @@
#define INA238_BUS_UNDER_VOLTAGE 0xf
#define INA238_TEMP_LIMIT 0x10
#define INA238_POWER_LIMIT 0x11
-#define INA238_DEVICE_ID 0x3f
+#define INA238_DEVICE_ID 0x3f /* not available on INA237 */
#define INA238_CONFIG_ADCRANGE BIT(4)
@@ -622,6 +622,7 @@ static const struct i2c_device_id ina238_id[] = {
MODULE_DEVICE_TABLE(i2c, ina238_id);
static const struct of_device_id __maybe_unused ina238_of_match[] = {
+ { .compatible = "ti,ina237" },
{ .compatible = "ti,ina238" },
{ },
};
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index 5ab944056e..5ffdc94db4 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -6,6 +6,7 @@
* Andrew F. Davis <afd@ti.com>
*/
+#include <linux/debugfs.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h>
@@ -99,11 +100,13 @@ enum ina3221_channels {
* @label: label of channel input source
* @shunt_resistor: shunt resistor value of channel input source
* @disconnected: connection status of channel input source
+ * @summation_disable: channel summation status of input source
*/
struct ina3221_input {
const char *label;
int shunt_resistor;
bool disconnected;
+ bool summation_disable;
};
/**
@@ -113,8 +116,10 @@ struct ina3221_input {
* @fields: Register fields of the device
* @inputs: Array of channel input source specific structures
* @lock: mutex lock to serialize sysfs attribute accesses
+ * @debugfs: Pointer to debugfs entry for device
* @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
* @single_shot: running in single-shot operating mode
*/
struct ina3221_data {
@@ -123,8 +128,10 @@ struct ina3221_data {
struct regmap_field *fields[F_MAX_FIELDS];
struct ina3221_input inputs[INA3221_NUM_CHANNELS];
struct mutex lock;
+ struct dentry *debugfs;
u32 reg_config;
int summation_shunt_resistor;
+ u32 summation_channel_control;
bool single_shot;
};
@@ -154,7 +161,8 @@ static inline int ina3221_summation_shunt_resistor(struct ina3221_data *ina)
int i, shunt_resistor = 0;
for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
- if (input[i].disconnected || !input[i].shunt_resistor)
+ if (input[i].disconnected || !input[i].shunt_resistor ||
+ input[i].summation_disable)
continue;
if (!shunt_resistor) {
/* Found the reference shunt resistor value */
@@ -786,6 +794,9 @@ static int ina3221_probe_child_from_dt(struct device *dev,
/* Save the connected input label if available */
of_property_read_string(child, "label", &input->label);
+ /* summation channel control */
+ input->summation_disable = of_property_read_bool(child, "ti,summation-disable");
+
/* Overwrite default shunt resistor value optionally */
if (!of_property_read_u32(child, "shunt-resistor-micro-ohms", &val)) {
if (val < 1 || val > INT_MAX) {
@@ -827,6 +838,7 @@ static int ina3221_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct ina3221_data *ina;
struct device *hwmon_dev;
+ char name[32];
int i, ret;
ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL);
@@ -873,6 +885,10 @@ static int ina3221_probe(struct i2c_client *client)
/* Initialize summation_shunt_resistor for summation channel control */
ina->summation_shunt_resistor = ina3221_summation_shunt_resistor(ina);
+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
+ if (!ina->inputs[i].summation_disable)
+ ina->summation_channel_control |= BIT(14 - i);
+ }
ina->pm_dev = dev;
mutex_init(&ina->lock);
@@ -900,6 +916,15 @@ static int ina3221_probe(struct i2c_client *client)
goto fail;
}
+ scnprintf(name, sizeof(name), "%s-%s", INA3221_DRIVER_NAME, dev_name(dev));
+ ina->debugfs = debugfs_create_dir(name, NULL);
+
+ for (i = 0; i < INA3221_NUM_CHANNELS; i++) {
+ scnprintf(name, sizeof(name), "in%d_summation_disable", i);
+ debugfs_create_bool(name, 0400, ina->debugfs,
+ &ina->inputs[i].summation_disable);
+ }
+
return 0;
fail:
@@ -918,6 +943,8 @@ static void ina3221_remove(struct i2c_client *client)
struct ina3221_data *ina = dev_get_drvdata(&client->dev);
int i;
+ debugfs_remove_recursive(ina->debugfs);
+
pm_runtime_disable(ina->pm_dev);
pm_runtime_set_suspended(ina->pm_dev);
@@ -978,13 +1005,13 @@ static int ina3221_resume(struct device *dev)
/* Initialize summation channel control */
if (ina->summation_shunt_resistor) {
/*
- * Take all three channels into summation by default
+ * Sum only channels that are not disabled for summation.
* Shunt measurements of disconnected channels should
* be 0, so it does not matter for summation.
*/
ret = regmap_update_bits(ina->regmap, INA3221_MASK_ENABLE,
INA3221_MASK_ENABLE_SCC_MASK,
- INA3221_MASK_ENABLE_SCC_MASK);
+ ina->summation_channel_control);
if (ret) {
dev_err(dev, "Unable to control summation channel\n");
return ret;
diff --git a/drivers/hwmon/ltc2991.c b/drivers/hwmon/ltc2991.c
new file mode 100644
index 0000000000..fc53fdcb2b
--- /dev/null
+++ b/drivers/hwmon/ltc2991.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Analog Devices, Inc.
+ * Author: Antoniu Miclaus <antoniu.miclaus@analog.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#define LTC2991_STATUS_LOW 0x00
+#define LTC2991_CH_EN_TRIGGER 0x01
+#define LTC2991_V1_V4_CTRL 0x06
+#define LTC2991_V5_V8_CTRL 0x07
+#define LTC2991_PWM_TH_LSB_T_INT 0x08
+#define LTC2991_PWM_TH_MSB 0x09
+#define LTC2991_CHANNEL_V_MSB(x) (0x0A + ((x) * 2))
+#define LTC2991_CHANNEL_T_MSB(x) (0x0A + ((x) * 4))
+#define LTC2991_CHANNEL_C_MSB(x) (0x0C + ((x) * 4))
+#define LTC2991_T_INT_MSB 0x1A
+#define LTC2991_VCC_MSB 0x1C
+
+#define LTC2991_V7_V8_EN BIT(7)
+#define LTC2991_V5_V6_EN BIT(6)
+#define LTC2991_V3_V4_EN BIT(5)
+#define LTC2991_V1_V2_EN BIT(4)
+#define LTC2991_T_INT_VCC_EN BIT(3)
+
+#define LTC2991_V3_V4_FILT_EN BIT(7)
+#define LTC2991_V3_V4_TEMP_EN BIT(5)
+#define LTC2991_V3_V4_DIFF_EN BIT(4)
+#define LTC2991_V1_V2_FILT_EN BIT(3)
+#define LTC2991_V1_V2_TEMP_EN BIT(1)
+#define LTC2991_V1_V2_DIFF_EN BIT(0)
+
+#define LTC2991_V7_V8_FILT_EN BIT(7)
+#define LTC2991_V7_V8_TEMP_EN BIT(5)
+#define LTC2991_V7_V8_DIFF_EN BIT(4)
+#define LTC2991_V5_V6_FILT_EN BIT(7)
+#define LTC2991_V5_V6_TEMP_EN BIT(5)
+#define LTC2991_V5_V6_DIFF_EN BIT(4)
+
+#define LTC2991_REPEAT_ACQ_EN BIT(4)
+#define LTC2991_T_INT_FILT_EN BIT(3)
+
+#define LTC2991_MAX_CHANNEL 4
+#define LTC2991_T_INT_CH_NR 4
+#define LTC2991_VCC_CH_NR 0
+
+struct ltc2991_state {
+ struct device *dev;
+ struct regmap *regmap;
+ u32 r_sense_uohm[LTC2991_MAX_CHANNEL];
+ bool temp_en[LTC2991_MAX_CHANNEL];
+};
+
+static int ltc2991_read_reg(struct ltc2991_state *st, u8 addr, u8 reg_len,
+ int *val)
+{
+ __be16 regvals;
+ int ret;
+
+ if (reg_len < 2)
+ return regmap_read(st->regmap, addr, val);
+
+ ret = regmap_bulk_read(st->regmap, addr, &regvals, reg_len);
+ if (ret)
+ return ret;
+
+ *val = be16_to_cpu(regvals);
+
+ return 0;
+}
+
+static int ltc2991_get_voltage(struct ltc2991_state *st, u32 reg, long *val)
+{
+ int reg_val, ret, offset = 0;
+
+ ret = ltc2991_read_reg(st, reg, 2, &reg_val);
+ if (ret)
+ return ret;
+
+ if (reg == LTC2991_VCC_MSB)
+ /* Vcc 2.5V offset */
+ offset = 2500;
+
+ /* Vx, 305.18uV/LSB */
+ *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 14) * 30518,
+ 1000 * 100) + offset;
+
+ return 0;
+}
+
+static int ltc2991_read_in(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct ltc2991_state *st = dev_get_drvdata(dev);
+ u32 reg;
+
+ switch (attr) {
+ case hwmon_in_input:
+ if (channel == LTC2991_VCC_CH_NR)
+ reg = LTC2991_VCC_MSB;
+ else
+ reg = LTC2991_CHANNEL_V_MSB(channel - 1);
+
+ return ltc2991_get_voltage(st, reg, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ltc2991_get_curr(struct ltc2991_state *st, u32 reg, int channel,
+ long *val)
+{
+ int reg_val, ret;
+
+ ret = ltc2991_read_reg(st, reg, 2, &reg_val);
+ if (ret)
+ return ret;
+
+ /* Vx-Vy, 19.075uV/LSB */
+ *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 14) * 19075,
+ st->r_sense_uohm[channel]);
+
+ return 0;
+}
+
+static int ltc2991_read_curr(struct device *dev, u32 attr, int channel,
+ long *val)
+{
+ struct ltc2991_state *st = dev_get_drvdata(dev);
+ u32 reg;
+
+ switch (attr) {
+ case hwmon_curr_input:
+ reg = LTC2991_CHANNEL_C_MSB(channel);
+ return ltc2991_get_curr(st, reg, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ltc2991_get_temp(struct ltc2991_state *st, u32 reg, int channel,
+ long *val)
+{
+ int reg_val, ret;
+
+ ret = ltc2991_read_reg(st, reg, 2, &reg_val);
+ if (ret)
+ return ret;
+
+ /* Temp LSB = 0.0625 Degrees */
+ *val = DIV_ROUND_CLOSEST(sign_extend32(reg_val, 12) * 1000, 16);
+
+ return 0;
+}
+
+static int ltc2991_read_temp(struct device *dev, u32 attr, int channel,
+ long *val)
+{
+ struct ltc2991_state *st = dev_get_drvdata(dev);
+ u32 reg;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ if (channel == LTC2991_T_INT_CH_NR)
+ reg = LTC2991_T_INT_MSB;
+ else
+ reg = LTC2991_CHANNEL_T_MSB(channel);
+
+ return ltc2991_get_temp(st, reg, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int ltc2991_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ switch (type) {
+ case hwmon_in:
+ return ltc2991_read_in(dev, attr, channel, val);
+ case hwmon_curr:
+ return ltc2991_read_curr(dev, attr, channel, val);
+ case hwmon_temp:
+ return ltc2991_read_temp(dev, attr, channel, val);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static umode_t ltc2991_is_visible(const void *data,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ const struct ltc2991_state *st = data;
+
+ switch (type) {
+ case hwmon_in:
+ switch (attr) {
+ case hwmon_in_input:
+ if (channel == LTC2991_VCC_CH_NR)
+ return 0444;
+ if (st->temp_en[(channel - 1) / 2])
+ break;
+ if (channel % 2)
+ return 0444;
+ if (!st->r_sense_uohm[(channel - 1) / 2])
+ return 0444;
+ }
+ break;
+ case hwmon_curr:
+ switch (attr) {
+ case hwmon_curr_input:
+ if (st->r_sense_uohm[channel])
+ return 0444;
+ break;
+ }
+ break;
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_input:
+ if (st->temp_en[channel] ||
+ channel == LTC2991_T_INT_CH_NR)
+ return 0444;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const struct hwmon_ops ltc2991_hwmon_ops = {
+ .is_visible = ltc2991_is_visible,
+ .read = ltc2991_read,
+};
+
+static const struct hwmon_channel_info *ltc2991_info[] = {
+ HWMON_CHANNEL_INFO(temp,
+ HWMON_T_INPUT,
+ HWMON_T_INPUT,
+ HWMON_T_INPUT,
+ HWMON_T_INPUT,
+ HWMON_T_INPUT
+ ),
+ HWMON_CHANNEL_INFO(curr,
+ HWMON_C_INPUT,
+ HWMON_C_INPUT,
+ HWMON_C_INPUT,
+ HWMON_C_INPUT
+ ),
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT,
+ HWMON_I_INPUT
+ ),
+ NULL
+};
+
+static const struct hwmon_chip_info ltc2991_chip_info = {
+ .ops = &ltc2991_hwmon_ops,
+ .info = ltc2991_info,
+};
+
+static const struct regmap_config ltc2991_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x1D,
+};
+
+static int ltc2991_init(struct ltc2991_state *st)
+{
+ struct fwnode_handle *child;
+ int ret;
+ u32 val, addr;
+ u8 v5_v8_reg_data = 0, v1_v4_reg_data = 0;
+
+ ret = devm_regulator_get_enable(st->dev, "vcc");
+ if (ret)
+ return dev_err_probe(st->dev, ret,
+ "failed to enable regulator\n");
+
+ device_for_each_child_node(st->dev, child) {
+ ret = fwnode_property_read_u32(child, "reg", &addr);
+ if (ret < 0) {
+ fwnode_handle_put(child);
+ return ret;
+ }
+
+ if (addr > 3) {
+ fwnode_handle_put(child);
+ return -EINVAL;
+ }
+
+ ret = fwnode_property_read_u32(child,
+ "shunt-resistor-micro-ohms",
+ &val);
+ if (!ret) {
+ if (!val)
+ return dev_err_probe(st->dev, -EINVAL,
+ "shunt resistor value cannot be zero\n");
+
+ st->r_sense_uohm[addr] = val;
+
+ switch (addr) {
+ case 0:
+ v1_v4_reg_data |= LTC2991_V1_V2_DIFF_EN;
+ break;
+ case 1:
+ v1_v4_reg_data |= LTC2991_V3_V4_DIFF_EN;
+ break;
+ case 2:
+ v5_v8_reg_data |= LTC2991_V5_V6_DIFF_EN;
+ break;
+ case 3:
+ v5_v8_reg_data |= LTC2991_V7_V8_DIFF_EN;
+ break;
+ default:
+ break;
+ }
+ }
+
+ ret = fwnode_property_read_bool(child,
+ "adi,temperature-enable");
+ if (ret) {
+ st->temp_en[addr] = ret;
+
+ switch (addr) {
+ case 0:
+ v1_v4_reg_data |= LTC2991_V1_V2_TEMP_EN;
+ break;
+ case 1:
+ v1_v4_reg_data |= LTC2991_V3_V4_TEMP_EN;
+ break;
+ case 2:
+ v5_v8_reg_data |= LTC2991_V5_V6_TEMP_EN;
+ break;
+ case 3:
+ v5_v8_reg_data |= LTC2991_V7_V8_TEMP_EN;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ ret = regmap_write(st->regmap, LTC2991_V5_V8_CTRL, v5_v8_reg_data);
+ if (ret)
+ return dev_err_probe(st->dev, ret,
+ "Error: Failed to set V5-V8 CTRL reg.\n");
+
+ ret = regmap_write(st->regmap, LTC2991_V1_V4_CTRL, v1_v4_reg_data);
+ if (ret)
+ return dev_err_probe(st->dev, ret,
+ "Error: Failed to set V1-V4 CTRL reg.\n");
+
+ ret = regmap_write(st->regmap, LTC2991_PWM_TH_LSB_T_INT,
+ LTC2991_REPEAT_ACQ_EN);
+ if (ret)
+ return dev_err_probe(st->dev, ret,
+ "Error: Failed to set continuous mode.\n");
+
+ /* Enable all channels and trigger conversions */
+ return regmap_write(st->regmap, LTC2991_CH_EN_TRIGGER,
+ LTC2991_V7_V8_EN | LTC2991_V5_V6_EN |
+ LTC2991_V3_V4_EN | LTC2991_V1_V2_EN |
+ LTC2991_T_INT_VCC_EN);
+}
+
+static int ltc2991_i2c_probe(struct i2c_client *client)
+{
+ int ret;
+ struct device *hwmon_dev;
+ struct ltc2991_state *st;
+
+ st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->dev = &client->dev;
+ st->regmap = devm_regmap_init_i2c(client, &ltc2991_regmap_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
+
+ ret = ltc2991_init(st);
+ if (ret)
+ return ret;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
+ client->name, st,
+ &ltc2991_chip_info,
+ NULL);
+
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct of_device_id ltc2991_of_match[] = {
+ { .compatible = "adi,ltc2991" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ltc2991_of_match);
+
+static const struct i2c_device_id ltc2991_i2c_id[] = {
+ { "ltc2991", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ltc2991_i2c_id);
+
+static struct i2c_driver ltc2991_i2c_driver = {
+ .driver = {
+ .name = "ltc2991",
+ .of_match_table = ltc2991_of_match,
+ },
+ .probe = ltc2991_i2c_probe,
+ .id_table = ltc2991_i2c_id,
+};
+
+module_i2c_driver(ltc2991_i2c_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
+MODULE_DESCRIPTION("Analog Devices LTC2991 HWMON Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c
index 589bcd07ce..001799bc28 100644
--- a/drivers/hwmon/ltc2992.c
+++ b/drivers/hwmon/ltc2992.c
@@ -875,8 +875,12 @@ static int ltc2992_parse_dt(struct ltc2992_state *st)
}
ret = fwnode_property_read_u32(child, "shunt-resistor-micro-ohms", &val);
- if (!ret)
+ if (!ret) {
+ if (!val)
+ return dev_err_probe(&st->client->dev, -EINVAL,
+ "shunt resistor value cannot be zero\n");
st->r_sense_uohm[addr] = val;
+ }
}
return 0;
diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c
index 56add579e3..bb30403f81 100644
--- a/drivers/hwmon/max197.c
+++ b/drivers/hwmon/max197.c
@@ -312,14 +312,12 @@ error:
return ret;
}
-static int max197_remove(struct platform_device *pdev)
+static void max197_remove(struct platform_device *pdev)
{
struct max197_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);
-
- return 0;
}
static const struct platform_device_id max197_device_ids[] = {
@@ -334,7 +332,7 @@ static struct platform_driver max197_driver = {
.name = "max197",
},
.probe = max197_probe,
- .remove = max197_remove,
+ .remove_new = max197_remove,
.id_table = max197_device_ids,
};
module_platform_driver(max197_driver);
diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c
index 602f4e4f81..a1ce651456 100644
--- a/drivers/hwmon/max31827.c
+++ b/drivers/hwmon/max31827.c
@@ -12,6 +12,7 @@
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#define MAX31827_T_REG 0x0
#define MAX31827_CONFIGURATION_REG 0x2
@@ -25,20 +26,32 @@
#define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK BIT(14)
#define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK BIT(15)
-#define MAX31827_12_BIT_CNV_TIME 141
-
-#define MAX31827_CNV_1_DIV_64_HZ 0x1
-#define MAX31827_CNV_1_DIV_32_HZ 0x2
-#define MAX31827_CNV_1_DIV_16_HZ 0x3
-#define MAX31827_CNV_1_DIV_4_HZ 0x4
-#define MAX31827_CNV_1_HZ 0x5
-#define MAX31827_CNV_4_HZ 0x6
-#define MAX31827_CNV_8_HZ 0x7
+#define MAX31827_12_BIT_CNV_TIME 140
#define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16)
#define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000)
#define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0)
+enum max31827_cnv {
+ MAX31827_CNV_1_DIV_64_HZ = 1,
+ MAX31827_CNV_1_DIV_32_HZ,
+ MAX31827_CNV_1_DIV_16_HZ,
+ MAX31827_CNV_1_DIV_4_HZ,
+ MAX31827_CNV_1_HZ,
+ MAX31827_CNV_4_HZ,
+ MAX31827_CNV_8_HZ,
+};
+
+static const u16 max31827_conversions[] = {
+ [MAX31827_CNV_1_DIV_64_HZ] = 64000,
+ [MAX31827_CNV_1_DIV_32_HZ] = 32000,
+ [MAX31827_CNV_1_DIV_16_HZ] = 16000,
+ [MAX31827_CNV_1_DIV_4_HZ] = 4000,
+ [MAX31827_CNV_1_HZ] = 1000,
+ [MAX31827_CNV_4_HZ] = 250,
+ [MAX31827_CNV_8_HZ] = 125,
+};
+
struct max31827_state {
/*
* Prevent simultaneous access to the i2c client.
@@ -54,15 +67,13 @@ static const struct regmap_config max31827_regmap = {
.max_register = 0xA,
};
-static int write_alarm_val(struct max31827_state *st, unsigned int reg,
- long val)
+static int shutdown_write(struct max31827_state *st, unsigned int reg,
+ unsigned int val)
{
unsigned int cfg;
- unsigned int tmp;
+ unsigned int cnv_rate;
int ret;
- val = MAX31827_M_DGR_TO_16_BIT(val);
-
/*
* Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold
* register values are changed over I2C, the part must be in shutdown
@@ -82,9 +93,10 @@ static int write_alarm_val(struct max31827_state *st, unsigned int reg,
if (ret)
goto unlock;
- tmp = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK |
+ 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, tmp);
+ ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
if (ret)
goto unlock;
@@ -92,13 +104,23 @@ static int write_alarm_val(struct max31827_state *st, unsigned int reg,
if (ret)
goto unlock;
- ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
+ ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
+ MAX31827_CONFIGURATION_CNV_RATE_MASK,
+ cnv_rate);
unlock:
mutex_unlock(&st->lock);
return ret;
}
+static int write_alarm_val(struct max31827_state *st, unsigned int reg,
+ long val)
+{
+ val = MAX31827_M_DGR_TO_16_BIT(val);
+
+ return shutdown_write(st, reg, val);
+}
+
static umode_t max31827_is_visible(const void *state,
enum hwmon_sensor_types type, u32 attr,
int channel)
@@ -243,32 +265,7 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK,
uval);
- switch (uval) {
- case MAX31827_CNV_1_DIV_64_HZ:
- *val = 64000;
- break;
- case MAX31827_CNV_1_DIV_32_HZ:
- *val = 32000;
- break;
- case MAX31827_CNV_1_DIV_16_HZ:
- *val = 16000;
- break;
- case MAX31827_CNV_1_DIV_4_HZ:
- *val = 4000;
- break;
- case MAX31827_CNV_1_HZ:
- *val = 1000;
- break;
- case MAX31827_CNV_4_HZ:
- *val = 250;
- break;
- case MAX31827_CNV_8_HZ:
- *val = 125;
- break;
- default:
- *val = 0;
- break;
- }
+ *val = max31827_conversions[uval];
}
break;
@@ -284,6 +281,7 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
struct max31827_state *st = dev_get_drvdata(dev);
+ int res = 1;
int ret;
switch (type) {
@@ -333,39 +331,27 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
if (!st->enable)
return -EINVAL;
- switch (val) {
- case 125:
- val = MAX31827_CNV_8_HZ;
- break;
- case 250:
- val = MAX31827_CNV_4_HZ;
- break;
- case 1000:
- val = MAX31827_CNV_1_HZ;
- break;
- case 4000:
- val = MAX31827_CNV_1_DIV_4_HZ;
- break;
- case 16000:
- val = MAX31827_CNV_1_DIV_16_HZ;
- break;
- case 32000:
- val = MAX31827_CNV_1_DIV_32_HZ;
- break;
- case 64000:
- val = MAX31827_CNV_1_DIV_64_HZ;
- break;
- default:
+ /*
+ * Convert the desired conversion rate into register
+ * bits. res is already initialized with 1.
+ *
+ * This was inspired by lm73 driver.
+ */
+ while (res < ARRAY_SIZE(max31827_conversions) &&
+ val < max31827_conversions[res])
+ res++;
+
+ if (res == ARRAY_SIZE(max31827_conversions) ||
+ val != max31827_conversions[res])
return -EINVAL;
- }
- val = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
- val);
+ res = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
+ res);
return regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_CNV_RATE_MASK,
- val);
+ res);
}
break;
@@ -427,6 +413,10 @@ static int max31827_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(st->regmap),
"Failed to allocate regmap.\n");
+ err = devm_regulator_get_enable(dev, "vref");
+ if (err)
+ return dev_err_probe(dev, err, "failed to enable regulator\n");
+
err = max31827_init_client(st);
if (err)
return err;
diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c
index ff147e5e1b..67471c9cd4 100644
--- a/drivers/hwmon/mc13783-adc.c
+++ b/drivers/hwmon/mc13783-adc.c
@@ -285,7 +285,7 @@ out_err_create_16chans:
return ret;
}
-static int mc13783_adc_remove(struct platform_device *pdev)
+static void mc13783_adc_remove(struct platform_device *pdev)
{
struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
@@ -299,8 +299,6 @@ static int mc13783_adc_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
-
- return 0;
}
static const struct platform_device_id mc13783_adc_idtable[] = {
@@ -317,7 +315,7 @@ static const struct platform_device_id mc13783_adc_idtable[] = {
MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
static struct platform_driver mc13783_adc_driver = {
- .remove = mc13783_adc_remove,
+ .remove_new = mc13783_adc_remove,
.driver = {
.name = DRIVER_NAME,
},
diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c
index f673f7d079..3f3f7a8841 100644
--- a/drivers/hwmon/nct6683.c
+++ b/drivers/hwmon/nct6683.c
@@ -176,6 +176,7 @@ superio_exit(int ioreg)
#define NCT6683_CUSTOMER_ID_MSI2 0x200
#define NCT6683_CUSTOMER_ID_ASROCK 0xe2c
#define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b
+#define NCT6683_CUSTOMER_ID_ASROCK3 0x1631
#define NCT6683_REG_BUILD_YEAR 0x604
#define NCT6683_REG_BUILD_MONTH 0x605
@@ -1227,6 +1228,8 @@ static int nct6683_probe(struct platform_device *pdev)
break;
case NCT6683_CUSTOMER_ID_ASROCK2:
break;
+ case NCT6683_CUSTOMER_ID_ASROCK3:
+ break;
default:
if (!force)
return -ENODEV;
diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c
index d928eb8ae5..f3bf2e4701 100644
--- a/drivers/hwmon/nct6775-core.c
+++ b/drivers/hwmon/nct6775-core.c
@@ -2553,6 +2553,13 @@ store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
int err;
u16 reg;
+ /*
+ * The fan control mode should be set to manual if the user wants to adjust
+ * the fan speed. Otherwise, it will fail to set.
+ */
+ if (index == 0 && data->pwm_enable[nr] > manual)
+ return -EBUSY;
+
err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
@@ -3505,6 +3512,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit;
const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL;
int num_reg_temp, num_reg_temp_mon, num_reg_tsi_temp;
+ int num_reg_temp_config;
struct device *hwmon_dev;
struct sensor_template_group tsi_temp_tg;
@@ -3587,6 +3595,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_over = NCT6106_REG_TEMP_OVER;
reg_temp_hyst = NCT6106_REG_TEMP_HYST;
reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+ num_reg_temp_config = ARRAY_SIZE(NCT6106_REG_TEMP_CONFIG);
reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6106_REG_TEMP_CRIT;
reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
@@ -3662,6 +3671,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_over = NCT6106_REG_TEMP_OVER;
reg_temp_hyst = NCT6106_REG_TEMP_HYST;
reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+ num_reg_temp_config = ARRAY_SIZE(NCT6106_REG_TEMP_CONFIG);
reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6106_REG_TEMP_CRIT;
reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
@@ -3739,6 +3749,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_over = NCT6775_REG_TEMP_OVER;
reg_temp_hyst = NCT6775_REG_TEMP_HYST;
reg_temp_config = NCT6775_REG_TEMP_CONFIG;
+ num_reg_temp_config = ARRAY_SIZE(NCT6775_REG_TEMP_CONFIG);
reg_temp_alternate = NCT6775_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6775_REG_TEMP_CRIT;
@@ -3814,6 +3825,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_over = NCT6775_REG_TEMP_OVER;
reg_temp_hyst = NCT6775_REG_TEMP_HYST;
reg_temp_config = NCT6776_REG_TEMP_CONFIG;
+ num_reg_temp_config = ARRAY_SIZE(NCT6776_REG_TEMP_CONFIG);
reg_temp_alternate = NCT6776_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6776_REG_TEMP_CRIT;
@@ -3893,6 +3905,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_over = NCT6779_REG_TEMP_OVER;
reg_temp_hyst = NCT6779_REG_TEMP_HYST;
reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+ num_reg_temp_config = ARRAY_SIZE(NCT6779_REG_TEMP_CONFIG);
reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6779_REG_TEMP_CRIT;
@@ -4027,6 +4040,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_over = NCT6779_REG_TEMP_OVER;
reg_temp_hyst = NCT6779_REG_TEMP_HYST;
reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+ num_reg_temp_config = ARRAY_SIZE(NCT6779_REG_TEMP_CONFIG);
reg_temp_alternate = NCT6779_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6779_REG_TEMP_CRIT;
@@ -4116,6 +4130,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
reg_temp_over = NCT6798_REG_TEMP_OVER;
reg_temp_hyst = NCT6798_REG_TEMP_HYST;
reg_temp_config = NCT6779_REG_TEMP_CONFIG;
+ num_reg_temp_config = ARRAY_SIZE(NCT6779_REG_TEMP_CONFIG);
reg_temp_alternate = NCT6798_REG_TEMP_ALTERNATE;
reg_temp_crit = NCT6798_REG_TEMP_CRIT;
@@ -4197,7 +4212,8 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
= reg_temp_crit[src - 1];
if (reg_temp_crit_l && reg_temp_crit_l[i])
data->reg_temp[4][src - 1] = reg_temp_crit_l[i];
- data->reg_temp_config[src - 1] = reg_temp_config[i];
+ if (i < num_reg_temp_config)
+ data->reg_temp_config[src - 1] = reg_temp_config[i];
data->temp_src[src - 1] = src;
continue;
}
@@ -4210,7 +4226,8 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
data->reg_temp[0][s] = reg_temp[i];
data->reg_temp[1][s] = reg_temp_over[i];
data->reg_temp[2][s] = reg_temp_hyst[i];
- data->reg_temp_config[s] = reg_temp_config[i];
+ if (i < num_reg_temp_config)
+ data->reg_temp_config[s] = reg_temp_config[i];
if (reg_temp_crit_h && reg_temp_crit_h[i])
data->reg_temp[3][s] = reg_temp_crit_h[i];
else if (reg_temp_crit[src - 1])
diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c
index 81bf03dad6..0adeeab7ee 100644
--- a/drivers/hwmon/nct6775-platform.c
+++ b/drivers/hwmon/nct6775-platform.c
@@ -1465,10 +1465,8 @@ static const char * const asus_msi_boards[] = {
static int nct6775_asuswmi_device_match(struct device *dev, void *data)
{
struct acpi_device *adev = to_acpi_device(dev);
- const char *uid = acpi_device_uid(adev);
- const char *hid = acpi_device_hid(adev);
- if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) {
+ if (acpi_dev_hid_uid_match(adev, ASUSWMI_DEVICE_HID, data)) {
asus_acpi_dev = adev;
return 1;
}
diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c
index 10ed3f4335..4702e4edc6 100644
--- a/drivers/hwmon/npcm750-pwm-fan.c
+++ b/drivers/hwmon/npcm750-pwm-fan.c
@@ -875,6 +875,8 @@ static int npcm7xx_en_pwm_fan(struct device *dev,
data->pwm_present[pwm_port] = true;
ret = npcm7xx_pwm_config_set(data, pwm_port,
NPCM7XX_PWM_CMR_DEFAULT_NUM);
+ if (ret)
+ return ret;
ret = of_property_count_u8_elems(child, "cooling-levels");
if (ret > 0) {
diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c
index 96521363b6..b5993c79c0 100644
--- a/drivers/hwmon/occ/p9_sbe.c
+++ b/drivers/hwmon/occ/p9_sbe.c
@@ -167,7 +167,7 @@ static int p9_sbe_occ_probe(struct platform_device *pdev)
return rc;
}
-static int p9_sbe_occ_remove(struct platform_device *pdev)
+static void p9_sbe_occ_remove(struct platform_device *pdev)
{
struct occ *occ = platform_get_drvdata(pdev);
struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);
@@ -178,8 +178,6 @@ static int p9_sbe_occ_remove(struct platform_device *pdev)
occ_shutdown(occ);
kvfree(ctx->ffdc);
-
- return 0;
}
static const struct of_device_id p9_sbe_occ_of_match[] = {
@@ -195,7 +193,7 @@ static struct platform_driver p9_sbe_occ_driver = {
.of_match_table = p9_sbe_occ_of_match,
},
.probe = p9_sbe_occ_probe,
- .remove = p9_sbe_occ_remove,
+ .remove_new = p9_sbe_occ_remove,
};
module_platform_driver(p9_sbe_occ_driver);
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index a4adc8bd53..926ea1fe13 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1586,14 +1586,12 @@ error:
return err;
}
-static int pc87360_remove(struct platform_device *pdev)
+static void pc87360_remove(struct platform_device *pdev)
{
struct pc87360_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
pc87360_remove_files(&pdev->dev);
-
- return 0;
}
/*
@@ -1604,7 +1602,7 @@ static struct platform_driver pc87360_driver = {
.name = DRIVER_NAME,
},
.probe = pc87360_probe,
- .remove = pc87360_remove,
+ .remove_new = pc87360_remove,
};
/*
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index eaab83d879..7bca04eb4e 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -1115,14 +1115,12 @@ exit_remove_files:
return err;
}
-static int pc87427_remove(struct platform_device *pdev)
+static void pc87427_remove(struct platform_device *pdev)
{
struct pc87427_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
pc87427_remove_files(&pdev->dev);
-
- return 0;
}
@@ -1131,7 +1129,7 @@ static struct platform_driver pc87427_driver = {
.name = DRVNAME,
},
.probe = pc87427_probe,
- .remove = pc87427_remove,
+ .remove_new = pc87427_remove,
};
static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data)
diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c
index f9aa576495..5d13bbfc8f 100644
--- a/drivers/hwmon/pmbus/max31785.c
+++ b/drivers/hwmon/pmbus/max31785.c
@@ -3,6 +3,7 @@
* Copyright (C) 2017 IBM Corp.
*/
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -23,19 +24,119 @@ enum max31785_regs {
#define MAX31785_NR_PAGES 23
#define MAX31785_NR_FAN_PAGES 6
+#define MAX31785_WAIT_DELAY_US 250
-static int max31785_read_byte_data(struct i2c_client *client, int page,
- int reg)
+struct max31785_data {
+ ktime_t access; /* Chip access time */
+ struct pmbus_driver_info info;
+};
+
+#define to_max31785_data(x) container_of(x, struct max31785_data, info)
+
+/*
+ * MAX31785 Driver Workaround
+ *
+ * The MAX31785 fan controller occasionally exhibits communication issues.
+ * These issues are not indicated by the device itself, except for occasional
+ * NACK responses during master transactions. No error bits are set in STATUS_BYTE.
+ *
+ * To address this, we introduce a delay of 250us between consecutive accesses
+ * to the fan controller. This delay helps mitigate communication problems by
+ * allowing sufficient time between accesses.
+ */
+static inline void max31785_wait(const struct max31785_data *data)
{
- if (page < MAX31785_NR_PAGES)
- return -ENODATA;
+ s64 delta = ktime_us_delta(ktime_get(), data->access);
+
+ if (delta < MAX31785_WAIT_DELAY_US)
+ usleep_range(MAX31785_WAIT_DELAY_US - delta,
+ MAX31785_WAIT_DELAY_US);
+}
+
+static int max31785_i2c_write_byte_data(struct i2c_client *client,
+ struct max31785_data *driver_data,
+ int command, u16 data)
+{
+ int rc;
+
+ max31785_wait(driver_data);
+ rc = i2c_smbus_write_byte_data(client, command, data);
+ driver_data->access = ktime_get();
+ return rc;
+}
+
+static int max31785_i2c_read_word_data(struct i2c_client *client,
+ struct max31785_data *driver_data,
+ int command)
+{
+ int rc;
+
+ max31785_wait(driver_data);
+ rc = i2c_smbus_read_word_data(client, command);
+ driver_data->access = ktime_get();
+ return rc;
+}
+
+static int _max31785_read_byte_data(struct i2c_client *client,
+ struct max31785_data *driver_data,
+ int page, int command)
+{
+ int rc;
+
+ max31785_wait(driver_data);
+ rc = pmbus_read_byte_data(client, page, command);
+ driver_data->access = ktime_get();
+ return rc;
+}
+
+static int _max31785_write_byte_data(struct i2c_client *client,
+ struct max31785_data *driver_data,
+ int page, int command, u16 data)
+{
+ int rc;
+
+ max31785_wait(driver_data);
+ rc = pmbus_write_byte_data(client, page, command, data);
+ driver_data->access = ktime_get();
+ return rc;
+}
+
+static int _max31785_read_word_data(struct i2c_client *client,
+ struct max31785_data *driver_data,
+ int page, int phase, int command)
+{
+ int rc;
+
+ max31785_wait(driver_data);
+ rc = pmbus_read_word_data(client, page, phase, command);
+ driver_data->access = ktime_get();
+ return rc;
+}
+
+static int _max31785_write_word_data(struct i2c_client *client,
+ struct max31785_data *driver_data,
+ int page, int command, u16 data)
+{
+ int rc;
+
+ max31785_wait(driver_data);
+ rc = pmbus_write_word_data(client, page, command, data);
+ driver_data->access = ktime_get();
+ return rc;
+}
+
+static int max31785_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct max31785_data *driver_data = to_max31785_data(info);
switch (reg) {
case PMBUS_VOUT_MODE:
return -ENOTSUPP;
case PMBUS_FAN_CONFIG_12:
- return pmbus_read_byte_data(client, page - MAX31785_NR_PAGES,
- reg);
+ return _max31785_read_byte_data(client, driver_data,
+ page - MAX31785_NR_PAGES,
+ reg);
}
return -ENODATA;
@@ -102,16 +203,19 @@ static int max31785_get_pwm(struct i2c_client *client, int page)
return rv;
}
-static int max31785_get_pwm_mode(struct i2c_client *client, int page)
+static int max31785_get_pwm_mode(struct i2c_client *client,
+ struct max31785_data *driver_data, int page)
{
int config;
int command;
- config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
+ config = _max31785_read_byte_data(client, driver_data, page,
+ PMBUS_FAN_CONFIG_12);
if (config < 0)
return config;
- command = pmbus_read_word_data(client, page, 0xff, PMBUS_FAN_COMMAND_1);
+ command = _max31785_read_word_data(client, driver_data, page, 0xff,
+ PMBUS_FAN_COMMAND_1);
if (command < 0)
return command;
@@ -129,6 +233,8 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page)
static int max31785_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 max31785_data *driver_data = to_max31785_data(info);
u32 val;
int rv;
@@ -157,7 +263,7 @@ static int max31785_read_word_data(struct i2c_client *client, int page,
rv = max31785_get_pwm(client, page);
break;
case PMBUS_VIRT_PWM_ENABLE_1:
- rv = max31785_get_pwm_mode(client, page);
+ rv = max31785_get_pwm_mode(client, driver_data, page);
break;
default:
rv = -ENODATA;
@@ -188,8 +294,36 @@ static inline u32 max31785_scale_pwm(u32 sensor_val)
return (sensor_val * 100) / 255;
}
-static int max31785_pwm_enable(struct i2c_client *client, int page,
- u16 word)
+static int max31785_update_fan(struct i2c_client *client,
+ struct max31785_data *driver_data, int page,
+ u8 config, u8 mask, u16 command)
+{
+ int from, rv;
+ u8 to;
+
+ from = _max31785_read_byte_data(client, driver_data, page,
+ PMBUS_FAN_CONFIG_12);
+ if (from < 0)
+ return from;
+
+ to = (from & ~mask) | (config & mask);
+
+ if (to != from) {
+ rv = _max31785_write_byte_data(client, driver_data, page,
+ PMBUS_FAN_CONFIG_12, to);
+ if (rv < 0)
+ return rv;
+ }
+
+ rv = _max31785_write_word_data(client, driver_data, page,
+ PMBUS_FAN_COMMAND_1, command);
+
+ return rv;
+}
+
+static int max31785_pwm_enable(struct i2c_client *client,
+ struct max31785_data *driver_data, int page,
+ u16 word)
{
int config = 0;
int rate;
@@ -217,18 +351,23 @@ static int max31785_pwm_enable(struct i2c_client *client, int page,
return -EINVAL;
}
- return pmbus_update_fan(client, page, 0, config, PB_FAN_1_RPM, rate);
+ return max31785_update_fan(client, driver_data, page, config,
+ PB_FAN_1_RPM, rate);
}
static int max31785_write_word_data(struct i2c_client *client, int page,
int reg, u16 word)
{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct max31785_data *driver_data = to_max31785_data(info);
+
switch (reg) {
case PMBUS_VIRT_PWM_1:
- return pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM,
- max31785_scale_pwm(word));
+ return max31785_update_fan(client, driver_data, page, 0,
+ PB_FAN_1_RPM,
+ max31785_scale_pwm(word));
case PMBUS_VIRT_PWM_ENABLE_1:
- return max31785_pwm_enable(client, page, word);
+ return max31785_pwm_enable(client, driver_data, page, word);
default:
break;
}
@@ -303,13 +442,16 @@ static int max31785_configure_dual_tach(struct i2c_client *client,
{
int ret;
int i;
+ struct max31785_data *driver_data = to_max31785_data(info);
for (i = 0; i < MAX31785_NR_FAN_PAGES; i++) {
- ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
+ ret = max31785_i2c_write_byte_data(client, driver_data,
+ PMBUS_PAGE, i);
if (ret < 0)
return ret;
- ret = i2c_smbus_read_word_data(client, MFR_FAN_CONFIG);
+ ret = max31785_i2c_read_word_data(client, driver_data,
+ MFR_FAN_CONFIG);
if (ret < 0)
return ret;
@@ -329,6 +471,7 @@ static int max31785_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct pmbus_driver_info *info;
+ struct max31785_data *driver_data;
bool dual_tach = false;
int ret;
@@ -337,13 +480,16 @@ static int max31785_probe(struct i2c_client *client)
I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
- info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL);
- if (!info)
+ driver_data = devm_kzalloc(dev, sizeof(struct max31785_data), GFP_KERNEL);
+ if (!driver_data)
return -ENOMEM;
+ info = &driver_data->info;
+ driver_data->access = ktime_get();
*info = max31785_info;
- ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
+ ret = max31785_i2c_write_byte_data(client, driver_data,
+ PMBUS_PAGE, 255);
if (ret < 0)
return ret;
diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c
index 6c62f01da7..67487867c7 100644
--- a/drivers/hwmon/pmbus/mpq7932.c
+++ b/drivers/hwmon/pmbus/mpq7932.c
@@ -21,6 +21,7 @@
#define MPQ7932_N_VOLTAGES 256
#define MPQ7932_VOUT_MAX 0xFF
#define MPQ7932_NUM_PAGES 6
+#define MPQ2286_NUM_PAGES 1
#define MPQ7932_TON_DELAY 0x60
#define MPQ7932_VOUT_STARTUP_SLEW 0xA3
@@ -48,6 +49,11 @@ static struct regulator_desc mpq7932_regulators_desc[] = {
PMBUS_REGULATOR_STEP("buck", 5, MPQ7932_N_VOLTAGES,
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
};
+
+static const struct regulator_desc mpq7932_regulators_desc_one[] = {
+ PMBUS_REGULATOR_STEP_ONE("buck", MPQ7932_N_VOLTAGES,
+ MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
+};
#endif
static int mpq7932_write_word_data(struct i2c_client *client, int page, int reg,
@@ -105,7 +111,7 @@ static int mpq7932_probe(struct i2c_client *client)
return -ENOMEM;
info = &data->info;
- info->pages = MPQ7932_NUM_PAGES;
+ info->pages = (int)(unsigned long)device_get_match_data(&client->dev);
info->format[PSC_VOLTAGE_OUT] = direct;
info->m[PSC_VOLTAGE_OUT] = 160;
info->b[PSC_VOLTAGE_OUT] = -33;
@@ -115,8 +121,11 @@ static int mpq7932_probe(struct i2c_client *client)
}
#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
- info->num_regulators = ARRAY_SIZE(mpq7932_regulators_desc);
- info->reg_desc = mpq7932_regulators_desc;
+ info->num_regulators = info->pages;
+ if (info->num_regulators == 1)
+ info->reg_desc = mpq7932_regulators_desc_one;
+ else
+ info->reg_desc = mpq7932_regulators_desc;
#endif
info->read_word_data = mpq7932_read_word_data;
@@ -129,12 +138,14 @@ static int mpq7932_probe(struct i2c_client *client)
}
static const struct of_device_id mpq7932_of_match[] = {
- { .compatible = "mps,mpq7932"},
+ { .compatible = "mps,mpq2286", .data = (void *)MPQ2286_NUM_PAGES },
+ { .compatible = "mps,mpq7932", .data = (void *)MPQ7932_NUM_PAGES },
{},
};
MODULE_DEVICE_TABLE(of, mpq7932_of_match);
static const struct i2c_device_id mpq7932_id[] = {
+ { "mpq2286", },
{ "mpq7932", },
{ },
};
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index b0832a4c69..fb442fae7b 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -244,6 +244,15 @@ enum pmbus_regs {
#define PB_OPERATION_CONTROL_ON BIT(7)
/*
+ * ON_OFF_CONFIG
+ */
+#define PB_ON_OFF_CONFIG_POWERUP_CONTROL BIT(4)
+#define PB_ON_OFF_CONFIG_OPERATION_REQ BIT(3)
+#define PB_ON_OFF_CONFIG_EN_PIN_REQ BIT(2)
+#define PB_ON_OFF_CONFIG_POLARITY_HIGH BIT(1)
+#define PB_ON_OFF_CONFIG_TURN_OFF_FAST BIT(0)
+
+/*
* WRITE_PROTECT
*/
#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */
@@ -480,6 +489,21 @@ extern const struct regulator_ops pmbus_regulator_ops;
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0)
+#define PMBUS_REGULATOR_STEP_ONE(_name, _voltages, _step, _min_uV) \
+ { \
+ .name = (_name), \
+ .of_match = of_match_ptr(_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &pmbus_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .n_voltages = _voltages, \
+ .uV_step = _step, \
+ .min_uV = _min_uV, \
+ }
+
+#define PMBUS_REGULATOR_ONE(_name) PMBUS_REGULATOR_STEP_ONE(_name, 0, 0, 0)
+
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
diff --git a/drivers/hwmon/pmbus/tda38640.c b/drivers/hwmon/pmbus/tda38640.c
index 450b0273fb..09cd114b17 100644
--- a/drivers/hwmon/pmbus/tda38640.c
+++ b/drivers/hwmon/pmbus/tda38640.c
@@ -18,6 +18,127 @@ static const struct regulator_desc __maybe_unused tda38640_reg_desc[] = {
PMBUS_REGULATOR("vout", 0),
};
+struct tda38640_data {
+ struct pmbus_driver_info info;
+ u32 en_pin_lvl;
+};
+
+#define to_tda38640_data(x) container_of(x, struct tda38640_data, info)
+
+/*
+ * Map PB_ON_OFF_CONFIG_POLARITY_HIGH to PB_OPERATION_CONTROL_ON.
+ */
+static int tda38640_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct tda38640_data *data = to_tda38640_data(info);
+ int ret, on_off_config, enabled;
+
+ if (reg != PMBUS_OPERATION)
+ return -ENODATA;
+
+ ret = pmbus_read_byte_data(client, page, reg);
+ if (ret < 0)
+ return ret;
+
+ on_off_config = pmbus_read_byte_data(client, page,
+ PMBUS_ON_OFF_CONFIG);
+ if (on_off_config < 0)
+ return on_off_config;
+
+ enabled = !!(on_off_config & PB_ON_OFF_CONFIG_POLARITY_HIGH);
+
+ enabled ^= data->en_pin_lvl;
+ if (enabled)
+ ret &= ~PB_OPERATION_CONTROL_ON;
+ else
+ ret |= PB_OPERATION_CONTROL_ON;
+
+ return ret;
+}
+
+/*
+ * Map PB_OPERATION_CONTROL_ON to PB_ON_OFF_CONFIG_POLARITY_HIGH.
+ */
+static int tda38640_write_byte_data(struct i2c_client *client, int page,
+ int reg, u8 byte)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct tda38640_data *data = to_tda38640_data(info);
+ int enable, ret;
+
+ if (reg != PMBUS_OPERATION)
+ return -ENODATA;
+
+ enable = !!(byte & PB_OPERATION_CONTROL_ON);
+
+ byte &= ~PB_OPERATION_CONTROL_ON;
+ ret = pmbus_write_byte_data(client, page, reg, byte);
+ if (ret < 0)
+ return ret;
+
+ enable ^= data->en_pin_lvl;
+
+ return pmbus_update_byte_data(client, page, PMBUS_ON_OFF_CONFIG,
+ PB_ON_OFF_CONFIG_POLARITY_HIGH,
+ enable ? 0 : PB_ON_OFF_CONFIG_POLARITY_HIGH);
+}
+
+static int svid_mode(struct i2c_client *client, struct tda38640_data *data)
+{
+ /* PMBUS_MFR_READ(0xD0) + MTP Address offset */
+ u8 write_buf[] = {0xd0, 0x44, 0x00};
+ u8 read_buf[2];
+ int ret, svid;
+ bool off, reg_en_pin_pol;
+
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = write_buf,
+ .len = sizeof(write_buf),
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .buf = read_buf,
+ .len = sizeof(read_buf),
+ }
+ };
+
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c_transfer failed. %d", ret);
+ return ret;
+ }
+
+ /*
+ * 0x44[15] determines PMBus Operating Mode
+ * If bit is set then it is SVID mode.
+ */
+ svid = !!(read_buf[1] & BIT(7));
+
+ /*
+ * Determine EN pin level for use in SVID mode.
+ * This is done with help of STATUS_BYTE bit 6(OFF) & ON_OFF_CONFIG bit 2(EN pin polarity).
+ */
+ if (svid) {
+ ret = i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE);
+ if (ret < 0)
+ return ret;
+ off = !!(ret & PB_STATUS_OFF);
+
+ ret = i2c_smbus_read_byte_data(client, PMBUS_ON_OFF_CONFIG);
+ if (ret < 0)
+ return ret;
+ reg_en_pin_pol = !!(ret & PB_ON_OFF_CONFIG_POLARITY_HIGH);
+ data->en_pin_lvl = off ^ reg_en_pin_pol;
+ }
+
+ return svid;
+}
+
static struct pmbus_driver_info tda38640_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
@@ -26,7 +147,6 @@ static struct pmbus_driver_info tda38640_info = {
.format[PSC_CURRENT_IN] = linear,
.format[PSC_POWER] = linear,
.format[PSC_TEMPERATURE] = linear,
-
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_IIN
@@ -41,7 +161,37 @@ static struct pmbus_driver_info tda38640_info = {
static int tda38640_probe(struct i2c_client *client)
{
- return pmbus_do_probe(client, &tda38640_info);
+ struct tda38640_data *data;
+ int svid;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ memcpy(&data->info, &tda38640_info, sizeof(tda38640_info));
+
+ if (IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR) &&
+ of_property_read_bool(client->dev.of_node, "infineon,en-pin-fixed-level")) {
+ svid = svid_mode(client, data);
+ if (svid < 0) {
+ dev_err_probe(&client->dev, svid, "Could not determine operating mode.");
+ return svid;
+ }
+
+ /*
+ * Apply ON_OFF_CONFIG workaround as enabling the regulator using the
+ * OPERATION register doesn't work in SVID mode.
+ *
+ * One should configure PMBUS_ON_OFF_CONFIG here, but
+ * PB_ON_OFF_CONFIG_POWERUP_CONTROL and PB_ON_OFF_CONFIG_EN_PIN_REQ
+ * are ignored by the device.
+ * Only PB_ON_OFF_CONFIG_POLARITY_HIGH has an effect.
+ */
+ if (svid) {
+ data->info.read_byte_data = tda38640_read_byte_data;
+ data->info.write_byte_data = tda38640_write_byte_data;
+ }
+ }
+ return pmbus_do_probe(client, &data->info);
}
static const struct i2c_device_id tda38640_id[] = {
diff --git a/drivers/hwmon/powerz.c b/drivers/hwmon/powerz.c
new file mode 100644
index 0000000000..cfb635f94d
--- /dev/null
+++ b/drivers/hwmon/powerz.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Thomas Weißschuh <linux@weissschuh.net>
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/usb.h>
+
+#define DRIVER_NAME "powerz"
+#define POWERZ_EP_CMD_OUT 0x01
+#define POWERZ_EP_DATA_IN 0x81
+
+struct powerz_sensor_data {
+ u8 _unknown_1[8];
+ __le32 V_bus;
+ __le32 I_bus;
+ __le32 V_bus_avg;
+ __le32 I_bus_avg;
+ u8 _unknown_2[8];
+ u8 temp[2];
+ __le16 V_cc1;
+ __le16 V_cc2;
+ __le16 V_dp;
+ __le16 V_dm;
+ __le16 V_dd;
+ u8 _unknown_3[4];
+} __packed;
+
+struct powerz_priv {
+ char transfer_buffer[64]; /* first member to satisfy DMA alignment */
+ struct mutex mutex;
+ struct completion completion;
+ struct urb *urb;
+ int status;
+};
+
+static const struct hwmon_channel_info *const powerz_info[] = {
+ HWMON_CHANNEL_INFO(in,
+ HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_AVERAGE,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL,
+ HWMON_I_INPUT | HWMON_I_LABEL),
+ HWMON_CHANNEL_INFO(curr,
+ HWMON_C_INPUT | HWMON_C_LABEL | HWMON_C_AVERAGE),
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL),
+ NULL
+};
+
+static umode_t powerz_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ return 0444;
+}
+
+static int powerz_read_string(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ if (type == hwmon_curr && attr == hwmon_curr_label) {
+ *str = "IBUS";
+ } else if (type == hwmon_in && attr == hwmon_in_label) {
+ if (channel == 0)
+ *str = "VBUS";
+ else if (channel == 1)
+ *str = "VCC1";
+ else if (channel == 2)
+ *str = "VCC2";
+ else if (channel == 3)
+ *str = "VDP";
+ else if (channel == 4)
+ *str = "VDM";
+ else if (channel == 5)
+ *str = "VDD";
+ else
+ return -EOPNOTSUPP;
+ } else if (type == hwmon_temp && attr == hwmon_temp_label) {
+ *str = "TEMP";
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void powerz_usb_data_complete(struct urb *urb)
+{
+ struct powerz_priv *priv = urb->context;
+
+ complete(&priv->completion);
+}
+
+static void powerz_usb_cmd_complete(struct urb *urb)
+{
+ struct powerz_priv *priv = urb->context;
+
+ usb_fill_bulk_urb(urb, urb->dev,
+ usb_rcvbulkpipe(urb->dev, POWERZ_EP_DATA_IN),
+ priv->transfer_buffer, sizeof(priv->transfer_buffer),
+ powerz_usb_data_complete, priv);
+
+ priv->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (priv->status)
+ complete(&priv->completion);
+}
+
+static int powerz_read_data(struct usb_device *udev, struct powerz_priv *priv)
+{
+ int ret;
+
+ priv->status = -ETIMEDOUT;
+ reinit_completion(&priv->completion);
+
+ priv->transfer_buffer[0] = 0x0c;
+ priv->transfer_buffer[1] = 0x00;
+ priv->transfer_buffer[2] = 0x02;
+ priv->transfer_buffer[3] = 0x00;
+
+ usb_fill_bulk_urb(priv->urb, udev,
+ usb_sndbulkpipe(udev, POWERZ_EP_CMD_OUT),
+ priv->transfer_buffer, 4, powerz_usb_cmd_complete,
+ priv);
+ ret = usb_submit_urb(priv->urb, GFP_KERNEL);
+ if (ret)
+ return ret;
+
+ if (!wait_for_completion_interruptible_timeout
+ (&priv->completion, msecs_to_jiffies(5))) {
+ usb_kill_urb(priv->urb);
+ return -EIO;
+ }
+
+ if (priv->urb->actual_length < sizeof(struct powerz_sensor_data))
+ return -EIO;
+
+ return priv->status;
+}
+
+static int powerz_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct usb_interface *intf = to_usb_interface(dev->parent);
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct powerz_priv *priv = usb_get_intfdata(intf);
+ struct powerz_sensor_data *data;
+ int ret;
+
+ if (!priv)
+ return -EIO; /* disconnected */
+
+ mutex_lock(&priv->mutex);
+ ret = powerz_read_data(udev, priv);
+ if (ret)
+ goto out;
+
+ data = (struct powerz_sensor_data *)priv->transfer_buffer;
+
+ if (type == hwmon_curr) {
+ if (attr == hwmon_curr_input)
+ *val = ((s32)le32_to_cpu(data->I_bus)) / 1000;
+ else if (attr == hwmon_curr_average)
+ *val = ((s32)le32_to_cpu(data->I_bus_avg)) / 1000;
+ else
+ ret = -EOPNOTSUPP;
+ } else if (type == hwmon_in) {
+ if (attr == hwmon_in_input) {
+ if (channel == 0)
+ *val = le32_to_cpu(data->V_bus) / 1000;
+ else if (channel == 1)
+ *val = le16_to_cpu(data->V_cc1) / 10;
+ else if (channel == 2)
+ *val = le16_to_cpu(data->V_cc2) / 10;
+ else if (channel == 3)
+ *val = le16_to_cpu(data->V_dp) / 10;
+ else if (channel == 4)
+ *val = le16_to_cpu(data->V_dm) / 10;
+ else if (channel == 5)
+ *val = le16_to_cpu(data->V_dd) / 10;
+ else
+ ret = -EOPNOTSUPP;
+ } else if (attr == hwmon_in_average && channel == 0) {
+ *val = le32_to_cpu(data->V_bus_avg) / 1000;
+ } else {
+ ret = -EOPNOTSUPP;
+ }
+ } else if (type == hwmon_temp && attr == hwmon_temp_input) {
+ *val = data->temp[1] * 2000 + data->temp[0] * 1000 / 128;
+ } else {
+ ret = -EOPNOTSUPP;
+ }
+
+out:
+ mutex_unlock(&priv->mutex);
+ return ret;
+}
+
+static const struct hwmon_ops powerz_hwmon_ops = {
+ .is_visible = powerz_is_visible,
+ .read = powerz_read,
+ .read_string = powerz_read_string,
+};
+
+static const struct hwmon_chip_info powerz_chip_info = {
+ .ops = &powerz_hwmon_ops,
+ .info = powerz_info,
+};
+
+static int powerz_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct powerz_priv *priv;
+ struct device *hwmon_dev;
+ struct device *parent;
+
+ parent = &intf->dev;
+
+ priv = devm_kzalloc(parent, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!priv->urb)
+ return -ENOMEM;
+ mutex_init(&priv->mutex);
+ init_completion(&priv->completion);
+
+ hwmon_dev =
+ devm_hwmon_device_register_with_info(parent, DRIVER_NAME, priv,
+ &powerz_chip_info, NULL);
+ if (IS_ERR(hwmon_dev)) {
+ usb_free_urb(priv->urb);
+ return PTR_ERR(hwmon_dev);
+ }
+
+ usb_set_intfdata(intf, priv);
+
+ return 0;
+}
+
+static void powerz_disconnect(struct usb_interface *intf)
+{
+ struct powerz_priv *priv = usb_get_intfdata(intf);
+
+ mutex_lock(&priv->mutex);
+ usb_kill_urb(priv->urb);
+ usb_free_urb(priv->urb);
+ mutex_unlock(&priv->mutex);
+}
+
+static const struct usb_device_id powerz_id_table[] = {
+ { USB_DEVICE_INTERFACE_NUMBER(0x5FC9, 0x0061, 0x00) }, /* ChargerLAB POWER-Z KM002C */
+ { USB_DEVICE_INTERFACE_NUMBER(0x5FC9, 0x0063, 0x00) }, /* ChargerLAB POWER-Z KM003C */
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, powerz_id_table);
+
+static struct usb_driver powerz_driver = {
+ .name = DRIVER_NAME,
+ .id_table = powerz_id_table,
+ .probe = powerz_probe,
+ .disconnect = powerz_disconnect,
+};
+
+module_usb_driver(powerz_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Thomas Weißschuh <linux@weissschuh.net>");
+MODULE_DESCRIPTION("ChargerLAB POWER-Z USB-C tester");
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
index bf408e35e2..1891d4d75a 100644
--- a/drivers/hwmon/sch5627.c
+++ b/drivers/hwmon/sch5627.c
@@ -7,9 +7,12 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bits.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
#include <linux/init.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
@@ -72,11 +75,9 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
"VCC", "VTT", "VBAT", "VTR", "V_IN" };
struct sch5627_data {
+ struct regmap *regmap;
unsigned short addr;
u8 control;
- u8 temp_max[SCH5627_NO_TEMPS];
- u8 temp_crit[SCH5627_NO_TEMPS];
- u16 fan_min[SCH5627_NO_FANS];
struct mutex update_lock;
unsigned long last_battery; /* In jiffies */
@@ -91,6 +92,36 @@ struct sch5627_data {
u16 in[SCH5627_NO_IN];
};
+static const struct regmap_range sch5627_tunables_ranges[] = {
+ regmap_reg_range(0x57, 0x57),
+ regmap_reg_range(0x59, 0x59),
+ regmap_reg_range(0x5B, 0x5B),
+ regmap_reg_range(0x5D, 0x5D),
+ regmap_reg_range(0x5F, 0x5F),
+ regmap_reg_range(0x61, 0x69),
+ regmap_reg_range(0x96, 0x9B),
+ regmap_reg_range(0xA0, 0xA3),
+ regmap_reg_range(0x184, 0x184),
+ regmap_reg_range(0x186, 0x186),
+ regmap_reg_range(0x1A8, 0x1A9),
+};
+
+static const struct regmap_access_table sch5627_tunables_table = {
+ .yes_ranges = sch5627_tunables_ranges,
+ .n_yes_ranges = ARRAY_SIZE(sch5627_tunables_ranges),
+};
+
+static const struct regmap_config sch5627_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .wr_table = &sch5627_tunables_table,
+ .rd_table = &sch5627_tunables_table,
+ .cache_type = REGCACHE_RBTREE,
+ .use_single_read = true,
+ .use_single_write = true,
+ .can_sleep = true,
+};
+
static int sch5627_update_temp(struct sch5627_data *data)
{
int ret = 0;
@@ -177,38 +208,6 @@ abort:
return ret;
}
-static int sch5627_read_limits(struct sch5627_data *data)
-{
- int i, val;
-
- for (i = 0; i < SCH5627_NO_TEMPS; i++) {
- /*
- * Note what SMSC calls ABS, is what lm_sensors calls max
- * (aka high), and HIGH is what lm_sensors calls crit.
- */
- val = sch56xx_read_virtual_reg(data->addr,
- SCH5627_REG_TEMP_ABS[i]);
- if (val < 0)
- return val;
- data->temp_max[i] = val;
-
- val = sch56xx_read_virtual_reg(data->addr,
- SCH5627_REG_TEMP_HIGH[i]);
- if (val < 0)
- return val;
- data->temp_crit[i] = val;
- }
- for (i = 0; i < SCH5627_NO_FANS; i++) {
- val = sch56xx_read_virtual_reg16(data->addr,
- SCH5627_REG_FAN_MIN[i]);
- if (val < 0)
- return val;
- data->fan_min[i] = val;
- }
-
- return 0;
-}
-
static int reg_to_temp(u16 reg)
{
return (reg * 625) / 10 - 64000;
@@ -229,6 +228,25 @@ static int reg_to_rpm(u16 reg)
return 5400540 / reg;
}
+static u8 sch5627_temp_limit_to_reg(long value)
+{
+ long limit = (value / 1000) + 64;
+
+ return clamp_val(limit, 0, U8_MAX);
+}
+
+static u16 sch5627_rpm_to_reg(long value)
+{
+ long pulses;
+
+ if (value <= 0)
+ return U16_MAX - 1;
+
+ pulses = 5400540 / value;
+
+ return clamp_val(pulses, 1, U16_MAX - 1);
+}
+
static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
int channel)
{
@@ -240,8 +258,35 @@ static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types t
if (data->control & SCH5627_CTRL_LOCK)
return 0444;
- if (type == hwmon_pwm && attr == hwmon_pwm_auto_channels_temp)
- return 0644;
+ switch (type) {
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_max:
+ case hwmon_temp_crit:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_min:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ case hwmon_pwm:
+ switch (attr) {
+ case hwmon_pwm_auto_channels_temp:
+ return 0644;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
return 0444;
}
@@ -250,24 +295,37 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at
long *val)
{
struct sch5627_data *data = dev_get_drvdata(dev);
- int ret;
+ int ret, value;
switch (type) {
case hwmon_temp:
- ret = sch5627_update_temp(data);
- if (ret < 0)
- return ret;
switch (attr) {
case hwmon_temp_input:
+ ret = sch5627_update_temp(data);
+ if (ret < 0)
+ return ret;
+
*val = reg_to_temp(data->temp[channel]);
return 0;
case hwmon_temp_max:
- *val = reg_to_temp_limit(data->temp_max[channel]);
+ ret = regmap_read(data->regmap, SCH5627_REG_TEMP_ABS[channel], &value);
+ if (ret < 0)
+ return ret;
+
+ *val = reg_to_temp_limit((u8)value);
return 0;
case hwmon_temp_crit:
- *val = reg_to_temp_limit(data->temp_crit[channel]);
+ ret = regmap_read(data->regmap, SCH5627_REG_TEMP_HIGH[channel], &value);
+ if (ret < 0)
+ return ret;
+
+ *val = reg_to_temp_limit((u8)value);
return 0;
case hwmon_temp_fault:
+ ret = sch5627_update_temp(data);
+ if (ret < 0)
+ return ret;
+
*val = (data->temp[channel] == 0);
return 0;
default:
@@ -275,23 +333,35 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at
}
break;
case hwmon_fan:
- ret = sch5627_update_fan(data);
- if (ret < 0)
- return ret;
switch (attr) {
case hwmon_fan_input:
+ ret = sch5627_update_fan(data);
+ if (ret < 0)
+ return ret;
+
ret = reg_to_rpm(data->fan[channel]);
if (ret < 0)
return ret;
+
*val = ret;
return 0;
case hwmon_fan_min:
- ret = reg_to_rpm(data->fan_min[channel]);
+ ret = sch56xx_regmap_read16(data->regmap, SCH5627_REG_FAN_MIN[channel],
+ &value);
if (ret < 0)
return ret;
+
+ ret = reg_to_rpm((u16)value);
+ if (ret < 0)
+ return ret;
+
*val = ret;
return 0;
case hwmon_fan_fault:
+ ret = sch5627_update_fan(data);
+ if (ret < 0)
+ return ret;
+
*val = (data->fan[channel] == 0xffff);
return 0;
default:
@@ -301,15 +371,11 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_auto_channels_temp:
- mutex_lock(&data->update_lock);
- ret = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel]);
- mutex_unlock(&data->update_lock);
-
+ ret = regmap_read(data->regmap, SCH5627_REG_PWM_MAP[channel], &value);
if (ret < 0)
return ret;
- *val = ret;
-
+ *val = value;
return 0;
default:
break;
@@ -359,9 +425,33 @@ static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 a
long val)
{
struct sch5627_data *data = dev_get_drvdata(dev);
- int ret;
+ u16 fan;
+ u8 temp;
switch (type) {
+ case hwmon_temp:
+ temp = sch5627_temp_limit_to_reg(val);
+
+ switch (attr) {
+ case hwmon_temp_max:
+ return regmap_write(data->regmap, SCH5627_REG_TEMP_ABS[channel], temp);
+ case hwmon_temp_crit:
+ return regmap_write(data->regmap, SCH5627_REG_TEMP_HIGH[channel], temp);
+ default:
+ break;
+ }
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_min:
+ fan = sch5627_rpm_to_reg(val);
+
+ return sch56xx_regmap_write16(data->regmap, SCH5627_REG_FAN_MIN[channel],
+ fan);
+ default:
+ break;
+ }
+ break;
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_auto_channels_temp:
@@ -369,12 +459,7 @@ static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 a
if (val > U8_MAX || val < 0)
return -EINVAL;
- mutex_lock(&data->update_lock);
- ret = sch56xx_write_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel],
- val);
- mutex_unlock(&data->update_lock);
-
- return ret;
+ return regmap_write(data->regmap, SCH5627_REG_PWM_MAP[channel], val);
default:
break;
}
@@ -436,7 +521,7 @@ static int sch5627_probe(struct platform_device *pdev)
{
struct sch5627_data *data;
struct device *hwmon_dev;
- int err, build_code, build_id, hwmon_rev, val;
+ int build_code, build_id, hwmon_rev, val;
data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
GFP_KERNEL);
@@ -501,19 +586,17 @@ static int sch5627_probe(struct platform_device *pdev)
pr_err("hardware monitoring not enabled\n");
return -ENODEV;
}
+
+ data->regmap = devm_regmap_init_sch56xx(&pdev->dev, &data->update_lock, data->addr,
+ &sch5627_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
/* Trigger a Vbat voltage measurement, so that we get a valid reading
the first time we read Vbat */
sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | SCH5627_CTRL_VBAT);
data->last_battery = jiffies;
- /*
- * Read limits, we do this only once as reading a register on
- * the sch5627 is quite expensive (and they don't change).
- */
- err = sch5627_read_limits(data);
- if (err)
- return err;
-
pr_info("found %s chip at %#hx\n", DEVNAME, data->addr);
pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
build_code, build_id, hwmon_rev);
@@ -531,6 +614,30 @@ static int sch5627_probe(struct platform_device *pdev)
return 0;
}
+static int sch5627_suspend(struct device *dev)
+{
+ struct sch5627_data *data = dev_get_drvdata(dev);
+
+ regcache_cache_only(data->regmap, true);
+ regcache_mark_dirty(data->regmap);
+
+ return 0;
+}
+
+static int sch5627_resume(struct device *dev)
+{
+ struct sch5627_data *data = dev_get_drvdata(dev);
+
+ regcache_cache_only(data->regmap, false);
+ /* We must not access the virtual registers when the lock bit is set */
+ if (data->control & SCH5627_CTRL_LOCK)
+ return regcache_drop_region(data->regmap, 0, U16_MAX);
+
+ return regcache_sync(data->regmap);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(sch5627_dev_pm_ops, sch5627_suspend, sch5627_resume);
+
static const struct platform_device_id sch5627_device_id[] = {
{
.name = "sch5627",
@@ -542,6 +649,7 @@ MODULE_DEVICE_TABLE(platform, sch5627_device_id);
static struct platform_driver sch5627_driver = {
.driver = {
.name = DRVNAME,
+ .pm = pm_sleep_ptr(&sch5627_dev_pm_ops),
},
.probe = sch5627_probe,
.id_table = sch5627_device_id,
diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c
index 269757bc3a..6e6d541584 100644
--- a/drivers/hwmon/sch5636.c
+++ b/drivers/hwmon/sch5636.c
@@ -367,7 +367,7 @@ static struct sensor_device_attribute sch5636_fan_attr[] = {
SENSOR_ATTR_RO(fan8_alarm, fan_alarm, 7),
};
-static int sch5636_remove(struct platform_device *pdev)
+static void sch5636_remove(struct platform_device *pdev)
{
struct sch5636_data *data = platform_get_drvdata(pdev);
int i;
@@ -385,8 +385,6 @@ static int sch5636_remove(struct platform_device *pdev)
for (i = 0; i < SCH5636_NO_FANS * 3; i++)
device_remove_file(&pdev->dev,
&sch5636_fan_attr[i].dev_attr);
-
- return 0;
}
static int sch5636_probe(struct platform_device *pdev)
@@ -515,7 +513,7 @@ static struct platform_driver sch5636_driver = {
.name = DRVNAME,
},
.probe = sch5636_probe,
- .remove = sch5636_remove,
+ .remove_new = sch5636_remove,
.id_table = sch5636_device_id,
};
diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c
index ac1f725807..71941b1bb5 100644
--- a/drivers/hwmon/sch56xx-common.c
+++ b/drivers/hwmon/sch56xx-common.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/acpi.h>
@@ -59,6 +60,11 @@ struct sch56xx_watchdog_data {
u8 watchdog_output_enable;
};
+struct sch56xx_bus_context {
+ struct mutex *lock; /* Used to serialize access to the mailbox registers */
+ u16 addr;
+};
+
static struct platform_device *sch56xx_pdev;
/* Super I/O functions */
@@ -239,6 +245,107 @@ int sch56xx_read_virtual_reg12(u16 addr, u16 msb_reg, u16 lsn_reg,
EXPORT_SYMBOL(sch56xx_read_virtual_reg12);
/*
+ * Regmap support
+ */
+
+int sch56xx_regmap_read16(struct regmap *map, unsigned int reg, unsigned int *val)
+{
+ int lsb, msb, ret;
+
+ /* See sch56xx_read_virtual_reg16() */
+ ret = regmap_read(map, reg, &lsb);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(map, reg + 1, &msb);
+ if (ret < 0)
+ return ret;
+
+ *val = lsb | (msb << 8);
+
+ return 0;
+}
+EXPORT_SYMBOL(sch56xx_regmap_read16);
+
+int sch56xx_regmap_write16(struct regmap *map, unsigned int reg, unsigned int val)
+{
+ int ret;
+
+ ret = regmap_write(map, reg, val & 0xff);
+ if (ret < 0)
+ return ret;
+
+ return regmap_write(map, reg + 1, (val >> 8) & 0xff);
+}
+EXPORT_SYMBOL(sch56xx_regmap_write16);
+
+static int sch56xx_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct sch56xx_bus_context *bus = context;
+ int ret;
+
+ mutex_lock(bus->lock);
+ ret = sch56xx_write_virtual_reg(bus->addr, (u16)reg, (u8)val);
+ mutex_unlock(bus->lock);
+
+ return ret;
+}
+
+static int sch56xx_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct sch56xx_bus_context *bus = context;
+ int ret;
+
+ mutex_lock(bus->lock);
+ ret = sch56xx_read_virtual_reg(bus->addr, (u16)reg);
+ mutex_unlock(bus->lock);
+
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+
+ return 0;
+}
+
+static void sch56xx_free_context(void *context)
+{
+ kfree(context);
+}
+
+static const struct regmap_bus sch56xx_bus = {
+ .reg_write = sch56xx_reg_write,
+ .reg_read = sch56xx_reg_read,
+ .free_context = sch56xx_free_context,
+ .reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
+ .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
+};
+
+struct regmap *devm_regmap_init_sch56xx(struct device *dev, struct mutex *lock, u16 addr,
+ const struct regmap_config *config)
+{
+ struct sch56xx_bus_context *context;
+ struct regmap *map;
+
+ if (config->reg_bits != 16 && config->val_bits != 8)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ context = kzalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+
+ context->lock = lock;
+ context->addr = addr;
+
+ map = devm_regmap_init(dev, &sch56xx_bus, context, config);
+ if (IS_ERR(map))
+ kfree(context);
+
+ return map;
+}
+EXPORT_SYMBOL(devm_regmap_init_sch56xx);
+
+/*
* Watchdog routines
*/
diff --git a/drivers/hwmon/sch56xx-common.h b/drivers/hwmon/sch56xx-common.h
index e907d9da0d..7479a549a0 100644
--- a/drivers/hwmon/sch56xx-common.h
+++ b/drivers/hwmon/sch56xx-common.h
@@ -5,9 +5,15 @@
***************************************************************************/
#include <linux/mutex.h>
+#include <linux/regmap.h>
struct sch56xx_watchdog_data;
+struct regmap *devm_regmap_init_sch56xx(struct device *dev, struct mutex *lock, u16 addr,
+ const struct regmap_config *config);
+int sch56xx_regmap_read16(struct regmap *map, unsigned int reg, unsigned int *val);
+int sch56xx_regmap_write16(struct regmap *map, unsigned int reg, unsigned int val);
+
int sch56xx_read_virtual_reg(u16 addr, u16 reg);
int sch56xx_write_virtual_reg(u16 addr, u16 reg, u8 val);
int sch56xx_read_virtual_reg16(u16 addr, u16 reg);
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 32a41fc56f..494f9655f4 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -1017,7 +1017,7 @@ err_release_reg:
return ret;
}
-static int sht15_remove(struct platform_device *pdev)
+static void sht15_remove(struct platform_device *pdev)
{
struct sht15_data *data = platform_get_drvdata(pdev);
int ret;
@@ -1033,8 +1033,6 @@ static int sht15_remove(struct platform_device *pdev)
regulator_unregister_notifier(data->reg, &data->nb);
regulator_disable(data->reg);
}
-
- return 0;
}
static const struct platform_device_id sht15_device_ids[] = {
@@ -1053,7 +1051,7 @@ static struct platform_driver sht15_driver = {
.of_match_table = of_match_ptr(sht15_dt_match),
},
.probe = sht15_probe,
- .remove = sht15_remove,
+ .remove_new = sht15_remove,
.id_table = sht15_device_ids,
};
module_platform_driver(sht15_driver);
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 0a0479501e..641be1f7f9 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -709,7 +709,7 @@ exit_remove_files:
return err;
}
-static int sis5595_remove(struct platform_device *pdev)
+static void sis5595_remove(struct platform_device *pdev)
{
struct sis5595_data *data = platform_get_drvdata(pdev);
@@ -717,8 +717,6 @@ static int sis5595_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_in4);
sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_temp1);
-
- return 0;
}
static const struct pci_device_id sis5595_pci_ids[] = {
@@ -790,7 +788,7 @@ static struct platform_driver sis5595_driver = {
.name = DRIVER_NAME,
},
.probe = sis5595_probe,
- .remove = sis5595_remove,
+ .remove_new = sis5595_remove,
};
static int sis5595_pci_probe(struct pci_dev *dev,
diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c
index 9a180b1030..8a7cf08733 100644
--- a/drivers/hwmon/tmp513.c
+++ b/drivers/hwmon/tmp513.c
@@ -73,9 +73,6 @@
#define TMP51X_PGA_DEFAULT 8
#define TMP51X_MAX_REGISTER_ADDR 0xFF
-#define TMP512_TEMP_CONFIG_DEFAULT 0xBF80
-#define TMP513_TEMP_CONFIG_DEFAULT 0xFF80
-
// Mask and shift
#define CURRENT_SENSE_VOLTAGE_320_MASK 0x1800
#define CURRENT_SENSE_VOLTAGE_160_MASK 0x1000
@@ -113,6 +110,17 @@
#define MAX_TEMP_HYST 127500
+#define TMP512_MAX_CHANNELS 3
+#define TMP513_MAX_CHANNELS 4
+
+#define TMP51X_TEMP_CONFIG_CONV_RATE GENMASK(9, 7)
+#define TMP51X_TEMP_CONFIG_RC BIT(10)
+#define TMP51X_TEMP_CHANNEL_MASK(n) (GENMASK((n) - 1, 0) << 11)
+#define TMP51X_TEMP_CONFIG_CONT BIT(15)
+#define TMP51X_TEMP_CONFIG_DEFAULT(n) \
+ (TMP51X_TEMP_CHANNEL_MASK(n) | TMP51X_TEMP_CONFIG_CONT | \
+ TMP51X_TEMP_CONFIG_CONV_RATE | TMP51X_TEMP_CONFIG_RC)
+
static const u8 TMP51X_TEMP_INPUT[4] = {
TMP51X_LOCAL_TEMP_RESULT,
TMP51X_REMOTE_TEMP_RESULT_1,
@@ -152,10 +160,6 @@ static struct regmap_config tmp51x_regmap_config = {
.max_register = TMP51X_MAX_REGISTER_ADDR,
};
-enum tmp51x_ids {
- tmp512, tmp513
-};
-
struct tmp51x_data {
u16 shunt_config;
u16 pga_gain;
@@ -169,7 +173,7 @@ struct tmp51x_data {
u32 curr_lsb_ua;
u32 pwr_lsb_uw;
- enum tmp51x_ids id;
+ u8 max_channels;
struct regmap *regmap;
};
@@ -434,7 +438,7 @@ static umode_t tmp51x_is_visible(const void *_data,
switch (type) {
case hwmon_temp:
- if (data->id == tmp512 && channel == 3)
+ if (channel >= data->max_channels)
return 0;
switch (attr) {
case hwmon_temp_input:
@@ -585,7 +589,7 @@ static int tmp51x_init(struct tmp51x_data *data)
if (ret < 0)
return ret;
- if (data->id == tmp513) {
+ if (data->max_channels == TMP513_MAX_CHANNELS) {
ret = regmap_write(data->regmap, TMP513_N_FACTOR_3,
data->nfactor[2] << 8);
if (ret < 0)
@@ -601,22 +605,16 @@ static int tmp51x_init(struct tmp51x_data *data)
}
static const struct i2c_device_id tmp51x_id[] = {
- { "tmp512", tmp512 },
- { "tmp513", tmp513 },
+ { "tmp512", TMP512_MAX_CHANNELS },
+ { "tmp513", TMP513_MAX_CHANNELS },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp51x_id);
static const struct of_device_id tmp51x_of_match[] = {
- {
- .compatible = "ti,tmp512",
- .data = (void *)tmp512
- },
- {
- .compatible = "ti,tmp513",
- .data = (void *)tmp513
- },
- { },
+ { .compatible = "ti,tmp512", .data = (void *)TMP512_MAX_CHANNELS },
+ { .compatible = "ti,tmp513", .data = (void *)TMP513_MAX_CHANNELS },
+ { }
};
MODULE_DEVICE_TABLE(of, tmp51x_of_match);
@@ -655,7 +653,6 @@ static int tmp51x_pga_gain_to_reg(struct device *dev, struct tmp51x_data *data)
static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data)
{
int ret;
- u32 nfactor[3];
u32 val;
ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val);
@@ -673,10 +670,8 @@ static int tmp51x_read_properties(struct device *dev, struct tmp51x_data *data)
if (ret < 0)
return ret;
- ret = device_property_read_u32_array(dev, "ti,nfactor", nfactor,
- (data->id == tmp513) ? 3 : 2);
- if (ret >= 0)
- memcpy(data->nfactor, nfactor, (data->id == tmp513) ? 3 : 2);
+ device_property_read_u32_array(dev, "ti,nfactor", data->nfactor,
+ data->max_channels - 1);
// Check if shunt value is compatible with pga-gain
if (data->shunt_uohms > data->pga_gain * 40 * 1000 * 1000) {
@@ -698,8 +693,7 @@ static void tmp51x_use_default(struct tmp51x_data *data)
static int tmp51x_configure(struct device *dev, struct tmp51x_data *data)
{
data->shunt_config = TMP51X_SHUNT_CONFIG_DEFAULT;
- data->temp_config = (data->id == tmp513) ?
- TMP513_TEMP_CONFIG_DEFAULT : TMP512_TEMP_CONFIG_DEFAULT;
+ data->temp_config = TMP51X_TEMP_CONFIG_DEFAULT(data->max_channels);
if (dev->of_node)
return tmp51x_read_properties(dev, data);
@@ -720,7 +714,7 @@ static int tmp51x_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
- data->id = (uintptr_t)i2c_get_match_data(client);
+ data->max_channels = (uintptr_t)i2c_get_match_data(client);
ret = tmp51x_configure(dev, data);
if (ret < 0) {
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
index 3b580f2298..9823afb067 100644
--- a/drivers/hwmon/ultra45_env.c
+++ b/drivers/hwmon/ultra45_env.c
@@ -291,7 +291,7 @@ out_iounmap:
goto out;
}
-static int env_remove(struct platform_device *op)
+static void env_remove(struct platform_device *op)
{
struct env *p = platform_get_drvdata(op);
@@ -300,8 +300,6 @@ static int env_remove(struct platform_device *op)
hwmon_device_unregister(p->hwmon_dev);
of_iounmap(&op->resource[0], p->regs, REG_SIZE);
}
-
- return 0;
}
static const struct of_device_id env_match[] = {
@@ -319,7 +317,7 @@ static struct platform_driver env_driver = {
.of_match_table = env_match,
},
.probe = env_probe,
- .remove = env_remove,
+ .remove_new = env_remove,
};
module_platform_driver(env_driver);
diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c
index e5d18dac8e..5abe95b683 100644
--- a/drivers/hwmon/via-cputemp.c
+++ b/drivers/hwmon/via-cputemp.c
@@ -182,7 +182,7 @@ exit_remove:
return err;
}
-static int via_cputemp_remove(struct platform_device *pdev)
+static void via_cputemp_remove(struct platform_device *pdev)
{
struct via_cputemp_data *data = platform_get_drvdata(pdev);
@@ -190,7 +190,6 @@ static int via_cputemp_remove(struct platform_device *pdev)
if (data->vrm)
device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
- return 0;
}
static struct platform_driver via_cputemp_driver = {
@@ -198,7 +197,7 @@ static struct platform_driver via_cputemp_driver = {
.name = DRVNAME,
},
.probe = via_cputemp_probe,
- .remove = via_cputemp_remove,
+ .remove_new = via_cputemp_remove,
};
struct pdev_entry {
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 407933d6e4..3a002ad3c0 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -786,14 +786,12 @@ exit_remove_files:
return err;
}
-static int via686a_remove(struct platform_device *pdev)
+static void via686a_remove(struct platform_device *pdev)
{
struct via686a_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
-
- return 0;
}
static struct platform_driver via686a_driver = {
@@ -801,7 +799,7 @@ static struct platform_driver via686a_driver = {
.name = DRIVER_NAME,
},
.probe = via686a_probe,
- .remove = via686a_remove,
+ .remove_new = via686a_remove,
};
static const struct pci_device_id via686a_pci_ids[] = {
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index fcd4be7a5a..2f3890463e 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -1208,14 +1208,12 @@ EXIT_DEV_REMOVE_SILENT:
return err;
}
-static int vt1211_remove(struct platform_device *pdev)
+static void vt1211_remove(struct platform_device *pdev)
{
struct vt1211_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
vt1211_remove_sysfs(pdev);
-
- return 0;
}
static struct platform_driver vt1211_driver = {
@@ -1223,7 +1221,7 @@ static struct platform_driver vt1211_driver = {
.name = DRVNAME,
},
.probe = vt1211_probe,
- .remove = vt1211_remove,
+ .remove_new = vt1211_remove,
};
static int __init vt1211_device_add(unsigned short address)
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 16bc16d33c..dcdd14ccd1 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -892,7 +892,7 @@ exit_remove_files:
return err;
}
-static int vt8231_remove(struct platform_device *pdev)
+static void vt8231_remove(struct platform_device *pdev)
{
struct vt8231_data *data = platform_get_drvdata(pdev);
int i;
@@ -906,8 +906,6 @@ static int vt8231_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
-
- return 0;
}
@@ -916,7 +914,7 @@ static struct platform_driver vt8231_driver = {
.name = DRIVER_NAME,
},
.probe = vt8231_probe,
- .remove = vt8231_remove,
+ .remove_new = vt8231_remove,
};
static const struct pci_device_id vt8231_pci_ids[] = {
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index b638d672ac..2fc9b718e2 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1828,7 +1828,7 @@ static int w83627hf_probe(struct platform_device *pdev)
return err;
}
-static int w83627hf_remove(struct platform_device *pdev)
+static void w83627hf_remove(struct platform_device *pdev)
{
struct w83627hf_data *data = platform_get_drvdata(pdev);
@@ -1836,8 +1836,6 @@ static int w83627hf_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
-
- return 0;
}
static struct platform_driver w83627hf_driver = {
@@ -1846,7 +1844,7 @@ static struct platform_driver w83627hf_driver = {
.pm = W83627HF_DEV_PM_OPS,
},
.probe = w83627hf_probe,
- .remove = w83627hf_remove,
+ .remove_new = w83627hf_remove,
};
static int __init w83627hf_find(int sioaddr, unsigned short *addr,
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index b33f382f23..cba5ec432e 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -1816,16 +1816,13 @@ w83781d_isa_probe(struct platform_device *pdev)
return err;
}
-static int
-w83781d_isa_remove(struct platform_device *pdev)
+static void w83781d_isa_remove(struct platform_device *pdev)
{
struct w83781d_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
w83781d_remove_files(&pdev->dev);
device_remove_file(&pdev->dev, &dev_attr_name);
-
- return 0;
}
static struct platform_driver w83781d_isa_driver = {
@@ -1833,7 +1830,7 @@ static struct platform_driver w83781d_isa_driver = {
.name = "w83781d",
},
.probe = w83781d_isa_probe,
- .remove = w83781d_isa_remove,
+ .remove_new = w83781d_isa_remove,
};
/* return 1 if a supported chip is found, 0 otherwise */
diff --git a/drivers/hwmon/xgene-hwmon.c b/drivers/hwmon/xgene-hwmon.c
index 78d9f52e2a..5e0759a70f 100644
--- a/drivers/hwmon/xgene-hwmon.c
+++ b/drivers/hwmon/xgene-hwmon.c
@@ -57,12 +57,6 @@
(MSG_TYPE_SET(MSG_TYPE_PWRMGMT) | \
MSG_SUBTYPE_SET(hndl) | TPC_CMD_SET(cmd) | type)
-/* PCC defines */
-#define PCC_SIGNATURE_MASK 0x50424300
-#define PCCC_GENERATE_DB_INT BIT(15)
-#define PCCS_CMD_COMPLETE BIT(0)
-#define PCCS_SCI_DOORBEL BIT(1)
-#define PCCS_PLATFORM_NOTIFICATION BIT(3)
/*
* Arbitrary retries in case the remote processor is slow to respond
* to PCC commands
@@ -142,15 +136,15 @@ static int xgene_hwmon_pcc_rd(struct xgene_hwmon_dev *ctx, u32 *msg)
/* Write signature for subspace */
WRITE_ONCE(generic_comm_base->signature,
- cpu_to_le32(PCC_SIGNATURE_MASK | ctx->mbox_idx));
+ cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx));
/* Write to the shared command region */
WRITE_ONCE(generic_comm_base->command,
- cpu_to_le16(MSG_TYPE(msg[0]) | PCCC_GENERATE_DB_INT));
+ cpu_to_le16(MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR));
/* Flip CMD COMPLETE bit */
val = le16_to_cpu(READ_ONCE(generic_comm_base->status));
- val &= ~PCCS_CMD_COMPLETE;
+ val &= ~PCC_STATUS_CMD_COMPLETE;
WRITE_ONCE(generic_comm_base->status, cpu_to_le16(val));
/* Copy the message to the PCC comm space */
@@ -544,7 +538,7 @@ static void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg)
msg = generic_comm_base + 1;
/* Check if platform sends interrupt */
if (!xgene_word_tst_and_clr(&generic_comm_base->status,
- PCCS_SCI_DOORBEL))
+ PCC_STATUS_SCI_DOORBELL))
return;
/*
@@ -566,7 +560,7 @@ static void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg)
TPC_CMD(((u32 *)msg)[0]) == TPC_ALARM))) {
/* Check if platform completes command */
if (xgene_word_tst_and_clr(&generic_comm_base->status,
- PCCS_CMD_COMPLETE)) {
+ PCC_STATUS_CMD_COMPLETE)) {
ctx->sync_msg.msg = ((u32 *)msg)[0];
ctx->sync_msg.param1 = ((u32 *)msg)[1];
ctx->sync_msg.param2 = ((u32 *)msg)[2];
@@ -757,7 +751,7 @@ out_mbox_free:
return rc;
}
-static int xgene_hwmon_remove(struct platform_device *pdev)
+static void xgene_hwmon_remove(struct platform_device *pdev)
{
struct xgene_hwmon_dev *ctx = platform_get_drvdata(pdev);
@@ -768,8 +762,6 @@ static int xgene_hwmon_remove(struct platform_device *pdev)
mbox_free_channel(ctx->mbox_chan);
else
pcc_mbox_free_channel(ctx->pcc_chan);
-
- return 0;
}
static const struct of_device_id xgene_hwmon_of_match[] = {
@@ -780,7 +772,7 @@ MODULE_DEVICE_TABLE(of, xgene_hwmon_of_match);
static struct platform_driver xgene_hwmon_driver = {
.probe = xgene_hwmon_probe,
- .remove = xgene_hwmon_remove,
+ .remove_new = xgene_hwmon_remove,
.driver = {
.name = "xgene-slimpro-hwmon",
.of_match_table = xgene_hwmon_of_match,