diff -rupN linux-6.1.2.orig/Documentation/hwmon/aquacomputer_d5next.rst linux-6.1.2/Documentation/hwmon/aquacomputer_d5next.rst --- linux-6.1.2.orig/Documentation/hwmon/aquacomputer_d5next.rst 2022-12-31 16:12:05.774603120 -0500 +++ linux-6.1.2/Documentation/hwmon/aquacomputer_d5next.rst 2022-12-31 16:19:55.381168081 -0500 @@ -39,7 +39,7 @@ current. The Quadro exposes four physical and sixteen virtual temperature sensors, a flow sensor and four PWM controllable fans, along with their speed (in RPM), power, -voltage and current. +voltage and current. Flow sensor pulses are also available. The Farbwerk and Farbwerk 360 expose four temperature sensors. Additionally, sixteen virtual temperature sensors of the Farbwerk 360 are exposed. @@ -62,7 +62,9 @@ Sysfs entries ================ ============================================================== temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius) +temp[1-4]_offset Temperature sensor correction offset (in millidegrees Celsius) fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h) +fan5_pulses Quadro flow sensor pulses power[1-8]_input Pump/fan power (in micro Watts) in[0-7]_input Pump/fan voltage (in milli Volts) curr[1-8]_input Pump/fan current (in milli Amperes) diff -rupN linux-6.1.2.orig/Documentation/hwmon/index.rst linux-6.1.2/Documentation/hwmon/index.rst --- linux-6.1.2.orig/Documentation/hwmon/index.rst 2022-12-31 16:12:05.774603120 -0500 +++ linux-6.1.2/Documentation/hwmon/index.rst 2022-12-31 16:19:53.949181008 -0500 @@ -160,6 +160,7 @@ Hardware Monitoring Kernel Drivers nzxt-kraken2 nzxt-smart2 occ + oxp-sensors pc87360 pc87427 pcf8591 @@ -187,6 +188,7 @@ Hardware Monitoring Kernel Drivers sis5595 sl28cpld smm665 + smpro-hwmon smsc47b397 smsc47m192 smsc47m1 diff -rupN linux-6.1.2.orig/Documentation/hwmon/oxp-sensors.rst linux-6.1.2/Documentation/hwmon/oxp-sensors.rst --- linux-6.1.2.orig/Documentation/hwmon/oxp-sensors.rst 1969-12-31 19:00:00.000000000 -0500 +++ linux-6.1.2/Documentation/hwmon/oxp-sensors.rst 2022-12-31 16:19:55.381168081 -0500 @@ -0,0 +1,44 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver oxp-sensors +========================= + +Author: + - Joaquín Ignacio Aramendía + +Description: +------------ + +One X Player devices from One Netbook provide fan readings and fan control +through its Embedded Controller. + +Currently only supports AMD boards from the One X Player and AOK ZOE lineup. +Intel boards could be supported if we could figure out the EC registers and +values to write to since the EC layout and model is different. + +Supported devices +----------------- + +Currently the driver supports the following handhelds: + + - AOK ZOE A1 + - OneXPlayer AMD + - OneXPlayer mini AMD + - OneXPlayer mini AMD PRO + +Sysfs entries +------------- + +The following attributes are supported: + +fan1_input + Read Only. Reads current fan RMP. + +pwm1_enable + Read Write. Enable manual fan control. Write "1" to set to manual, write "0" + to let the EC control de fan speed. Read this attribute to see current status. + +pwm1 + Read Write. Read this attribute to see current duty cycle in the range [0-255]. + When pwm1_enable is set to "1" (manual) write any value in the range [0-255] + to set fan speed. diff -rupN linux-6.1.2.orig/Documentation/hwmon/smpro-hwmon.rst linux-6.1.2/Documentation/hwmon/smpro-hwmon.rst --- linux-6.1.2.orig/Documentation/hwmon/smpro-hwmon.rst 1969-12-31 19:00:00.000000000 -0500 +++ linux-6.1.2/Documentation/hwmon/smpro-hwmon.rst 2022-12-31 16:19:53.945181044 -0500 @@ -0,0 +1,102 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +Kernel driver Ampere(R)'s Altra(R) SMpro hwmon +============================================== + +Supported chips: + + * Ampere(R) Altra(R) + + Prefix: ``smpro`` + + Reference: `Altra SoC BMC Interface Specification` + +Author: Thu Nguyen + +Description +----------- +The smpro-hwmon driver supports hardware monitoring for Ampere(R) Altra(R) +SoCs based on the SMpro co-processor (SMpro). The following sensor metrics +are supported by the driver: + + * temperature + * voltage + * current + * power + +The interface provides the registers to query the various sensors and +their values which are then exported to userspace by this driver. + +Usage Notes +----------- + +The driver creates at least two sysfs files for each sensor. + +* ``_label`` reports the sensor label. +* ``_input`` returns the sensor value. + +The sysfs files are allocated in the SMpro rootfs folder, with one root +directory for each instance. + +When the SoC is turned off, the driver will fail to read registers and +return ``-ENXIO``. + +Sysfs entries +------------- + +The following sysfs files are supported: + +* Ampere(R) Altra(R): + + ============ ============= ====== =============================================== + Name Unit Perm Description + ============ ============= ====== =============================================== + temp1_input millicelsius RO SoC temperature + temp2_input millicelsius RO Max temperature reported among SoC VRDs + temp2_crit millicelsius RO SoC VRD HOT Threshold temperature + temp3_input millicelsius RO Max temperature reported among DIMM VRDs + temp4_input millicelsius RO Max temperature reported among Core VRDs + temp5_input millicelsius RO Temperature of DIMM0 on CH0 + temp5_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp6_input millicelsius RO Temperature of DIMM0 on CH1 + temp6_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp7_input millicelsius RO Temperature of DIMM0 on CH2 + temp7_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp8_input millicelsius RO Temperature of DIMM0 on CH3 + temp8_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp9_input millicelsius RO Temperature of DIMM0 on CH4 + temp9_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp10_input millicelsius RO Temperature of DIMM0 on CH5 + temp10_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp11_input millicelsius RO Temperature of DIMM0 on CH6 + temp11_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp12_input millicelsius RO Temperature of DIMM0 on CH7 + temp12_crit millicelsius RO MEM HOT Threshold for all DIMMs + temp13_input millicelsius RO Max temperature reported among RCA VRDs + in0_input millivolts RO Core voltage + in1_input millivolts RO SoC voltage + in2_input millivolts RO DIMM VRD1 voltage + in3_input millivolts RO DIMM VRD2 voltage + in4_input millivolts RO RCA VRD voltage + cur1_input milliamperes RO Core VRD current + cur2_input milliamperes RO SoC VRD current + cur3_input milliamperes RO DIMM VRD1 current + cur4_input milliamperes RO DIMM VRD2 current + cur5_input milliamperes RO RCA VRD current + power1_input microwatts RO Core VRD power + power2_input microwatts RO SoC VRD power + power3_input microwatts RO DIMM VRD1 power + power4_input microwatts RO DIMM VRD2 power + power5_input microwatts RO RCA VRD power + ============ ============= ====== =============================================== + + Example:: + + # cat in0_input + 830 + # cat temp1_input + 37000 + # cat curr1_input + 9000 + # cat power5_input + 19500000 diff -rupN linux-6.1.2.orig/drivers/hwmon/adm1177.c linux-6.1.2/drivers/hwmon/adm1177.c --- linux-6.1.2.orig/drivers/hwmon/adm1177.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/adm1177.c 2022-12-31 16:19:46.457248898 -0500 @@ -26,14 +26,12 @@ /** * struct adm1177_state - driver instance specific data * @client: pointer to i2c client - * @reg: regulator info for the power supply of the device * @r_sense_uohm: current sense resistor value * @alert_threshold_ua: current limit for shutdown * @vrange_high: internal voltage divider */ struct adm1177_state { struct i2c_client *client; - struct regulator *reg; u32 r_sense_uohm; u32 alert_threshold_ua; bool vrange_high; @@ -189,13 +187,6 @@ static const struct hwmon_chip_info adm1 .info = adm1177_info, }; -static void adm1177_remove(void *data) -{ - struct adm1177_state *st = data; - - regulator_disable(st->reg); -} - static int adm1177_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -210,21 +201,9 @@ static int adm1177_probe(struct i2c_clie st->client = client; - st->reg = devm_regulator_get_optional(&client->dev, "vref"); - if (IS_ERR(st->reg)) { - if (PTR_ERR(st->reg) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - st->reg = NULL; - } else { - ret = regulator_enable(st->reg); - if (ret) - return ret; - ret = devm_add_action_or_reset(&client->dev, adm1177_remove, - st); - if (ret) - return ret; - } + ret = devm_regulator_get_enable_optional(&client->dev, "vref"); + if (ret == -EPROBE_DEFER) + return -EPROBE_DEFER; if (device_property_read_u32(dev, "shunt-resistor-micro-ohms", &st->r_sense_uohm)) diff -rupN linux-6.1.2.orig/drivers/hwmon/aht10.c linux-6.1.2/drivers/hwmon/aht10.c --- linux-6.1.2.orig/drivers/hwmon/aht10.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/aht10.c 2022-12-31 16:19:46.453248935 -0500 @@ -289,8 +289,7 @@ static const struct hwmon_chip_info aht1 .info = aht10_info, }; -static int aht10_probe(struct i2c_client *client, - const struct i2c_device_id *aht10_id) +static int aht10_probe(struct i2c_client *client) { struct device *device = &client->dev; struct device *hwmon_dev; @@ -336,7 +335,7 @@ static struct i2c_driver aht10_driver = .driver = { .name = "aht10", }, - .probe = aht10_probe, + .probe_new = aht10_probe, .id_table = aht10_id, }; diff -rupN linux-6.1.2.orig/drivers/hwmon/aquacomputer_d5next.c linux-6.1.2/drivers/hwmon/aquacomputer_d5next.c --- linux-6.1.2.orig/drivers/hwmon/aquacomputer_d5next.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/aquacomputer_d5next.c 2022-12-31 16:19:55.385168045 -0500 @@ -59,7 +59,7 @@ static u8 secondary_ctrl_report[] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6 }; -/* Register offsets for all Aquacomputer devices */ +/* Sensor sizes and offsets for all Aquacomputer devices */ #define AQC_TEMP_SENSOR_SIZE 0x02 #define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF #define AQC_FAN_PERCENT_OFFSET 0x00 @@ -68,62 +68,81 @@ static u8 secondary_ctrl_report[] = { #define AQC_FAN_POWER_OFFSET 0x06 #define AQC_FAN_SPEED_OFFSET 0x08 -/* Register offsets for the D5 Next pump */ -#define D5NEXT_POWER_CYCLES 0x18 -#define D5NEXT_COOLANT_TEMP 0x57 +/* Specs of the D5 Next pump */ #define D5NEXT_NUM_FANS 2 #define D5NEXT_NUM_SENSORS 1 #define D5NEXT_NUM_VIRTUAL_SENSORS 8 -#define D5NEXT_VIRTUAL_SENSORS_START 0x3f +#define D5NEXT_CTRL_REPORT_SIZE 0x329 + +/* Sensor report offsets for the D5 Next pump */ +#define D5NEXT_POWER_CYCLES 0x18 +#define D5NEXT_COOLANT_TEMP 0x57 #define D5NEXT_PUMP_OFFSET 0x6c #define D5NEXT_FAN_OFFSET 0x5f #define D5NEXT_5V_VOLTAGE 0x39 #define D5NEXT_12V_VOLTAGE 0x37 -#define D5NEXT_CTRL_REPORT_SIZE 0x329 +#define D5NEXT_VIRTUAL_SENSORS_START 0x3f static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET }; -/* Pump and fan speed registers in D5 Next control report (from 0-100%) */ -static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; +/* Control report offsets for the D5 Next pump */ +#define D5NEXT_TEMP_CTRL_OFFSET 0x2D /* Temperature sensor offsets location */ +static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (from 0-100%) */ -/* Register offsets for the Farbwerk RGB controller */ +/* Spec and sensor report offset for the Farbwerk RGB controller */ #define FARBWERK_NUM_SENSORS 4 #define FARBWERK_SENSOR_START 0x2f -/* Register offsets for the Farbwerk 360 RGB controller */ +/* Specs of the Farbwerk 360 RGB controller */ #define FARBWERK360_NUM_SENSORS 4 -#define FARBWERK360_SENSOR_START 0x32 #define FARBWERK360_NUM_VIRTUAL_SENSORS 16 +#define FARBWERK360_CTRL_REPORT_SIZE 0x682 + +/* Sensor report offsets for the Farbwerk 360 */ +#define FARBWERK360_SENSOR_START 0x32 #define FARBWERK360_VIRTUAL_SENSORS_START 0x3a -/* Register offsets for the Octo fan controller */ -#define OCTO_POWER_CYCLES 0x18 +/* Control report offsets for the Farbwerk 360 */ +#define FARBWERK360_TEMP_CTRL_OFFSET 0x8 + +/* Specs of the Octo fan controller */ #define OCTO_NUM_FANS 8 #define OCTO_NUM_SENSORS 4 -#define OCTO_SENSOR_START 0x3D #define OCTO_NUM_VIRTUAL_SENSORS 16 -#define OCTO_VIRTUAL_SENSORS_START 0x45 #define OCTO_CTRL_REPORT_SIZE 0x65F + +/* Sensor report offsets for the Octo */ +#define OCTO_POWER_CYCLES 0x18 +#define OCTO_SENSOR_START 0x3D +#define OCTO_VIRTUAL_SENSORS_START 0x45 static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 }; -/* Fan speed registers in Octo control report (from 0-100%) */ +/* Control report offsets for the Octo */ +#define OCTO_TEMP_CTRL_OFFSET 0xA +/* Fan speed offsets (0-100%) */ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0x259, 0x2AE }; -/* Register offsets for the Quadro fan controller */ -#define QUADRO_POWER_CYCLES 0x18 +/* Specs of Quadro fan controller */ #define QUADRO_NUM_FANS 4 #define QUADRO_NUM_SENSORS 4 -#define QUADRO_SENSOR_START 0x34 #define QUADRO_NUM_VIRTUAL_SENSORS 16 -#define QUADRO_VIRTUAL_SENSORS_START 0x3c #define QUADRO_CTRL_REPORT_SIZE 0x3c1 + +/* Sensor report offsets for the Quadro */ +#define QUADRO_POWER_CYCLES 0x18 +#define QUADRO_SENSOR_START 0x34 +#define QUADRO_VIRTUAL_SENSORS_START 0x3c #define QUADRO_FLOW_SENSOR_OFFSET 0x6e static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 }; -/* Fan speed registers in Quadro control report (from 0-100%) */ -static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; +/* Control report offsets for the Quadro */ +#define QUADRO_TEMP_CTRL_OFFSET 0xA +#define QUADRO_FLOW_PULSES_CTRL_OFFSET 0x6 +static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed offsets (0-100%) */ -/* Register offsets for the High Flow Next */ +/* Specs of High Flow Next flow sensor */ #define HIGHFLOWNEXT_NUM_SENSORS 2 + +/* Sensor report offsets for the High Flow Next */ #define HIGHFLOWNEXT_SENSOR_START 85 #define HIGHFLOWNEXT_FLOW 81 #define HIGHFLOWNEXT_WATER_QUALITY 89 @@ -282,8 +301,10 @@ struct aqc_data { int temp_sensor_start_offset; int num_virtual_temp_sensors; int virtual_temp_sensor_start_offset; + u16 temp_ctrl_offset; u16 power_cycle_count_offset; u8 flow_sensor_offset; + u8 flow_pulses_ctrl_offset; /* General info, same across all devices */ u32 serial_number[2]; @@ -365,8 +386,8 @@ static int aqc_send_ctrl_data(struct aqc return ret; } -/* Refreshes the control buffer and returns value at offset */ -static int aqc_get_ctrl_val(struct aqc_data *priv, int offset) +/* Refreshes the control buffer and stores value at offset in val */ +static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val) { int ret; @@ -376,7 +397,7 @@ static int aqc_get_ctrl_val(struct aqc_d if (ret < 0) goto unlock_and_return; - ret = get_unaligned_be16(priv->buffer + offset); + *val = (s16)get_unaligned_be16(priv->buffer + offset); unlock_and_return: mutex_unlock(&priv->mutex); @@ -393,7 +414,7 @@ static int aqc_set_ctrl_val(struct aqc_d if (ret < 0) goto unlock_and_return; - put_unaligned_be16((u16)val, priv->buffer + offset); + put_unaligned_be16((s16)val, priv->buffer + offset); ret = aqc_send_ctrl_data(priv); @@ -408,8 +429,28 @@ static umode_t aqc_is_visible(const void switch (type) { case hwmon_temp: + if (channel < priv->num_temp_sensors) { + switch (attr) { + case hwmon_temp_label: + case hwmon_temp_input: + return 0444; + case hwmon_temp_offset: + if (priv->temp_ctrl_offset != 0) + return 0644; + break; + default: + break; + } + } + if (channel < priv->num_temp_sensors + priv->num_virtual_temp_sensors) - return 0444; + switch (attr) { + case hwmon_temp_label: + case hwmon_temp_input: + return 0444; + default: + break; + } break; case hwmon_pwm: if (priv->fan_ctrl_offsets && channel < priv->num_fans) { @@ -422,20 +463,34 @@ static umode_t aqc_is_visible(const void } break; case hwmon_fan: - switch (priv->kind) { - case highflownext: - /* Special case to support flow sensor, water quality and conductivity */ - if (channel < 3) - return 0444; + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_label: + switch (priv->kind) { + case highflownext: + /* Special case to support flow sensor, water quality + * and conductivity + */ + if (channel < 3) + return 0444; + break; + case quadro: + /* Special case to support flow sensor */ + if (channel < priv->num_fans + 1) + return 0444; + break; + default: + if (channel < priv->num_fans) + return 0444; + break; + } break; - case quadro: - /* Special case to support flow sensor */ - if (channel < priv->num_fans + 1) - return 0444; + case hwmon_fan_pulses: + /* Special case for Quadro flow sensor */ + if (priv->kind == quadro && channel == priv->num_fans) + return 0644; break; default: - if (channel < priv->num_fans) - return 0444; break; } break; @@ -492,20 +547,46 @@ static int aqc_read(struct device *dev, switch (type) { case hwmon_temp: - if (priv->temp_input[channel] == -ENODATA) - return -ENODATA; + switch (attr) { + case hwmon_temp_input: + if (priv->temp_input[channel] == -ENODATA) + return -ENODATA; - *val = priv->temp_input[channel]; + *val = priv->temp_input[channel]; + break; + case hwmon_temp_offset: + ret = + aqc_get_ctrl_val(priv, priv->temp_ctrl_offset + + channel * AQC_TEMP_SENSOR_SIZE, val); + if (ret < 0) + return ret; + + *val *= 10; + break; + default: + break; + } break; case hwmon_fan: - *val = priv->speed_input[channel]; + switch (attr) { + case hwmon_fan_input: + *val = priv->speed_input[channel]; + break; + case hwmon_fan_pulses: + ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val); + if (ret < 0) + return ret; + break; + default: + break; + } break; case hwmon_power: *val = priv->power_input[channel]; break; case hwmon_pwm: if (priv->fan_ctrl_offsets) { - ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel]); + ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel], val); if (ret < 0) return ret; @@ -563,6 +644,33 @@ static int aqc_write(struct device *dev, struct aqc_data *priv = dev_get_drvdata(dev); switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_offset: + /* Limit temp offset to +/- 15K as in the official software */ + val = clamp_val(val, -15000, 15000) / 10; + ret = + aqc_set_ctrl_val(priv, priv->temp_ctrl_offset + + channel * AQC_TEMP_SENSOR_SIZE, val); + if (ret < 0) + return ret; + break; + default: + return -EOPNOTSUPP; + } + break; + case hwmon_fan: + switch (attr) { + case hwmon_fan_pulses: + val = clamp_val(val, 10, 1000); + ret = aqc_set_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val); + if (ret < 0) + return ret; + break; + default: + break; + } + break; case hwmon_pwm: switch (attr) { case hwmon_pwm_input: @@ -597,10 +705,10 @@ static const struct hwmon_ops aqc_hwmon_ static const struct hwmon_channel_info *aqc_info[] = { HWMON_CHANNEL_INFO(temp, - HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, @@ -622,7 +730,7 @@ static const struct hwmon_channel_info * HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, - HWMON_F_INPUT | HWMON_F_LABEL, + HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_PULSES, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL), @@ -847,13 +955,17 @@ static int aqc_probe(struct hid_device * priv->num_fans = D5NEXT_NUM_FANS; priv->fan_sensor_offsets = d5next_sensor_fan_offsets; priv->fan_ctrl_offsets = d5next_ctrl_fan_offsets; + priv->num_temp_sensors = D5NEXT_NUM_SENSORS; priv->temp_sensor_start_offset = D5NEXT_COOLANT_TEMP; priv->num_virtual_temp_sensors = D5NEXT_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = D5NEXT_VIRTUAL_SENSORS_START; - priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES; + priv->temp_ctrl_offset = D5NEXT_TEMP_CTRL_OFFSET; + priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE; + priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES; + priv->temp_label = label_d5next_temp; priv->virtual_temp_label = label_virtual_temp_sensors; priv->speed_label = label_d5next_speeds; @@ -865,18 +977,24 @@ static int aqc_probe(struct hid_device * priv->kind = farbwerk; priv->num_fans = 0; + priv->num_temp_sensors = FARBWERK_NUM_SENSORS; priv->temp_sensor_start_offset = FARBWERK_SENSOR_START; + priv->temp_label = label_temp_sensors; break; case USB_PRODUCT_ID_FARBWERK360: priv->kind = farbwerk360; priv->num_fans = 0; + priv->num_temp_sensors = FARBWERK360_NUM_SENSORS; priv->temp_sensor_start_offset = FARBWERK360_SENSOR_START; priv->num_virtual_temp_sensors = FARBWERK360_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = FARBWERK360_VIRTUAL_SENSORS_START; + priv->temp_ctrl_offset = FARBWERK360_TEMP_CTRL_OFFSET; + + priv->buffer_size = FARBWERK360_CTRL_REPORT_SIZE; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; @@ -887,13 +1005,17 @@ static int aqc_probe(struct hid_device * priv->num_fans = OCTO_NUM_FANS; priv->fan_sensor_offsets = octo_sensor_fan_offsets; priv->fan_ctrl_offsets = octo_ctrl_fan_offsets; + priv->num_temp_sensors = OCTO_NUM_SENSORS; priv->temp_sensor_start_offset = OCTO_SENSOR_START; priv->num_virtual_temp_sensors = OCTO_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = OCTO_VIRTUAL_SENSORS_START; - priv->power_cycle_count_offset = OCTO_POWER_CYCLES; + priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET; + priv->buffer_size = OCTO_CTRL_REPORT_SIZE; + priv->power_cycle_count_offset = OCTO_POWER_CYCLES; + priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; priv->speed_label = label_fan_speed; @@ -907,13 +1029,18 @@ static int aqc_probe(struct hid_device * priv->num_fans = QUADRO_NUM_FANS; priv->fan_sensor_offsets = quadro_sensor_fan_offsets; priv->fan_ctrl_offsets = quadro_ctrl_fan_offsets; + priv->num_temp_sensors = QUADRO_NUM_SENSORS; priv->temp_sensor_start_offset = QUADRO_SENSOR_START; priv->num_virtual_temp_sensors = QUADRO_NUM_VIRTUAL_SENSORS; priv->virtual_temp_sensor_start_offset = QUADRO_VIRTUAL_SENSORS_START; - priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; + priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET; + priv->buffer_size = QUADRO_CTRL_REPORT_SIZE; + priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET; + priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET; + priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; @@ -926,8 +1053,10 @@ static int aqc_probe(struct hid_device * priv->kind = highflownext; priv->num_fans = 0; + priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS; priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START; + priv->power_cycle_count_offset = QUADRO_POWER_CYCLES; priv->temp_label = label_highflownext_temp_sensors; diff -rupN linux-6.1.2.orig/drivers/hwmon/atxp1.c linux-6.1.2/drivers/hwmon/atxp1.c --- linux-6.1.2.orig/drivers/hwmon/atxp1.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/atxp1.c 2022-12-31 16:19:53.945181044 -0500 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff -rupN linux-6.1.2.orig/drivers/hwmon/coretemp.c linux-6.1.2/drivers/hwmon/coretemp.c --- linux-6.1.2.orig/drivers/hwmon/coretemp.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/coretemp.c 2022-12-31 16:19:53.953180971 -0500 @@ -55,6 +55,8 @@ MODULE_PARM_DESC(tjmax, "TjMax value in /* * Per-Core Temperature Data + * @tjmax: The static tjmax value when tjmax cannot be retrieved from + * IA32_TEMPERATURE_TARGET MSR. * @last_updated: The time when the current temperature value was updated * earlier (in jiffies). * @cpu_core_id: The CPU Core from which temperature values should be read @@ -64,11 +66,9 @@ MODULE_PARM_DESC(tjmax, "TjMax value in * @attr_size: Total number of pre-core attrs displayed in the sysfs. * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data. * Otherwise, temp_data holds coretemp data. - * @valid: If this is 1, the current temperature is valid. */ struct temp_data { int temp; - int ttarget; int tjmax; unsigned long last_updated; unsigned int cpu; @@ -76,7 +76,6 @@ struct temp_data { u32 status_reg; int attr_size; bool is_pkg_data; - bool valid; struct sensor_device_attribute sd_attrs[TOTAL_ATTRS]; char attr_name[TOTAL_ATTRS][CORETEMP_NAME_LENGTH]; struct attribute *attrs[TOTAL_ATTRS + 1]; @@ -95,85 +94,6 @@ struct platform_data { struct device_attribute name_attr; }; -/* Keep track of how many zone pointers we allocated in init() */ -static int max_zones __read_mostly; -/* Array of zone pointers. Serialized by cpu hotplug lock */ -static struct platform_device **zone_devices; - -static ssize_t show_label(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - if (tdata->is_pkg_data) - return sprintf(buf, "Package id %u\n", pdata->pkg_id); - - return sprintf(buf, "Core %u\n", tdata->cpu_core_id); -} - -static ssize_t show_crit_alarm(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - u32 eax, edx; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - mutex_lock(&tdata->update_lock); - rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); - mutex_unlock(&tdata->update_lock); - - return sprintf(buf, "%d\n", (eax >> 5) & 1); -} - -static ssize_t show_tjmax(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax); -} - -static ssize_t show_ttarget(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); -} - -static ssize_t show_temp(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - u32 eax, edx; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - mutex_lock(&tdata->update_lock); - - /* Check whether the time interval has elapsed */ - if (!tdata->valid || time_after(jiffies, tdata->last_updated + HZ)) { - rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); - /* - * Ignore the valid bit. In all observed cases the register - * value is either low or zero if the valid bit is 0. - * Return it instead of reporting an error which doesn't - * really help at all. - */ - tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; - tdata->valid = true; - tdata->last_updated = jiffies; - } - - mutex_unlock(&tdata->update_lock); - return sprintf(buf, "%d\n", tdata->temp); -} - struct tjmax_pci { unsigned int device; int tjmax; @@ -340,20 +260,25 @@ static bool cpu_has_tjmax(struct cpuinfo model != 0x36; } -static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) +static int get_tjmax(struct temp_data *tdata, struct device *dev) { + struct cpuinfo_x86 *c = &cpu_data(tdata->cpu); int err; u32 eax, edx; u32 val; + /* use static tjmax once it is set */ + if (tdata->tjmax) + return tdata->tjmax; + /* * A new feature of current Intel(R) processors, the * IA32_TEMPERATURE_TARGET contains the TjMax value */ - err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + err = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); if (err) { if (cpu_has_tjmax(c)) - dev_warn(dev, "Unable to read TjMax from CPU %u\n", id); + dev_warn(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu); } else { val = (eax >> 16) & 0xff; /* @@ -369,14 +294,133 @@ static int get_tjmax(struct cpuinfo_x86 if (force_tjmax) { dev_notice(dev, "TjMax forced to %d degrees C by user\n", force_tjmax); - return force_tjmax * 1000; + tdata->tjmax = force_tjmax * 1000; + } else { + /* + * An assumption is made for early CPUs and unreadable MSR. + * NOTE: the calculated value may not be correct. + */ + tdata->tjmax = adjust_tjmax(c, tdata->cpu, dev); } + return tdata->tjmax; +} + +static int get_ttarget(struct temp_data *tdata, struct device *dev) +{ + u32 eax, edx; + int tjmax, ttarget_offset, ret; /* - * An assumption is made for early CPUs and unreadable MSR. - * NOTE: the calculated value may not be correct. + * ttarget is valid only if tjmax can be retrieved from + * MSR_IA32_TEMPERATURE_TARGET */ - return adjust_tjmax(c, id, dev); + if (tdata->tjmax) + return -ENODEV; + + ret = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + if (ret) + return ret; + + tjmax = (eax >> 16) & 0xff; + + /* Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. */ + ttarget_offset = (eax >> 8) & 0xff; + + return (tjmax - ttarget_offset) * 1000; +} + +/* Keep track of how many zone pointers we allocated in init() */ +static int max_zones __read_mostly; +/* Array of zone pointers. Serialized by cpu hotplug lock */ +static struct platform_device **zone_devices; + +static ssize_t show_label(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + + if (tdata->is_pkg_data) + return sprintf(buf, "Package id %u\n", pdata->pkg_id); + + return sprintf(buf, "Core %u\n", tdata->cpu_core_id); +} + +static ssize_t show_crit_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u32 eax, edx; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + + mutex_lock(&tdata->update_lock); + rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); + mutex_unlock(&tdata->update_lock); + + return sprintf(buf, "%d\n", (eax >> 5) & 1); +} + +static ssize_t show_tjmax(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + int tjmax; + + mutex_lock(&tdata->update_lock); + tjmax = get_tjmax(tdata, dev); + mutex_unlock(&tdata->update_lock); + + return sprintf(buf, "%d\n", tjmax); +} + +static ssize_t show_ttarget(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + int ttarget; + + mutex_lock(&tdata->update_lock); + ttarget = get_ttarget(tdata, dev); + mutex_unlock(&tdata->update_lock); + + if (ttarget < 0) + return ttarget; + return sprintf(buf, "%d\n", ttarget); +} + +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + u32 eax, edx; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct platform_data *pdata = dev_get_drvdata(dev); + struct temp_data *tdata = pdata->core_data[attr->index]; + int tjmax; + + mutex_lock(&tdata->update_lock); + + tjmax = get_tjmax(tdata, dev); + /* Check whether the time interval has elapsed */ + if (time_after(jiffies, tdata->last_updated + HZ)) { + rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); + /* + * Ignore the valid bit. In all observed cases the register + * value is either low or zero if the valid bit is 0. + * Return it instead of reporting an error which doesn't + * really help at all. + */ + tdata->temp = tjmax - ((eax >> 16) & 0x7f) * 1000; + tdata->last_updated = jiffies; + } + + mutex_unlock(&tdata->update_lock); + return sprintf(buf, "%d\n", tdata->temp); } static int create_core_attrs(struct temp_data *tdata, struct device *dev, @@ -490,23 +534,17 @@ static int create_core_data(struct platf if (err) goto exit_free; - /* We can access status register. Get Critical Temperature */ - tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); + /* Make sure tdata->tjmax is a valid indicator for dynamic/static tjmax */ + get_tjmax(tdata, &pdev->dev); /* - * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. - * The target temperature is available on older CPUs but not in this - * register. Atoms don't have the register at all. + * The target temperature is available on older CPUs but not in the + * MSR_IA32_TEMPERATURE_TARGET register. Atoms don't have the register + * at all. */ - if (c->x86_model > 0xe && c->x86_model != 0x1c) { - err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, - &eax, &edx); - if (!err) { - tdata->ttarget - = tdata->tjmax - ((eax >> 8) & 0xff) * 1000; + if (c->x86_model > 0xe && c->x86_model != 0x1c) + if (get_ttarget(tdata, &pdev->dev) >= 0) tdata->attr_size++; - } - } pdata->core_data[attr_no] = tdata; diff -rupN linux-6.1.2.orig/drivers/hwmon/dell-smm-hwmon.c linux-6.1.2/drivers/hwmon/dell-smm-hwmon.c --- linux-6.1.2.orig/drivers/hwmon/dell-smm-hwmon.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/dell-smm-hwmon.c 2022-12-31 16:19:55.385168045 -0500 @@ -1447,9 +1447,10 @@ static int __init i8k_init(void) */ if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { - pr_err("unable to get SMM Dell signature\n"); if (!force) return -ENODEV; + + pr_err("Unable to get Dell SMM signature\n"); } dell_smm_device = platform_create_bundle(&dell_smm_driver, dell_smm_probe, NULL, 0, NULL, diff -rupN linux-6.1.2.orig/drivers/hwmon/ds1621.c linux-6.1.2/drivers/hwmon/ds1621.c --- linux-6.1.2.orig/drivers/hwmon/ds1621.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/ds1621.c 2022-12-31 16:19:55.385168045 -0500 @@ -269,7 +269,7 @@ static ssize_t update_interval_show(stru struct device_attribute *da, char *buf) { struct ds1621_data *data = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval); + return sysfs_emit(buf, "%hu\n", data->update_interval); } static ssize_t update_interval_store(struct device *dev, diff -rupN linux-6.1.2.orig/drivers/hwmon/emc2305.c linux-6.1.2/drivers/hwmon/emc2305.c --- linux-6.1.2.orig/drivers/hwmon/emc2305.c 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/emc2305.c 2022-12-31 16:19:46.453248935 -0500 @@ -528,7 +528,7 @@ static int emc2305_identify(struct devic return 0; } -static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int emc2305_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; struct device *dev = &client->dev; @@ -613,7 +613,7 @@ static struct i2c_driver emc2305_driver .driver = { .name = "emc2305", }, - .probe = emc2305_probe, + .probe_new = emc2305_probe, .remove = emc2305_remove, .id_table = emc2305_ids, .address_list = emc2305_normal_i2c, diff -rupN linux-6.1.2.orig/drivers/hwmon/fschmd.c linux-6.1.2/drivers/hwmon/fschmd.c --- linux-6.1.2.orig/drivers/hwmon/fschmd.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/fschmd.c 2022-12-31 16:19:46.453248935 -0500 @@ -1083,9 +1083,9 @@ static int fschmd_detect(struct i2c_clie static int fschmd_probe(struct i2c_client *client) { struct fschmd_data *data; - const char * const names[7] = { "Poseidon", "Hermes", "Scylla", + static const char * const names[7] = { "Poseidon", "Hermes", "Scylla", "Heracles", "Heimdall", "Hades", "Syleus" }; - const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; + static const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; int i, err; enum chips kind = i2c_match_id(fschmd_id, client)->driver_data; diff -rupN linux-6.1.2.orig/drivers/hwmon/gpio-fan.c linux-6.1.2/drivers/hwmon/gpio-fan.c --- linux-6.1.2.orig/drivers/hwmon/gpio-fan.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/gpio-fan.c 2022-12-31 16:19:53.945181044 -0500 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff -rupN linux-6.1.2.orig/drivers/hwmon/gsc-hwmon.c linux-6.1.2/drivers/hwmon/gsc-hwmon.c --- linux-6.1.2.orig/drivers/hwmon/gsc-hwmon.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/gsc-hwmon.c 2022-12-31 16:19:55.381168081 -0500 @@ -257,13 +257,10 @@ gsc_hwmon_get_devtree_pdata(struct devic if (nchannels == 0) return ERR_PTR(-ENODEV); - pdata = devm_kzalloc(dev, - sizeof(*pdata) + nchannels * sizeof(*ch), + pdata = devm_kzalloc(dev, struct_size(pdata, channels, nchannels), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - ch = (struct gsc_hwmon_channel *)(pdata + 1); - pdata->channels = ch; pdata->nchannels = nchannels; /* fan controller base address */ @@ -277,6 +274,7 @@ gsc_hwmon_get_devtree_pdata(struct devic of_node_put(fan); + ch = pdata->channels; /* allocate structures for channels and count instances of each type */ device_for_each_child_node(dev, child) { if (fwnode_property_read_string(child, "label", &ch->name)) { diff -rupN linux-6.1.2.orig/drivers/hwmon/hwmon.c linux-6.1.2/drivers/hwmon/hwmon.c --- linux-6.1.2.orig/drivers/hwmon/hwmon.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/hwmon.c 2022-12-31 16:19:53.945181044 -0500 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff -rupN linux-6.1.2.orig/drivers/hwmon/it87.c linux-6.1.2/drivers/hwmon/it87.c --- linux-6.1.2.orig/drivers/hwmon/it87.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/it87.c 2022-12-31 16:19:53.949181008 -0500 @@ -69,6 +69,10 @@ static unsigned short force_id; module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); +static bool ignore_resource_conflict; +module_param(ignore_resource_conflict, bool, 0); +MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict"); + static struct platform_device *it87_pdev[2]; #define REG_2E 0x2e /* The register to read/write */ @@ -563,6 +567,14 @@ struct it87_data { s8 auto_temp[NUM_AUTO_PWM][5]; /* [nr][0] is point1_temp_hyst */ }; +/* Board specific settings from DMI matching */ +struct it87_dmi_data { + u8 skip_pwm; /* pwm channels to skip for this board */ +}; + +/* Global for results from DMI matching, if needed */ +static struct it87_dmi_data *dmi_data; + static int adc_lsb(const struct it87_data *data, int nr) { int lsb; @@ -2389,7 +2401,6 @@ static int __init it87_find(int sioaddr, { int err; u16 chip_type; - const char *board_vendor, *board_name; const struct it87_devices *config; err = superio_enter(sioaddr); @@ -2397,7 +2408,13 @@ static int __init it87_find(int sioaddr, return err; err = -ENODEV; - chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID); + chip_type = superio_inw(sioaddr, DEVID); + /* check first for a valid chip before forcing chip id */ + if (chip_type == 0xffff) + goto exit; + + if (force_id) + chip_type = force_id; switch (chip_type) { case IT8705F_DEVID: @@ -2802,24 +2819,9 @@ static int __init it87_find(int sioaddr, if (sio_data->beep_pin) pr_info("Beeping is supported\n"); - /* Disable specific features based on DMI strings */ - board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); - board_name = dmi_get_system_info(DMI_BOARD_NAME); - if (board_vendor && board_name) { - if (strcmp(board_vendor, "nVIDIA") == 0 && - strcmp(board_name, "FN68PT") == 0) { - /* - * On the Shuttle SN68PT, FAN_CTL2 is apparently not - * connected to a fan, but to something else. One user - * has reported instant system power-off when changing - * the PWM2 duty cycle, so we disable it. - * I use the board name string as the trigger in case - * the same board is ever used in other systems. - */ - pr_info("Disabling pwm2 due to hardware constraints\n"); - sio_data->skip_pwm = BIT(1); - } - } + /* Set values based on DMI matches */ + if (dmi_data) + sio_data->skip_pwm |= dmi_data->skip_pwm; exit: superio_exit(sioaddr); @@ -3261,8 +3263,10 @@ static int __init it87_device_add(int in int err; err = acpi_check_resource_conflict(&res); - if (err) - return err; + if (err) { + if (!ignore_resource_conflict) + return err; + } pdev = platform_device_alloc(DRVNAME, address); if (!pdev) @@ -3295,6 +3299,46 @@ exit_device_put: return err; } +/* callback function for DMI */ +static int it87_dmi_cb(const struct dmi_system_id *dmi_entry) +{ + dmi_data = dmi_entry->driver_data; + + if (dmi_data && dmi_data->skip_pwm) + pr_info("Disabling pwm2 due to hardware constraints\n"); + + return 1; +} + +/* + * On the Shuttle SN68PT, FAN_CTL2 is apparently not + * connected to a fan, but to something else. One user + * has reported instant system power-off when changing + * the PWM2 duty cycle, so we disable it. + * I use the board name string as the trigger in case + * the same board is ever used in other systems. + */ +static struct it87_dmi_data nvidia_fn68pt = { + .skip_pwm = BIT(1), +}; + +#define IT87_DMI_MATCH_VND(vendor, name, cb, data) \ + { \ + .callback = cb, \ + .matches = { \ + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, vendor), \ + DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \ + }, \ + .driver_data = data, \ + } + +static const struct dmi_system_id it87_dmi_table[] __initconst = { + IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt), + { } + +}; +MODULE_DEVICE_TABLE(dmi, it87_dmi_table); + static int __init sm_it87_init(void) { int sioaddr[2] = { REG_2E, REG_4E }; @@ -3307,6 +3351,8 @@ static int __init sm_it87_init(void) if (err) return err; + dmi_check_system(it87_dmi_table); + for (i = 0; i < ARRAY_SIZE(sioaddr); i++) { memset(&sio_data, 0, sizeof(struct it87_sio_data)); isa_address[i] = 0; diff -rupN linux-6.1.2.orig/drivers/hwmon/jc42.c linux-6.1.2/drivers/hwmon/jc42.c --- linux-6.1.2.orig/drivers/hwmon/jc42.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/jc42.c 2022-12-31 16:19:53.945181044 -0500 @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -37,20 +38,19 @@ static const unsigned short normal_i2c[] #define JC42_REG_SMBUS 0x22 /* NXP and Atmel, possibly others? */ /* Status bits in temperature register */ -#define JC42_ALARM_CRIT_BIT 15 -#define JC42_ALARM_MAX_BIT 14 -#define JC42_ALARM_MIN_BIT 13 +#define JC42_ALARM_CRIT BIT(15) +#define JC42_ALARM_MAX BIT(14) +#define JC42_ALARM_MIN BIT(13) /* Configuration register defines */ -#define JC42_CFG_CRIT_ONLY (1 << 2) -#define JC42_CFG_TCRIT_LOCK (1 << 6) -#define JC42_CFG_EVENT_LOCK (1 << 7) -#define JC42_CFG_SHUTDOWN (1 << 8) -#define JC42_CFG_HYST_SHIFT 9 -#define JC42_CFG_HYST_MASK (0x03 << 9) +#define JC42_CFG_CRIT_ONLY BIT(2) +#define JC42_CFG_TCRIT_LOCK BIT(6) +#define JC42_CFG_EVENT_LOCK BIT(7) +#define JC42_CFG_SHUTDOWN BIT(8) +#define JC42_CFG_HYST_MASK GENMASK(10, 9) /* Capabilities */ -#define JC42_CAP_RANGE (1 << 2) +#define JC42_CAP_RANGE BIT(2) /* Manufacturer IDs */ #define ADT_MANID 0x11d4 /* Analog Devices */ @@ -277,8 +277,8 @@ static int jc42_read(struct device *dev, break; temp = jc42_temp_from_reg(regval); - hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) - >> JC42_CFG_HYST_SHIFT]; + hyst = jc42_hysteresis[FIELD_GET(JC42_CFG_HYST_MASK, + data->config)]; *val = temp - hyst; break; case hwmon_temp_crit_hyst: @@ -288,8 +288,8 @@ static int jc42_read(struct device *dev, break; temp = jc42_temp_from_reg(regval); - hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK) - >> JC42_CFG_HYST_SHIFT]; + hyst = jc42_hysteresis[FIELD_GET(JC42_CFG_HYST_MASK, + data->config)]; *val = temp - hyst; break; case hwmon_temp_min_alarm: @@ -297,21 +297,21 @@ static int jc42_read(struct device *dev, if (ret) break; - *val = (regval >> JC42_ALARM_MIN_BIT) & 1; + *val = FIELD_GET(JC42_ALARM_MIN, regval); break; case hwmon_temp_max_alarm: ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); if (ret) break; - *val = (regval >> JC42_ALARM_MAX_BIT) & 1; + *val = FIELD_GET(JC42_ALARM_MAX, regval); break; case hwmon_temp_crit_alarm: ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val); if (ret) break; - *val = (regval >> JC42_ALARM_CRIT_BIT) & 1; + *val = FIELD_GET(JC42_ALARM_CRIT, regval); break; default: ret = -EOPNOTSUPP; @@ -370,7 +370,7 @@ static int jc42_write(struct device *dev hyst = 3; /* 6.0 degrees C */ } data->config = (data->config & ~JC42_CFG_HYST_MASK) | - (hyst << JC42_CFG_HYST_SHIFT); + FIELD_PREP(JC42_CFG_HYST_MASK, hyst); ret = regmap_write(data->regmap, JC42_REG_CONFIG, data->config); break; diff -rupN linux-6.1.2.orig/drivers/hwmon/Kconfig linux-6.1.2/drivers/hwmon/Kconfig --- linux-6.1.2.orig/drivers/hwmon/Kconfig 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/Kconfig 2022-12-31 16:19:53.953180971 -0500 @@ -67,6 +67,14 @@ config SENSORS_ABITUGURU3 This driver can also be built as a module. If so, the module will be called abituguru3. +config SENSORS_SMPRO + tristate "Ampere's Altra SMpro hardware monitoring driver" + depends on MFD_SMPRO + help + If you say yes here you get support for the thermal, voltage, + current and power sensors of Ampere's Altra processor family SoC + with SMpro co-processor. + config SENSORS_AD7314 tristate "Analog Devices AD7314 and compatibles" depends on SPI @@ -1608,6 +1616,17 @@ config SENSORS_NZXT_SMART2 source "drivers/hwmon/occ/Kconfig" +config SENSORS_OXP + tristate "OneXPlayer EC fan control" + depends on ACPI + depends on X86 + help + If you say yes here you get support for fan readings and control over + OneXPlayer handheld devices. Only OneXPlayer mini AMD handheld variant + boards are supported. + + Can also be built as a module. In that case it will be called oxp-sensors. + config SENSORS_PCF8591 tristate "Philips PCF8591 ADC/DAC" depends on I2C diff -rupN linux-6.1.2.orig/drivers/hwmon/lm73.c linux-6.1.2/drivers/hwmon/lm73.c --- linux-6.1.2.orig/drivers/hwmon/lm73.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/lm73.c 2022-12-31 16:19:55.385168045 -0500 @@ -92,7 +92,7 @@ static ssize_t temp_show(struct device * /* use integer division instead of equivalent right shift to guarantee arithmetic shift and preserve the sign */ temp = (((s16) err) * 250) / 32; - return scnprintf(buf, PAGE_SIZE, "%d\n", temp); + return sysfs_emit(buf, "%d\n", temp); } static ssize_t convrate_store(struct device *dev, struct device_attribute *da, @@ -137,7 +137,7 @@ static ssize_t convrate_show(struct devi int res; res = (data->ctrl & LM73_CTRL_RES_MASK) >> LM73_CTRL_RES_SHIFT; - return scnprintf(buf, PAGE_SIZE, "%hu\n", lm73_convrates[res]); + return sysfs_emit(buf, "%hu\n", lm73_convrates[res]); } static ssize_t maxmin_alarm_show(struct device *dev, @@ -154,7 +154,7 @@ static ssize_t maxmin_alarm_show(struct data->ctrl = ctrl; mutex_unlock(&data->lock); - return scnprintf(buf, PAGE_SIZE, "%d\n", (ctrl >> attr->index) & 1); + return sysfs_emit(buf, "%d\n", (ctrl >> attr->index) & 1); abort: mutex_unlock(&data->lock); diff -rupN linux-6.1.2.orig/drivers/hwmon/lm90.c linux-6.1.2/drivers/hwmon/lm90.c --- linux-6.1.2.orig/drivers/hwmon/lm90.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/lm90.c 2022-12-31 16:19:53.945181044 -0500 @@ -103,6 +103,7 @@ #include #include #include +#include #include #include #include @@ -2663,11 +2664,6 @@ static void lm90_remove_pec(void *dev) device_remove_file(dev, &dev_attr_pec); } -static void lm90_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int lm90_probe_channel_from_dt(struct i2c_client *client, struct device_node *child, struct lm90_data *data) @@ -2749,24 +2745,13 @@ static int lm90_probe(struct i2c_client struct device *dev = &client->dev; struct i2c_adapter *adapter = client->adapter; struct hwmon_channel_info *info; - struct regulator *regulator; struct device *hwmon_dev; struct lm90_data *data; int err; - regulator = devm_regulator_get(dev, "vcc"); - if (IS_ERR(regulator)) - return PTR_ERR(regulator); - - err = regulator_enable(regulator); - if (err < 0) { - dev_err(dev, "Failed to enable regulator: %d\n", err); - return err; - } - - err = devm_add_action_or_reset(dev, lm90_regulator_disable, regulator); + err = devm_regulator_get_enable(dev, "vcc"); if (err) - return err; + return dev_err_probe(dev, err, "Failed to enable regulator\n"); data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL); if (!data) diff -rupN linux-6.1.2.orig/drivers/hwmon/ltc2992.c linux-6.1.2/drivers/hwmon/ltc2992.c --- linux-6.1.2.orig/drivers/hwmon/ltc2992.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/ltc2992.c 2022-12-31 16:19:46.453248935 -0500 @@ -881,7 +881,7 @@ static int ltc2992_parse_dt(struct ltc29 return 0; } -static int ltc2992_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int ltc2992_i2c_probe(struct i2c_client *client) { struct device *hwmon_dev; struct ltc2992_state *st; @@ -927,7 +927,7 @@ static struct i2c_driver ltc2992_i2c_dri .name = "ltc2992", .of_match_table = ltc2992_of_match, }, - .probe = ltc2992_i2c_probe, + .probe_new = ltc2992_i2c_probe, .id_table = ltc2992_i2c_id, }; diff -rupN linux-6.1.2.orig/drivers/hwmon/Makefile linux-6.1.2/drivers/hwmon/Makefile --- linux-6.1.2.orig/drivers/hwmon/Makefile 2022-12-31 16:12:06.934585693 -0500 +++ linux-6.1.2/drivers/hwmon/Makefile 2022-12-31 16:19:53.953180971 -0500 @@ -167,6 +167,7 @@ obj-$(CONFIG_SENSORS_NSA320) += nsa320-h obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o obj-$(CONFIG_SENSORS_NZXT_KRAKEN2) += nzxt-kraken2.o obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o +obj-$(CONFIG_SENSORS_OXP) += oxp-sensors.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o @@ -187,6 +188,7 @@ obj-$(CONFIG_SENSORS_SHT4x) += sht4x.o obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMM665) += smm665.o +obj-$(CONFIG_SENSORS_SMPRO) += smpro-hwmon.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o diff -rupN linux-6.1.2.orig/drivers/hwmon/max127.c linux-6.1.2/drivers/hwmon/max127.c --- linux-6.1.2.orig/drivers/hwmon/max127.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/max127.c 2022-12-31 16:19:46.453248935 -0500 @@ -303,8 +303,7 @@ static const struct hwmon_chip_info max1 .info = max127_info, }; -static int max127_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int max127_probe(struct i2c_client *client) { int i; struct device *hwmon_dev; @@ -340,7 +339,7 @@ static struct i2c_driver max127_driver = .driver = { .name = "max127", }, - .probe = max127_probe, + .probe_new = max127_probe, .id_table = max127_id, }; diff -rupN linux-6.1.2.orig/drivers/hwmon/mr75203.c linux-6.1.2/drivers/hwmon/mr75203.c --- linux-6.1.2.orig/drivers/hwmon/mr75203.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/mr75203.c 2022-12-31 16:19:53.945181044 -0500 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff -rupN linux-6.1.2.orig/drivers/hwmon/occ/Kconfig linux-6.1.2/drivers/hwmon/occ/Kconfig --- linux-6.1.2.orig/drivers/hwmon/occ/Kconfig 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/occ/Kconfig 2022-12-31 16:19:46.457248898 -0500 @@ -6,7 +6,6 @@ config SENSORS_OCC_P8_I2C tristate "POWER8 OCC through I2C" depends on I2C - depends on ARM || ARM64 || COMPILE_TEST select SENSORS_OCC help This option enables support for monitoring sensors provided by the @@ -21,7 +20,6 @@ config SENSORS_OCC_P8_I2C config SENSORS_OCC_P9_SBE tristate "POWER9 OCC through SBE" depends on FSI_OCC - depends on ARM || ARM64 || COMPILE_TEST select SENSORS_OCC help This option enables support for monitoring sensors provided by the diff -rupN linux-6.1.2.orig/drivers/hwmon/oxp-sensors.c linux-6.1.2/drivers/hwmon/oxp-sensors.c --- linux-6.1.2.orig/drivers/hwmon/oxp-sensors.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-6.1.2/drivers/hwmon/oxp-sensors.c 2022-12-31 16:19:55.385168045 -0500 @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Platform driver for OXP Handhelds that expose fan reading and control + * via hwmon sysfs. + * + * Old boards have the same DMI strings and they are told appart by the + * boot cpu vendor (Intel/AMD). Currently only AMD boards are supported + * but the code is made to be simple to add other handheld boards in the + * future. + * Fan control is provided via pwm interface in the range [0-255]. + * Old AMD boards use [0-100] as range in the EC, the written value is + * scaled to accommodate for that. Newer boards like the mini PRO and + * AOK ZOE are not scaled but have the same EC layout. + * + * Copyright (C) 2022 Joaquín I. Aramendía + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Handle ACPI lock mechanism */ +static u32 oxp_mutex; + +#define ACPI_LOCK_DELAY_MS 500 + +static bool lock_global_acpi_lock(void) +{ + return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex)); +} + +static bool unlock_global_acpi_lock(void) +{ + return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex)); +} + +enum oxp_board { + aok_zoe_a1 = 1, + oxp_mini_amd, + oxp_mini_amd_pro, +}; + +static enum oxp_board board; + +#define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ +#define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */ +#define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */ + +static const struct dmi_system_id dmi_table[] = { + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"), + }, + .driver_data = (void *) &(enum oxp_board) {aok_zoe_a1}, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"), + }, + .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd}, + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"), + }, + .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro}, + }, + {}, +}; + +/* Helper functions to handle EC read/write */ +static int read_from_ec(u8 reg, int size, long *val) +{ + int i; + int ret; + u8 buffer; + + if (!lock_global_acpi_lock()) + return -EBUSY; + + *val = 0; + for (i = 0; i < size; i++) { + ret = ec_read(reg + i, &buffer); + if (ret) + return ret; + *val <<= i * 8; + *val += buffer; + } + + if (!unlock_global_acpi_lock()) + return -EBUSY; + + return 0; +} + +static int write_to_ec(const struct device *dev, u8 reg, u8 value) +{ + int ret; + + if (!lock_global_acpi_lock()) + return -EBUSY; + + ret = ec_write(reg, value); + + if (!unlock_global_acpi_lock()) + return -EBUSY; + + return ret; +} + +static int oxp_pwm_enable(const struct device *dev) +{ + return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01); +} + +static int oxp_pwm_disable(const struct device *dev) +{ + return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00); +} + +/* Callbacks for hwmon interface */ +static umode_t oxp_ec_hwmon_is_visible(const void *drvdata, + enum hwmon_sensor_types type, u32 attr, int channel) +{ + switch (type) { + case hwmon_fan: + return 0444; + case hwmon_pwm: + return 0644; + default: + return 0; + } +} + +static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + int ret; + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_input: + return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); + default: + break; + } + break; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); + if (ret) + return ret; + if (board == oxp_mini_amd) + *val = (*val * 255) / 100; + return 0; + case hwmon_pwm_enable: + return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_enable: + if (val == 1) + return oxp_pwm_enable(dev); + else if (val == 0) + return oxp_pwm_disable(dev); + return -EINVAL; + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + if (board == oxp_mini_amd) + val = (val * 100) / 255; + return write_to_ec(dev, OXP_SENSOR_PWM_REG, val); + default: + break; + } + break; + default: + break; + } + return -EOPNOTSUPP; +} + +/* Known sensors in the OXP EC controllers */ +static const struct hwmon_channel_info *oxp_platform_sensors[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), + NULL, +}; + +static const struct hwmon_ops oxp_ec_hwmon_ops = { + .is_visible = oxp_ec_hwmon_is_visible, + .read = oxp_platform_read, + .write = oxp_platform_write, +}; + +static const struct hwmon_chip_info oxp_ec_chip_info = { + .ops = &oxp_ec_hwmon_ops, + .info = oxp_platform_sensors, +}; + +/* Initialization logic */ +static int oxp_platform_probe(struct platform_device *pdev) +{ + const struct dmi_system_id *dmi_entry; + struct device *dev = &pdev->dev; + struct device *hwdev; + + /* + * Have to check for AMD processor here because DMI strings are the + * same between Intel and AMD boards, the only way to tell them appart + * is the CPU. + * Intel boards seem to have different EC registers and values to + * read/write. + */ + dmi_entry = dmi_first_match(dmi_table); + if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return -ENODEV; + + board = *((enum oxp_board *) dmi_entry->driver_data); + + hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL, + &oxp_ec_chip_info, NULL); + + return PTR_ERR_OR_ZERO(hwdev); +} + +static struct platform_driver oxp_platform_driver = { + .driver = { + .name = "oxp-platform", + }, + .probe = oxp_platform_probe, +}; + +static struct platform_device *oxp_platform_device; + +static int __init oxp_platform_init(void) +{ + oxp_platform_device = + platform_create_bundle(&oxp_platform_driver, + oxp_platform_probe, NULL, 0, NULL, 0); + + return PTR_ERR_OR_ZERO(oxp_platform_device); +} + +static void __exit oxp_platform_exit(void) +{ + platform_device_unregister(oxp_platform_device); + platform_driver_unregister(&oxp_platform_driver); +} + +MODULE_DEVICE_TABLE(dmi, dmi_table); + +module_init(oxp_platform_init); +module_exit(oxp_platform_exit); + +MODULE_AUTHOR("Joaquín Ignacio Aramendía "); +MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices"); +MODULE_LICENSE("GPL"); diff -rupN linux-6.1.2.orig/drivers/hwmon/pcf8591.c linux-6.1.2/drivers/hwmon/pcf8591.c --- linux-6.1.2.orig/drivers/hwmon/pcf8591.c 2022-12-31 16:12:06.938585633 -0500 +++ linux-6.1.2/drivers/hwmon/pcf8591.c 2022-12-31 16:19:53.949181008 -0500 @@ -14,6 +14,7 @@ #include #include #include +#include /* Insmod parameters */ diff -rupN linux-6.1.2.orig/drivers/hwmon/pmbus/ltc2978.c linux-6.1.2/drivers/hwmon/pmbus/ltc2978.c --- linux-6.1.2.orig/drivers/hwmon/pmbus/ltc2978.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/pmbus/ltc2978.c 2022-12-31 16:19:53.945181044 -0500 @@ -23,7 +23,7 @@ enum chips { /* Managers */ ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980, /* Controllers */ - ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7880, + ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, ltc7880, /* Modules */ ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686, ltm4700, @@ -45,15 +45,14 @@ enum chips { #define LTC2974_MFR_IOUT_PEAK 0xd7 #define LTC2974_MFR_IOUT_MIN 0xd8 -/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, and LTM4676 */ +/* LTC3880, LTC3882, LTC3883, LTC3887, LTM4675, LTM4676, LTC7132 */ #define LTC3880_MFR_IOUT_PEAK 0xd7 #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883, LTC3884, LTC3886, LTC3889 and LTC7880 only */ +/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7880 */ #define LTC3883_MFR_IIN_PEAK 0xe1 - /* LTC2975 only */ #define LTC2975_MFR_IIN_PEAK 0xc4 #define LTC2975_MFR_IIN_MIN 0xc5 @@ -79,10 +78,11 @@ enum chips { #define LTC3884_ID 0x4C00 #define LTC3886_ID 0x4600 #define LTC3887_ID 0x4700 -#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ -#define LTM2987_ID_B 0x8020 #define LTC3889_ID 0x4900 +#define LTC7132_ID 0x4CE0 #define LTC7880_ID 0x49E0 +#define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ +#define LTM2987_ID_B 0x8020 #define LTM4664_ID 0x4120 #define LTM4675_ID 0x47a0 #define LTM4676_ID_REV1 0x4400 @@ -547,6 +547,7 @@ static const struct i2c_device_id ltc297 {"ltc3886", ltc3886}, {"ltc3887", ltc3887}, {"ltc3889", ltc3889}, + {"ltc7132", ltc7132}, {"ltc7880", ltc7880}, {"ltm2987", ltm2987}, {"ltm4664", ltm4664}, @@ -651,6 +652,8 @@ static int ltc2978_get_id(struct i2c_cli return ltc3887; else if (chip_id == LTC3889_ID) return ltc3889; + else if (chip_id == LTC7132_ID) + return ltc7132; else if (chip_id == LTC7880_ID) return ltc7880; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) @@ -831,6 +834,7 @@ static int ltc2978_probe(struct i2c_clie case ltc3884: case ltc3886: case ltc3889: + case ltc7132: case ltc7880: case ltm4664: case ltm4678: @@ -902,6 +906,7 @@ static const struct of_device_id ltc2978 { .compatible = "lltc,ltc3886" }, { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltc3889" }, + { .compatible = "lltc,ltc7132" }, { .compatible = "lltc,ltc7880" }, { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4664" }, diff -rupN linux-6.1.2.orig/drivers/hwmon/pmbus/pmbus_core.c linux-6.1.2/drivers/hwmon/pmbus/pmbus_core.c --- linux-6.1.2.orig/drivers/hwmon/pmbus/pmbus_core.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/pmbus/pmbus_core.c 2022-12-31 16:19:55.381168081 -0500 @@ -2827,9 +2827,13 @@ static int pmbus_regulator_get_error_fla if (status < 0) return status; - if (pmbus_regulator_is_enabled(rdev) && (status & PB_STATUS_OFF)) - *flags |= REGULATOR_ERROR_FAIL; + if (pmbus_regulator_is_enabled(rdev)) { + if (status & PB_STATUS_OFF) + *flags |= REGULATOR_ERROR_FAIL; + if (status & PB_STATUS_POWER_GOOD_N) + *flags |= REGULATOR_ERROR_REGULATION_OUT; + } /* * Unlike most other status bits, PB_STATUS_{IOUT_OC,VOUT_OV} are * defined strictly as fault indicators (not warnings). @@ -2851,6 +2855,49 @@ static int pmbus_regulator_get_error_fla return 0; } +static int pmbus_regulator_get_status(struct regulator_dev *rdev) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_data *data = i2c_get_clientdata(client); + u8 page = rdev_get_id(rdev); + int status, ret; + + mutex_lock(&data->update_lock); + status = pmbus_get_status(client, page, PMBUS_STATUS_WORD); + if (status < 0) { + ret = status; + goto unlock; + } + + if (status & PB_STATUS_OFF) { + ret = REGULATOR_STATUS_OFF; + goto unlock; + } + + /* If regulator is ON & reports power good then return ON */ + if (!(status & PB_STATUS_POWER_GOOD_N)) { + ret = REGULATOR_STATUS_ON; + goto unlock; + } + + ret = pmbus_regulator_get_error_flags(rdev, &status); + if (ret) + goto unlock; + + if (status & (REGULATOR_ERROR_UNDER_VOLTAGE | REGULATOR_ERROR_OVER_CURRENT | + REGULATOR_ERROR_REGULATION_OUT | REGULATOR_ERROR_FAIL | REGULATOR_ERROR_OVER_TEMP)) { + ret = REGULATOR_STATUS_ERROR; + goto unlock; + } + + ret = REGULATOR_STATUS_UNDEFINED; + +unlock: + mutex_unlock(&data->update_lock); + return ret; +} + static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page) { struct pmbus_data *data = i2c_get_clientdata(client); @@ -2991,6 +3038,7 @@ const struct regulator_ops pmbus_regulat .disable = pmbus_regulator_disable, .is_enabled = pmbus_regulator_is_enabled, .get_error_flags = pmbus_regulator_get_error_flags, + .get_status = pmbus_regulator_get_status, .get_voltage = pmbus_regulator_get_voltage, .set_voltage = pmbus_regulator_set_voltage, .list_voltage = pmbus_regulator_list_voltage, diff -rupN linux-6.1.2.orig/drivers/hwmon/pmbus/q54sj108a2.c linux-6.1.2/drivers/hwmon/pmbus/q54sj108a2.c --- linux-6.1.2.orig/drivers/hwmon/pmbus/q54sj108a2.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/pmbus/q54sj108a2.c 2022-12-31 16:19:53.949181008 -0500 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include "pmbus.h" diff -rupN linux-6.1.2.orig/drivers/hwmon/sbrmi.c linux-6.1.2/drivers/hwmon/sbrmi.c --- linux-6.1.2.orig/drivers/hwmon/sbrmi.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/sbrmi.c 2022-12-31 16:19:46.453248935 -0500 @@ -297,8 +297,7 @@ static int sbrmi_get_max_pwr_limit(struc return ret; } -static int sbrmi_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sbrmi_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -348,7 +347,7 @@ static struct i2c_driver sbrmi_driver = .name = "sbrmi", .of_match_table = of_match_ptr(sbrmi_of_match), }, - .probe = sbrmi_probe, + .probe_new = sbrmi_probe, .id_table = sbrmi_id, }; diff -rupN linux-6.1.2.orig/drivers/hwmon/sbtsi_temp.c linux-6.1.2/drivers/hwmon/sbtsi_temp.c --- linux-6.1.2.orig/drivers/hwmon/sbtsi_temp.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/sbtsi_temp.c 2022-12-31 16:19:46.453248935 -0500 @@ -199,8 +199,7 @@ static const struct hwmon_chip_info sbts .info = sbtsi_info, }; -static int sbtsi_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int sbtsi_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device *hwmon_dev; @@ -239,7 +238,7 @@ static struct i2c_driver sbtsi_driver = .name = "sbtsi", .of_match_table = of_match_ptr(sbtsi_of_match), }, - .probe = sbtsi_probe, + .probe_new = sbtsi_probe, .id_table = sbtsi_id, }; diff -rupN linux-6.1.2.orig/drivers/hwmon/sht3x.c linux-6.1.2/drivers/hwmon/sht3x.c --- linux-6.1.2.orig/drivers/hwmon/sht3x.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/sht3x.c 2022-12-31 16:19:55.385168045 -0500 @@ -320,7 +320,7 @@ static ssize_t temp1_limit_show(struct d u8 index = to_sensor_dev_attr(attr)->index; int temperature_limit = data->temperature_limits[index]; - return scnprintf(buf, PAGE_SIZE, "%d\n", temperature_limit); + return sysfs_emit(buf, "%d\n", temperature_limit); } static ssize_t humidity1_limit_show(struct device *dev, @@ -331,7 +331,7 @@ static ssize_t humidity1_limit_show(stru u8 index = to_sensor_dev_attr(attr)->index; u32 humidity_limit = data->humidity_limits[index]; - return scnprintf(buf, PAGE_SIZE, "%u\n", humidity_limit); + return sysfs_emit(buf, "%u\n", humidity_limit); } /* @@ -483,7 +483,7 @@ static ssize_t temp1_alarm_show(struct d if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x04)); + return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x04)); } static ssize_t humidity1_alarm_show(struct device *dev, @@ -498,7 +498,7 @@ static ssize_t humidity1_alarm_show(stru if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x08)); + return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x08)); } static ssize_t heater_enable_show(struct device *dev, @@ -513,7 +513,7 @@ static ssize_t heater_enable_show(struct if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x20)); + return sysfs_emit(buf, "%d\n", !!(buffer[0] & 0x20)); } static ssize_t heater_enable_store(struct device *dev, @@ -550,7 +550,7 @@ static ssize_t update_interval_show(stru { struct sht3x_data *data = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%u\n", + return sysfs_emit(buf, "%u\n", mode_to_update_interval[data->mode]); } diff -rupN linux-6.1.2.orig/drivers/hwmon/sht4x.c linux-6.1.2/drivers/hwmon/sht4x.c --- linux-6.1.2.orig/drivers/hwmon/sht4x.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/sht4x.c 2022-12-31 16:19:46.457248898 -0500 @@ -232,8 +232,7 @@ static const struct hwmon_chip_info sht4 .info = sht4x_info, }; -static int sht4x_probe(struct i2c_client *client, - const struct i2c_device_id *sht4x_id) +static int sht4x_probe(struct i2c_client *client) { struct device *device = &client->dev; struct device *hwmon_dev; @@ -292,7 +291,7 @@ static struct i2c_driver sht4x_driver = .name = "sht4x", .of_match_table = sht4x_of_match, }, - .probe = sht4x_probe, + .probe_new = sht4x_probe, .id_table = sht4x_id, }; diff -rupN linux-6.1.2.orig/drivers/hwmon/smpro-hwmon.c linux-6.1.2/drivers/hwmon/smpro-hwmon.c --- linux-6.1.2.orig/drivers/hwmon/smpro-hwmon.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-6.1.2/drivers/hwmon/smpro-hwmon.c 2022-12-31 16:19:53.945181044 -0500 @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Ampere Computing SoC's SMPro Hardware Monitoring Driver + * + * Copyright (c) 2022, Ampere Computing LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Logical Power Sensor Registers */ +#define SOC_TEMP 0x10 +#define SOC_VRD_TEMP 0x11 +#define DIMM_VRD_TEMP 0x12 +#define CORE_VRD_TEMP 0x13 +#define CH0_DIMM_TEMP 0x14 +#define CH1_DIMM_TEMP 0x15 +#define CH2_DIMM_TEMP 0x16 +#define CH3_DIMM_TEMP 0x17 +#define CH4_DIMM_TEMP 0x18 +#define CH5_DIMM_TEMP 0x19 +#define CH6_DIMM_TEMP 0x1A +#define CH7_DIMM_TEMP 0x1B +#define RCA_VRD_TEMP 0x1C + +#define CORE_VRD_PWR 0x20 +#define SOC_PWR 0x21 +#define DIMM_VRD1_PWR 0x22 +#define DIMM_VRD2_PWR 0x23 +#define CORE_VRD_PWR_MW 0x26 +#define SOC_PWR_MW 0x27 +#define DIMM_VRD1_PWR_MW 0x28 +#define DIMM_VRD2_PWR_MW 0x29 +#define RCA_VRD_PWR 0x2A +#define RCA_VRD_PWR_MW 0x2B + +#define MEM_HOT_THRESHOLD 0x32 +#define SOC_VR_HOT_THRESHOLD 0x33 +#define CORE_VRD_VOLT 0x34 +#define SOC_VRD_VOLT 0x35 +#define DIMM_VRD1_VOLT 0x36 +#define DIMM_VRD2_VOLT 0x37 +#define RCA_VRD_VOLT 0x38 + +#define CORE_VRD_CURR 0x39 +#define SOC_VRD_CURR 0x3A +#define DIMM_VRD1_CURR 0x3B +#define DIMM_VRD2_CURR 0x3C +#define RCA_VRD_CURR 0x3D + +struct smpro_hwmon { + struct regmap *regmap; +}; + +struct smpro_sensor { + const u8 reg; + const u8 reg_ext; + const char *label; +}; + +static const struct smpro_sensor temperature[] = { + { + .reg = SOC_TEMP, + .label = "temp1 SoC" + }, + { + .reg = SOC_VRD_TEMP, + .reg_ext = SOC_VR_HOT_THRESHOLD, + .label = "temp2 SoC VRD" + }, + { + .reg = DIMM_VRD_TEMP, + .label = "temp3 DIMM VRD" + }, + { + .reg = CORE_VRD_TEMP, + .label = "temp4 CORE VRD" + }, + { + .reg = CH0_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp5 CH0 DIMM" + }, + { + .reg = CH1_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp6 CH1 DIMM" + }, + { + .reg = CH2_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp7 CH2 DIMM" + }, + { + .reg = CH3_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp8 CH3 DIMM" + }, + { + .reg = CH4_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp9 CH4 DIMM" + }, + { + .reg = CH5_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp10 CH5 DIMM" + }, + { + .reg = CH6_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp11 CH6 DIMM" + }, + { + .reg = CH7_DIMM_TEMP, + .reg_ext = MEM_HOT_THRESHOLD, + .label = "temp12 CH7 DIMM" + }, + { + .reg = RCA_VRD_TEMP, + .label = "temp13 RCA VRD" + }, +}; + +static const struct smpro_sensor voltage[] = { + { + .reg = CORE_VRD_VOLT, + .label = "vout0 CORE VRD" + }, + { + .reg = SOC_VRD_VOLT, + .label = "vout1 SoC VRD" + }, + { + .reg = DIMM_VRD1_VOLT, + .label = "vout2 DIMM VRD1" + }, + { + .reg = DIMM_VRD2_VOLT, + .label = "vout3 DIMM VRD2" + }, + { + .reg = RCA_VRD_VOLT, + .label = "vout4 RCA VRD" + }, +}; + +static const struct smpro_sensor curr_sensor[] = { + { + .reg = CORE_VRD_CURR, + .label = "iout1 CORE VRD" + }, + { + .reg = SOC_VRD_CURR, + .label = "iout2 SoC VRD" + }, + { + .reg = DIMM_VRD1_CURR, + .label = "iout3 DIMM VRD1" + }, + { + .reg = DIMM_VRD2_CURR, + .label = "iout4 DIMM VRD2" + }, + { + .reg = RCA_VRD_CURR, + .label = "iout5 RCA VRD" + }, +}; + +static const struct smpro_sensor power[] = { + { + .reg = CORE_VRD_PWR, + .reg_ext = CORE_VRD_PWR_MW, + .label = "power1 CORE VRD" + }, + { + .reg = SOC_PWR, + .reg_ext = SOC_PWR_MW, + .label = "power2 SoC" + }, + { + .reg = DIMM_VRD1_PWR, + .reg_ext = DIMM_VRD1_PWR_MW, + .label = "power3 DIMM VRD1" + }, + { + .reg = DIMM_VRD2_PWR, + .reg_ext = DIMM_VRD2_PWR_MW, + .label = "power4 DIMM VRD2" + }, + { + .reg = RCA_VRD_PWR, + .reg_ext = RCA_VRD_PWR_MW, + .label = "power5 RCA VRD" + }, +}; + +static int smpro_read_temp(struct device *dev, u32 attr, int channel, long *val) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int value; + int ret; + + switch (attr) { + case hwmon_temp_input: + ret = regmap_read(hwmon->regmap, temperature[channel].reg, &value); + if (ret) + return ret; + break; + case hwmon_temp_crit: + ret = regmap_read(hwmon->regmap, temperature[channel].reg_ext, &value); + if (ret) + return ret; + break; + default: + return -EOPNOTSUPP; + } + + *val = sign_extend32(value, 8) * 1000; + return 0; +} + +static int smpro_read_in(struct device *dev, u32 attr, int channel, long *val) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int value; + int ret; + + switch (attr) { + case hwmon_in_input: + ret = regmap_read(hwmon->regmap, voltage[channel].reg, &value); + if (ret < 0) + return ret; + /* 15-bit value in 1mV */ + *val = value & 0x7fff; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read_curr(struct device *dev, u32 attr, int channel, long *val) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int value; + int ret; + + switch (attr) { + case hwmon_curr_input: + ret = regmap_read(hwmon->regmap, curr_sensor[channel].reg, &value); + if (ret < 0) + return ret; + /* Scale reported by the hardware is 1mA */ + *val = value & 0x7fff; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read_power(struct device *dev, u32 attr, int channel, long *val_pwr) +{ + struct smpro_hwmon *hwmon = dev_get_drvdata(dev); + unsigned int val = 0, val_mw = 0; + int ret; + + switch (attr) { + case hwmon_power_input: + ret = regmap_read(hwmon->regmap, power[channel].reg, &val); + if (ret) + return ret; + + ret = regmap_read(hwmon->regmap, power[channel].reg_ext, &val_mw); + if (ret) + return ret; + /* 10-bit value */ + *val_pwr = (val & 0x3ff) * 1000000 + (val_mw & 0x3ff) * 1000; + return 0; + + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_temp: + return smpro_read_temp(dev, attr, channel, val); + case hwmon_in: + return smpro_read_in(dev, attr, channel, val); + case hwmon_power: + return smpro_read_power(dev, attr, channel, val); + case hwmon_curr: + return smpro_read_curr(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int smpro_read_string(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, const char **str) +{ + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_label: + *str = temperature[channel].label; + return 0; + default: + break; + } + break; + + case hwmon_in: + switch (attr) { + case hwmon_in_label: + *str = voltage[channel].label; + return 0; + default: + break; + } + break; + + case hwmon_curr: + switch (attr) { + case hwmon_curr_label: + *str = curr_sensor[channel].label; + return 0; + default: + break; + } + break; + + case hwmon_power: + switch (attr) { + case hwmon_power_label: + *str = power[channel].label; + return 0; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +} + +static umode_t smpro_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + const struct smpro_hwmon *hwmon = data; + unsigned int value; + int ret; + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_label: + case hwmon_temp_crit: + ret = regmap_read(hwmon->regmap, temperature[channel].reg, &value); + if (ret || value == 0xFFFF) + return 0; + break; + default: + break; + } + break; + default: + break; + } + + return 0444; +} + +static const struct hwmon_channel_info *smpro_info[] = { + HWMON_CHANNEL_INFO(temp, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, + HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_CHANNEL_INFO(in, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_CHANNEL_INFO(power, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL, + HWMON_P_INPUT | HWMON_P_LABEL), + HWMON_CHANNEL_INFO(curr, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL, + HWMON_C_INPUT | HWMON_C_LABEL), + NULL +}; + +static const struct hwmon_ops smpro_hwmon_ops = { + .is_visible = smpro_is_visible, + .read = smpro_read, + .read_string = smpro_read_string, +}; + +static const struct hwmon_chip_info smpro_chip_info = { + .ops = &smpro_hwmon_ops, + .info = smpro_info, +}; + +static int smpro_hwmon_probe(struct platform_device *pdev) +{ + struct smpro_hwmon *hwmon; + struct device *hwmon_dev; + + hwmon = devm_kzalloc(&pdev->dev, sizeof(struct smpro_hwmon), GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!hwmon->regmap) + return -ENODEV; + + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "smpro_hwmon", + hwmon, &smpro_chip_info, NULL); + + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static struct platform_driver smpro_hwmon_driver = { + .probe = smpro_hwmon_probe, + .driver = { + .name = "smpro-hwmon", + }, +}; + +module_platform_driver(smpro_hwmon_driver); + +MODULE_AUTHOR("Thu Nguyen "); +MODULE_AUTHOR("Quan Nguyen "); +MODULE_DESCRIPTION("Ampere Altra SMPro hwmon driver"); +MODULE_LICENSE("GPL"); diff -rupN linux-6.1.2.orig/drivers/hwmon/vt8231.c linux-6.1.2/drivers/hwmon/vt8231.c --- linux-6.1.2.orig/drivers/hwmon/vt8231.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/vt8231.c 2022-12-31 16:19:53.953180971 -0500 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff -rupN linux-6.1.2.orig/drivers/hwmon/w83l786ng.c linux-6.1.2/drivers/hwmon/w83l786ng.c --- linux-6.1.2.orig/drivers/hwmon/w83l786ng.c 2022-12-31 16:12:06.942585573 -0500 +++ linux-6.1.2/drivers/hwmon/w83l786ng.c 2022-12-31 16:19:53.953180971 -0500 @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff -rupN linux-6.1.2.orig/include/linux/hwmon-sysfs.h linux-6.1.2/include/linux/hwmon-sysfs.h --- linux-6.1.2.orig/include/linux/hwmon-sysfs.h 2022-12-31 16:12:07.878571532 -0500 +++ linux-6.1.2/include/linux/hwmon-sysfs.h 2022-12-31 16:19:53.949181008 -0500 @@ -8,6 +8,7 @@ #define _LINUX_HWMON_SYSFS_H #include +#include struct sensor_device_attribute{ struct device_attribute dev_attr; diff -rupN linux-6.1.2.orig/include/linux/platform_data/gsc_hwmon.h linux-6.1.2/include/linux/platform_data/gsc_hwmon.h --- linux-6.1.2.orig/include/linux/platform_data/gsc_hwmon.h 2022-12-31 16:12:07.910571053 -0500 +++ linux-6.1.2/include/linux/platform_data/gsc_hwmon.h 2022-12-31 16:19:55.381168081 -0500 @@ -29,18 +29,17 @@ struct gsc_hwmon_channel { /** * struct gsc_hwmon_platform_data - platform data for gsc_hwmon driver - * @channels: pointer to array of gsc_hwmon_channel structures - * describing channels * @nchannels: number of elements in @channels array * @vreference: voltage reference (mV) * @resolution: ADC bit resolution * @fan_base: register base for FAN controller + * @channels: array of gsc_hwmon_channel structures describing channels */ struct gsc_hwmon_platform_data { - const struct gsc_hwmon_channel *channels; int nchannels; unsigned int resolution; unsigned int vreference; unsigned int fan_base; + struct gsc_hwmon_channel channels[]; }; #endif diff -rupN linux-6.1.2.orig/MAINTAINERS linux-6.1.2/MAINTAINERS --- linux-6.1.2.orig/MAINTAINERS 2022-12-31 16:12:05.838602157 -0500 +++ linux-6.1.2/MAINTAINERS 2022-12-31 16:19:53.953180971 -0500 @@ -15345,6 +15345,12 @@ S: Maintained F: drivers/mtd/nand/onenand/ F: include/linux/mtd/onenand*.h +ONEXPLAYER FAN DRIVER +M: Joaquín Ignacio Aramendía +L: linux-hwmon@vger.kernel.org +S: Maintained +F: drivers/hwmon/oxp-sensors.c + ONION OMEGA2+ BOARD M: Harvey Hunt L: linux-mips@vger.kernel.org