diff options
| -rw-r--r-- | Documentation/hwmon/asus_rog_ryujin.rst | 6 | ||||
| -rw-r--r-- | drivers/hwmon/acpi_power_meter.c | 100 | ||||
| -rw-r--r-- | drivers/hwmon/aquacomputer_d5next.c | 58 | ||||
| -rw-r--r-- | drivers/hwmon/asus_rog_ryujin.c | 81 | ||||
| -rw-r--r-- | drivers/hwmon/asus_wmi_sensors.c | 13 | ||||
| -rw-r--r-- | drivers/hwmon/chipcap2.c | 192 | ||||
| -rw-r--r-- | drivers/hwmon/coretemp.c | 26 | ||||
| -rw-r--r-- | drivers/hwmon/corsair-cpro.c | 3 | ||||
| -rw-r--r-- | drivers/hwmon/gpd-fan.c | 1 | ||||
| -rw-r--r-- | drivers/hwmon/gpio-fan.c | 7 | ||||
| -rw-r--r-- | drivers/hwmon/hp-wmi-sensors.c | 31 | ||||
| -rw-r--r-- | drivers/hwmon/lm75.c | 9 | ||||
| -rw-r--r-- | drivers/hwmon/lm87.c | 7 | ||||
| -rw-r--r-- | drivers/hwmon/nct6683.c | 4 | ||||
| -rw-r--r-- | drivers/hwmon/peci/dimmtemp.c | 21 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 58 | ||||
| -rw-r--r-- | drivers/hwmon/pmbus/q54sj108a2.c | 2 | ||||
| -rw-r--r-- | drivers/hwmon/sht15.c | 22 | ||||
| -rw-r--r-- | drivers/hwmon/sht4x.c | 4 | ||||
| -rw-r--r-- | drivers/hwmon/tmp108.c | 26 |
20 files changed, 463 insertions, 208 deletions
diff --git a/Documentation/hwmon/asus_rog_ryujin.rst b/Documentation/hwmon/asus_rog_ryujin.rst index 3ebab230e8ca..fe072e94d87b 100644 --- a/Documentation/hwmon/asus_rog_ryujin.rst +++ b/Documentation/hwmon/asus_rog_ryujin.rst @@ -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 ------------- diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 3891962f03db..300acf1998ce 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -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); diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 1ca70e726298..3d3786c82931 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -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; diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c index 5ced69e94ead..111e0099fd9c 100644 --- a/drivers/hwmon/asus_rog_ryujin.c +++ b/drivers/hwmon/asus_rog_ryujin.c @@ -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)) { diff --git a/drivers/hwmon/asus_wmi_sensors.c b/drivers/hwmon/asus_wmi_sensors.c index 621e3506972d..0feab3f62496 100644 --- a/drivers/hwmon/asus_wmi_sensors.c +++ b/drivers/hwmon/asus_wmi_sensors.c @@ -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), diff --git a/drivers/hwmon/chipcap2.c b/drivers/hwmon/chipcap2.c index 9bef767b589e..00f62a33d463 100644 --- a/drivers/hwmon/chipcap2.c +++ b/drivers/hwmon/chipcap2.c @@ -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; + if (data->irq_ready > 0) { + scoped_guard(mutex, &data->irq_lock) + data->process_irqs = false; + + synchronize_irq(data->irq_ready); + + scoped_guard(mutex, &data->irq_lock) + reinit_completion(&data->complete); + } + /* exclusive regulator, check in case a disable failed */ - if (regulator_is_enabled(data->regulator)) + if (data->regulator_enabled) { + scoped_guard(mutex, &data->irq_lock) + data->process_irqs = true; return 0; - - /* clear any pending completion */ - try_wait_for_completion(&data->complete); + } 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) { - int ret = 0; - data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready"); - if (data->irq_ready > 0) { + 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; + + 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,13 +790,17 @@ 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 request ready irq\n"); + return dev_err_probe(dev, ret, "Failed to get IRQs\n"); - ret = cc2_request_alarm_irqs(data, dev); + ret = devm_add_action_or_reset(dev, cc2_disable_action, data); if (ret) - return dev_err_probe(dev, ret, "Failed to request alarm irqs\n"); + return ret; + + ret = cc2_request_data_ready(data, dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to request ready irq\n"); data->hwmon = devm_hwmon_device_register_with_info(dev, client->name, data, &cc2_chip_info, @@ -741,14 +809,11 @@ static int cc2_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(data->hwmon), "Failed to register hwmon device\n"); - return 0; -} - -static void cc2_remove(struct i2c_client *client) -{ - struct cc2_data *data = i2c_get_clientdata(client); + ret = cc2_request_alarms(data, dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to request alarm irqs\n"); - cc2_disable(data); + return 0; } static const struct i2c_device_id cc2_id[] = { @@ -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); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 3836beade59f..96d57fe12de6 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -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; diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c index e6d31d367698..6ce5da37de03 100644 --- a/drivers/hwmon/corsair-cpro.c +++ b/drivers/hwmon/corsair-cpro.c @@ -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; diff --git a/drivers/hwmon/gpd-fan.c b/drivers/hwmon/gpd-fan.c index ed212615b2fe..b3b75f99f588 100644 --- a/drivers/hwmon/gpd-fan.c +++ b/drivers/hwmon/gpd-fan.c @@ -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; } } diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 3f78375eeb44..08b58b49be5b 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -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; } diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c index d8bcfeb8d5b2..1a4955dbddd0 100644 --- a/drivers/hwmon/hp-wmi-sensors.c +++ b/drivers/hwmon/hp-wmi-sensors.c @@ -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); } diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 2d2d752aeac9..917ac250a648 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -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")) diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index c09074f44708..bb4e15b66355 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -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; diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index e1c36c95affb..f34cb62305be 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -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; diff --git a/drivers/hwmon/peci/dimmtemp.c b/drivers/hwmon/peci/dimmtemp.c index bd3e8715dfec..617a4cc0f65c 100644 --- a/drivers/hwmon/peci/dimmtemp.c +++ b/drivers/hwmon/peci/dimmtemp.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index d69f1bde1795..8fa379d04cd1 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -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, diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c index ecac405d7536..b018a611d9b6 100644 --- a/drivers/hwmon/pmbus/q54sj108a2.c +++ b/drivers/hwmon/pmbus/q54sj108a2.c @@ -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); diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 7bb2105d1ae2..48d93c61345c 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -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); } } diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 8372b4fc902e..020a523bf863 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -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 + diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 91d20a1ce112..862b944d3e60 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -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, ®val); 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; } |
