hwmon fixes for v7.4-rc2

* acpi_power_meter: Check for 32-bit and 64-bit unknown ACPI values,
   Fix missing locking in sysfs show callbacks and resume, and Prevent
   spurious power alarm when power is unknown
 
 * aquacomputer_d5next: Avoid truncating scaled sensor readings, Check
   maxcollection when probing AQUAERO devices, and reject short status
   reports
 
 * asus_rog_ryujin: Fix pump control source on the Ryujin III, and Fix
   timeout when reading 0% duty cycle
 
 * asus_wmi_sensors: Avoid global struct mutation
 
 * chipcap2: Series of fixes addressing various bugs in the driver
 
 * coretemp: Check for NULL platform device in hotplug callbacks,
   Fix 32-bit jiffies wraparound in show_temp() hnd Set nr_cores only
   after core_data allocation succeeds
 
 * corsair-cpro: Cache fan target only after a successful command
 
 * gpd-fan: Reset both fans to automatic on duo boards, and
   Update the speed cache before dropping the PM reference
 
 * hp-wmi-sensors: Avoid global struct mutation, Fix unbounded loops in
   scale_numeric_sensor(), and Serialize alarm flag read-and-clear with
   state->lock
 
 * lm75: Fix setting polarity mask for chips with 16-bit config register
 
 * lm87: Fix drvdata type confusion in vrm_show() and vrm_store()
 
 * nct6683: Fix incorrect struct cast in show_pwm() and store_pwm()
 
 * peci/dimmtemp: Fix devres leak and UAF on concurrent unbind
 
 * pmbus core: Check return value from pmbus_thermal_add_sensor(),
   Register the thermal sensors with a 0-based index, and Fix return value
   check from thermal zone registration, and release devres allocated memory
   after devm_thermal_of_zone_register error
 
 * pmbus/q54sj108a2: Add missing NULL pointer check
 
 * sht15: Stop deferred work before releasing its resources
 
 * sht4x: Convert update_interval to jiffies in pending data check
 
 * tmp108: Fix initial conversion delay and wait until ready
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmrrtEsACgkQyx8mb86f
 mYFOtw/7Bzpn9T0daAQtJ/oM5wWeMQFDGyAQCyHlgRavcGhKwhNbU1CF6ESQ14ud
 7tIubFVDRuO4wqYrRkiGcf6e65npD2WNaacEbIjNXaFtT5XmNM8xFwF6wQfS8SHz
 jWUfb79zDo1zw0bFFkCpxyh0xmH3nhRJdVKBpB6Akqcd+0M5c8lX+vF3Vwu1sFby
 kCxclMun8n40MQ2ypaHKjP1nFhFSU5IlD5ojQsDwGyfJEUV32K074+Davq/MqOC7
 0Ev6IupMTq9gp/vZTsxj0bLIeTxz2ee6eIftTCav/1Ifp1RoWRz4hlw6WxxK/nx8
 n6v6+v1+fEXCvg0Dubf607r6+PeT4AX46YQsLV/UVz1UmFvziavm7KZvEtypCwTC
 +fB+W70gXNUTcohnY3gm2SPlmRgnN+32N+Oo6T9CuCLmPZ0eKUnVAjrJpQidHfGc
 HfbSyx7Cmf5gpRtKpmqZ0Z7ya/FZFY9jq4WmzoBuh2qDMEf2afUHqBrYVO/ZA4Ho
 cz2UeV47BM0HOQomqVRcWTRe4aehO28QxnKguQnD3bqvABn219mw6Jp5oxhDFHVF
 iv2MNMVFN2WKfjjDNJmFfJJzw98nzHy+Ip7Z3SE3Gl3sovkBm7vFBJ3/FC1jKxMk
 eTUlsiZDewox7gQUzm4iChtKtu2eaUYomfsqk9xySq8zC9OcXkw=
 =ALE6
 -----END PGP SIGNATURE-----

Merge tag 'hwmon-for-v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - acpi_power_meter: Check for 32-bit and 64-bit unknown ACPI values,
   Fix missing locking in sysfs show callbacks and resume, and Prevent
   spurious power alarm when power is unknown

 - aquacomputer_d5next: Avoid truncating scaled sensor readings, Check
   maxcollection when probing AQUAERO devices, and reject short status
   reports

 - asus_rog_ryujin: Fix pump control source on the Ryujin III, and Fix
   timeout when reading 0% duty cycle

 - asus_wmi_sensors: Avoid global struct mutation

 - chipcap2: Series of fixes addressing various bugs in the driver

 - coretemp: Check for NULL platform device in hotplug callbacks, Fix
   32-bit jiffies wraparound in show_temp() hnd Set nr_cores only after
   core_data allocation succeeds

 - corsair-cpro: Cache fan target only after a successful command

 - gpd-fan: Reset both fans to automatic on duo boards, and Update the
   speed cache before dropping the PM reference

 - hp-wmi-sensors: Avoid global struct mutation, Fix unbounded loops in
   scale_numeric_sensor(), and Serialize alarm flag read-and-clear with
   state->lock

 - lm75: Fix setting polarity mask for chips with 16-bit config register

 - lm87: Fix drvdata type confusion in vrm_show() and vrm_store()

 - nct6683: Fix incorrect struct cast in show_pwm() and store_pwm()

 - peci/dimmtemp: Fix devres leak and UAF on concurrent unbind

 - pmbus core: Check return value from pmbus_thermal_add_sensor(),
   Register the thermal sensors with a 0-based index, and Fix return
   value check from thermal zone registration, and release devres
   allocated memory after devm_thermal_of_zone_register error

 - pmbus/q54sj108a2: Add missing NULL pointer check

 - sht15: Stop deferred work before releasing its resources

 - sht4x: Convert update_interval to jiffies in pending data check

 - tmp108: Fix initial conversion delay and wait until ready

* tag 'hwmon-for-v7.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (41 commits)
  hwmon: (asus_rog_ryujin) Fix timeout when reading 0% duty cycle
  hwmon: (hp-wmi-sensors) Serialize alarm flag read-and-clear with state->lock
  hwmon: (acpi_power_meter) Check for 32-bit and 64-bit unknown ACPI values
  hwmon: (acpi_power_meter) Prevent spurious power alarm when power is unknown
  hwmon: (acpi_power_meter) Fix missing locking in sysfs show callbacks and resume
  hwmon: (aquacomputer_d5next) Avoid truncating scaled sensor readings
  hwmon: (sht4x) Convert update_interval to jiffies in pending data check
  hwmon: (coretemp) Fix 32-bit jiffies wraparound in show_temp()
  hwmon: (coretemp) Set nr_cores only after core_data allocation succeeds
  hwmon: (coretemp) Check for NULL platform device in hotplug callbacks
  hwmon: (gpio-fan) Update the speed cache before dropping the PM reference
  hwmon: (tmp108) Fix initial conversion delay and wait until ready
  hwmon: (lm75) Fix setting polarity mask for chips with 16-bit config register
  hwmon: (pmbus) Fix return value check from thermal zone registration
  hwmon: (pmbus) Release devres allocated memory after devm_thermal_of_zone_register error
  hwmon: (pmbus) Check return value from pmbus_thermal_add_sensor()
  hwmon: (pmbus/q54sj108a2) Add missing NULL pointer check
  hwmon: (peci/dimmtemp) Fix devres leak and UAF on concurrent unbind
  hwmon: (nct6683) Fix incorrect struct cast in show_pwm() and store_pwm()
  hwmon: (lm87) Fix drvdata type confusion in vrm_show() and vrm_store()
  ...
This commit is contained in:
Linus Torvalds 2026-11-05 16:37:21 -08:00
commit 3e516eae69
20 changed files with 465 additions and 210 deletions

View File

@ -34,6 +34,12 @@ Usage notes
As these are USB HIDs, the driver can be loaded automatically by the kernel and
supports hot swapping.
The pump of the RYUJIN III also has a 4-pin cable for a motherboard fan header.
The cooler either hands the pump to its internal controller, which follows the
PWM of the header its 4-pin cable is plugged into, or runs it at the pump duty
set over USB. Writing pwm1 selects the duty set over USB. Writing pwm2 sets
only the internal fan duty and leaves the pump control as it is.
Sysfs entries
-------------

View File

@ -30,13 +30,6 @@
#define POWER_METER_CAN_CAP (1 << 2)
#define POWER_METER_CAN_NOTIFY (1 << 3)
#define POWER_METER_IS_BATTERY (1 << 8)
#define UNKNOWN_HYSTERESIS 0xFFFFFFFF
/*
* ACPI integers can either be 32-bit or 64-bit wide, so
* we have to check for both values.
*/
#define UNKNOWN_POWER_32 U32_MAX
#define UNKNOWN_POWER_64 U64_MAX
#define METER_NOTIFY_CONFIG 0x80
#define METER_NOTIFY_TRIP 0x81
@ -54,6 +47,15 @@ static bool force_cap_on;
static DEFINE_MUTEX(acpi_notify_lock);
/*
* ACPI integers can either be 32-bit or 64-bit wide, so
* we have to check for both values.
*/
static bool acpi_power_meter_is_unknown(u64 val)
{
return val == U32_MAX || val == U64_MAX;
}
static int can_cap_in_hardware(void)
{
return force_cap_on || cap_in_hardware;
@ -179,9 +181,10 @@ static int update_meter(struct acpi_power_meter_resource *resource)
acpi_status status;
unsigned long local_jiffies = jiffies;
if (time_before(local_jiffies, resource->sensors_last_updated +
if (!acpi_power_meter_is_unknown(resource->caps.sampling_time) &&
time_before(local_jiffies, resource->sensors_last_updated +
msecs_to_jiffies(resource->caps.sampling_time)) &&
resource->sensors_valid)
resource->sensors_valid)
return 0;
status = acpi_evaluate_integer(resource->acpi_dev->handle, "_PMM",
@ -377,28 +380,30 @@ static int set_avg_interval(struct acpi_power_meter_resource *resource,
return 0;
}
static int get_power_alarm_state(struct acpi_power_meter_resource *resource,
long *val)
static bool get_power_alarm_state(struct acpi_power_meter_resource *resource)
{
bool alarm = false;
int ret;
if (resource->caps.flags & POWER_METER_CAN_NOTIFY)
alarm = resource->power_alarm;
resource->power_alarm = false;
ret = update_meter(resource);
if (ret)
return ret;
if (ret || acpi_power_meter_is_unknown(resource->power))
return alarm;
/* need to update cap if not to support the notification. */
if (!(resource->caps.flags & POWER_METER_CAN_NOTIFY)) {
ret = update_cap(resource);
if (ret)
return ret;
resource->power_alarm = resource->power > resource->cap;
*val = resource->power_alarm;
} else {
*val = resource->power_alarm || resource->power > resource->cap;
resource->power_alarm = resource->power > resource->cap;
return false;
}
return 0;
if (acpi_power_meter_is_unknown(resource->cap))
return alarm;
return alarm || resource->power > resource->cap;
}
static umode_t power_meter_is_visible(const void *data,
@ -458,37 +463,47 @@ static int power_meter_read(struct device *dev, enum hwmon_sensor_types type,
ret = update_meter(res);
if (ret)
return ret;
if (res->power == UNKNOWN_POWER_32 || res->power == UNKNOWN_POWER_64)
if (acpi_power_meter_is_unknown(res->power))
return -ENODATA;
*val = res->power * 1000;
break;
case hwmon_power_average_interval_min:
if (acpi_power_meter_is_unknown(res->caps.min_avg_interval))
return -ENODATA;
*val = res->caps.min_avg_interval;
break;
case hwmon_power_average_interval_max:
if (acpi_power_meter_is_unknown(res->caps.max_avg_interval))
return -ENODATA;
*val = res->caps.max_avg_interval;
break;
case hwmon_power_average_interval:
ret = update_avg_interval(res);
if (ret)
return ret;
*val = (res)->avg_interval;
if (acpi_power_meter_is_unknown(res->avg_interval))
return -ENODATA;
*val = res->avg_interval;
break;
case hwmon_power_cap_min:
if (acpi_power_meter_is_unknown(res->caps.min_cap))
return -ENODATA;
*val = res->caps.min_cap * 1000;
break;
case hwmon_power_cap_max:
if (acpi_power_meter_is_unknown(res->caps.max_cap))
return -ENODATA;
*val = res->caps.max_cap * 1000;
break;
case hwmon_power_alarm:
ret = get_power_alarm_state(res, val);
if (ret)
return ret;
*val = get_power_alarm_state(res);
break;
case hwmon_power_cap:
ret = update_cap(res);
if (ret)
return ret;
if (acpi_power_meter_is_unknown(res->cap))
return -ENODATA;
*val = res->cap * 1000;
break;
default:
@ -584,6 +599,8 @@ static ssize_t power1_average_min_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (res->trip[POWER_METER_TRIP_AVERAGE_MIN_IDX] < 0)
return sysfs_emit(buf, "unknown\n");
@ -596,6 +613,8 @@ static ssize_t power1_average_max_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (res->trip[POWER_METER_TRIP_AVERAGE_MAX_IDX] < 0)
return sysfs_emit(buf, "unknown\n");
@ -608,7 +627,9 @@ static ssize_t power1_cap_hyst_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
if (res->caps.hysteresis == UNKNOWN_HYSTERESIS)
guard(mutex)(&res->lock);
if (acpi_power_meter_is_unknown(res->caps.hysteresis))
return sysfs_emit(buf, "unknown\n");
return sysfs_emit(buf, "%llu\n", res->caps.hysteresis * 1000);
@ -619,8 +640,14 @@ static ssize_t power1_accuracy_show(struct device *dev,
char *buf)
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
unsigned int acc = res->caps.accuracy;
unsigned int acc;
guard(mutex)(&res->lock);
if (acpi_power_meter_is_unknown(res->caps.accuracy))
return sysfs_emit(buf, "unknown\n");
acc = res->caps.accuracy;
return sysfs_emit(buf, "%u.%u%%\n", acc / 1000, acc % 1000);
}
@ -630,6 +657,8 @@ static ssize_t power1_is_battery_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
return sysfs_emit(buf, "%u\n",
res->caps.flags & POWER_METER_IS_BATTERY ? 1 : 0);
}
@ -640,6 +669,11 @@ static ssize_t power1_model_number_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (!res->model_number)
return -ENODATA;
return sysfs_emit(buf, "%s\n", res->model_number);
}
@ -649,6 +683,11 @@ static ssize_t power1_oem_info_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (!res->oem_info)
return -ENODATA;
return sysfs_emit(buf, "%s\n", res->oem_info);
}
@ -658,6 +697,11 @@ static ssize_t power1_serial_number_show(struct device *dev,
{
struct acpi_power_meter_resource *res = dev_get_drvdata(dev);
guard(mutex)(&res->lock);
if (!res->serial_number)
return -ENODATA;
return sysfs_emit(buf, "%s\n", res->serial_number);
}
@ -984,6 +1028,8 @@ static int acpi_power_meter_resume(struct device *dev)
{
struct acpi_power_meter_resource *resource = dev_get_drvdata(dev);
guard(mutex)(&resource->lock);
free_capabilities(resource);
read_capabilities(resource);

View File

@ -19,6 +19,7 @@
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/ktime.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/unaligned.h>
@ -132,6 +133,7 @@ static u8 aquaero_secondary_ctrl_report[] = {
#define AQUAERO_FAN_CURRENT_OFFSET 0x06
#define AQUAERO_FAN_POWER_OFFSET 0x08
#define AQUAERO_FAN_SPEED_OFFSET 0x00
#define AQUAERO_MIN_STATUS_REPORT_SIZE (0x18B + AQUAERO_FAN_POWER_OFFSET + sizeof(u16))
static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
/* Control report offsets for the Aquaero fan controllers */
@ -155,6 +157,8 @@ static u16 aquaero_ctrl_fan_offsets[] = { 0x20c, 0x220, 0x234, 0x248 };
#define D5NEXT_5V_VOLTAGE 0x39
#define D5NEXT_12V_VOLTAGE 0x37
#define D5NEXT_VIRTUAL_SENSORS_START 0x3f
#define D5NEXT_MIN_STATUS_REPORT_SIZE (D5NEXT_PUMP_OFFSET + AQC_FAN_SPEED_OFFSET + \
sizeof(u16))
static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
/* Control report offsets for the D5 Next pump */
@ -179,11 +183,14 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (fr
#define AQUASTREAMULT_FAN_CURRENT_OFFSET 0x00
#define AQUASTREAMULT_FAN_POWER_OFFSET 0x04
#define AQUASTREAMULT_FAN_SPEED_OFFSET 0x06
#define AQUASTREAMULT_MIN_STATUS_REPORT_SIZE (AQUASTREAMULT_PRESSURE_OFFSET + sizeof(u16))
static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
/* Spec and sensor report offset for the Farbwerk RGB controller */
#define FARBWERK_NUM_SENSORS 4
#define FARBWERK_SENSOR_START 0x2f
#define FARBWERK_MIN_STATUS_REPORT_SIZE (FARBWERK_SENSOR_START + \
FARBWERK_NUM_SENSORS * AQC_SENSOR_SIZE)
/* Specs of the Farbwerk 360 RGB controller */
#define FARBWERK360_NUM_SENSORS 4
@ -193,6 +200,8 @@ static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
/* Sensor report offsets for the Farbwerk 360 */
#define FARBWERK360_SENSOR_START 0x32
#define FARBWERK360_VIRTUAL_SENSORS_START 0x3a
#define FARBWERK360_MIN_STATUS_REPORT_SIZE (FARBWERK360_VIRTUAL_SENSORS_START + \
FARBWERK360_NUM_VIRTUAL_SENSORS * AQC_SENSOR_SIZE)
/* Control report offsets for the Farbwerk 360 */
#define FARBWERK360_TEMP_CTRL_OFFSET 0x8
@ -209,6 +218,7 @@ static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
#define OCTO_SENSOR_START 0x3D
#define OCTO_VIRTUAL_SENSORS_START 0x45
#define OCTO_FLOW_SENSOR_OFFSET 0x7B
#define OCTO_MIN_STATUS_REPORT_SIZE (0xD8 + AQC_FAN_SPEED_OFFSET + sizeof(u16))
static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
/* Control report offsets for the Octo */
@ -229,6 +239,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
#define QUADRO_SENSOR_START 0x34
#define QUADRO_VIRTUAL_SENSORS_START 0x3c
#define QUADRO_FLOW_SENSOR_OFFSET 0x6e
#define QUADRO_MIN_STATUS_REPORT_SIZE (0x97 + AQC_FAN_SPEED_OFFSET + sizeof(u16))
static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
/* Control report offsets for the Quadro */
@ -248,6 +259,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
#define HIGHFLOWNEXT_CONDUCTIVITY 95
#define HIGHFLOWNEXT_5V_VOLTAGE 97
#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99
#define HIGHFLOWNEXT_MIN_STATUS_REPORT_SIZE (HIGHFLOWNEXT_5V_VOLTAGE_USB + sizeof(u16))
/* Specs of the Leakshield */
#define LEAKSHIELD_NUM_SENSORS 2
@ -263,6 +275,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
#define LEAKSHIELD_FLOW_IN 111
#define LEAKSHIELD_RESERVOIR_VOLUME 313
#define LEAKSHIELD_RESERVOIR_FILLED 311
#define LEAKSHIELD_MIN_STATUS_REPORT_SIZE (LEAKSHIELD_RESERVOIR_VOLUME + sizeof(u16))
/* Specs of the Aquastream XT pump */
#define AQUASTREAMXT_SERIAL_START 0x3a
@ -554,6 +567,7 @@ struct aqc_data {
const char *name;
int status_report_id; /* Used for legacy devices, report is stored in buffer */
u16 min_report_size;
int ctrl_report_id;
int secondary_ctrl_report_id;
int secondary_ctrl_report_size;
@ -599,9 +613,9 @@ struct aqc_data {
u32 speed_input_min[1];
u32 speed_input_target[1];
u32 speed_input_max[1];
u32 power_input[8];
long power_input[8];
u16 voltage_input[8];
u16 current_input[8];
u32 current_input[8];
/* Label values */
const char *const *temp_label;
@ -976,7 +990,7 @@ static int aqc_legacy_read(struct aqc_data *priv)
/* Calculation derived from linear regression */
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_CURR_OFFSET);
priv->current_input[0] = DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52;
priv->current_input[0] = max(DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52, 0);
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_VOLTAGE_OFFSET);
priv->voltage_input[0] = DIV_ROUND_CLOSEST(sensor_value * 1000, 61);
@ -1006,6 +1020,7 @@ static int aqc_legacy_read(struct aqc_data *priv)
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
long power;
int ret;
struct aqc_data *priv = dev_get_drvdata(dev);
@ -1070,7 +1085,10 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
}
break;
case hwmon_power:
*val = priv->power_input[channel];
power = READ_ONCE(priv->power_input[channel]);
if (power == -ENODATA)
return -ENODATA;
*val = power;
break;
case hwmon_pwm:
switch (priv->kind) {
@ -1333,6 +1351,8 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
return 0;
priv = hid_get_drvdata(hdev);
if (!priv->min_report_size || size < priv->min_report_size)
return 0;
/* Info provided with every report */
priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
@ -1368,9 +1388,9 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->speed_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->speed);
priv->power_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->power) * 10000;
WRITE_ONCE(priv->power_input[i],
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->power) * 10000);
priv->voltage_input[i] =
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
priv->fan_structure->voltage) * 10;
@ -1410,7 +1430,8 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET);
priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET);
priv->power_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000;
WRITE_ONCE(priv->power_input[1],
get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000);
priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10;
@ -1423,10 +1444,11 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
case highflownext:
/* If external temp sensor is not connected, its power reading is also N/A */
if (priv->temp_input[1] == -ENODATA)
priv->power_input[0] = -ENODATA;
WRITE_ONCE(priv->power_input[0], -ENODATA);
else
priv->power_input[0] =
get_unaligned_be16(data + HIGHFLOWNEXT_POWER) * 1000000;
WRITE_ONCE(priv->power_input[0],
min_t(u64, get_unaligned_be16(data + HIGHFLOWNEXT_POWER) *
1000000ULL, LONG_MAX));
priv->voltage_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE) * 10;
priv->voltage_input[1] =
@ -1518,6 +1540,7 @@ static void aqc_debugfs_init(struct aqc_data *priv)
static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct aqc_data *priv;
u16 min_report_size = 0;
int ret;
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
@ -1554,7 +1577,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
* they present. The two other devices have the type of the second element in
* their respective collections set to 1, while the real device has it set to 0.
*/
if (hdev->collection[1].type != 0) {
if (hdev->maxcollection < 2 || hdev->collection[1].type != 0) {
ret = -ENODEV;
goto fail_and_close;
}
@ -1585,6 +1608,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_fan_power;
priv->voltage_label = label_fan_voltage;
priv->current_label = label_fan_current;
min_report_size = AQUAERO_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_D5NEXT:
priv->kind = d5next;
@ -1610,6 +1634,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_d5next_power;
priv->voltage_label = label_d5next_voltages;
priv->current_label = label_d5next_current;
min_report_size = D5NEXT_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_FARBWERK:
priv->kind = farbwerk;
@ -1620,6 +1645,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_sensor_start_offset = FARBWERK_SENSOR_START;
priv->temp_label = label_temp_sensors;
min_report_size = FARBWERK_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_FARBWERK360:
priv->kind = farbwerk360;
@ -1636,6 +1662,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_label = label_temp_sensors;
priv->virtual_temp_label = label_virtual_temp_sensors;
min_report_size = FARBWERK360_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_OCTO:
priv->kind = octo;
@ -1665,6 +1692,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_fan_power;
priv->voltage_label = label_fan_voltage;
priv->current_label = label_fan_current;
min_report_size = OCTO_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_QUADRO:
priv->kind = quadro;
@ -1694,6 +1722,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_fan_power;
priv->voltage_label = label_fan_voltage;
priv->current_label = label_fan_current;
min_report_size = QUADRO_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_HIGHFLOWNEXT:
priv->kind = highflownext;
@ -1711,6 +1740,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->speed_label = label_highflownext_fan_speed;
priv->power_label = label_highflownext_power;
priv->voltage_label = label_highflownext_voltage;
min_report_size = HIGHFLOWNEXT_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_LEAKSHIELD:
/*
@ -1730,6 +1760,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_label = label_leakshield_temp_sensors;
priv->speed_label = label_leakshield_fan_speed;
min_report_size = LEAKSHIELD_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_AQUASTREAMXT:
priv->kind = aquastreamxt;
@ -1760,6 +1791,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->power_label = label_aquastreamult_power;
priv->voltage_label = label_aquastreamult_voltages;
priv->current_label = label_aquastreamult_current;
min_report_size = AQUASTREAMULT_MIN_STATUS_REPORT_SIZE;
break;
case USB_PRODUCT_ID_POWERADJUST3:
priv->kind = poweradjust3;
@ -1833,6 +1865,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
break;
}
priv->min_report_size = min_report_size;
if (priv->buffer_size != 0) {
priv->checksum_start = 0x01;
priv->checksum_length = priv->buffer_size - 3;

View File

@ -50,6 +50,7 @@ static const struct rog_ryujin_device_info rog_ryujin_iii_info = {
#define MAX_REPORT_LENGTH 65
/* Cooler duty report offsets */
#define RYUJIN_PUMP_SOURCE 3
#define RYUJIN_PUMP_DUTY 4
#define RYUJIN_INTERNAL_FAN_DUTY 5
@ -70,10 +71,15 @@ static const u8 get_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x9A };
static const u8 get_controller_speed_cmd[] = { RYUJIN_CMD_PREFIX, 0xA0 };
static const u8 get_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0xA1 };
#define RYUJIN_SET_COOLER_CHANNEL_OFFSET 2
#define RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET 3
#define RYUJIN_SET_COOLER_FAN_DUTY_OFFSET 4
static const u8 set_cooler_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x1A, 0x00, 0x00, 0x00 };
/* Pump control sources in the set cooler duty command and the cooler duty report */
#define RYUJIN_SOURCE_HEADER 0
#define RYUJIN_SOURCE_USB 1
#define RYUJIN_SET_CONTROLLER_FAN_DUTY_OFFSET 4
static const u8 set_controller_duty_cmd[] = { RYUJIN_CMD_PREFIX, 0x21, 0x00, 0x00, 0x00 };
@ -117,6 +123,7 @@ struct rog_ryujin_data {
s32 temp_input[1];
u16 speed_input[6]; /* Pump, internal fan and four controller fan speeds in RPM */
u8 duty_input[3]; /* Pump, internal fan and controller fan duty in PWM */
u8 pump_source; /* Pump control source from the cooler duty report */
u8 *buffer;
unsigned long updated; /* jiffies */
@ -200,16 +207,23 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i
/* Send command for getting data */
ret = rog_ryujin_write_expanded(priv, cmd, cmd_length);
if (ret < 0)
return ret;
goto out_complete;
ret = wait_for_completion_interruptible_timeout(status_completion,
msecs_to_jiffies(STATUS_VALIDITY));
if (ret == 0)
return -ETIMEDOUT;
else if (ret < 0)
return ret;
ret = -ETIMEDOUT;
if (ret < 0)
goto out_complete;
return 0;
out_complete:
spin_lock_irqsave(&priv->status_report_request_lock, flags);
if (!completion_done(status_completion))
complete_all(status_completion);
spin_unlock_irqrestore(&priv->status_report_request_lock, flags);
return ret;
}
static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
@ -306,6 +320,44 @@ static int rog_ryujin_read_string(struct device *dev, enum hwmon_sensor_types ty
return 0;
}
/*
* On devices with a non-zero duty_channel (the RYUJIN III), the channel byte of
* the set cooler duty command selects the pump control source.
* RYUJIN_SOURCE_HEADER hands the pump to its internal controller, which follows
* the PWM of the header its 4-pin cable is plugged into. RYUJIN_SOURCE_USB
* makes the pump follow the pump duty in the command. The cooler duty report
* returns the current source.
*
* A fan duty write sends the reported source back, so that it leaves the pump
* control source as it is. A pump duty write selects USB. The cooler does not
* pass on a pump duty equal to the one it reports, and after power-on it
* reports 40% while a pump handed over at that duty runs at full speed. So
* when a pump duty write asks for the reported duty, write a duty 1% away
* first.
*/
static int rog_ryujin_select_pump_source(struct rog_ryujin_data *priv, u8 *set_cmd,
int channel)
{
u8 duty = set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET];
int ret;
if (channel == 1) {
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = priv->pump_source;
return 0;
}
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = RYUJIN_SOURCE_USB;
if (duty != rog_ryujin_pwm_to_percent(priv->duty_input[0]))
return 0;
set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = duty < 100 ? duty + 1 : duty - 1;
ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
set_cmd[RYUJIN_SET_COOLER_PUMP_DUTY_OFFSET] = duty;
return ret;
}
static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel, int val)
{
u8 set_cmd[SET_CMD_LENGTH];
@ -323,7 +375,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
return ret;
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
set_cmd[2] = priv->info->duty_channel;
set_cmd[RYUJIN_SET_COOLER_CHANNEL_OFFSET] = priv->info->duty_channel;
/* Cooler duties are set as 0-100% */
val = rog_ryujin_pwm_to_percent(val);
@ -340,6 +392,12 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
}
if (priv->info->duty_channel) {
ret = rog_ryujin_select_pump_source(priv, set_cmd, channel);
if (ret < 0)
return ret;
}
return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
} else {
/*
@ -482,6 +540,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo
goto unlock;
}
read_cooler_duty:
priv->pump_source = data[RYUJIN_PUMP_SOURCE];
priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]);
priv->duty_input[1] = rog_ryujin_percent_to_pwm(data[RYUJIN_INTERNAL_FAN_DUTY]);
@ -578,6 +637,18 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id
init_completion(&priv->cooler_duty_set);
init_completion(&priv->controller_duty_set);
/*
* Start completions in the completed state so rog_ryujin_raw_event()
* only sees !completion_done() while rog_ryujin_execute_cmd() is
* awaiting a response.
*/
complete_all(&priv->cooler_status_received);
complete_all(&priv->controller_status_received);
complete_all(&priv->cooler_duty_received);
complete_all(&priv->controller_duty_received);
complete_all(&priv->cooler_duty_set);
complete_all(&priv->controller_duty_set);
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "rog_ryujin",
priv, &rog_ryujin_chip_info, NULL);
if (IS_ERR(priv->hwmon_dev)) {

View File

@ -164,6 +164,7 @@ struct asus_wmi_wmi_info {
struct asus_wmi_sensors {
struct asus_wmi_wmi_info wmi;
struct hwmon_chip_info chip_info;
/* lock access to internal cache */
struct mutex lock;
};
@ -496,11 +497,6 @@ static const struct hwmon_ops asus_wmi_hwmon_ops = {
.read_string = asus_wmi_hwmon_read_string,
};
static struct hwmon_chip_info asus_wmi_chip_info = {
.ops = &asus_wmi_hwmon_ops,
.info = NULL,
};
static int asus_wmi_configure_sensor_setup(struct device *dev,
struct asus_wmi_sensors *sensor_data)
{
@ -508,7 +504,7 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
struct hwmon_channel_info *asus_wmi_hwmon_chan;
int nr_count[hwmon_max] = {}, nr_types = 0;
struct asus_wmi_sensor_info *temp_sensor;
const struct hwmon_chip_info *chip_info;
struct hwmon_chip_info *chip_info;
enum hwmon_sensor_types type;
struct device *hwdev;
int i, idx;
@ -549,8 +545,9 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
if (!ptr_asus_wmi_ci)
return -ENOMEM;
asus_wmi_chip_info.info = ptr_asus_wmi_ci;
chip_info = &asus_wmi_chip_info;
chip_info = &sensor_data->chip_info;
chip_info->ops = &asus_wmi_hwmon_ops;
chip_info->info = ptr_asus_wmi_ci;
sensor_data->wmi.info_by_id = devm_kcalloc(dev, sensor_data->wmi.sensor_count,
sizeof(*sensor_data->wmi.info_by_id),

View File

@ -20,7 +20,9 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/unaligned.h>
#include <linux/regulator/consumer.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
@ -90,6 +92,9 @@ struct cc2_data {
int irq_low;
int irq_high;
bool process_irqs;
/* protects process_irqs and the alarm indicators */
struct mutex irq_lock;
bool regulator_enabled;
};
/* %RH as a per cent mille from a register value */
@ -118,20 +123,33 @@ static int cc2_enable(struct cc2_data *data)
{
int ret;
/* exclusive regulator, check in case a disable failed */
if (regulator_is_enabled(data->regulator))
return 0;
if (data->irq_ready > 0) {
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = false;
/* clear any pending completion */
try_wait_for_completion(&data->complete);
synchronize_irq(data->irq_ready);
scoped_guard(mutex, &data->irq_lock)
reinit_completion(&data->complete);
}
/* exclusive regulator, check in case a disable failed */
if (data->regulator_enabled) {
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = true;
return 0;
}
ret = regulator_enable(data->regulator);
if (ret < 0)
return ret;
data->regulator_enabled = true;
usleep_range(CC2_STARTUP_TIME_US, CC2_STARTUP_TIME_US + 125);
data->process_irqs = true;
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = true;
return 0;
}
@ -140,15 +158,36 @@ static void cc2_disable(struct cc2_data *data)
{
int err;
/* let the alarms already raised by the last measurement be processed */
if (data->irq_low > 0)
synchronize_irq(data->irq_low);
if (data->irq_high > 0)
synchronize_irq(data->irq_high);
/* ignore alarms triggered by voltage toggling when powering up */
data->process_irqs = false;
scoped_guard(mutex, &data->irq_lock)
data->process_irqs = false;
if (data->irq_ready > 0)
synchronize_irq(data->irq_ready);
/* exclusive regulator, check in case an enable failed */
if (regulator_is_enabled(data->regulator)) {
err = regulator_disable(data->regulator);
if (err)
dev_dbg(&data->client->dev, "Failed to disable device");
if (!data->regulator_enabled)
return;
err = regulator_disable(data->regulator);
if (err) {
dev_dbg(&data->client->dev, "Failed to disable device");
return;
}
data->regulator_enabled = false;
}
static void cc2_disable_action(void *data)
{
cc2_disable(data);
}
static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
@ -167,13 +206,13 @@ static int cc2_cmd_response_diagnostic(struct device *dev, u8 status)
case CC2_RESPONSE_BUSY:
return -EBUSY;
case CC2_RESPONSE_NACK:
if (resp & CC2_ERR_CORR_EEPROM)
if (status & CC2_ERR_CORR_EEPROM)
dev_dbg(dev, "Command failed: corrected EEPROM\n");
if (resp & CC2_ERR_UNCORR_EEPROM)
if (status & CC2_ERR_UNCORR_EEPROM)
dev_dbg(dev, "Command failed: uncorrected EEPROM\n");
if (resp & CC2_ERR_RAM_PARITY)
if (status & CC2_ERR_RAM_PARITY)
dev_dbg(dev, "Command failed: RAM parity\n");
if (resp & CC2_ERR_RAM_PARITY)
if (status & CC2_ERR_CONFIG_LOAD)
dev_dbg(dev, "Command failed: configuration error\n");
return -ENODATA;
default:
@ -226,7 +265,7 @@ static int cc2_command_mode_start(struct cc2_data *data)
2 * CC2_RESP_START_CM_US);
}
ret = cc2_read_command_status(data->client);
if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES)
if (ret != -ETIMEDOUT || i == CC2_CM_RETRIES - 1)
break;
/* command window missed, prepare for a retry */
@ -260,8 +299,7 @@ static int cc2_write_reg(struct cc2_data *data, u8 reg, u16 val)
if (ret < 0)
goto disable;
cpu_to_be16s(&val);
ret = i2c_smbus_write_word_data(data->client, reg, val);
ret = i2c_smbus_write_word_swapped(data->client, reg, val);
if (ret < 0)
goto disable;
@ -311,7 +349,7 @@ static int cc2_read_reg(struct cc2_data *data, u8 reg, u16 *val)
if (ret != CC2_EEPROM_DATA_LEN)
return ret < 0 ? ret : -EIO;
*val = be16_to_cpup((__be16 *)&buf[1]);
*val = get_unaligned_be16(&buf[1]);
return cc2_read_command_status(data->client);
}
@ -351,10 +389,10 @@ static int cc2_data_fetch(struct i2c_client *client,
switch (type) {
case hwmon_humidity:
*val = cc2_rh_convert(be16_to_cpup((__be16 *)&data[0]));
*val = cc2_rh_convert(get_unaligned_be16(&data[0]));
break;
case hwmon_temp:
*val = cc2_temp_convert(be16_to_cpup((__be16 *)&data[2]));
*val = cc2_temp_convert(get_unaligned_be16(&data[2]));
break;
default:
return -EINVAL;
@ -482,8 +520,10 @@ static irqreturn_t cc2_ready_interrupt(int irq, void *data)
{
struct cc2_data *cc2 = data;
if (cc2->process_irqs)
complete(&cc2->complete);
scoped_guard(mutex, &cc2->irq_lock) {
if (cc2->process_irqs)
complete(&cc2->complete);
}
return IRQ_HANDLED;
}
@ -492,10 +532,12 @@ static irqreturn_t cc2_low_interrupt(int irq, void *data)
{
struct cc2_data *cc2 = data;
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_min_alarm, 0);
cc2->rh_alarm.low_alarm = true;
scoped_guard(mutex, &cc2->irq_lock) {
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_min_alarm, 0);
cc2->rh_alarm.low_alarm = true;
}
}
return IRQ_HANDLED;
@ -505,10 +547,12 @@ static irqreturn_t cc2_high_interrupt(int irq, void *data)
{
struct cc2_data *cc2 = data;
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_max_alarm, 0);
cc2->rh_alarm.high_alarm = true;
scoped_guard(mutex, &cc2->irq_lock) {
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
hwmon_humidity_max_alarm, 0);
cc2->rh_alarm.high_alarm = true;
}
}
return IRQ_HANDLED;
@ -524,11 +568,13 @@ static int cc2_humidity_min_alarm_status(struct cc2_data *data, long *val)
if (ret < 0)
return ret;
if (data->rh_alarm.low_alarm) {
*val = (measurement < min_hyst) ? 1 : 0;
data->rh_alarm.low_alarm = *val;
} else {
*val = 0;
scoped_guard(mutex, &data->irq_lock) {
if (data->rh_alarm.low_alarm) {
*val = (measurement < min_hyst) ? 1 : 0;
data->rh_alarm.low_alarm = *val;
} else {
*val = 0;
}
}
return 0;
@ -544,11 +590,13 @@ static int cc2_humidity_max_alarm_status(struct cc2_data *data, long *val)
if (ret < 0)
return ret;
if (data->rh_alarm.high_alarm) {
*val = (measurement > max_hyst) ? 1 : 0;
data->rh_alarm.high_alarm = *val;
} else {
*val = 0;
scoped_guard(mutex, &data->irq_lock) {
if (data->rh_alarm.high_alarm) {
*val = (measurement > max_hyst) ? 1 : 0;
data->rh_alarm.high_alarm = *val;
} else {
*val = 0;
}
}
return 0;
@ -631,28 +679,47 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
}
}
static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev)
static int cc2_get_irqs(struct cc2_data *data, struct device *dev)
{
data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
if (data->irq_ready == -EPROBE_DEFER)
return data->irq_ready;
if (data->irq_ready > 0)
init_completion(&data->complete);
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
if (data->irq_low == -EPROBE_DEFER)
return data->irq_low;
if (data->irq_low > 0)
data->rh_alarm.low_alarm_visible = true;
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
if (data->irq_high == -EPROBE_DEFER)
return data->irq_high;
if (data->irq_high > 0)
data->rh_alarm.high_alarm_visible = true;
return 0;
}
static int cc2_request_data_ready(struct cc2_data *data, struct device *dev)
{
int ret = 0;
data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
if (data->irq_ready > 0) {
init_completion(&data->complete);
if (data->irq_ready > 0)
ret = devm_request_threaded_irq(dev, data->irq_ready, NULL,
cc2_ready_interrupt,
IRQF_ONESHOT |
IRQF_TRIGGER_RISING,
dev_name(dev), data);
}
return ret;
}
static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
static int cc2_request_alarms(struct cc2_data *data, struct device *dev)
{
int ret = 0;
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
if (data->irq_low > 0) {
ret = devm_request_threaded_irq(dev, data->irq_low, NULL,
cc2_low_interrupt,
@ -661,11 +728,8 @@ static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
dev_name(dev), data);
if (ret)
return ret;
data->rh_alarm.low_alarm_visible = true;
}
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
if (data->irq_high > 0) {
ret = devm_request_threaded_irq(dev, data->irq_high, NULL,
cc2_high_interrupt,
@ -674,8 +738,6 @@ static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
dev_name(dev), data);
if (ret)
return ret;
data->rh_alarm.high_alarm_visible = true;
}
return ret;
@ -717,6 +779,8 @@ static int cc2_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
mutex_init(&data->irq_lock);
data->client = client;
data->regulator = devm_regulator_get_exclusive(dev, "vdd");
@ -726,14 +790,18 @@ static int cc2_probe(struct i2c_client *client)
device_property_read_string(dev, "label", &data->label);
ret = cc2_request_ready_irq(data, dev);
ret = cc2_get_irqs(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to get IRQs\n");
ret = devm_add_action_or_reset(dev, cc2_disable_action, data);
if (ret)
return ret;
ret = cc2_request_data_ready(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to request ready irq\n");
ret = cc2_request_alarm_irqs(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
data->hwmon = devm_hwmon_device_register_with_info(dev, client->name,
data, &cc2_chip_info,
NULL);
@ -741,16 +809,13 @@ static int cc2_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(data->hwmon),
"Failed to register hwmon device\n");
ret = cc2_request_alarms(data, dev);
if (ret)
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
return 0;
}
static void cc2_remove(struct i2c_client *client)
{
struct cc2_data *data = i2c_get_clientdata(client);
cc2_disable(data);
}
static const struct i2c_device_id cc2_id[] = {
{ .name = "cc2d23" },
{ .name = "cc2d23s" },
@ -783,7 +848,6 @@ static struct i2c_driver cc2_driver = {
.of_match_table = cc2_of_match,
},
.probe = cc2_probe,
.remove = cc2_remove,
.id_table = cc2_id,
};
module_i2c_driver(cc2_driver);

View File

@ -76,7 +76,7 @@ struct temp_data {
int temp;
bool temp_valid;
int tjmax;
unsigned long last_updated;
u64 last_updated;
unsigned int cpu;
int index;
u32 cpu_core_id;
@ -407,7 +407,7 @@ static ssize_t show_temp(struct device *dev,
mutex_lock(&tdata->update_lock);
/* Check whether the time interval has elapsed */
if (time_after(jiffies, tdata->last_updated + HZ)) {
if (time_after64(get_jiffies_64(), tdata->last_updated + HZ)) {
tjmax = get_tjmax(tdata, dev);
rdmsrq_on_cpu(tdata->cpu, tdata->status_reg, &val.q);
/*
@ -417,7 +417,7 @@ static ssize_t show_temp(struct device *dev,
*/
tdata->temp_valid = (val.l >> 31) & 1;
tdata->temp = tjmax - ((val.l >> 16) & 0xff) * 1000;
tdata->last_updated = jiffies;
tdata->last_updated = get_jiffies_64();
}
valid = tdata->temp_valid;
@ -491,11 +491,12 @@ init_temp_data(struct platform_data *pdata, unsigned int cpu, int pkg_flag)
struct temp_data *tdata;
if (!pdata->core_data) {
pdata->nr_cores = topology_num_cores_per_package();
pdata->core_data = kzalloc_objs(struct temp_data *,
pdata->nr_cores);
int nr_cores = topology_num_cores_per_package();
pdata->core_data = kzalloc_objs(struct temp_data *, nr_cores);
if (!pdata->core_data)
return NULL;
pdata->nr_cores = nr_cores;
}
tdata = kzalloc_obj(struct temp_data);
@ -520,11 +521,8 @@ init_temp_data(struct platform_data *pdata, unsigned int cpu, int pkg_flag)
tdata->cpu = cpu;
tdata->cpu_core_id = topology_core_id(cpu);
tdata->attr_size = MAX_CORE_ATTRS;
/*
* A zero timestamp does not look stale on 32-bit, where jiffies
* starts just short of wrapping. Backdate it instead.
*/
tdata->last_updated = jiffies - HZ - 1;
/* Backdate to force a refresh on the first read */
tdata->last_updated = get_jiffies_64() - HZ - 1;
mutex_init(&tdata->update_lock);
return tdata;
}
@ -695,6 +693,9 @@ static int coretemp_cpu_online(unsigned int cpu)
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
return 0;
if (!pdev)
return 0;
pdata = platform_get_drvdata(pdev);
if (!pdata->hwmon_dev) {
struct device *hwmon;
@ -746,6 +747,9 @@ static int coretemp_cpu_offline(unsigned int cpu)
return 0;
/* If the physical CPU device does not exist, just return */
if (!pdev)
return 0;
pd = platform_get_drvdata(pdev);
if (!pd->hwmon_dev)
return 0;

View File

@ -215,10 +215,11 @@ static int set_target(struct ccp_device *ccp, int channel, long val)
int ret;
val = clamp_val(val, 0, 0xFFFF);
ccp->target[channel] = val;
mutex_lock(&ccp->mutex);
ret = send_usb_cmd(ccp, CTL_SET_FAN_TARGET, channel, val >> 8, val);
if (!ret)
ccp->target[channel] = val;
mutex_unlock(&ccp->mutex);
return ret;

View File

@ -444,6 +444,7 @@ static void gpd_duo_set_pwm_enable(struct gpd_fan_data *data, enum FAN_PWM_ENABL
break;
case AUTOMATIC:
gpd_ecram_write(data->drvdata, data->drvdata->pwm_write, 0);
gpd_ecram_write(data->drvdata, data->drvdata->pwm_write + 1, 0);
break;
}
}

View File

@ -150,7 +150,10 @@ static int set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
__set_fan_ctrl(fan_data, fan_data->speed[speed_index].ctrl_val);
if (fan_data->speed_index > 0 && speed_index == 0) {
/* The GPIOs have changed, and a PM put drops the reference on error. */
fan_data->speed_index = speed_index;
if (speed_index == 0) {
int ret;
ret = pm_runtime_put_sync(fan_data->dev);
@ -158,8 +161,6 @@ static int set_fan_speed(struct gpio_fan_data *fan_data, int speed_index)
return ret;
}
fan_data->speed_index = speed_index;
return 0;
}

View File

@ -390,6 +390,7 @@ struct hp_wmi_info {
*/
struct hp_wmi_sensors {
struct wmi_device *wdev;
struct hwmon_chip_info chip_info;
struct hp_wmi_info **info_map[hwmon_max];
u8 channel_count[hwmon_max];
bool has_intrusion;
@ -738,15 +739,21 @@ static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)
val = current_reading;
for (; unit_modifier < target_modifier; unit_modifier++)
for (; val && unit_modifier < target_modifier; unit_modifier++)
val = DIV_ROUND_CLOSEST(val, 10);
for (; unit_modifier > target_modifier; unit_modifier--) {
if (val > LONG_MAX / 10) {
val = LONG_MAX;
break;
if (val) {
for (; unit_modifier > target_modifier; unit_modifier--) {
if (val > LONG_MAX / 10) {
val = LONG_MAX;
break;
}
if (val < LONG_MIN / 10) {
val = LONG_MIN;
break;
}
val *= 10;
}
val *= 10;
}
if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {
@ -1473,8 +1480,10 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
(type == hwmon_fan && attr == hwmon_fan_alarm)) {
mutex_lock(&state->lock);
*out_val = info->alarm ? 1 : 0;
info->alarm = false;
mutex_unlock(&state->lock);
return 0;
}
@ -1531,11 +1540,6 @@ static const struct hwmon_ops hp_wmi_hwmon_ops = {
.write = hp_wmi_hwmon_write,
};
static struct hwmon_chip_info hp_wmi_chip_info = {
.ops = &hp_wmi_hwmon_ops,
.info = NULL,
};
static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,
const char *event_description)
{
@ -1962,7 +1966,8 @@ static int make_chip_info(struct hp_wmi_sensors *state, bool has_events)
if (!ptr_channel_info)
return -ENOMEM;
hp_wmi_chip_info.info = ptr_channel_info;
state->chip_info.ops = &hp_wmi_hwmon_ops;
state->chip_info.info = ptr_channel_info;
for (type = hwmon_chip; type < hwmon_max; type++) {
count = channel_count[type];
@ -2053,7 +2058,7 @@ static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
return err;
hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",
state, &hp_wmi_chip_info,
state, &state->chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwdev);
}

View File

@ -123,8 +123,7 @@ struct lm75_data {
static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 };
#define LM75_ALERT_POLARITY_HIGH_8_BIT (BIT(2))
#define LM75_ALERT_POLARITY_HIGH_16_BIT (BIT(2) << 8)
#define LM75_ALERT_POLARITY_HIGH_BIT BIT(2)
#define LM75_SAMPLE_CLEAR_MASK (3 << 5)
/* The structure below stores the configuration values of the supported devices.
@ -770,11 +769,7 @@ static int lm75_generic_probe(struct device *dev, const char *name,
data->orig_conf = status;
/* Enforce polarity active-low (default) or active-high (devicetree) */
if (!data->params->config_reg_16bits)
pol_mask = LM75_ALERT_POLARITY_HIGH_8_BIT;
else
pol_mask = LM75_ALERT_POLARITY_HIGH_16_BIT;
pol_mask = LM75_ALERT_POLARITY_HIGH_BIT;
clr_mask = data->params->clr_mask | pol_mask;
set_mask = data->params->set_mask & ~pol_mask;
if (device_property_read_bool(dev, "ti,alert-polarity-active-high"))

View File

@ -606,13 +606,16 @@ static DEVICE_ATTR_RO(cpu0_vid);
static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lm87_data *data = dev_get_drvdata(dev);
struct i2c_client *client = dev_get_drvdata(dev);
struct lm87_data *data = i2c_get_clientdata(client);
return sprintf(buf, "%d\n", data->vrm);
}
static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lm87_data *data = dev_get_drvdata(dev);
struct i2c_client *client = dev_get_drvdata(dev);
struct lm87_data *data = i2c_get_clientdata(client);
unsigned long val;
int err;

View File

@ -920,7 +920,7 @@ static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
{
struct nct6683_data *data = nct6683_update_device(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int index = sattr->index;
return sprintf(buf, "%d\n", data->pwm[index]);
@ -930,7 +930,7 @@ static ssize_t
store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
struct nct6683_data *data = dev_get_drvdata(dev);
int index = sattr->index;
unsigned long val;

View File

@ -4,7 +4,6 @@
#include <linux/auxiliary_bus.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/devm-helpers.h>
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/module.h>
@ -326,11 +325,13 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
if (ret == -ENODEV) {
dev_dbg(priv->dev, "No DIMMs found\n");
return 0;
} else if (ret) {
}
if (ret == -EAGAIN) {
schedule_delayed_work(&priv->detect_work, DIMM_MASK_CHECK_DELAY_JIFFIES);
dev_dbg(priv->dev, "Deferred populating DIMM temp info\n");
return ret;
}
if (ret)
return ret;
channels = priv->gen_info->chan_rank_max * priv->gen_info->dimm_idx_max;
@ -398,10 +399,8 @@ static int peci_dimmtemp_probe(struct auxiliary_device *adev, const struct auxil
"Unexpected PECI revision %#x, some features may be unavailable\n",
peci_dev->info.peci_revision);
ret = devm_delayed_work_autocancel(priv->dev, &priv->detect_work,
create_dimm_temp_info_delayed);
if (ret)
return ret;
auxiliary_set_drvdata(adev, priv);
INIT_DELAYED_WORK(&priv->detect_work, create_dimm_temp_info_delayed);
ret = create_dimm_temp_info(priv);
if (ret && ret != -EAGAIN) {
@ -412,6 +411,13 @@ static int peci_dimmtemp_probe(struct auxiliary_device *adev, const struct auxil
return 0;
}
static void peci_dimmtemp_remove(struct auxiliary_device *adev)
{
struct peci_dimmtemp *priv = auxiliary_get_drvdata(adev);
cancel_delayed_work_sync(&priv->detect_work);
}
static int
read_thresholds_hsx(struct peci_dimmtemp *priv, int dimm_order, int chan_rank, u32 *data)
{
@ -665,6 +671,7 @@ MODULE_DEVICE_TABLE(auxiliary, peci_dimmtemp_ids);
static struct auxiliary_driver peci_dimmtemp_driver = {
.probe = peci_dimmtemp_probe,
.remove = peci_dimmtemp_remove,
.id_table = peci_dimmtemp_ids,
};

View File

@ -1524,14 +1524,22 @@ static int pmbus_thermal_add_sensor(struct pmbus_data *pmbus_data,
tdata->sensor = sensor;
tdata->pmbus_data = pmbus_data;
tzd = devm_thermal_of_zone_register(dev, index, tdata,
/*
* The PMBus core numbers its temperature sensors from 1, as the
* hwmon tempN attributes, while the thermal core expects a 0-based
* sensor index.
*/
tzd = devm_thermal_of_zone_register(dev, index - 1, tdata,
&pmbus_thermal_ops);
/*
* If CONFIG_THERMAL_OF is disabled, this returns -ENODEV,
* so ignore that error but forward any other error.
* If CONFIG_THERMAL_OF is disabled, devm_thermal_of_zone_register()
* returns -ENOTSUPP. If no thermal zone is configured for the sensor,
* it returns -ENODEV. Ignore those errors but forward any other error.
*/
if (IS_ERR(tzd) && (PTR_ERR(tzd) != -ENODEV))
if (IS_ERR(tzd) && PTR_ERR(tzd) != -ENODEV && PTR_ERR(tzd) != -ENOTSUPP) {
devm_kfree(dev, tdata);
return PTR_ERR(tzd);
}
return 0;
}
@ -1546,10 +1554,11 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
{
struct sensor_device_attribute *a;
struct pmbus_sensor *sensor;
int err;
sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return NULL;
return ERR_PTR(-ENOMEM);
a = &sensor->attribute;
if (type)
@ -1574,14 +1583,17 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
pmbus_set_sensor, -1);
if (pmbus_add_attribute(data, &a->dev_attr.attr))
return NULL;
return ERR_PTR(-ENOMEM);
sensor->next = data->sensors;
data->sensors = sensor;
/* temperature sensors with _input values are registered with thermal */
if (class == PSC_TEMPERATURE && strcmp(type, "input") == 0)
pmbus_thermal_add_sensor(data, sensor, seq);
if (class == PSC_TEMPERATURE && strcmp(type, "input") == 0) {
err = pmbus_thermal_add_sensor(data, sensor, seq);
if (err)
return ERR_PTR(err);
}
return sensor;
}
@ -1682,8 +1694,8 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
page, 0xff, l->reg, attr->class,
attr->update || l->update,
l->readonly, l->writeonly, true);
if (!curr)
return -ENOMEM;
if (IS_ERR(curr))
return PTR_ERR(curr);
if (l->sbit && (info->func[page] & attr->sfunc)) {
ret = pmbus_add_boolean(data, name,
l->alarm, index,
@ -1722,8 +1734,8 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
}
base = pmbus_add_sensor(data, name, "input", index, page, phase,
attr->reg, attr->class, true, true, false, true);
if (!base)
return -ENOMEM;
if (IS_ERR(base))
return PTR_ERR(base);
/* No limit and alarm attributes for phase specific sensors */
if (attr->sfunc && phase == 0xff) {
ret = pmbus_add_limit_attrs(client, data, info, name,
@ -2396,8 +2408,8 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
false, false, false, true);
if (!sensor)
return -ENOMEM;
if (IS_ERR(sensor))
return PTR_ERR(sensor);
if (!((data->info->func[page] & PMBUS_HAVE_PWM12) ||
(data->info->func[page] & PMBUS_HAVE_PWM34)))
@ -2407,15 +2419,15 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM,
false, false, false, true);
if (!sensor)
return -ENOMEM;
if (IS_ERR(sensor))
return PTR_ERR(sensor);
sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
true, false, false, false);
if (!sensor)
return -ENOMEM;
if (IS_ERR(sensor))
return PTR_ERR(sensor);
return 0;
}
@ -2432,6 +2444,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
int f;
for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) {
struct pmbus_sensor *sensor;
int regval;
if (!(info->func[page] & pmbus_fan_flags[f]))
@ -2452,10 +2465,11 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
(!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
continue;
if (pmbus_add_sensor(data, "fan", "input", index,
page, 0xff, pmbus_fan_registers[f],
PSC_FAN, true, true, false, true) == NULL)
return -ENOMEM;
sensor = pmbus_add_sensor(data, "fan", "input", index,
page, 0xff, pmbus_fan_registers[f],
PSC_FAN, true, true, false, true);
if (IS_ERR(sensor))
return PTR_ERR(sensor);
/* Fan control */
if (pmbus_check_word_register(client, page,

View File

@ -351,6 +351,8 @@ static int q54sj108a2_probe(struct i2c_client *client)
psu->client = client;
debugfs = pmbus_get_debugfs_dir(client);
if (!debugfs)
return 0;
q54sj108a2_dir = debugfs_create_dir(client->name, debugfs);

View File

@ -31,6 +31,7 @@
#include <linux/bitrev.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/workqueue.h>
/* Commands */
#define SHT15_MEASURE_TEMP 0x03
@ -976,25 +977,22 @@ static int sht15_probe(struct platform_device *pdev)
goto err_release_reg;
}
ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
sht15_interrupt_fired,
IRQF_TRIGGER_FALLING,
"sht15 data",
data);
ret = request_irq(gpiod_to_irq(data->data), sht15_interrupt_fired,
IRQF_TRIGGER_FALLING, "sht15 data", data);
if (ret)
goto err_release_reg;
disable_irq_nosync(gpiod_to_irq(data->data));
ret = sht15_connection_reset(data);
if (ret)
goto err_release_reg;
goto err_free_irq;
ret = sht15_soft_reset(data);
if (ret)
goto err_release_reg;
goto err_free_irq;
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
if (ret) {
dev_err(&pdev->dev, "sysfs create failed\n");
goto err_release_reg;
goto err_free_irq;
}
data->hwmon_dev = hwmon_device_register(data->dev);
@ -1007,9 +1005,13 @@ static int sht15_probe(struct platform_device *pdev)
err_release_sysfs_group:
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
err_free_irq:
disable_work_sync(&data->read_work);
free_irq(gpiod_to_irq(data->data), data);
err_release_reg:
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
cancel_work_sync(&data->update_supply_work);
regulator_disable(data->reg);
}
return ret;
@ -1023,12 +1025,16 @@ static void sht15_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
disable_work_sync(&data->read_work);
free_irq(gpiod_to_irq(data->data), data);
ret = sht15_soft_reset(data);
if (ret)
dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
cancel_work_sync(&data->update_supply_work);
regulator_disable(data->reg);
}
}

View File

@ -111,7 +111,9 @@ static int sht4x_read_values(struct sht4x_data *data)
}
if (data->data_pending &&
time_before64(get_jiffies_64(), data->heating_complete + data->update_interval)) {
time_before64(get_jiffies_64(),
data->heating_complete +
msecs_to_jiffies(data->update_interval))) {
data->data_pending = false;
} else {
next_update = data->last_updated +

View File

@ -13,7 +13,7 @@
#include <linux/i2c.h>
#include <linux/i3c/device.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/ktime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@ -78,7 +78,7 @@
struct tmp108 {
struct regmap *regmap;
u16 orig_config;
u64 ready_time;
ktime_t ready_time;
const struct tmp108_params *params;
};
@ -121,6 +121,7 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
struct tmp108 *tmp108 = dev_get_drvdata(dev);
unsigned int regval;
int err, hyst;
s64 delay;
if (type == hwmon_chip) {
if (attr == hwmon_chip_update_interval) {
@ -137,12 +138,10 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
switch (attr) {
case hwmon_temp_input:
/* Is it too early to return a conversion ? */
if (time_before64(get_jiffies_64(), tmp108->ready_time)) {
dev_dbg(dev, "%s: Conversion not ready yet..\n",
__func__);
return -EAGAIN;
}
/* Wait if it is too early to return a conversion */
delay = ktime_us_delta(tmp108->ready_time, ktime_get());
if (delay > 0)
usleep_range(delay, delay + 1000);
err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, &regval);
if (err < 0)
return err;
@ -477,11 +476,8 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
return err;
}
tmp108->ready_time = get_jiffies_64();
if ((tmp108->orig_config & TMP108_CONF_MODE_MASK) ==
TMP108_MODE_SHUTDOWN)
tmp108->ready_time +=
msecs_to_jiffies(TMP108_CONVERSION_TIME_MS);
tmp108->ready_time = ktime_add_ms(ktime_get(),
TMP108_CONVERSION_TIME_MS);
err = devm_add_action_or_reset(dev, tmp108_restore_config, tmp108);
if (err) {
@ -528,8 +524,8 @@ static int tmp108_resume(struct device *dev)
err = regmap_update_bits(tmp108->regmap, TMP108_REG_CONF,
TMP108_CONF_MODE_MASK, TMP108_MODE_CONTINUOUS);
tmp108->ready_time = get_jiffies_64() +
msecs_to_jiffies(TMP108_CONVERSION_TIME_MS);
tmp108->ready_time = ktime_add_ms(ktime_get(),
TMP108_CONVERSION_TIME_MS);
return err;
}