diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-25 17:43:44 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-04-25 17:43:44 -0700 |
commit | 4173cf6fb6b7d1b4569cca08af318c4561356fb5 (patch) | |
tree | 54d34e0eab0b8cb372e85ab2bad1d6b1612bb89d /drivers | |
parent | 3361e9a4ea957b09c5d6242613360c415194dbb5 (diff) | |
parent | 1c19ac768b8eeb0304c4ed7db66c2bb89c6ad226 (diff) | |
download | lwn-4173cf6fb6b7d1b4569cca08af318c4561356fb5.tar.gz lwn-4173cf6fb6b7d1b4569cca08af318c4561356fb5.zip |
Merge tag 'hwmon-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
"New drivers
- Driver for Acbel FSB032 power supply
- Driver for StarFive JH71x0 temperature sensor
Added support to existing drivers:
- aquacomputer_d5next: Support for Aquacomputer Aquastream XT
- nct6775: Added various ASUS boards to list of boards supporting WMI
- asus-ec-sensors: ROG STRIX Z390-F GAMING, ProArt B550-Creator,
Notable improvements:
- Regulator event and sysfs notification support for PMBus drivers
Notable cleanup:
- Constified pointers to hwmon_channel_info
.. and various other minor bug fixes and improvements"
* tag 'hwmon-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (131 commits)
hwmon: lochnagar: Remove the unneeded include <linux/i2c.h>
hwmon: (pmbus/fsp-3y) Fix functionality bitmask in FSP-3Y YM-2151E
hwmon: (adt7475) Use device_property APIs when configuring polarity
hwmon: (aquacomputer_d5next) Add support for Aquacomputer Aquastream XT
hwmon: (it87) Disable/enable SMBus access for IT8622E chipset
hwmon: (it87) Add calls to smbus_enable/smbus_disable as required
hwmon: (it87) Test for error in it87_update_device
hwmon: (it87) Disable SMBus access for environmental controller registers.
docs: hwmon: Add documentaion for acbel-fsg032 PSU
hwmon: (pmbus/acbel-fsg032) Add Acbel power supply
dt-bindings: trivial-devices: Add acbel,fsg032
dt-bindings: vendor-prefixes: Add prefix for acbel
hwmon: (sfctemp) Simplify error message
hwmon: (pmbus/ibm-cffps) Use default debugfs attributes and lock function
hwmon: (pmbus/core) Add lock and unlock functions
hwmon: (pmbus/core) Request threaded interrupt with IRQF_ONESHOT
hwmon: (nct6775) update ASUS WMI monitoring list A620/B760/W790
hwmon: ina2xx: add optional regulator support
dt-bindings: hwmon: ina2xx: add supply property
dt-bindings: hwmon: pwm-fan: Convert to DT schema
...
Diffstat (limited to 'drivers')
93 files changed, 1791 insertions, 449 deletions
diff --git a/drivers/accel/habanalabs/common/hwmon.c b/drivers/accel/habanalabs/common/hwmon.c index 55eb0203817f..8598056216e7 100644 --- a/drivers/accel/habanalabs/common/hwmon.c +++ b/drivers/accel/habanalabs/common/hwmon.c @@ -914,7 +914,7 @@ void hl_hwmon_fini(struct hl_device *hdev) void hl_hwmon_release_resources(struct hl_device *hdev) { - const struct hwmon_channel_info **channel_info_arr; + const struct hwmon_channel_info * const *channel_info_arr; int i = 0; if (!hdev->hl_chip_info->info) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5b3b76477b0e..fc640201a2de 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1929,6 +1929,16 @@ config SENSORS_STTS751 This driver can also be built as a module. If so, the module will be called stts751. +config SENSORS_SFCTEMP + tristate "Starfive JH71x0 temperature sensor" + depends on ARCH_STARFIVE || COMPILE_TEST + help + If you say yes here you get support for temperature sensor + on the Starfive JH71x0 SoCs. + + This driver can also be built as a module. If so, the module + will be called sfctemp. + config SENSORS_SMM665 tristate "Summit Microelectronics SMM665" depends on I2C @@ -1976,7 +1986,7 @@ config SENSORS_ADS7871 config SENSORS_AMC6821 tristate "Texas Instruments AMC6821" - depends on I2C + depends on I2C help If you say yes here you get support for the Texas Instruments AMC6821 hardware monitoring chips. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 88712b5031c8..cd8c568c80a9 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_HWMON) += hwmon.o obj-$(CONFIG_HWMON_VID) += hwmon-vid.o -# APCI drivers +# ACPI drivers obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o obj-$(CONFIG_SENSORS_ASUS_EC) += asus-ec-sensors.o @@ -181,6 +181,7 @@ obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o +obj-$(CONFIG_SENSORS_SFCTEMP) += sfctemp.o obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c index be17a26a84f1..bfe070a1b501 100644 --- a/drivers/hwmon/adm1177.c +++ b/drivers/hwmon/adm1177.c @@ -168,7 +168,7 @@ static umode_t adm1177_is_visible(const void *data, return 0; } -static const struct hwmon_channel_info *adm1177_info[] = { +static const struct hwmon_channel_info * const adm1177_info[] = { HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_MAX_ALARM), HWMON_CHANNEL_INFO(in, diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 40e3558d3709..9eb973a38e4b 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -731,7 +731,7 @@ static const struct hwmon_ops adm9240_hwmon_ops = { .write = adm9240_write, }; -static const struct hwmon_channel_info *adm9240_info[] = { +static const struct hwmon_channel_info * const adm9240_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_ALARMS), HWMON_CHANNEL_INFO(intrusion, HWMON_INTRUSION_ALARM), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index bf5c5618f8d0..6ba84921614f 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -636,7 +636,7 @@ static int adt7411_init_device(struct adt7411_data *data) return i2c_smbus_write_byte_data(data->client, ADT7411_REG_CFG1, val); } -static const struct hwmon_channel_info *adt7411_info[] = { +static const struct hwmon_channel_info * const adt7411_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 927f8df05b7c..64f801b859ff 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -1187,7 +1187,7 @@ static const struct hwmon_ops adt7470_hwmon_ops = { .write = adt7470_write, }; -static const struct hwmon_channel_info *adt7470_info[] = { +static const struct hwmon_channel_info * const adt7470_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM, diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 6e4c92b500b8..6a6ebcc896b1 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -1604,9 +1604,9 @@ static int adt7475_set_pwm_polarity(struct i2c_client *client) int ret, i; u8 val; - ret = of_property_read_u32_array(client->dev.of_node, - "adi,pwm-active-state", states, - ARRAY_SIZE(states)); + ret = device_property_read_u32_array(&client->dev, + "adi,pwm-active-state", states, + ARRAY_SIZE(states)); if (ret) return ret; diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index da67734edafd..6701920de17f 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -309,7 +309,7 @@ static int adt7x10_write(struct device *dev, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *adt7x10_info[] = { +static const struct hwmon_channel_info * const adt7x10_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_CRIT | HWMON_T_MAX_HYST | HWMON_T_MIN_HYST | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM | diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index 9babd69d54a3..b8fe3f7248ba 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -270,7 +270,7 @@ static int aht10_hwmon_write(struct device *dev, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *aht10_info[] = { +static const struct hwmon_channel_info * const aht10_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT), diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 12682a610ce7..a4fcd4ebf76c 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -29,12 +29,14 @@ #define USB_PRODUCT_ID_FARBWERK360 0xf010 #define USB_PRODUCT_ID_OCTO 0xf011 #define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012 +#define USB_PRODUCT_ID_AQUASTREAMXT 0xf0b6 #define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b #define USB_PRODUCT_ID_POWERADJUST3 0xf0bd enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, - highflownext, aquaero, poweradjust3, aquastreamult + highflownext, aquaero, poweradjust3, aquastreamult, + aquastreamxt }; static const char *const aqc_device_names[] = { @@ -44,6 +46,7 @@ static const char *const aqc_device_names[] = { [octo] = "octo", [quadro] = "quadro", [highflownext] = "highflownext", + [aquastreamxt] = "aquastreamxt", [aquaero] = "aquaero", [aquastreamult] = "aquastreamultimate", [poweradjust3] = "poweradjust3" @@ -56,6 +59,7 @@ static const char *const aqc_device_names[] = { #define SERIAL_PART_OFFSET 2 #define CTRL_REPORT_ID 0x03 +#define AQUAERO_CTRL_REPORT_ID 0x0b /* The HID report that the official software always sends * after writing values, currently same for all devices @@ -67,9 +71,23 @@ static u8 secondary_ctrl_report[] = { 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6 }; +/* Secondary HID report values for Aquaero */ +#define AQUAERO_SECONDARY_CTRL_REPORT_ID 0x06 +#define AQUAERO_SECONDARY_CTRL_REPORT_SIZE 0x07 + +static u8 aquaero_secondary_ctrl_report[] = { + 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 +}; + /* Report IDs for legacy devices */ +#define AQUASTREAMXT_STATUS_REPORT_ID 0x04 + #define POWERADJUST3_STATUS_REPORT_ID 0x03 +/* Data types for reading and writing control reports */ +#define AQC_8 0 +#define AQC_BE16 1 + /* Info, sensor sizes and offsets for most Aquacomputer devices */ #define AQC_SERIAL_START 0x3 #define AQC_FIRMWARE_VERSION 0xD @@ -90,6 +108,10 @@ static u8 secondary_ctrl_report[] = { #define AQUAERO_NUM_VIRTUAL_SENSORS 8 #define AQUAERO_NUM_CALC_VIRTUAL_SENSORS 4 #define AQUAERO_NUM_FLOW_SENSORS 2 +#define AQUAERO_CTRL_REPORT_SIZE 0xa93 +#define AQUAERO_CTRL_PRESET_ID 0x5c +#define AQUAERO_CTRL_PRESET_SIZE 0x02 +#define AQUAERO_CTRL_PRESET_START 0x55c /* Sensor report offsets for Aquaero fan controllers */ #define AQUAERO_SENSOR_START 0x65 @@ -102,6 +124,13 @@ static u8 secondary_ctrl_report[] = { #define AQUAERO_FAN_SPEED_OFFSET 0x00 static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B }; +/* Control report offsets for the Aquaero fan controllers */ +#define AQUAERO_TEMP_CTRL_OFFSET 0xdb +#define AQUAERO_FAN_CTRL_MIN_PWR_OFFSET 0x04 +#define AQUAERO_FAN_CTRL_MAX_PWR_OFFSET 0x06 +#define AQUAERO_FAN_CTRL_SRC_OFFSET 0x10 +static u16 aquaero_ctrl_fan_offsets[] = { 0x20c, 0x220, 0x234, 0x248 }; + /* Specs of the D5 Next pump */ #define D5NEXT_NUM_FANS 2 #define D5NEXT_NUM_SENSORS 1 @@ -207,6 +236,24 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed #define HIGHFLOWNEXT_5V_VOLTAGE 97 #define HIGHFLOWNEXT_5V_VOLTAGE_USB 99 +/* Specs of the Aquastream XT pump */ +#define AQUASTREAMXT_SERIAL_START 0x3a +#define AQUASTREAMXT_FIRMWARE_VERSION 0x32 +#define AQUASTREAMXT_NUM_FANS 2 +#define AQUASTREAMXT_NUM_SENSORS 3 +#define AQUASTREAMXT_FAN_STOPPED 0x4 +#define AQUASTREAMXT_PUMP_CONVERSION_CONST 45000000 +#define AQUASTREAMXT_FAN_CONVERSION_CONST 5646000 +#define AQUASTREAMXT_SENSOR_REPORT_SIZE 0x42 + +/* Sensor report offsets and info for Aquastream XT */ +#define AQUASTREAMXT_SENSOR_START 0xd +#define AQUASTREAMXT_FAN_VOLTAGE_OFFSET 0x7 +#define AQUASTREAMXT_FAN_STATUS_OFFSET 0x1d +#define AQUASTREAMXT_PUMP_VOLTAGE_OFFSET 0x9 +#define AQUASTREAMXT_PUMP_CURR_OFFSET 0xb +static u16 aquastreamxt_sensor_fan_offsets[] = { 0x13, 0x1b }; + /* Specs of the Poweradjust 3 */ #define POWERADJUST3_NUM_SENSORS 1 #define POWERADJUST3_SENSOR_REPORT_SIZE 0x32 @@ -364,6 +411,13 @@ static const char *const label_highflownext_voltage[] = { "+5V USB voltage" }; +/* Labels for Aquastream XT */ +static const char *const label_aquastreamxt_temp_sensors[] = { + "Fan IC temp", + "External sensor", + "Coolant temp" +}; + /* Labels for Aquastream Ultimate */ static const char *const label_aquastreamult_temp[] = { "Coolant temp", @@ -437,6 +491,10 @@ struct aqc_data { const char *name; int status_report_id; /* Used for legacy devices, report is stored in buffer */ + int ctrl_report_id; + int secondary_ctrl_report_id; + int secondary_ctrl_report_size; + u8 *secondary_ctrl_report; int buffer_size; u8 *buffer; @@ -503,13 +561,29 @@ static int aqc_pwm_to_percent(long val) return DIV_ROUND_CLOSEST(val * 100 * 100, 255); } +/* Converts raw value for Aquastream XT pump speed to RPM */ +static int aqc_aquastreamxt_convert_pump_rpm(u16 val) +{ + if (val > 0) + return DIV_ROUND_CLOSEST(AQUASTREAMXT_PUMP_CONVERSION_CONST, val); + return 0; +} + +/* Converts raw value for Aquastream XT fan speed to RPM */ +static int aqc_aquastreamxt_convert_fan_rpm(u16 val) +{ + if (val > 0) + return DIV_ROUND_CLOSEST(AQUASTREAMXT_FAN_CONVERSION_CONST, val); + return 0; +} + /* Expects the mutex to be locked */ static int aqc_get_ctrl_data(struct aqc_data *priv) { int ret; memset(priv->buffer, 0x00, priv->buffer_size); - ret = hid_hw_raw_request(priv->hdev, CTRL_REPORT_ID, priv->buffer, priv->buffer_size, + ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); if (ret < 0) ret = -ENODATA; @@ -523,28 +597,32 @@ static int aqc_send_ctrl_data(struct aqc_data *priv) int ret; u16 checksum; - /* Init and xorout value for CRC-16/USB is 0xffff */ - checksum = crc16(0xffff, priv->buffer + priv->checksum_start, priv->checksum_length); - checksum ^= 0xffff; + /* Checksum is not needed for Aquaero */ + if (priv->kind != aquaero) { + /* Init and xorout value for CRC-16/USB is 0xffff */ + checksum = crc16(0xffff, priv->buffer + priv->checksum_start, + priv->checksum_length); + checksum ^= 0xffff; - /* Place the new checksum at the end of the report */ - put_unaligned_be16(checksum, priv->buffer + priv->checksum_offset); + /* Place the new checksum at the end of the report */ + put_unaligned_be16(checksum, priv->buffer + priv->checksum_offset); + } /* Send the patched up report back to the device */ - ret = hid_hw_raw_request(priv->hdev, CTRL_REPORT_ID, priv->buffer, priv->buffer_size, + ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); if (ret < 0) return ret; /* The official software sends this report after every change, so do it here as well */ - ret = hid_hw_raw_request(priv->hdev, SECONDARY_CTRL_REPORT_ID, secondary_ctrl_report, - SECONDARY_CTRL_REPORT_SIZE, HID_FEATURE_REPORT, - HID_REQ_SET_REPORT); + ret = hid_hw_raw_request(priv->hdev, priv->secondary_ctrl_report_id, + priv->secondary_ctrl_report, priv->secondary_ctrl_report_size, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); return ret; } /* 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) +static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int type) { int ret; @@ -554,16 +632,25 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val) if (ret < 0) goto unlock_and_return; - *val = (s16)get_unaligned_be16(priv->buffer + offset); + switch (type) { + case AQC_BE16: + *val = (s16)get_unaligned_be16(priv->buffer + offset); + break; + case AQC_8: + *val = priv->buffer[offset]; + break; + default: + ret = -EINVAL; + } unlock_and_return: mutex_unlock(&priv->mutex); return ret; } -static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val) +static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, int *types, int len) { - int ret; + int ret, i; mutex_lock(&priv->mutex); @@ -571,7 +658,21 @@ static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val) if (ret < 0) goto unlock_and_return; - put_unaligned_be16((s16)val, priv->buffer + offset); + for (i = 0; i < len; i++) { + switch (types[i]) { + case AQC_BE16: + put_unaligned_be16((s16)vals[i], priv->buffer + offsets[i]); + break; + case AQC_8: + priv->buffer[offsets[i]] = (u8)vals[i]; + break; + default: + ret = -EINVAL; + } + } + + if (ret < 0) + goto unlock_and_return; ret = aqc_send_ctrl_data(priv); @@ -580,6 +681,11 @@ unlock_and_return: return ret; } +static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val, int type) +{ + return aqc_set_ctrl_vals(priv, &offset, &val, &type, 1); +} + static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) { const struct aqc_data *priv = data; @@ -674,6 +780,8 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 if (channel == 0) return 0444; break; + case aquastreamxt: + break; default: if (channel < priv->num_fans) return 0444; @@ -687,6 +795,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3 if (channel < 2) return 0444; break; + case aquastreamxt: + /* Special case to support pump current */ + if (channel == 0) + return 0444; + break; default: if (channel < priv->num_fans) return 0444; @@ -739,6 +852,43 @@ static int aqc_legacy_read(struct aqc_data *priv) priv->temp_input[i] = sensor_value * 10; } + /* Special-case sensor readings */ + switch (priv->kind) { + case aquastreamxt: + /* Info provided with every report */ + priv->serial_number[0] = get_unaligned_le16(priv->buffer + + priv->serial_number_start_offset); + priv->firmware_version = + get_unaligned_le16(priv->buffer + priv->firmware_version_offset); + + /* Read pump speed in RPM */ + sensor_value = get_unaligned_le16(priv->buffer + priv->fan_sensor_offsets[0]); + priv->speed_input[0] = aqc_aquastreamxt_convert_pump_rpm(sensor_value); + + /* Read fan speed in RPM, if available */ + sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_STATUS_OFFSET); + if (sensor_value == AQUASTREAMXT_FAN_STOPPED) { + priv->speed_input[1] = 0; + } else { + sensor_value = + get_unaligned_le16(priv->buffer + priv->fan_sensor_offsets[1]); + priv->speed_input[1] = aqc_aquastreamxt_convert_fan_rpm(sensor_value); + } + + /* 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; + + sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_VOLTAGE_OFFSET); + priv->voltage_input[0] = DIV_ROUND_CLOSEST(sensor_value * 1000, 61); + + sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_VOLTAGE_OFFSET); + priv->voltage_input[1] = DIV_ROUND_CLOSEST(sensor_value * 1000, 63); + break; + default: + break; + } + priv->updated = jiffies; unlock_and_return: @@ -775,7 +925,7 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_temp_offset: ret = aqc_get_ctrl_val(priv, priv->temp_ctrl_offset + - channel * AQC_SENSOR_SIZE, val); + channel * AQC_SENSOR_SIZE, val, AQC_BE16); if (ret < 0) return ret; @@ -791,7 +941,8 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, *val = priv->speed_input[channel]; break; case hwmon_fan_pulses: - ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val); + ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset, + val, AQC_BE16); if (ret < 0) return ret; break; @@ -803,12 +954,23 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, *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], val); + switch (priv->kind) { + case aquaero: + ret = aqc_get_ctrl_val(priv, + AQUAERO_CTRL_PRESET_START + channel * AQUAERO_CTRL_PRESET_SIZE, + val, AQC_BE16); + if (ret < 0) + return ret; + *val = aqc_percent_to_pwm(*val); + break; + default: + ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel], + val, AQC_BE16); if (ret < 0) return ret; *val = aqc_percent_to_pwm(ret); + break; } break; case hwmon_in: @@ -867,6 +1029,10 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, long val) { int ret, pwm_value; + /* Arrays for setting multiple values at once in the control report */ + int ctrl_values_offsets[4]; + long ctrl_values[4]; + int ctrl_values_types[4]; struct aqc_data *priv = dev_get_drvdata(dev); switch (type) { @@ -877,7 +1043,7 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, val = clamp_val(val, -15000, 15000) / 10; ret = aqc_set_ctrl_val(priv, priv->temp_ctrl_offset + - channel * AQC_SENSOR_SIZE, val); + channel * AQC_SENSOR_SIZE, val, AQC_BE16); if (ret < 0) return ret; break; @@ -889,7 +1055,8 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, switch (attr) { case hwmon_fan_pulses: val = clamp_val(val, 10, 1000); - ret = aqc_set_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val); + ret = aqc_set_ctrl_val(priv, priv->flow_pulses_ctrl_offset, + val, AQC_BE16); if (ret < 0) return ret; break; @@ -900,15 +1067,47 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, case hwmon_pwm: switch (attr) { case hwmon_pwm_input: - if (priv->fan_ctrl_offsets) { - pwm_value = aqc_pwm_to_percent(val); - if (pwm_value < 0) - return pwm_value; + pwm_value = aqc_pwm_to_percent(val); + if (pwm_value < 0) + return pwm_value; + switch (priv->kind) { + case aquaero: + /* Write pwm value to preset corresponding to the channel */ + ctrl_values_offsets[0] = AQUAERO_CTRL_PRESET_START + + channel * AQUAERO_CTRL_PRESET_SIZE; + ctrl_values[0] = pwm_value; + ctrl_values_types[0] = AQC_BE16; + + /* Write preset number in fan control source */ + ctrl_values_offsets[1] = priv->fan_ctrl_offsets[channel] + + AQUAERO_FAN_CTRL_SRC_OFFSET; + ctrl_values[1] = AQUAERO_CTRL_PRESET_ID + channel; + ctrl_values_types[1] = AQC_BE16; + + /* Set minimum power to 0 to allow the fan to turn off */ + ctrl_values_offsets[2] = priv->fan_ctrl_offsets[channel] + + AQUAERO_FAN_CTRL_MIN_PWR_OFFSET; + ctrl_values[2] = 0; + ctrl_values_types[2] = AQC_BE16; + + /* Set maximum power to 255 to allow the fan to reach max speed */ + ctrl_values_offsets[3] = priv->fan_ctrl_offsets[channel] + + AQUAERO_FAN_CTRL_MAX_PWR_OFFSET; + ctrl_values[3] = aqc_pwm_to_percent(255); + ctrl_values_types[3] = AQC_BE16; + + ret = aqc_set_ctrl_vals(priv, ctrl_values_offsets, ctrl_values, + ctrl_values_types, 4); + if (ret < 0) + return ret; + break; + default: ret = aqc_set_ctrl_val(priv, priv->fan_ctrl_offsets[channel], - pwm_value); + pwm_value, AQC_BE16); if (ret < 0) return ret; + break; } break; default: @@ -929,16 +1128,16 @@ static const struct hwmon_ops aqc_hwmon_ops = { .write = aqc_write }; -static const struct hwmon_channel_info *aqc_info[] = { +static const struct hwmon_channel_info * const aqc_info[] = { HWMON_CHANNEL_INFO(temp, 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, - 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, @@ -1231,6 +1430,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->num_fans = AQUAERO_NUM_FANS; priv->fan_sensor_offsets = aquaero_sensor_fan_offsets; + priv->fan_ctrl_offsets = aquaero_ctrl_fan_offsets; priv->num_temp_sensors = AQUAERO_NUM_SENSORS; priv->temp_sensor_start_offset = AQUAERO_SENSOR_START; @@ -1241,6 +1441,9 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS; priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START; + priv->buffer_size = AQUAERO_CTRL_REPORT_SIZE; + priv->temp_ctrl_offset = AQUAERO_TEMP_CTRL_OFFSET; + priv->temp_label = label_temp_sensors; priv->virtual_temp_label = label_virtual_temp_sensors; priv->calc_virt_temp_label = label_aquaero_calc_temp_sensors; @@ -1368,6 +1571,21 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->power_label = label_highflownext_power; priv->voltage_label = label_highflownext_voltage; break; + case USB_PRODUCT_ID_AQUASTREAMXT: + priv->kind = aquastreamxt; + + priv->num_fans = AQUASTREAMXT_NUM_FANS; + priv->fan_sensor_offsets = aquastreamxt_sensor_fan_offsets; + + priv->num_temp_sensors = AQUASTREAMXT_NUM_SENSORS; + priv->temp_sensor_start_offset = AQUASTREAMXT_SENSOR_START; + priv->buffer_size = AQUASTREAMXT_SENSOR_REPORT_SIZE; + + priv->temp_label = label_aquastreamxt_temp_sensors; + priv->speed_label = label_d5next_speeds; + priv->voltage_label = label_d5next_voltages; + priv->current_label = label_d5next_current; + break; case USB_PRODUCT_ID_AQUASTREAMULT: priv->kind = aquastreamult; @@ -1404,14 +1622,30 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id) priv->firmware_version_offset = AQUAERO_FIRMWARE_VERSION; priv->fan_structure = &aqc_aquaero_fan_structure; + + priv->ctrl_report_id = AQUAERO_CTRL_REPORT_ID; + priv->secondary_ctrl_report_id = AQUAERO_SECONDARY_CTRL_REPORT_ID; + priv->secondary_ctrl_report_size = AQUAERO_SECONDARY_CTRL_REPORT_SIZE; + priv->secondary_ctrl_report = aquaero_secondary_ctrl_report; break; case poweradjust3: priv->status_report_id = POWERADJUST3_STATUS_REPORT_ID; break; + case aquastreamxt: + priv->serial_number_start_offset = AQUASTREAMXT_SERIAL_START; + priv->firmware_version_offset = AQUASTREAMXT_FIRMWARE_VERSION; + + priv->status_report_id = AQUASTREAMXT_STATUS_REPORT_ID; + break; default: priv->serial_number_start_offset = AQC_SERIAL_START; priv->firmware_version_offset = AQC_FIRMWARE_VERSION; + priv->ctrl_report_id = CTRL_REPORT_ID; + priv->secondary_ctrl_report_id = SECONDARY_CTRL_REPORT_ID; + priv->secondary_ctrl_report_size = SECONDARY_CTRL_REPORT_SIZE; + priv->secondary_ctrl_report = secondary_ctrl_report; + if (priv->kind == aquastreamult) priv->fan_structure = &aqc_aquastreamult_fan_structure; else @@ -1473,6 +1707,7 @@ static const struct hid_device_id aqc_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) }, + { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) }, { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) }, { } diff --git a/drivers/hwmon/as370-hwmon.c b/drivers/hwmon/as370-hwmon.c index 63b5b2d6e593..fffbf385a57f 100644 --- a/drivers/hwmon/as370-hwmon.c +++ b/drivers/hwmon/as370-hwmon.c @@ -76,7 +76,7 @@ as370_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *as370_hwmon_info[] = { +static const struct hwmon_channel_info * const as370_hwmon_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), NULL }; diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index 2768b7511684..e5be0cf472fc 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -303,6 +303,14 @@ static const struct ec_board_info board_info_pro_art_x570_creator_wifi = { .family = family_amd_500_series, }; +static const struct ec_board_info board_info_pro_art_b550_creator = { + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | + SENSOR_TEMP_T_SENSOR | + SENSOR_FAN_CPU_OPT, + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, + .family = family_amd_500_series, +}; + static const struct ec_board_info board_info_pro_ws_x570_ace = { .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET | @@ -400,6 +408,14 @@ static const struct ec_board_info board_info_strix_x570_i_gaming = { .family = family_amd_500_series, }; +static const struct ec_board_info board_info_strix_z390_f_gaming = { + .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM | + SENSOR_TEMP_T_SENSOR | + SENSOR_FAN_CPU_OPT, + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, + .family = family_intel_300_series, +}; + static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = { .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM, .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, @@ -435,6 +451,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_prime_x570_pro), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X570-CREATOR WIFI", &board_info_pro_art_x570_creator_wifi), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR", + &board_info_pro_art_b550_creator), DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE", &board_info_pro_ws_x570_ace), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII DARK HERO", @@ -463,6 +481,8 @@ static const struct dmi_system_id dmi_table[] = { &board_info_strix_x570_f_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-I GAMING", &board_info_strix_x570_i_gaming), + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING", + &board_info_strix_z390_f_gaming), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4", &board_info_strix_z690_a_gaming_wifi_d4), DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME", diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c index 6724e0dd3088..5fd136baf1cd 100644 --- a/drivers/hwmon/axi-fan-control.c +++ b/drivers/hwmon/axi-fan-control.c @@ -394,7 +394,7 @@ static int axi_fan_control_init(struct axi_fan_control_data *ctl, return ret; } -static const struct hwmon_channel_info *axi_fan_control_info[] = { +static const struct hwmon_channel_info * const axi_fan_control_info[] = { HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_LABEL), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), diff --git a/drivers/hwmon/bt1-pvt.c b/drivers/hwmon/bt1-pvt.c index 21ab172774ec..8d402a627306 100644 --- a/drivers/hwmon/bt1-pvt.c +++ b/drivers/hwmon/bt1-pvt.c @@ -379,7 +379,7 @@ static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type, return 0; } -static const struct hwmon_channel_info *pvt_channel_info[] = { +static const struct hwmon_channel_info * const pvt_channel_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, @@ -523,7 +523,7 @@ static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type, return -EOPNOTSUPP; } -static const struct hwmon_channel_info *pvt_channel_info[] = { +static const struct hwmon_channel_info * const pvt_channel_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 30d77f451937..eba94f68585a 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -282,14 +282,8 @@ static int get_tjmax(struct temp_data *tdata, struct device *dev) dev_warn(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu); } else { val = (eax >> 16) & 0xff; - /* - * If the TjMax is not plausible, an assumption - * will be used - */ - if (val) { - dev_dbg(dev, "TjMax is %d degrees C\n", val); + if (val) return val * 1000; - } } if (force_tjmax) { diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c index fa6aa4fc8b52..463ab4296ede 100644 --- a/drivers/hwmon/corsair-cpro.c +++ b/drivers/hwmon/corsair-cpro.c @@ -385,7 +385,7 @@ static const struct hwmon_ops ccp_hwmon_ops = { .write = ccp_write, }; -static const struct hwmon_channel_info *ccp_info[] = { +static const struct hwmon_channel_info * const ccp_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index 2210aa62e3d0..dc24c566d08b 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -571,7 +571,7 @@ static const struct hwmon_ops corsairpsu_hwmon_ops = { .read_string = corsairpsu_hwmon_ops_read_string, }; -static const struct hwmon_channel_info *corsairpsu_info[] = { +static const struct hwmon_channel_info * const corsairpsu_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 7ac778aedc68..44aaf9b9191d 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -920,7 +920,7 @@ static const struct hwmon_ops dell_smm_ops = { .write = dell_smm_write, }; -static const struct hwmon_channel_info *dell_smm_info[] = { +static const struct hwmon_channel_info * const dell_smm_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL, diff --git a/drivers/hwmon/drivetemp.c b/drivers/hwmon/drivetemp.c index 8e5759b42390..e73b7bfc6af3 100644 --- a/drivers/hwmon/drivetemp.c +++ b/drivers/hwmon/drivetemp.c @@ -526,7 +526,7 @@ static umode_t drivetemp_is_visible(const void *data, return 0; } -static const struct hwmon_channel_info *drivetemp_info[] = { +static const struct hwmon_channel_info * const drivetemp_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index f65467fbd86c..723f57518c9a 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -479,7 +479,7 @@ static const struct hwmon_ops emc2305_ops = { .write = emc2305_write, }; -static const struct hwmon_channel_info *emc2305_info[] = { +static const struct hwmon_channel_info * const emc2305_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index 25afd9167a34..f5a4d91a7e90 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -520,7 +520,7 @@ static const struct hwmon_ops fts_ops = { .write = fts_write, }; -static const struct hwmon_channel_info *fts_info[] = { +static const struct hwmon_channel_info * const fts_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT, diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 64a0599b2da5..e2c3c34f06e8 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -620,7 +620,12 @@ static int g762_of_clock_enable(struct i2c_client *client) data = i2c_get_clientdata(client); data->clk = clk; - devm_add_action(&client->dev, g762_of_clock_disable, data); + ret = devm_add_action(&client->dev, g762_of_clock_disable, data); + if (ret) { + dev_err(&client->dev, "failed to add disable clock action\n"); + goto clk_unprep; + } + return 0; clk_unprep: diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index e75db6f64e8c..d92c536be9af 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -586,7 +586,7 @@ static struct platform_driver gpio_fan_driver = { .driver = { .name = "gpio-fan", .pm = pm_sleep_ptr(&gpio_fan_pm), - .of_match_table = of_match_ptr(of_gpio_fan_match), + .of_match_table = of_gpio_fan_match, }, }; diff --git a/drivers/hwmon/gxp-fan-ctrl.c b/drivers/hwmon/gxp-fan-ctrl.c index 0014b8b0fd41..2e05bc2f627a 100644 --- a/drivers/hwmon/gxp-fan-ctrl.c +++ b/drivers/hwmon/gxp-fan-ctrl.c @@ -168,7 +168,7 @@ static const struct hwmon_ops gxp_fan_ctrl_ops = { .write = gxp_fan_ctrl_write, }; -static const struct hwmon_channel_info *gxp_fan_ctrl_info[] = { +static const struct hwmon_channel_info * const gxp_fan_ctrl_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_FAULT | HWMON_F_ENABLE, HWMON_F_FAULT | HWMON_F_ENABLE, diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index d193ed3cb35e..c7ebef1990c8 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -174,7 +174,7 @@ static int hwmon_thermal_set_trips(struct thermal_zone_device *tz, int low, int struct hwmon_thermal_data *tdata = tz->devdata; struct hwmon_device *hwdev = to_hwmon_device(tdata->dev); const struct hwmon_chip_info *chip = hwdev->chip; - const struct hwmon_channel_info **info = chip->info; + const struct hwmon_channel_info * const *info = chip->info; unsigned int i; int err; @@ -253,7 +253,7 @@ static int hwmon_thermal_register_sensors(struct device *dev) { struct hwmon_device *hwdev = to_hwmon_device(dev); const struct hwmon_chip_info *chip = hwdev->chip; - const struct hwmon_channel_info **info = chip->info; + const struct hwmon_channel_info * const *info = chip->info; void *drvdata = dev_get_drvdata(dev); int i; diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c index 23b9f94fe0a9..7b00b38c7f7b 100644 --- a/drivers/hwmon/i5500_temp.c +++ b/drivers/hwmon/i5500_temp.c @@ -88,7 +88,7 @@ static const struct hwmon_ops i5500_ops = { .read = i5500_read, }; -static const struct hwmon_channel_info *i5500_info[] = { +static const struct hwmon_channel_info * const i5500_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_CRIT | diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c index 8e3724728cce..594254d6a72d 100644 --- a/drivers/hwmon/ibmpowernv.c +++ b/drivers/hwmon/ibmpowernv.c @@ -456,9 +456,9 @@ static int populate_attr_groups(struct platform_device *pdev) */ if (!of_property_read_string(np, "label", &label)) sensor_groups[type].attr_count++; - if (of_find_property(np, "sensor-data-min", NULL)) + if (of_property_present(np, "sensor-data-min")) sensor_groups[type].attr_count++; - if (of_find_property(np, "sensor-data-max", NULL)) + if (of_property_present(np, "sensor-data-max")) sensor_groups[type].attr_count++; } diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 50eb9c5e132e..8af07bc0c50e 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -501,7 +501,7 @@ static umode_t ina238_is_visible(const void *drvdata, HWMON_I_MAX | HWMON_I_MAX_ALARM | \ HWMON_I_MIN | HWMON_I_MIN_ALARM) -static const struct hwmon_channel_info *ina238_info[] = { +static const struct hwmon_channel_info * const ina238_info[] = { HWMON_CHANNEL_INFO(in, /* 0: shunt voltage */ INA238_HWMON_IN_CONFIG, diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 00fc70305a89..fd50d9785ccb 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -656,6 +656,10 @@ static int ina2xx_probe(struct i2c_client *client) return PTR_ERR(data->regmap); } + ret = devm_regulator_get_enable(dev, "vs"); + if (ret) + return dev_err_probe(dev, ret, "failed to enable vs regulator\n"); + ret = ina2xx_init(data); if (ret < 0) { dev_err(dev, "error configuring the device: %d\n", ret); diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index f3a4c5633b1e..2735e3782ffb 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -650,7 +650,7 @@ static umode_t ina3221_is_visible(const void *drvdata, HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \ HWMON_C_MAX | HWMON_C_MAX_ALARM) -static const struct hwmon_channel_info *ina3221_info[] = { +static const struct hwmon_channel_info * const ina3221_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_SAMPLES, HWMON_C_UPDATE_INTERVAL), diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index 2f0323c14bab..6512f4bec79a 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -24,7 +24,7 @@ struct m10bmc_sdata { struct m10bmc_hwmon_board_data { const struct m10bmc_sdata *tables[hwmon_max]; - const struct hwmon_channel_info **hinfo; + const struct hwmon_channel_info * const *hinfo; }; struct m10bmc_hwmon { @@ -67,7 +67,7 @@ static const struct m10bmc_sdata n3000bmc_power_tbl[] = { { 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" }, }; -static const struct hwmon_channel_info *n3000bmc_hinfo[] = { +static const struct hwmon_channel_info * const n3000bmc_hinfo[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, @@ -154,7 +154,7 @@ static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = { .hinfo = n3000bmc_hinfo, }; -static const struct hwmon_channel_info *d5005bmc_hinfo[] = { +static const struct hwmon_channel_info * const d5005bmc_hinfo[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL, @@ -280,7 +280,7 @@ static const struct m10bmc_sdata n5010bmc_curr_tbl[] = { { 0x1a0, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Current" }, }; -static const struct hwmon_channel_info *n5010bmc_hinfo[] = { +static const struct hwmon_channel_info * const n5010bmc_hinfo[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL, @@ -432,7 +432,7 @@ static const struct m10bmc_sdata n6000bmc_power_tbl[] = { { 0x724, 0x0, 0x0, 0x0, 0x0, 1, "Board Power" }, }; -static const struct hwmon_channel_info *n6000bmc_hinfo[] = { +static const struct hwmon_channel_info * const n6000bmc_hinfo[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_LABEL, diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index e9614eb557d4..eb38f54ebeb6 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -162,8 +162,11 @@ static inline void superio_exit(int ioreg, bool noexit) #define IT8623E_DEVID 0x8623 #define IT8628E_DEVID 0x8628 #define IT87952E_DEVID 0x8695 -#define IT87_ACT_REG 0x30 -#define IT87_BASE_REG 0x60 + +/* Logical device 4 (Environmental Monitor) registers */ +#define IT87_ACT_REG 0x30 +#define IT87_BASE_REG 0x60 +#define IT87_SPECIAL_CFG_REG 0xf3 /* special configuration register */ /* Logical device 7 registers (IT8712F and later) */ #define IT87_SIO_GPIO1_REG 0x25 @@ -284,6 +287,8 @@ struct it87_devices { u32 features; u8 peci_mask; u8 old_peci_mask; + u8 smbus_bitmap; /* SMBus enable bits in extra config register */ + u8 ec_special_config; }; #define FEAT_12MV_ADC BIT(0) @@ -469,6 +474,7 @@ static const struct it87_devices it87_devices[] = { | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 | FEAT_AVCC3 | FEAT_VIN3_5V, .peci_mask = 0x07, + .smbus_bitmap = BIT(1) | BIT(2), }, [it8628] = { .name = "it8628", @@ -533,6 +539,8 @@ struct it87_sio_data { u8 skip_fan; u8 skip_pwm; u8 skip_temp; + u8 smbus_bitmap; + u8 ec_special_config; }; /* @@ -547,6 +555,9 @@ struct it87_data { u8 peci_mask; u8 old_peci_mask; + u8 smbus_bitmap; /* !=0 if SMBus needs to be disabled */ + u8 ec_special_config; /* EC special config register restore value */ + unsigned short addr; const char *name; struct mutex update_lock; @@ -701,8 +712,42 @@ static const unsigned int pwm_freq[8] = { 750000, }; +static int smbus_disable(struct it87_data *data) +{ + int err; + + if (data->smbus_bitmap) { + err = superio_enter(data->sioaddr); + if (err) + return err; + superio_select(data->sioaddr, PME); + superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG, + data->ec_special_config & ~data->smbus_bitmap); + superio_exit(data->sioaddr, has_conf_noexit(data)); + } + return 0; +} + +static int smbus_enable(struct it87_data *data) +{ + int err; + + if (data->smbus_bitmap) { + err = superio_enter(data->sioaddr); + if (err) + return err; + + superio_select(data->sioaddr, PME); + superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG, + data->ec_special_config); + superio_exit(data->sioaddr, has_conf_noexit(data)); + } + return 0; +} + /* * Must be called with data->update_lock held, except during initialization. + * Must be called with SMBus accesses disabled. * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, * would slow down the IT87 access and should not be necessary. */ @@ -714,6 +759,7 @@ static int it87_read_value(struct it87_data *data, u8 reg) /* * Must be called with data->update_lock held, except during initialization. + * Must be called with SMBus accesses disabled. * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, * would slow down the IT87 access and should not be necessary. */ @@ -773,15 +819,39 @@ static void it87_update_pwm_ctrl(struct it87_data *data, int nr) } } +static int it87_lock(struct it87_data *data) +{ + int err; + + mutex_lock(&data->update_lock); + err = smbus_disable(data); + if (err) + mutex_unlock(&data->update_lock); + return err; +} + +static void it87_unlock(struct it87_data *data) +{ + smbus_enable(data); + mutex_unlock(&data->update_lock); +} + static struct it87_data *it87_update_device(struct device *dev) { struct it87_data *data = dev_get_drvdata(dev); + struct it87_data *ret = data; + int err; int i; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || - !data->valid) { + !data->valid) { + err = smbus_disable(data); + if (err) { + ret = ERR_PTR(err); + goto unlock; + } if (update_vbat) { /* * Cleared after each update, so reenable. Value @@ -884,11 +954,11 @@ static struct it87_data *it87_update_device(struct device *dev) } data->last_updated = jiffies; data->valid = true; + smbus_enable(data); } - +unlock: mutex_unlock(&data->update_lock); - - return data; + return ret; } static ssize_t show_in(struct device *dev, struct device_attribute *attr, @@ -899,6 +969,9 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, int index = sattr->index; int nr = sattr->nr; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index])); } @@ -910,17 +983,21 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, int index = sattr->index; int nr = sattr->nr; unsigned long val; + int err; if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + data->in[nr][index] = in_to_reg(data, nr, val); it87_write_value(data, index == 1 ? IT87_REG_VIN_MIN(nr) : IT87_REG_VIN_MAX(nr), data->in[nr][index]); - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -987,6 +1064,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, int index = sattr->index; struct it87_data *data = it87_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); } @@ -999,11 +1079,14 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); long val; u8 reg, regval; + int err; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; switch (index) { default: @@ -1026,7 +1109,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, data->temp[nr][index] = TEMP_TO_REG(val); it87_write_value(data, reg, data->temp[nr][index]); - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1061,8 +1144,13 @@ static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct it87_data *data = it87_update_device(dev); - u8 reg = data->sensor; /* In case value is updated while used */ - u8 extra = data->extra; + u8 reg, extra; + + if (IS_ERR(data)) + return PTR_ERR(data); + + reg = data->sensor; /* In case value is updated while used */ + extra = data->extra; if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) || (has_temp_old_peci(data, nr) && (extra & 0x80))) @@ -1083,10 +1171,15 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); long val; u8 reg, extra; + int err; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; + err = it87_lock(data); + if (err) + return err; + reg = it87_read_value(data, IT87_REG_TEMP_ENABLE); reg &= ~(1 << nr); reg &= ~(8 << nr); @@ -1109,17 +1202,19 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr, reg |= (nr + 1) << 6; else if (has_temp_old_peci(data, nr) && val == 6) extra |= 0x80; - else if (val != 0) - return -EINVAL; + else if (val != 0) { + count = -EINVAL; + goto unlock; + } - mutex_lock(&data->update_lock); data->sensor = reg; data->extra = extra; it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor); if (has_temp_old_peci(data, nr)) it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra); data->valid = false; /* Force cache refresh */ - mutex_unlock(&data->update_lock); +unlock: + it87_unlock(data); return count; } @@ -1154,6 +1249,9 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, int speed; struct it87_data *data = it87_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + speed = has_16bit_fans(data) ? FAN16_FROM_REG(data->fan[nr][index]) : FAN_FROM_REG(data->fan[nr][index], @@ -1168,6 +1266,9 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, struct it87_data *data = it87_update_device(dev); int nr = sensor_attr->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr])); } @@ -1178,6 +1279,9 @@ static ssize_t show_pwm_enable(struct device *dev, struct it87_data *data = it87_update_device(dev); int nr = sensor_attr->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", pwm_mode(data, nr)); } @@ -1188,6 +1292,9 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, struct it87_data *data = it87_update_device(dev); int nr = sensor_attr->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", pwm_from_reg(data, data->pwm_duty[nr])); } @@ -1201,6 +1308,9 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, unsigned int freq; int index; + if (IS_ERR(data)) + return PTR_ERR(data); + if (has_pwm_freq2(data) && nr == 1) index = (data->extra >> 4) & 0x07; else @@ -1220,12 +1330,15 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); long val; + int err; u8 reg; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; if (has_16bit_fans(data)) { data->fan[nr][index] = FAN16_TO_REG(val); @@ -1252,7 +1365,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, data->fan[nr][index]); } - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1263,13 +1376,16 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); int nr = sensor_attr->index; unsigned long val; - int min; + int min, err; u8 old; if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + old = it87_read_value(data, IT87_REG_FAN_DIV); /* Save fan min limit */ @@ -1297,7 +1413,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]); - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1338,6 +1454,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); int nr = sensor_attr->index; long val; + int err; if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2) return -EINVAL; @@ -1348,7 +1465,9 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, return -EINVAL; } - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; if (val == 0) { if (nr < 3 && data->type != it8603) { @@ -1399,7 +1518,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, } } - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1410,11 +1529,15 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); int nr = sensor_attr->index; long val; + int err; if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + it87_update_pwm_ctrl(data, nr); if (has_newer_autopwm(data)) { /* @@ -1422,8 +1545,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, * is read-only so we can't write the value. */ if (data->pwm_ctrl[nr] & 0x80) { - mutex_unlock(&data->update_lock); - return -EBUSY; + count = -EBUSY; + goto unlock; } data->pwm_duty[nr] = pwm_to_reg(data, val); it87_write_value(data, IT87_REG_PWM_DUTY[nr], @@ -1440,7 +1563,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_ctrl[nr]); } } - mutex_unlock(&data->update_lock); +unlock: + it87_unlock(data); return count; } @@ -1451,6 +1575,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr, struct it87_data *data = dev_get_drvdata(dev); int nr = sensor_attr->index; unsigned long val; + int err; int i; if (kstrtoul(buf, 10, &val) < 0) @@ -1465,7 +1590,10 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr, break; } - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + if (nr == 0) { data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f; data->fan_ctl |= i << 4; @@ -1475,7 +1603,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr, data->extra |= i << 4; it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra); } - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1488,6 +1616,9 @@ static ssize_t show_pwm_temp_map(struct device *dev, int nr = sensor_attr->index; int map; + if (IS_ERR(data)) + return PTR_ERR(data); + map = data->pwm_temp_map[nr]; if (map >= 3) map = 0; /* Should never happen */ @@ -1505,6 +1636,7 @@ static ssize_t set_pwm_temp_map(struct device *dev, struct it87_data *data = dev_get_drvdata(dev); int nr = sensor_attr->index; long val; + int err; u8 reg; if (kstrtol(buf, 10, &val) < 0) @@ -1527,7 +1659,10 @@ static ssize_t set_pwm_temp_map(struct device *dev, return -EINVAL; } - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + it87_update_pwm_ctrl(data, nr); data->pwm_temp_map[nr] = reg; /* @@ -1539,7 +1674,7 @@ static ssize_t set_pwm_temp_map(struct device *dev, data->pwm_temp_map[nr]; it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]); } - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1552,6 +1687,9 @@ static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr, int nr = sensor_attr->nr; int point = sensor_attr->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", pwm_from_reg(data, data->auto_pwm[nr][point])); } @@ -1566,18 +1704,22 @@ static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr, int point = sensor_attr->index; int regaddr; long val; + int err; if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + data->auto_pwm[nr][point] = pwm_to_reg(data, val); if (has_newer_autopwm(data)) regaddr = IT87_REG_AUTO_TEMP(nr, 3); else regaddr = IT87_REG_AUTO_PWM(nr, point); it87_write_value(data, regaddr, data->auto_pwm[nr][point]); - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1588,6 +1730,9 @@ static ssize_t show_auto_pwm_slope(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", data->auto_pwm[nr][1] & 0x7f); } @@ -1599,15 +1744,19 @@ static ssize_t set_auto_pwm_slope(struct device *dev, struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; unsigned long val; + int err; if (kstrtoul(buf, 10, &val) < 0 || val > 127) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val; it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4), data->auto_pwm[nr][1]); - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1621,6 +1770,9 @@ static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr, int point = sensor_attr->index; int reg; + if (IS_ERR(data)) + return PTR_ERR(data); + if (has_old_autopwm(data) || point) reg = data->auto_temp[nr][point]; else @@ -1639,11 +1791,15 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr, int point = sensor_attr->index; long val; int reg; + int err; if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + if (has_newer_autopwm(data) && !point) { reg = data->auto_temp[nr][1] - TEMP_TO_REG(val); reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0); @@ -1656,7 +1812,7 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr, point--; it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg); } - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1841,6 +1997,9 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, { struct it87_data *data = it87_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR_RO(alarms); @@ -1851,6 +2010,9 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, struct it87_data *data = it87_update_device(dev); int bitnr = to_sensor_dev_attr(attr)->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } @@ -1859,13 +2021,16 @@ static ssize_t clear_intrusion(struct device *dev, size_t count) { struct it87_data *data = dev_get_drvdata(dev); - int config; + int err, config; long val; if (kstrtol(buf, 10, &val) < 0 || val != 0) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + config = it87_read_value(data, IT87_REG_CONFIG); if (config < 0) { count = config; @@ -1875,8 +2040,7 @@ static ssize_t clear_intrusion(struct device *dev, /* Invalidate cache to force re-read */ data->valid = false; } - mutex_unlock(&data->update_lock); - + it87_unlock(data); return count; } @@ -1906,6 +2070,9 @@ static ssize_t show_beep(struct device *dev, struct device_attribute *attr, struct it87_data *data = it87_update_device(dev); int bitnr = to_sensor_dev_attr(attr)->index; + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1); } @@ -1915,18 +2082,22 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr, int bitnr = to_sensor_dev_attr(attr)->index; struct it87_data *data = dev_get_drvdata(dev); long val; + int err; if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1)) return -EINVAL; - mutex_lock(&data->update_lock); + err = it87_lock(data); + if (err) + return err; + data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE); if (val) data->beeps |= BIT(bitnr); else data->beeps &= ~BIT(bitnr); it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps); - mutex_unlock(&data->update_lock); + it87_unlock(data); return count; } @@ -1979,6 +2150,9 @@ static ssize_t cpu0_vid_show(struct device *dev, { struct it87_data *data = it87_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR_RO(cpu0_vid); @@ -2004,7 +2178,7 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, if (has_vin3_5v(data) && nr == 0) label = labels[0]; - else if (has_12mv_adc(data) || has_10_9mv_adc(data)) + else if (has_scaling(data)) label = labels_it8721[nr]; else label = labels[nr]; @@ -2859,6 +3033,15 @@ static int __init it87_find(int sioaddr, unsigned short *address, if (dmi_data) sio_data->skip_pwm |= dmi_data->skip_pwm; + if (config->smbus_bitmap) { + u8 reg; + + superio_select(sioaddr, PME); + reg = superio_inb(sioaddr, IT87_SPECIAL_CFG_REG); + sio_data->ec_special_config = reg; + sio_data->smbus_bitmap = reg & config->smbus_bitmap; + } + exit: superio_exit(sioaddr, config ? has_conf_noexit(config) : false); return err; @@ -3077,6 +3260,7 @@ static int it87_probe(struct platform_device *pdev) struct it87_sio_data *sio_data = dev_get_platdata(dev); int enable_pwm_interface; struct device *hwmon_dev; + int err; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT, @@ -3094,6 +3278,8 @@ static int it87_probe(struct platform_device *pdev) data->addr = res->start; data->sioaddr = sio_data->sioaddr; data->type = sio_data->type; + data->smbus_bitmap = sio_data->smbus_bitmap; + data->ec_special_config = sio_data->ec_special_config; data->features = it87_devices[sio_data->type].features; data->peci_mask = it87_devices[sio_data->type].peci_mask; data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask; @@ -3120,15 +3306,21 @@ static int it87_probe(struct platform_device *pdev) break; } - /* Now, we do the remaining detection. */ - if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) || - it87_read_value(data, IT87_REG_CHIPID) != 0x90) - return -ENODEV; - platform_set_drvdata(pdev, data); mutex_init(&data->update_lock); + err = smbus_disable(data); + if (err) + return err; + + /* Now, we do the remaining detection. */ + if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) || + it87_read_value(data, IT87_REG_CHIPID) != 0x90) { + smbus_enable(data); + return -ENODEV; + } + /* Check PWM configuration */ enable_pwm_interface = it87_check_pwm(dev); if (!enable_pwm_interface) @@ -3189,6 +3381,8 @@ static int it87_probe(struct platform_device *pdev) /* Initialize the IT87 chip */ it87_init_device(pdev); + smbus_enable(data); + if (!sio_data->skip_vid) { data->has_vid = true; data->vrm = vid_which_vrm(); @@ -3256,7 +3450,7 @@ static int it87_resume(struct device *dev) it87_resume_sio(pdev); - mutex_lock(&data->update_lock); + it87_lock(data); it87_check_pwm(dev); it87_check_limit_regs(data); @@ -3269,7 +3463,7 @@ static int it87_resume(struct device *dev) /* force update */ data->valid = false; - mutex_unlock(&data->update_lock); + it87_unlock(data); it87_update_device(dev); diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 8523bf974310..4c60dc520b12 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -450,7 +450,7 @@ static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info) return -ENODEV; } -static const struct hwmon_channel_info *jc42_info[] = { +static const struct hwmon_channel_info * const jc42_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 5a9d47a229e4..ba2f6a4f8c16 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -75,6 +75,7 @@ static DEFINE_MUTEX(nb_smu_ind_mutex); #define ZEN_CUR_TEMP_SHIFT 21 #define ZEN_CUR_TEMP_RANGE_SEL_MASK BIT(19) +#define ZEN_CUR_TEMP_TJ_SEL_MASK GENMASK(17, 16) struct k10temp_data { struct pci_dev *pdev; @@ -155,7 +156,8 @@ static long get_raw_temp(struct k10temp_data *data) data->read_tempreg(data->pdev, ®val); temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125; - if (regval & data->temp_adjust_mask) + if ((regval & data->temp_adjust_mask) || + (regval & ZEN_CUR_TEMP_TJ_SEL_MASK) == ZEN_CUR_TEMP_TJ_SEL_MASK) temp -= 49000; return temp; } @@ -332,7 +334,7 @@ static bool has_erratum_319(struct pci_dev *pdev) (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2); } -static const struct hwmon_channel_info *k10temp_info[] = { +static const struct hwmon_channel_info * const k10temp_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_CRIT_HYST | diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index f73bd4eceb28..2b80ac410cd1 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -118,7 +118,7 @@ static const struct hwmon_ops k8temp_ops = { .read = k8temp_read, }; -static const struct hwmon_channel_info *k8temp_info[] = { +static const struct hwmon_channel_info * const k8temp_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT), NULL diff --git a/drivers/hwmon/lan966x-hwmon.c b/drivers/hwmon/lan966x-hwmon.c index f41df053ac31..f8658359a098 100644 --- a/drivers/hwmon/lan966x-hwmon.c +++ b/drivers/hwmon/lan966x-hwmon.c @@ -260,7 +260,7 @@ static umode_t lan966x_hwmon_is_visible(const void *data, return mode; } -static const struct hwmon_channel_info *lan966x_hwmon_info[] = { +static const struct hwmon_channel_info * const lan966x_hwmon_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index bcc3adcb3af1..dbb99ea4a0ec 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -512,7 +512,7 @@ static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, return 0; } -static const struct hwmon_channel_info *lm75_info[] = { +static const struct hwmon_channel_info * const lm75_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 616449f2cc50..bcaf31ec176e 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -337,7 +337,7 @@ static umode_t lm83_is_visible(const void *_data, enum hwmon_sensor_types type, return 0; } -static const struct hwmon_channel_info *lm83_info[] = { +static const struct hwmon_channel_info * const lm83_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_ALARMS), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index f1ed777a8735..647a90570bc6 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -409,7 +409,7 @@ static void lm95241_init_client(struct i2c_client *client, data->model); } -static const struct hwmon_channel_info *lm95241_info[] = { +static const struct hwmon_channel_info * const lm95241_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index c433f0af2d31..4236d1e0544d 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -523,7 +523,7 @@ static const struct regmap_config lm95245_regmap_config = { .use_single_write = true, }; -static const struct hwmon_channel_info *lm95245_info[] = { +static const struct hwmon_channel_info * const lm95245_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/lochnagar-hwmon.c b/drivers/hwmon/lochnagar-hwmon.c index 8b19adf2eeb0..6350904a8a8b 100644 --- a/drivers/hwmon/lochnagar-hwmon.c +++ b/drivers/hwmon/lochnagar-hwmon.c @@ -11,7 +11,6 @@ #include <linux/delay.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <linux/i2c.h> #include <linux/math64.h> #include <linux/mfd/lochnagar.h> #include <linux/mfd/lochnagar2_regs.h> @@ -321,7 +320,7 @@ static const struct hwmon_ops lochnagar_ops = { .write = lochnagar_write, }; -static const struct hwmon_channel_info *lochnagar_info[] = { +static const struct hwmon_channel_info * const lochnagar_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, diff --git a/drivers/hwmon/ltc2947-core.c b/drivers/hwmon/ltc2947-core.c index 2dbbbac9de09..d2ff6e700770 100644 --- a/drivers/hwmon/ltc2947-core.c +++ b/drivers/hwmon/ltc2947-core.c @@ -901,7 +901,7 @@ static umode_t ltc2947_is_visible(const void *data, } } -static const struct hwmon_channel_info *ltc2947_info[] = { +static const struct hwmon_channel_info * const ltc2947_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST | HWMON_I_MAX | HWMON_I_MIN | HWMON_I_RESET_HISTORY | diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c index 69341de397cb..429a7f5837f0 100644 --- a/drivers/hwmon/ltc2992.c +++ b/drivers/hwmon/ltc2992.c @@ -812,7 +812,7 @@ static const struct hwmon_ops ltc2992_hwmon_ops = { .write = ltc2992_write, }; -static const struct hwmon_channel_info *ltc2992_info[] = { +static const struct hwmon_channel_info * const ltc2992_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_IN_RESET_HISTORY), HWMON_CHANNEL_INFO(in, diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index 5088d28b3a7c..fb9bc8dbe99b 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -387,7 +387,7 @@ static umode_t ltc4245_is_visible(const void *_data, } } -static const struct hwmon_channel_info *ltc4245_info[] = { +static const struct hwmon_channel_info * const ltc4245_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT, HWMON_I_INPUT | HWMON_I_MIN_ALARM, @@ -434,7 +434,7 @@ static bool ltc4245_use_extra_gpios(struct i2c_client *client) return pdata->use_extra_gpios; /* fallback on OF */ - if (of_find_property(np, "ltc4245,use-extra-gpios", NULL)) + if (of_property_read_bool(np, "ltc4245,use-extra-gpios")) return true; return false; diff --git a/drivers/hwmon/ltq-cputemp.c b/drivers/hwmon/ltq-cputemp.c index 019e770d4c0c..08e09a82acab 100644 --- a/drivers/hwmon/ltq-cputemp.c +++ b/drivers/hwmon/ltq-cputemp.c @@ -65,7 +65,7 @@ static umode_t ltq_is_visible(const void *_data, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *ltq_info[] = { +static const struct hwmon_channel_info * const ltq_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/max127.c b/drivers/hwmon/max127.c index 0e21e7e6bbd2..49de1d2be294 100644 --- a/drivers/hwmon/max127.c +++ b/drivers/hwmon/max127.c @@ -285,7 +285,7 @@ static const struct hwmon_ops max127_hwmon_ops = { .write = max127_write, }; -static const struct hwmon_channel_info *max127_info[] = { +static const struct hwmon_channel_info * const max127_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX, HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX, diff --git a/drivers/hwmon/max31730.c b/drivers/hwmon/max31730.c index 746a767c9fc6..924333d89ce4 100644 --- a/drivers/hwmon/max31730.c +++ b/drivers/hwmon/max31730.c @@ -248,7 +248,7 @@ static umode_t max31730_is_visible(const void *data, return 0; } -static const struct hwmon_channel_info *max31730_info[] = { +static const struct hwmon_channel_info * const max31730_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/max31760.c b/drivers/hwmon/max31760.c index 06d5f39dc33d..4489110f109c 100644 --- a/drivers/hwmon/max31760.c +++ b/drivers/hwmon/max31760.c @@ -318,7 +318,7 @@ static int max31760_write(struct device *dev, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *max31760_info[] = { +static const struct hwmon_channel_info * const max31760_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(fan, diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 20bf5ffadefe..6caba6e8ee8f 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -445,7 +445,7 @@ static umode_t max31790_is_visible(const void *data, } } -static const struct hwmon_channel_info *max31790_info[] = { +static const struct hwmon_channel_info * const max31790_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE, diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c index 202b6438179d..0f277d945ea2 100644 --- a/drivers/hwmon/max6620.c +++ b/drivers/hwmon/max6620.c @@ -401,7 +401,7 @@ error: return ret; } -static const struct hwmon_channel_info *max6620_info[] = { +static const struct hwmon_channel_info * const max6620_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM, HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM, diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c index 7821132e17fa..0656eb1e7959 100644 --- a/drivers/hwmon/max6621.c +++ b/drivers/hwmon/max6621.c @@ -449,7 +449,7 @@ static const struct regmap_config max6621_regmap_config = { .num_reg_defaults = ARRAY_SIZE(max6621_regmap_default), }; -static const struct hwmon_channel_info *max6621_info[] = { +static const struct hwmon_channel_info * const max6621_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index f8d4534ce172..19e2c762ed2d 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -737,7 +737,7 @@ static umode_t max6650_is_visible(const void *_data, return 0; } -static const struct hwmon_channel_info *max6650_info[] = { +static const struct hwmon_channel_info * const max6650_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV | HWMON_F_MIN_ALARM | HWMON_F_MAX_ALARM | HWMON_F_FAULT, diff --git a/drivers/hwmon/mc34vr500.c b/drivers/hwmon/mc34vr500.c index 6268e973049c..6a7a950a9332 100644 --- a/drivers/hwmon/mc34vr500.c +++ b/drivers/hwmon/mc34vr500.c @@ -138,7 +138,7 @@ static int mc34vr500_read(struct device *dev, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *mc34vr500_info[] = { +static const struct hwmon_channel_info * const mc34vr500_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_MIN_ALARM), HWMON_CHANNEL_INFO(temp, HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM), diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index e093b1998296..a5f7a294f33d 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -102,7 +102,7 @@ static umode_t mcp3021_is_visible(const void *_data, return 0444; } -static const struct hwmon_channel_info *mcp3021_info[] = { +static const struct hwmon_channel_info * const mcp3021_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), NULL }; diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c index 96017cc8da7e..c2a96468c9b4 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -285,7 +285,7 @@ static char *mlxreg_fan_name[] = { "mlxreg_fan3", }; -static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = { +static const struct hwmon_channel_info * const mlxreg_fan_hwmon_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT, HWMON_F_INPUT | HWMON_F_FAULT, diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 76c6b564d7fc..5782acfb4ee1 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -149,7 +149,7 @@ static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 va return -EIO; if (retval) - *retval = (u32)result & 0xFFFFFFFF; + *retval = result; return 0; #else @@ -1052,33 +1052,117 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) static struct platform_device *pdev[2]; static const char * const asus_wmi_boards[] = { - "PRO H410T", - "ProArt B550-CREATOR", - "ProArt X570-CREATOR WIFI", - "ProArt Z490-CREATOR 10G", - "Pro B550M-C", - "Pro WS X570-ACE", + "B360M-BASALT", + "B360M-D3H", + "EX-B360M-V", + "EX-B360M-V3", + "EX-B360M-V5", + "EX-B460M-V5", + "EX-H410M-V3", + "PRIME A520M-A", + "PRIME A520M-A II", + "PRIME A520M-E", + "PRIME A520M-K", "PRIME B360-PLUS", + "PRIME B360M-A", + "PRIME B360M-C", + "PRIME B360M-D", + "PRIME B360M-K", "PRIME B460-PLUS", + "PRIME B460I-PLUS", + "PRIME B460M-A", + "PRIME B460M-A R2.0", + "PRIME B460M-K", "PRIME B550-PLUS", + "PRIME B550-PLUS AC-HES", "PRIME B550M-A", "PRIME B550M-A (WI-FI)", + "PRIME B550M-A AC", + "PRIME B550M-A WIFI II", + "PRIME B550M-K", + "PRIME H310-PLUS", + "PRIME H310I-PLUS", + "PRIME H310M-A", + "PRIME H310M-C", + "PRIME H310M-D", + "PRIME H310M-DASH", + "PRIME H310M-E", + "PRIME H310M-E/BR", + "PRIME H310M-F", + "PRIME H310M-K", + "PRIME H310T", + "PRIME H370-A", + "PRIME H370-PLUS", + "PRIME H370M-PLUS", + "PRIME H410I-PLUS", + "PRIME H410M-A", + "PRIME H410M-D", + "PRIME H410M-E", + "PRIME H410M-F", + "PRIME H410M-K", + "PRIME H410M-K R2.0", "PRIME H410M-R", + "PRIME H470-PLUS", + "PRIME H470M-PLUS", + "PRIME H510M-K R2.0", + "PRIME Q370M-C", "PRIME X570-P", "PRIME X570-PRO", + "PRIME Z390-A", + "PRIME Z390-A/H10", + "PRIME Z390-P", + "PRIME Z390M-PLUS", + "PRIME Z490-A", + "PRIME Z490-P", + "PRIME Z490-V", + "PRIME Z490M-PLUS", + "PRO B460M-C", + "PRO H410M-C", + "PRO H410T", + "PRO Q470M-C", + "Pro A520M-C", + "Pro A520M-C II", + "Pro B550M-C", + "Pro WS X570-ACE", + "ProArt B550-CREATOR", + "ProArt X570-CREATOR WIFI", + "ProArt Z490-CREATOR 10G", "ROG CROSSHAIR VIII DARK HERO", "ROG CROSSHAIR VIII EXTREME", "ROG CROSSHAIR VIII FORMULA", "ROG CROSSHAIR VIII HERO", "ROG CROSSHAIR VIII HERO (WI-FI)", "ROG CROSSHAIR VIII IMPACT", + "ROG MAXIMUS XI APEX", + "ROG MAXIMUS XI CODE", + "ROG MAXIMUS XI EXTREME", + "ROG MAXIMUS XI FORMULA", + "ROG MAXIMUS XI GENE", + "ROG MAXIMUS XI HERO", + "ROG MAXIMUS XI HERO (WI-FI)", + "ROG MAXIMUS XII APEX", + "ROG MAXIMUS XII EXTREME", + "ROG MAXIMUS XII FORMULA", + "ROG MAXIMUS XII HERO (WI-FI)", + "ROG STRIX B360-F GAMING", + "ROG STRIX B360-G GAMING", + "ROG STRIX B360-H GAMING", + "ROG STRIX B360-H GAMING/OPTANE", + "ROG STRIX B360-I GAMING", + "ROG STRIX B460-F GAMING", + "ROG STRIX B460-G GAMING", + "ROG STRIX B460-H GAMING", + "ROG STRIX B460-I GAMING", "ROG STRIX B550-A GAMING", "ROG STRIX B550-E GAMING", "ROG STRIX B550-F GAMING", "ROG STRIX B550-F GAMING (WI-FI)", "ROG STRIX B550-F GAMING WIFI II", "ROG STRIX B550-I GAMING", - "ROG STRIX B550-XE GAMING (WI-FI)", + "ROG STRIX B550-XE GAMING WIFI", + "ROG STRIX H370-F GAMING", + "ROG STRIX H370-I GAMING", + "ROG STRIX H470-I GAMING", "ROG STRIX X570-E GAMING", "ROG STRIX X570-E GAMING WIFI II", "ROG STRIX X570-F GAMING", @@ -1094,65 +1178,248 @@ static const char * const asus_wmi_boards[] = { "ROG STRIX Z490-G GAMING (WI-FI)", "ROG STRIX Z490-H GAMING", "ROG STRIX Z490-I GAMING", + "TUF B360-PLUS GAMING", + "TUF B360-PRO GAMING", + "TUF B360-PRO GAMING (WI-FI)", + "TUF B360M-E GAMING", + "TUF B360M-PLUS GAMING", + "TUF B360M-PLUS GAMING S", + "TUF B360M-PLUS GAMING/BR", + "TUF GAMING A520M-PLUS", + "TUF GAMING A520M-PLUS II", + "TUF GAMING A520M-PLUS WIFI", + "TUF GAMING B460-PLUS", + "TUF GAMING B460-PRO (WI-FI)", + "TUF GAMING B460M-PLUS", + "TUF GAMING B460M-PLUS (WI-FI)", + "TUF GAMING B460M-PRO", + "TUF GAMING B550-PLUS", + "TUF GAMING B550-PLUS (WI-FI)", + "TUF GAMING B550-PLUS WIFI II", + "TUF GAMING B550-PRO", + "TUF GAMING B550M ZAKU (WI-FI)", "TUF GAMING B550M-E", - "TUF GAMING B550M-E (WI-FI)", + "TUF GAMING B550M-E WIFI", "TUF GAMING B550M-PLUS", "TUF GAMING B550M-PLUS (WI-FI)", "TUF GAMING B550M-PLUS WIFI II", - "TUF GAMING B550-PLUS", - "TUF GAMING B550-PLUS WIFI II", - "TUF GAMING B550-PRO", + "TUF GAMING H470-PRO", + "TUF GAMING H470-PRO (WI-FI)", "TUF GAMING X570-PLUS", "TUF GAMING X570-PLUS (WI-FI)", + "TUF GAMING X570-PLUS_BR", "TUF GAMING X570-PRO (WI-FI)", + "TUF GAMING X570-PRO WIFI II", "TUF GAMING Z490-PLUS", "TUF GAMING Z490-PLUS (WI-FI)", + "TUF H310-PLUS GAMING", + "TUF H310M-PLUS GAMING", + "TUF H310M-PLUS GAMING/BR", + "TUF H370-PRO GAMING", + "TUF H370-PRO GAMING (WI-FI)", + "TUF Z390-PLUS GAMING", + "TUF Z390-PLUS GAMING (WI-FI)", + "TUF Z390-PRO GAMING", + "TUF Z390M-PRO GAMING", + "TUF Z390M-PRO GAMING (WI-FI)", + "WS Z390 PRO", + "Z490-GUNDAM (WI-FI)", }; static const char * const asus_msi_boards[] = { + "B560M-P", + "EX-B560M-V5", + "EX-B660M-V5 D4", "EX-B660M-V5 PRO D4", + "EX-B760M-V5 D4", + "EX-H510M-V3", + "EX-H610M-V3 D4", + "PRIME A620M-A", + "PRIME B560-PLUS", + "PRIME B560-PLUS AC-HES", + "PRIME B560M-A", + "PRIME B560M-A AC", + "PRIME B560M-K", "PRIME B650-PLUS", "PRIME B650M-A", "PRIME B650M-A AX", + "PRIME B650M-A AX II", "PRIME B650M-A II", "PRIME B650M-A WIFI", "PRIME B650M-A WIFI II", + "PRIME B660-PLUS D4", + "PRIME B660M-A AC D4", "PRIME B660M-A D4", "PRIME B660M-A WIFI D4", + "PRIME B760-PLUS", + "PRIME B760-PLUS D4", + "PRIME B760M-A", + "PRIME B760M-A AX D4", + "PRIME B760M-A D4", + "PRIME B760M-A WIFI", + "PRIME B760M-A WIFI D4", + "PRIME B760M-AJ D4", + "PRIME B760M-K D4", + "PRIME H510M-A", + "PRIME H510M-A WIFI", + "PRIME H510M-D", + "PRIME H510M-E", + "PRIME H510M-F", + "PRIME H510M-K", + "PRIME H510M-R", + "PRIME H510T2/CSM", + "PRIME H570-PLUS", + "PRIME H570M-PLUS", + "PRIME H610I-PLUS D4", + "PRIME H610M-A D4", + "PRIME H610M-A WIFI D4", + "PRIME H610M-D D4", + "PRIME H610M-E D4", + "PRIME H610M-F D4", + "PRIME H610M-K D4", + "PRIME H610M-R D4", + "PRIME H670-PLUS D4", + "PRIME H770-PLUS D4", "PRIME X670-P", "PRIME X670-P WIFI", "PRIME X670E-PRO WIFI", - "Pro B660M-C-D4", + "PRIME Z590-A", + "PRIME Z590-P", + "PRIME Z590-P WIFI", + "PRIME Z590-V", + "PRIME Z590M-PLUS", + "PRIME Z690-A", + "PRIME Z690-P", + "PRIME Z690-P D4", + "PRIME Z690-P WIFI", + "PRIME Z690-P WIFI D4", + "PRIME Z690M-PLUS D4", + "PRIME Z790-A WIFI", + "PRIME Z790-P", + "PRIME Z790-P D4", + "PRIME Z790-P WIFI", + "PRIME Z790-P WIFI D4", + "PRIME Z790M-PLUS", + "PRIME Z790M-PLUS D4", + "Pro B560M-C", + "Pro B560M-CT", + "Pro B660M-C", + "Pro B660M-C D4", + "Pro B760M-C", + "Pro B760M-CT", + "Pro H510M-C", + "Pro H510M-CT", + "Pro H610M-C", + "Pro H610M-C D4", + "Pro H610M-CT D4", + "Pro H610T D4", + "Pro Q670M-C", + "Pro WS W680-ACE", + "Pro WS W680-ACE IPMI", + "Pro WS W790-ACE", + "Pro WS W790E-SAGE SE", + "ProArt B650-CREATOR", "ProArt B660-CREATOR D4", + "ProArt B760-CREATOR D4", "ProArt X670E-CREATOR WIFI", + "ProArt Z690-CREATOR WIFI", + "ProArt Z790-CREATOR WIFI", "ROG CROSSHAIR X670E EXTREME", "ROG CROSSHAIR X670E GENE", "ROG CROSSHAIR X670E HERO", + "ROG MAXIMUS XIII APEX", + "ROG MAXIMUS XIII EXTREME", "ROG MAXIMUS XIII EXTREME GLACIAL", + "ROG MAXIMUS XIII HERO", + "ROG MAXIMUS Z690 APEX", "ROG MAXIMUS Z690 EXTREME", "ROG MAXIMUS Z690 EXTREME GLACIAL", + "ROG MAXIMUS Z690 FORMULA", + "ROG MAXIMUS Z690 HERO", + "ROG MAXIMUS Z690 HERO EVA", + "ROG MAXIMUS Z790 APEX", + "ROG MAXIMUS Z790 EXTREME", + "ROG MAXIMUS Z790 HERO", + "ROG STRIX B560-A GAMING WIFI", + "ROG STRIX B560-E GAMING WIFI", + "ROG STRIX B560-F GAMING WIFI", + "ROG STRIX B560-G GAMING WIFI", + "ROG STRIX B560-I GAMING WIFI", "ROG STRIX B650-A GAMING WIFI", "ROG STRIX B650E-E GAMING WIFI", "ROG STRIX B650E-F GAMING WIFI", "ROG STRIX B650E-I GAMING WIFI", + "ROG STRIX B660-A GAMING WIFI", "ROG STRIX B660-A GAMING WIFI D4", "ROG STRIX B660-F GAMING WIFI", "ROG STRIX B660-G GAMING WIFI", "ROG STRIX B660-I GAMING WIFI", + "ROG STRIX B760-A GAMING WIFI", + "ROG STRIX B760-A GAMING WIFI D4", + "ROG STRIX B760-F GAMING WIFI", + "ROG STRIX B760-G GAMING WIFI", + "ROG STRIX B760-G GAMING WIFI D4", + "ROG STRIX B760-I GAMING WIFI", "ROG STRIX X670E-A GAMING WIFI", "ROG STRIX X670E-E GAMING WIFI", "ROG STRIX X670E-F GAMING WIFI", "ROG STRIX X670E-I GAMING WIFI", + "ROG STRIX Z590-A GAMING WIFI", "ROG STRIX Z590-A GAMING WIFI II", + "ROG STRIX Z590-E GAMING WIFI", + "ROG STRIX Z590-F GAMING WIFI", + "ROG STRIX Z590-I GAMING WIFI", + "ROG STRIX Z690-A GAMING WIFI", "ROG STRIX Z690-A GAMING WIFI D4", + "ROG STRIX Z690-E GAMING WIFI", + "ROG STRIX Z690-F GAMING WIFI", + "ROG STRIX Z690-G GAMING WIFI", + "ROG STRIX Z690-I GAMING WIFI", + "ROG STRIX Z790-A GAMING WIFI", + "ROG STRIX Z790-A GAMING WIFI D4", + "ROG STRIX Z790-E GAMING WIFI", + "ROG STRIX Z790-F GAMING WIFI", + "ROG STRIX Z790-H GAMING WIFI", + "ROG STRIX Z790-I GAMING WIFI", + "TUF GAMING A620M-PLUS", + "TUF GAMING A620M-PLUS WIFI", + "TUF GAMING B560-PLUS WIFI", + "TUF GAMING B560M-E", + "TUF GAMING B560M-PLUS", + "TUF GAMING B560M-PLUS WIFI", "TUF GAMING B650-PLUS", "TUF GAMING B650-PLUS WIFI", "TUF GAMING B650M-PLUS", "TUF GAMING B650M-PLUS WIFI", + "TUF GAMING B660-PLUS WIFI D4", + "TUF GAMING B660M-E D4", + "TUF GAMING B660M-PLUS D4", "TUF GAMING B660M-PLUS WIFI", + "TUF GAMING B660M-PLUS WIFI D4", + "TUF GAMING B760-PLUS WIFI", + "TUF GAMING B760-PLUS WIFI D4", + "TUF GAMING B760M-BTF WIFI D4", + "TUF GAMING B760M-E D4", + "TUF GAMING B760M-PLUS", + "TUF GAMING B760M-PLUS D4", + "TUF GAMING B760M-PLUS WIFI", + "TUF GAMING B760M-PLUS WIFI D4", + "TUF GAMING H570-PRO", + "TUF GAMING H570-PRO WIFI", + "TUF GAMING H670-PRO WIFI D4", + "TUF GAMING H770-PRO WIFI", "TUF GAMING X670E-PLUS", "TUF GAMING X670E-PLUS WIFI", + "TUF GAMING Z590-PLUS", "TUF GAMING Z590-PLUS WIFI", + "TUF GAMING Z690-PLUS", + "TUF GAMING Z690-PLUS D4", + "TUF GAMING Z690-PLUS WIFI", + "TUF GAMING Z690-PLUS WIFI D4", + "TUF GAMING Z790-PLUS D4", + "TUF GAMING Z790-PLUS WIFI", + "TUF GAMING Z790-PLUS WIFI D4", + "Z590 WIFI GUNDAM EDITION", }; #if IS_ENABLED(CONFIG_ACPI) diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index ecc5db0011a3..007bae4c7028 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -803,7 +803,7 @@ static int nct7904_detect(struct i2c_client *client, return 0; } -static const struct hwmon_channel_info *nct7904_info[] = { +static const struct hwmon_channel_info * const nct7904_info[] = { HWMON_CHANNEL_INFO(in, /* dummy, skipped in is_visible */ HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c index 11a28609da3c..10ed3f4335d4 100644 --- a/drivers/hwmon/npcm750-pwm-fan.c +++ b/drivers/hwmon/npcm750-pwm-fan.c @@ -629,7 +629,7 @@ static umode_t npcm7xx_is_visible(const void *data, } } -static const struct hwmon_channel_info *npcm7xx_info[] = { +static const struct hwmon_channel_info * const npcm7xx_info[] = { HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT, HWMON_PWM_INPUT, diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 9c9e9f4ccb9e..ef75b63f5894 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -546,7 +546,7 @@ static umode_t ntc_is_visible(const void *data, enum hwmon_sensor_types type, return 0; } -static const struct hwmon_channel_info *ntc_info[] = { +static const struct hwmon_channel_info * const ntc_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_TYPE), NULL diff --git a/drivers/hwmon/nzxt-kraken2.c b/drivers/hwmon/nzxt-kraken2.c index 89f7ea4f42d4..428c77b5fce5 100644 --- a/drivers/hwmon/nzxt-kraken2.c +++ b/drivers/hwmon/nzxt-kraken2.c @@ -86,7 +86,7 @@ static const struct hwmon_ops kraken2_hwmon_ops = { .read_string = kraken2_read_string, }; -static const struct hwmon_channel_info *kraken2_info[] = { +static const struct hwmon_channel_info * const kraken2_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(fan, diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c index 2b93ba89610a..7aa586eb74be 100644 --- a/drivers/hwmon/nzxt-smart2.c +++ b/drivers/hwmon/nzxt-smart2.c @@ -663,7 +663,7 @@ static const struct hwmon_ops nzxt_smart2_hwmon_ops = { .write = nzxt_smart2_hwmon_write, }; -static const struct hwmon_channel_info *nzxt_smart2_channel_info[] = { +static const struct hwmon_channel_info * const nzxt_smart2_channel_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL, HWMON_F_INPUT | HWMON_F_LABEL), @@ -721,6 +721,11 @@ static int __maybe_unused nzxt_smart2_hid_reset_resume(struct hid_device *hdev) return init_device(drvdata, drvdata->update_interval); } +static void mutex_fini(void *lock) +{ + mutex_destroy(lock); +} + static int nzxt_smart2_hid_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -737,8 +742,9 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev, init_waitqueue_head(&drvdata->wq); mutex_init(&drvdata->mutex); - devm_add_action(&hdev->dev, (void (*)(void *))mutex_destroy, - &drvdata->mutex); + ret = devm_add_action_or_reset(&hdev->dev, mutex_fini, &drvdata->mutex); + if (ret) + return ret; ret = hid_parse(hdev); if (ret) @@ -791,7 +797,8 @@ static const struct hid_device_id nzxt_smart2_hid_id_table[] = { { HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */ { HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */ - { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller */ + { HID_USB_DEVICE(0x1e71, 0x2011) }, /* NZXT RGB & Fan Controller (6 RGB) */ + { HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller (6 RGB) */ {}, }; diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index 36872b57912a..ae67207030e8 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -239,7 +239,7 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, } /* Known sensors in the OXP EC controllers */ -static const struct hwmon_channel_info *oxp_platform_sensors[] = { +static const struct hwmon_channel_info * const oxp_platform_sensors[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), HWMON_CHANNEL_INFO(pwm, diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c index 87d56f0fc888..e5b65a382772 100644 --- a/drivers/hwmon/peci/cputemp.c +++ b/drivers/hwmon/peci/cputemp.c @@ -447,7 +447,7 @@ static const struct hwmon_ops peci_cputemp_ops = { .read = cputemp_read, }; -static const struct hwmon_channel_info *peci_cputemp_info[] = { +static const struct hwmon_channel_info * const peci_cputemp_info[] = { HWMON_CHANNEL_INFO(temp, /* Die temperature */ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | diff --git a/drivers/hwmon/peci/dimmtemp.c b/drivers/hwmon/peci/dimmtemp.c index 0a633bda3668..ed968401f93c 100644 --- a/drivers/hwmon/peci/dimmtemp.c +++ b/drivers/hwmon/peci/dimmtemp.c @@ -300,7 +300,7 @@ static int create_dimm_temp_label(struct peci_dimmtemp *priv, int chan) return 0; } -static const struct hwmon_channel_info *peci_dimmtemp_temp_info[] = { +static const struct hwmon_channel_info * const peci_dimmtemp_temp_info[] = { HWMON_CHANNEL_INFO(temp, [0 ... DIMM_NUMS_MAX - 1] = HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT), diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 59d9a7430499..270b6336b76d 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -27,6 +27,15 @@ config SENSORS_PMBUS This driver can also be built as a module. If so, the module will be called pmbus. +config SENSORS_ACBEL_FSG032 + tristate "ACBEL FSG032 Power Supply" + help + If you say yes here you get hardware monitoring support for the ACBEL + FSG032 Power Supply. + + This driver can also be built as a module. If so, the module will + be called acbel-fsg032. + config SENSORS_ADM1266 tristate "Analog Devices ADM1266 Sequencer" select CRC8 diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 3ae019916267..84ee960a6c2d 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o +obj-$(CONFIG_SENSORS_ACBEL_FSG032) += acbel-fsg032.o obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o diff --git a/drivers/hwmon/pmbus/acbel-fsg032.c b/drivers/hwmon/pmbus/acbel-fsg032.c new file mode 100644 index 000000000000..28a25f30e2cf --- /dev/null +++ b/drivers/hwmon/pmbus/acbel-fsg032.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2023 IBM Corp. + */ + +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pmbus.h> +#include <linux/hwmon-sysfs.h> +#include "pmbus.h" + +static const struct i2c_device_id acbel_fsg032_id[] = { + { "acbel_fsg032" }, + {} +}; + +static struct pmbus_driver_info acbel_fsg032_info = { + .pages = 1, + .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | + PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | + PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | + PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP | + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_FAN12, +}; + +static int acbel_fsg032_probe(struct i2c_client *client) +{ + u8 buf[I2C_SMBUS_BLOCK_MAX + 1]; + struct device *dev = &client->dev; + int rc; + + rc = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); + if (rc < 0) { + dev_err(dev, "Failed to read PMBUS_MFR_ID\n"); + return rc; + } + if (strncmp(buf, "ACBEL", 5)) { + buf[rc] = '\0'; + dev_err(dev, "Manufacturer '%s' not supported\n", buf); + return -ENODEV; + } + + rc = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf); + if (rc < 0) { + dev_err(dev, "Failed to read PMBUS_MFR_MODEL\n"); + return rc; + } + + if (strncmp(buf, "FSG032", 6)) { + buf[rc] = '\0'; + dev_err(dev, "Model '%s' not supported\n", buf); + return -ENODEV; + } + + rc = pmbus_do_probe(client, &acbel_fsg032_info); + if (rc) + return rc; + + return 0; +} + +static const struct of_device_id acbel_fsg032_of_match[] = { + { .compatible = "acbel,fsg032" }, + {} +}; +MODULE_DEVICE_TABLE(of, acbel_fsg032_of_match); + +static struct i2c_driver acbel_fsg032_driver = { + .driver = { + .name = "acbel-fsg032", + .of_match_table = acbel_fsg032_of_match, + }, + .probe_new = acbel_fsg032_probe, + .id_table = acbel_fsg032_id, +}; + +module_i2c_driver(acbel_fsg032_driver); + +MODULE_AUTHOR("Lakshmi Yadlapati"); +MODULE_DESCRIPTION("PMBus driver for AcBel Power System power supplies"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/fsp-3y.c b/drivers/hwmon/pmbus/fsp-3y.c index aec294cc72d1..c7469d2cdedc 100644 --- a/drivers/hwmon/pmbus/fsp-3y.c +++ b/drivers/hwmon/pmbus/fsp-3y.c @@ -180,7 +180,6 @@ static struct pmbus_driver_info fsp3y_info[] = { PMBUS_HAVE_FAN12, .func[YM2151_PAGE_5VSB_LOG] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT, - PMBUS_HAVE_IIN, .read_word_data = fsp3y_read_word_data, .read_byte_data = fsp3y_read_byte_data, }, diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index e3294a1a54bb..76e72e9acda7 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -18,12 +18,6 @@ #include "pmbus.h" -#define CFFPS_MFG_ID_CMD 0x99 -#define CFFPS_FRU_CMD 0x9A -#define CFFPS_PN_CMD 0x9B -#define CFFPS_HEADER_CMD 0x9C -#define CFFPS_SN_CMD 0x9E -#define CFFPS_MAX_POWER_OUT_CMD 0xA7 #define CFFPS_CCIN_CMD 0xBD #define CFFPS_FW_CMD 0xFA #define CFFPS1_FW_NUM_BYTES 4 @@ -32,7 +26,7 @@ #define CFFPS_12VCS_VOUT_CMD 0xDE #define CFFPS_INPUT_HISTORY_CMD 0xD6 -#define CFFPS_INPUT_HISTORY_SIZE 100 +#define CFFPS_INPUT_HISTORY_SIZE 101 #define CFFPS_CCIN_REVISION GENMASK(7, 0) #define CFFPS_CCIN_REVISION_LEGACY 0xde @@ -57,13 +51,7 @@ #define CFFPS_BLINK_RATE_MS 250 enum { - CFFPS_DEBUGFS_INPUT_HISTORY = 0, - CFFPS_DEBUGFS_MFG_ID, - CFFPS_DEBUGFS_FRU, - CFFPS_DEBUGFS_PN, - CFFPS_DEBUGFS_HEADER, - CFFPS_DEBUGFS_SN, - CFFPS_DEBUGFS_MAX_POWER_OUT, + CFFPS_DEBUGFS_MAX_POWER_OUT = 0, CFFPS_DEBUGFS_CCIN, CFFPS_DEBUGFS_FW, CFFPS_DEBUGFS_ON_OFF_CONFIG, @@ -72,19 +60,11 @@ enum { enum versions { cffps1, cffps2, cffps_unknown }; -struct ibm_cffps_input_history { - struct mutex update_lock; - unsigned long last_update; - - u8 byte_count; - u8 data[CFFPS_INPUT_HISTORY_SIZE]; -}; - struct ibm_cffps { enum versions version; struct i2c_client *client; - struct ibm_cffps_input_history input_history; + u8 input_history[CFFPS_INPUT_HISTORY_SIZE]; int debugfs_entries[CFFPS_DEBUGFS_NUM_ENTRIES]; @@ -93,118 +73,98 @@ struct ibm_cffps { struct led_classdev led; }; -static const struct i2c_device_id ibm_cffps_id[]; - #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)]) -static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu, - char __user *buf, size_t count, - loff_t *ppos) +static ssize_t ibm_cffps_debugfs_read_input_history(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { int rc; - u8 msgbuf0[1] = { CFFPS_INPUT_HISTORY_CMD }; - u8 msgbuf1[CFFPS_INPUT_HISTORY_SIZE + 1] = { 0 }; + u8 cmd = CFFPS_INPUT_HISTORY_CMD; + struct ibm_cffps *psu = file->private_data; struct i2c_msg msg[2] = { { .addr = psu->client->addr, .flags = psu->client->flags, .len = 1, - .buf = msgbuf0, + .buf = &cmd, }, { .addr = psu->client->addr, .flags = psu->client->flags | I2C_M_RD, - .len = CFFPS_INPUT_HISTORY_SIZE + 1, - .buf = msgbuf1, + .len = CFFPS_INPUT_HISTORY_SIZE, + .buf = psu->input_history, }, }; if (!*ppos) { - mutex_lock(&psu->input_history.update_lock); - if (time_after(jiffies, psu->input_history.last_update + HZ)) { - /* - * Use a raw i2c transfer, since we need more bytes - * than Linux I2C supports through smbus xfr (only 32). - */ - rc = i2c_transfer(psu->client->adapter, msg, 2); - if (rc < 0) { - mutex_unlock(&psu->input_history.update_lock); - return rc; - } + rc = pmbus_lock_interruptible(psu->client); + if (rc) + return rc; - psu->input_history.byte_count = msgbuf1[0]; - memcpy(psu->input_history.data, &msgbuf1[1], - CFFPS_INPUT_HISTORY_SIZE); - psu->input_history.last_update = jiffies; + rc = pmbus_set_page(psu->client, 0, 0xff); + if (rc) { + pmbus_unlock(psu->client); + return rc; } - mutex_unlock(&psu->input_history.update_lock); + /* + * Use a raw i2c transfer, since we need more bytes + * than Linux I2C supports through smbus xfr (only 32). + */ + rc = i2c_transfer(psu->client->adapter, msg, 2); + pmbus_unlock(psu->client); + if (rc < 0) + return rc; } return simple_read_from_buffer(buf, count, ppos, - psu->input_history.data, - psu->input_history.byte_count); + psu->input_history + 1, + psu->input_history[0]); } +static const struct file_operations ibm_cffps_input_history_fops = { + .llseek = noop_llseek, + .read = ibm_cffps_debugfs_read_input_history, + .open = simple_open, +}; + static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - u8 cmd; int i, rc; int *idxp = file->private_data; int idx = *idxp; struct ibm_cffps *psu = to_psu(idxp, idx); char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 }; - pmbus_set_page(psu->client, 0, 0xff); + rc = pmbus_lock_interruptible(psu->client); + if (rc) + return rc; + + rc = pmbus_set_page(psu->client, 0, 0xff); + if (rc) + goto unlock; switch (idx) { - case CFFPS_DEBUGFS_INPUT_HISTORY: - return ibm_cffps_read_input_history(psu, buf, count, ppos); - case CFFPS_DEBUGFS_MFG_ID: - cmd = CFFPS_MFG_ID_CMD; - break; - case CFFPS_DEBUGFS_FRU: - cmd = CFFPS_FRU_CMD; - break; - case CFFPS_DEBUGFS_PN: - cmd = CFFPS_PN_CMD; - break; - case CFFPS_DEBUGFS_HEADER: - cmd = CFFPS_HEADER_CMD; - break; - case CFFPS_DEBUGFS_SN: - cmd = CFFPS_SN_CMD; - break; case CFFPS_DEBUGFS_MAX_POWER_OUT: - if (psu->version == cffps1) { - rc = i2c_smbus_read_word_swapped(psu->client, - CFFPS_MAX_POWER_OUT_CMD); - } else { - rc = i2c_smbus_read_word_data(psu->client, - CFFPS_MAX_POWER_OUT_CMD); - } - - if (rc < 0) - return rc; - - rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc); - goto done; + if (psu->version == cffps1) + rc = i2c_smbus_read_word_swapped(psu->client, PMBUS_MFR_POUT_MAX); + else + rc = i2c_smbus_read_word_data(psu->client, PMBUS_MFR_POUT_MAX); + if (rc >= 0) + rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc); + break; case CFFPS_DEBUGFS_CCIN: rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD); - if (rc < 0) - return rc; - - rc = snprintf(data, 5, "%04X", rc); - goto done; + if (rc >= 0) + rc = snprintf(data, 5, "%04X", rc); + break; case CFFPS_DEBUGFS_FW: switch (psu->version) { case cffps1: for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) { - rc = i2c_smbus_read_byte_data(psu->client, - CFFPS_FW_CMD + - i); + rc = i2c_smbus_read_byte_data(psu->client, CFFPS_FW_CMD + i); if (rc < 0) - return rc; + goto unlock; snprintf(&data[i * 2], 3, "%02X", rc); } @@ -213,11 +173,9 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf, break; case cffps2: for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) { - rc = i2c_smbus_read_word_data(psu->client, - CFFPS_FW_CMD + - i); + rc = i2c_smbus_read_word_data(psu->client, CFFPS_FW_CMD + i); if (rc < 0) - return rc; + goto unlock; snprintf(&data[i * 4], 5, "%04X", rc); } @@ -225,26 +183,25 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf, rc = i * 4; break; default: - return -EOPNOTSUPP; + rc = -EOPNOTSUPP; + break; } - goto done; + break; case CFFPS_DEBUGFS_ON_OFF_CONFIG: - rc = i2c_smbus_read_byte_data(psu->client, - PMBUS_ON_OFF_CONFIG); - if (rc < 0) - return rc; - - rc = snprintf(data, 3, "%02x", rc); - goto done; + rc = i2c_smbus_read_byte_data(psu->client, PMBUS_ON_OFF_CONFIG); + if (rc >= 0) + rc = snprintf(data, 3, "%02x", rc); + break; default: - return -EINVAL; + rc = -EINVAL; + break; } - rc = i2c_smbus_read_block_data(psu->client, cmd, data); +unlock: + pmbus_unlock(psu->client); if (rc < 0) return rc; -done: data[rc] = '\n'; rc += 2; @@ -263,14 +220,22 @@ static ssize_t ibm_cffps_debugfs_write(struct file *file, switch (idx) { case CFFPS_DEBUGFS_ON_OFF_CONFIG: - pmbus_set_page(psu->client, 0, 0xff); - rc = simple_write_to_buffer(&data, 1, ppos, buf, count); if (rc <= 0) return rc; - rc = i2c_smbus_write_byte_data(psu->client, - PMBUS_ON_OFF_CONFIG, data); + rc = pmbus_lock_interruptible(psu->client); + if (rc) + return rc; + + rc = pmbus_set_page(psu->client, 0, 0xff); + if (rc) { + pmbus_unlock(psu->client); + return rc; + } + + rc = i2c_smbus_write_byte_data(psu->client, PMBUS_ON_OFF_CONFIG, data); + pmbus_unlock(psu->client); if (rc) return rc; @@ -396,10 +361,19 @@ static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev, dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n", brightness, next_led_state); - pmbus_set_page(psu->client, 0, 0xff); + rc = pmbus_lock_interruptible(psu->client); + if (rc) + return rc; + + rc = pmbus_set_page(psu->client, 0, 0xff); + if (rc) { + pmbus_unlock(psu->client); + return rc; + } rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, next_led_state); + pmbus_unlock(psu->client); if (rc < 0) return rc; @@ -418,10 +392,19 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev, dev_dbg(&psu->client->dev, "LED blink set.\n"); - pmbus_set_page(psu->client, 0, 0xff); + rc = pmbus_lock_interruptible(psu->client); + if (rc) + return rc; + + rc = pmbus_set_page(psu->client, 0, 0xff); + if (rc) { + pmbus_unlock(psu->client); + return rc; + } rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, CFFPS_LED_BLINK); + pmbus_unlock(psu->client); if (rc < 0) return rc; @@ -474,9 +457,11 @@ static struct pmbus_driver_info ibm_cffps_info[] = { PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_VMON, - .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | - PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | - PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT, + .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | + PMBUS_HAVE_PIN | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | + PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT | + PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT | + PMBUS_HAVE_STATUS_TEMP, .read_byte_data = ibm_cffps_read_byte_data, .read_word_data = ibm_cffps_read_word_data, }, @@ -486,12 +471,19 @@ static struct pmbus_platform_data ibm_cffps_pdata = { .flags = PMBUS_SKIP_STATUS_CHECK | PMBUS_NO_CAPABILITY, }; +static const struct i2c_device_id ibm_cffps_id[] = { + { "ibm_cffps1", cffps1 }, + { "ibm_cffps2", cffps2 }, + { "ibm_cffps", cffps_unknown }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ibm_cffps_id); + static int ibm_cffps_probe(struct i2c_client *client) { int i, rc; enum versions vs = cffps_unknown; struct dentry *debugfs; - struct dentry *ibm_cffps_dir; struct ibm_cffps *psu; const void *md = of_device_get_match_data(&client->dev); const struct i2c_device_id *id; @@ -560,8 +552,6 @@ static int ibm_cffps_probe(struct i2c_client *client) psu->version = vs; psu->client = client; - mutex_init(&psu->input_history.update_lock); - psu->input_history.last_update = jiffies - HZ; ibm_cffps_create_led_class(psu); @@ -570,55 +560,29 @@ static int ibm_cffps_probe(struct i2c_client *client) if (!debugfs) return 0; - ibm_cffps_dir = debugfs_create_dir(client->name, debugfs); - if (!ibm_cffps_dir) - return 0; - for (i = 0; i < CFFPS_DEBUGFS_NUM_ENTRIES; ++i) psu->debugfs_entries[i] = i; - debugfs_create_file("input_history", 0444, ibm_cffps_dir, - &psu->debugfs_entries[CFFPS_DEBUGFS_INPUT_HISTORY], - &ibm_cffps_fops); - debugfs_create_file("mfg_id", 0444, ibm_cffps_dir, - &psu->debugfs_entries[CFFPS_DEBUGFS_MFG_ID], - &ibm_cffps_fops); - debugfs_create_file("fru", 0444, ibm_cffps_dir, - &psu->debugfs_entries[CFFPS_DEBUGFS_FRU], - &ibm_cffps_fops); - debugfs_create_file("part_number", 0444, ibm_cffps_dir, - &psu->debugfs_entries[CFFPS_DEBUGFS_PN], - &ibm_cffps_fops); - debugfs_create_file("header", 0444, ibm_cffps_dir, - &psu->debugfs_entries[CFFPS_DEBUGFS_HEADER], - &ibm_cffps_fops); - debugfs_create_file("serial_number", 0444, ibm_cffps_dir, - &psu->debugfs_entries[CFFPS_DEBUGFS_SN], - &ibm_cffps_fops); - debugfs_create_file("max_power_out", 0444, ibm_cffps_dir, + debugfs_create_file("input_history", 0444, debugfs, psu, &ibm_cffps_input_history_fops); + debugfs_create_file("max_power_out", 0444, debugfs, &psu->debugfs_entries[CFFPS_DEBUGFS_MAX_POWER_OUT], &ibm_cffps_fops); - debugfs_create_file("ccin", 0444, ibm_cffps_dir, + debugfs_create_file("ccin", 0444, debugfs, &psu->debugfs_entries[CFFPS_DEBUGFS_CCIN], &ibm_cffps_fops); - debugfs_create_file("fw_version", 0444, ibm_cffps_dir, + debugfs_create_file("fw_version", 0444, debugfs, &psu->debugfs_entries[CFFPS_DEBUGFS_FW], &ibm_cffps_fops); - debugfs_create_file("on_off_config", 0644, ibm_cffps_dir, + debugfs_create_file("on_off_config", 0644, debugfs, &psu->debugfs_entries[CFFPS_DEBUGFS_ON_OFF_CONFIG], &ibm_cffps_fops); + /* For compatibility with users of the old naming scheme. */ + debugfs_create_symlink(client->name, debugfs, "."); + return 0; } -static const struct i2c_device_id ibm_cffps_id[] = { - { "ibm_cffps1", cffps1 }, - { "ibm_cffps2", cffps2 }, - { "ibm_cffps", cffps_unknown }, - {} -}; -MODULE_DEVICE_TABLE(i2c, ibm_cffps_id); - static const struct of_device_id ibm_cffps_of_match[] = { { .compatible = "ibm,cffps1", diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index 713ea7915425..b0832a4c690d 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -26,7 +26,7 @@ enum pmbus_regs { PMBUS_CAPABILITY = 0x19, PMBUS_QUERY = 0x1A, - + PMBUS_SMBALERT_MASK = 0x1B, PMBUS_VOUT_MODE = 0x20, PMBUS_VOUT_COMMAND = 0x21, PMBUS_VOUT_TRIM = 0x22, @@ -505,6 +505,8 @@ int pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, enum pmbus_fan_mode mode); int pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, enum pmbus_fan_mode mode); +int pmbus_lock_interruptible(struct i2c_client *client); +void pmbus_unlock(struct i2c_client *client); int pmbus_update_fan(struct i2c_client *client, int page, int id, u8 config, u8 mask, u16 command); struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 95e95783972a..80ec4a5493b4 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -81,6 +81,7 @@ struct pmbus_label { struct pmbus_data { struct device *dev; struct device *hwmon_dev; + struct regulator_dev **rdevs; u32 flags; /* from platform data */ @@ -2692,18 +2693,64 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, return 0; } -#if IS_ENABLED(CONFIG_REGULATOR) -static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) +/* A PMBus status flag and the corresponding REGULATOR_ERROR_* and REGULATOR_EVENTS_* flag */ +struct pmbus_status_assoc { + int pflag, rflag, eflag; +}; + +/* PMBus->regulator bit mappings for a PMBus status register */ +struct pmbus_status_category { + int func; + int reg; + const struct pmbus_status_assoc *bits; /* zero-terminated */ +}; + +static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[] = { + { + .func = PMBUS_HAVE_STATUS_VOUT, + .reg = PMBUS_STATUS_VOUT, + .bits = (const struct pmbus_status_assoc[]) { + { PB_VOLTAGE_UV_WARNING, REGULATOR_ERROR_UNDER_VOLTAGE_WARN, + REGULATOR_EVENT_UNDER_VOLTAGE_WARN }, + { PB_VOLTAGE_UV_FAULT, REGULATOR_ERROR_UNDER_VOLTAGE, + REGULATOR_EVENT_UNDER_VOLTAGE }, + { PB_VOLTAGE_OV_WARNING, REGULATOR_ERROR_OVER_VOLTAGE_WARN, + REGULATOR_EVENT_OVER_VOLTAGE_WARN }, + { PB_VOLTAGE_OV_FAULT, REGULATOR_ERROR_REGULATION_OUT, + REGULATOR_EVENT_OVER_VOLTAGE_WARN }, + { }, + }, + }, { + .func = PMBUS_HAVE_STATUS_IOUT, + .reg = PMBUS_STATUS_IOUT, + .bits = (const struct pmbus_status_assoc[]) { + { PB_IOUT_OC_WARNING, REGULATOR_ERROR_OVER_CURRENT_WARN, + REGULATOR_EVENT_OVER_CURRENT_WARN }, + { PB_IOUT_OC_FAULT, REGULATOR_ERROR_OVER_CURRENT, + REGULATOR_EVENT_OVER_CURRENT }, + { PB_IOUT_OC_LV_FAULT, REGULATOR_ERROR_OVER_CURRENT, + REGULATOR_EVENT_OVER_CURRENT }, + { }, + }, + }, { + .func = PMBUS_HAVE_STATUS_TEMP, + .reg = PMBUS_STATUS_TEMPERATURE, + .bits = (const struct pmbus_status_assoc[]) { + { PB_TEMP_OT_WARNING, REGULATOR_ERROR_OVER_TEMP_WARN, + REGULATOR_EVENT_OVER_TEMP_WARN }, + { PB_TEMP_OT_FAULT, REGULATOR_ERROR_OVER_TEMP, + REGULATOR_EVENT_OVER_TEMP }, + { }, + }, + }, +}; + +static int _pmbus_is_enabled(struct device *dev, u8 page) { - 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 ret; - mutex_lock(&data->update_lock); ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION); - mutex_unlock(&data->update_lock); if (ret < 0) return ret; @@ -2711,106 +2758,77 @@ static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) return !!(ret & PB_OPERATION_CONTROL_ON); } -static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) +static int __maybe_unused pmbus_is_enabled(struct device *dev, u8 page) { - 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 ret; mutex_lock(&data->update_lock); - ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION, - PB_OPERATION_CONTROL_ON, - enable ? PB_OPERATION_CONTROL_ON : 0); + ret = _pmbus_is_enabled(dev, page); mutex_unlock(&data->update_lock); - return ret; + return !!(ret & PB_OPERATION_CONTROL_ON); } -static int pmbus_regulator_enable(struct regulator_dev *rdev) -{ - return _pmbus_regulator_on_off(rdev, 1); -} +#define to_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct device_attribute, attr) -static int pmbus_regulator_disable(struct regulator_dev *rdev) +static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags) { - return _pmbus_regulator_on_off(rdev, 0); -} - -/* A PMBus status flag and the corresponding REGULATOR_ERROR_* flag */ -struct pmbus_regulator_status_assoc { - int pflag, rflag; -}; + int i; -/* PMBus->regulator bit mappings for a PMBus status register */ -struct pmbus_regulator_status_category { - int func; - int reg; - const struct pmbus_regulator_status_assoc *bits; /* zero-terminated */ -}; + for (i = 0; i < data->num_attributes; i++) { + struct device_attribute *da = to_dev_attr(data->group.attrs[i]); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int index = attr->index; + u16 smask = pb_index_to_mask(index); + u8 spage = pb_index_to_page(index); + u16 sreg = pb_index_to_reg(index); + + if (reg == sreg && page == spage && (smask & flags)) { + dev_dbg(data->dev, "sysfs notify: %s", da->attr.name); + sysfs_notify(&data->dev->kobj, NULL, da->attr.name); + kobject_uevent(&data->dev->kobj, KOBJ_CHANGE); + flags &= ~smask; + } -static const struct pmbus_regulator_status_category pmbus_regulator_flag_map[] = { - { - .func = PMBUS_HAVE_STATUS_VOUT, - .reg = PMBUS_STATUS_VOUT, - .bits = (const struct pmbus_regulator_status_assoc[]) { - { PB_VOLTAGE_UV_WARNING, REGULATOR_ERROR_UNDER_VOLTAGE_WARN }, - { PB_VOLTAGE_UV_FAULT, REGULATOR_ERROR_UNDER_VOLTAGE }, - { PB_VOLTAGE_OV_WARNING, REGULATOR_ERROR_OVER_VOLTAGE_WARN }, - { PB_VOLTAGE_OV_FAULT, REGULATOR_ERROR_REGULATION_OUT }, - { }, - }, - }, { - .func = PMBUS_HAVE_STATUS_IOUT, - .reg = PMBUS_STATUS_IOUT, - .bits = (const struct pmbus_regulator_status_assoc[]) { - { PB_IOUT_OC_WARNING, REGULATOR_ERROR_OVER_CURRENT_WARN }, - { PB_IOUT_OC_FAULT, REGULATOR_ERROR_OVER_CURRENT }, - { PB_IOUT_OC_LV_FAULT, REGULATOR_ERROR_OVER_CURRENT }, - { }, - }, - }, { - .func = PMBUS_HAVE_STATUS_TEMP, - .reg = PMBUS_STATUS_TEMPERATURE, - .bits = (const struct pmbus_regulator_status_assoc[]) { - { PB_TEMP_OT_WARNING, REGULATOR_ERROR_OVER_TEMP_WARN }, - { PB_TEMP_OT_FAULT, REGULATOR_ERROR_OVER_TEMP }, - { }, - }, - }, -}; + if (!flags) + break; + } +} -static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) +static int _pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags, + unsigned int *event, bool notify) { int i, status; - const struct pmbus_regulator_status_category *cat; - const struct pmbus_regulator_status_assoc *bit; - 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); + const struct pmbus_status_category *cat; + const struct pmbus_status_assoc *bit; + struct device *dev = data->dev; + struct i2c_client *client = to_i2c_client(dev); int func = data->info->func[page]; *flags = 0; + *event = 0; - mutex_lock(&data->update_lock); - - for (i = 0; i < ARRAY_SIZE(pmbus_regulator_flag_map); i++) { - cat = &pmbus_regulator_flag_map[i]; + for (i = 0; i < ARRAY_SIZE(pmbus_status_flag_map); i++) { + cat = &pmbus_status_flag_map[i]; if (!(func & cat->func)) continue; status = _pmbus_read_byte_data(client, page, cat->reg); - if (status < 0) { - mutex_unlock(&data->update_lock); + if (status < 0) return status; - } - for (bit = cat->bits; bit->pflag; bit++) { - if (status & bit->pflag) + for (bit = cat->bits; bit->pflag; bit++) + if (status & bit->pflag) { *flags |= bit->rflag; - } + *event |= bit->eflag; + } + + if (notify && status) + pmbus_notify(data, page, cat->reg, status); + } /* @@ -2823,25 +2841,32 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned * REGULATOR_ERROR_<foo>_WARN. */ status = pmbus_get_status(client, page, PMBUS_STATUS_WORD); - mutex_unlock(&data->update_lock); if (status < 0) return status; - if (pmbus_regulator_is_enabled(rdev)) { - if (status & PB_STATUS_OFF) + if (_pmbus_is_enabled(dev, page)) { + if (status & PB_STATUS_OFF) { *flags |= REGULATOR_ERROR_FAIL; + *event |= REGULATOR_EVENT_FAIL; + } - if (status & PB_STATUS_POWER_GOOD_N) + if (status & PB_STATUS_POWER_GOOD_N) { *flags |= REGULATOR_ERROR_REGULATION_OUT; + *event |= REGULATOR_EVENT_REGULATION_OUT; + } } /* * Unlike most other status bits, PB_STATUS_{IOUT_OC,VOUT_OV} are * defined strictly as fault indicators (not warnings). */ - if (status & PB_STATUS_IOUT_OC) + if (status & PB_STATUS_IOUT_OC) { *flags |= REGULATOR_ERROR_OVER_CURRENT; - if (status & PB_STATUS_VOUT_OV) + *event |= REGULATOR_EVENT_OVER_CURRENT; + } + if (status & PB_STATUS_VOUT_OV) { *flags |= REGULATOR_ERROR_REGULATION_OUT; + *event |= REGULATOR_EVENT_FAIL; + } /* * If we haven't discovered any thermal faults or warnings via @@ -2849,12 +2874,70 @@ static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned * a (conservative) best-effort interpretation. */ if (!(*flags & (REGULATOR_ERROR_OVER_TEMP | REGULATOR_ERROR_OVER_TEMP_WARN)) && - (status & PB_STATUS_TEMPERATURE)) + (status & PB_STATUS_TEMPERATURE)) { *flags |= REGULATOR_ERROR_OVER_TEMP_WARN; + *event |= REGULATOR_EVENT_OVER_TEMP_WARN; + } + return 0; } +static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags, + unsigned int *event, bool notify) +{ + int ret; + + mutex_lock(&data->update_lock); + ret = _pmbus_get_flags(data, page, flags, event, notify); + mutex_unlock(&data->update_lock); + + return ret; +} + +#if IS_ENABLED(CONFIG_REGULATOR) +static int pmbus_regulator_is_enabled(struct regulator_dev *rdev) +{ + return pmbus_is_enabled(rdev_get_dev(rdev), rdev_get_id(rdev)); +} + +static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable) +{ + 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 ret; + + mutex_lock(&data->update_lock); + ret = pmbus_update_byte_data(client, page, PMBUS_OPERATION, + PB_OPERATION_CONTROL_ON, + enable ? PB_OPERATION_CONTROL_ON : 0); + mutex_unlock(&data->update_lock); + + return ret; +} + +static int pmbus_regulator_enable(struct regulator_dev *rdev) +{ + return _pmbus_regulator_on_off(rdev, 1); +} + +static int pmbus_regulator_disable(struct regulator_dev *rdev) +{ + return _pmbus_regulator_on_off(rdev, 0); +} + +static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) +{ + struct device *dev = rdev_get_dev(rdev); + struct i2c_client *client = to_i2c_client(dev->parent); + struct pmbus_data *data = i2c_get_clientdata(client); + int event; + + return pmbus_get_flags(data, rdev_get_id(rdev), flags, &event, false); +} + static int pmbus_regulator_get_status(struct regulator_dev *rdev) { struct device *dev = rdev_get_dev(rdev); @@ -3050,9 +3133,13 @@ static int pmbus_regulator_register(struct pmbus_data *data) struct device *dev = data->dev; const struct pmbus_driver_info *info = data->info; const struct pmbus_platform_data *pdata = dev_get_platdata(dev); - struct regulator_dev *rdev; int i; + data->rdevs = devm_kzalloc(dev, sizeof(struct regulator_dev *) * info->num_regulators, + GFP_KERNEL); + if (!data->rdevs) + return -ENOMEM; + for (i = 0; i < info->num_regulators; i++) { struct regulator_config config = { }; @@ -3062,23 +3149,113 @@ static int pmbus_regulator_register(struct pmbus_data *data) if (pdata && pdata->reg_init_data) config.init_data = &pdata->reg_init_data[i]; - rdev = devm_regulator_register(dev, &info->reg_desc[i], - &config); - if (IS_ERR(rdev)) - return dev_err_probe(dev, PTR_ERR(rdev), + data->rdevs[i] = devm_regulator_register(dev, &info->reg_desc[i], + &config); + if (IS_ERR(data->rdevs[i])) + return dev_err_probe(dev, PTR_ERR(data->rdevs[i]), "Failed to register %s regulator\n", info->reg_desc[i].name); } return 0; } + +static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event) +{ + int j; + + for (j = 0; j < data->info->num_regulators; j++) { + if (page == rdev_get_id(data->rdevs[j])) { + regulator_notifier_call_chain(data->rdevs[j], event, NULL); + break; + } + } + return 0; +} #else static int pmbus_regulator_register(struct pmbus_data *data) { return 0; } + +static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event) +{ + return 0; +} #endif +static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val) +{ + return pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8)); +} + +static irqreturn_t pmbus_fault_handler(int irq, void *pdata) +{ + struct pmbus_data *data = pdata; + struct i2c_client *client = to_i2c_client(data->dev); + + int i, status, event; + mutex_lock(&data->update_lock); + for (i = 0; i < data->info->pages; i++) { + _pmbus_get_flags(data, i, &status, &event, true); + + if (event) + pmbus_regulator_notify(data, i, event); + } + + pmbus_clear_faults(client); + mutex_unlock(&data->update_lock); + + return IRQ_HANDLED; +} + +static int pmbus_irq_setup(struct i2c_client *client, struct pmbus_data *data) +{ + struct device *dev = &client->dev; + const struct pmbus_status_category *cat; + const struct pmbus_status_assoc *bit; + int i, j, err, func; + u8 mask; + + static const u8 misc_status[] = {PMBUS_STATUS_CML, PMBUS_STATUS_OTHER, + PMBUS_STATUS_MFR_SPECIFIC, PMBUS_STATUS_FAN_12, + PMBUS_STATUS_FAN_34}; + + if (!client->irq) + return 0; + + for (i = 0; i < data->info->pages; i++) { + func = data->info->func[i]; + + for (j = 0; j < ARRAY_SIZE(pmbus_status_flag_map); j++) { + cat = &pmbus_status_flag_map[j]; + if (!(func & cat->func)) + continue; + mask = 0; + for (bit = cat->bits; bit->pflag; bit++) + mask |= bit->pflag; + + err = pmbus_write_smbalert_mask(client, i, cat->reg, ~mask); + if (err) + dev_dbg_once(dev, "Failed to set smbalert for reg 0x%02x\n", + cat->reg); + } + + for (j = 0; j < ARRAY_SIZE(misc_status); j++) + pmbus_write_smbalert_mask(client, i, misc_status[j], 0xff); + } + + /* Register notifiers */ + err = devm_request_threaded_irq(dev, client->irq, NULL, pmbus_fault_handler, + IRQF_ONESHOT, "pmbus-irq", data); + if (err) { + dev_err(dev, "failed to request an irq %d\n", err); + return err; + } + + return 0; +} + static struct dentry *pmbus_debugfs_dir; /* pmbus debugfs directory */ #if IS_ENABLED(CONFIG_DEBUG_FS) @@ -3086,8 +3263,13 @@ static int pmbus_debugfs_get(void *data, u64 *val) { int rc; struct pmbus_debugfs_entry *entry = data; + struct pmbus_data *pdata = i2c_get_clientdata(entry->client); + rc = mutex_lock_interruptible(&pdata->update_lock); + if (rc) + return rc; rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg); + mutex_unlock(&pdata->update_lock); if (rc < 0) return rc; @@ -3104,7 +3286,11 @@ static int pmbus_debugfs_get_status(void *data, u64 *val) struct pmbus_debugfs_entry *entry = data; struct pmbus_data *pdata = i2c_get_clientdata(entry->client); + rc = mutex_lock_interruptible(&pdata->update_lock); + if (rc) + return rc; rc = pdata->read_status(entry->client, entry->page); + mutex_unlock(&pdata->update_lock); if (rc < 0) return rc; @@ -3120,10 +3306,15 @@ static ssize_t pmbus_debugfs_mfr_read(struct file *file, char __user *buf, { int rc; struct pmbus_debugfs_entry *entry = file->private_data; + struct pmbus_data *pdata = i2c_get_clientdata(entry->client); char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 }; + rc = mutex_lock_interruptible(&pdata->update_lock); + if (rc) + return rc; rc = pmbus_read_block_data(entry->client, entry->page, entry->reg, data); + mutex_unlock(&pdata->update_lock); if (rc < 0) return rc; @@ -3441,6 +3632,10 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info) if (ret) return ret; + ret = pmbus_irq_setup(client, data); + if (ret) + return ret; + ret = pmbus_init_debugfs(client, data); if (ret) dev_warn(dev, "Failed to register debugfs\n"); @@ -3457,6 +3652,22 @@ struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client) } EXPORT_SYMBOL_NS_GPL(pmbus_get_debugfs_dir, PMBUS); +int pmbus_lock_interruptible(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + return mutex_lock_interruptible(&data->update_lock); +} +EXPORT_SYMBOL_NS_GPL(pmbus_lock_interruptible, PMBUS); + +void pmbus_unlock(struct i2c_client *client) +{ + struct pmbus_data *data = i2c_get_clientdata(client); + + mutex_unlock(&data->update_lock); +} +EXPORT_SYMBOL_NS_GPL(pmbus_unlock, PMBUS); + static int __init pmbus_core_init(void) { pmbus_debugfs_dir = debugfs_create_dir("pmbus", NULL); diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index f77dc6db31ac..9cb0c2de5219 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c @@ -248,7 +248,7 @@ powr1220_read(struct device *dev, enum hwmon_sensor_types type, u32 return 0; } -static const struct hwmon_channel_info *powr1220_info[] = { +static const struct hwmon_channel_info * const powr1220_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL, diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 83a347ca35da..6e4516c2ab89 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -427,7 +427,7 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, struct device_node *np = dev->of_node; int num, i, ret; - if (!of_find_property(np, "cooling-levels", NULL)) + if (!of_property_present(np, "cooling-levels")) return 0; ret = of_property_count_u32_elems(np, "cooling-levels"); @@ -508,6 +508,14 @@ static int pwm_fan_probe(struct platform_device *pdev) pwm_init_state(ctx->pwm, &ctx->pwm_state); /* + * PWM fans are controlled solely by the duty cycle of the PWM signal, + * they do not care about the exact timing. Thus set usage_power to true + * to allow less flexible hardware to work as a PWM source for fan + * control. + */ + ctx->pwm_state.usage_power = true; + + /* * set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned * long. Check this here to prevent the fan running at a too low * frequency. diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c index 1650d3b4c26e..65cc52e47db0 100644 --- a/drivers/hwmon/raspberrypi-hwmon.c +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -87,7 +87,7 @@ static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type, return 0444; } -static const struct hwmon_channel_info *rpi_info[] = { +static const struct hwmon_channel_info * const rpi_info[] = { HWMON_CHANNEL_INFO(in, HWMON_I_LCRIT_ALARM), NULL diff --git a/drivers/hwmon/sbrmi.c b/drivers/hwmon/sbrmi.c index 8ea5a4d3219f..529f0e766319 100644 --- a/drivers/hwmon/sbrmi.c +++ b/drivers/hwmon/sbrmi.c @@ -265,7 +265,7 @@ static umode_t sbrmi_is_visible(const void *data, return 0; } -static const struct hwmon_channel_info *sbrmi_info[] = { +static const struct hwmon_channel_info * const sbrmi_info[] = { HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX), NULL diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c index 4c37de846f93..7049d9464ac6 100644 --- a/drivers/hwmon/sbtsi_temp.c +++ b/drivers/hwmon/sbtsi_temp.c @@ -182,7 +182,7 @@ static umode_t sbtsi_is_visible(const void *data, return 0; } -static const struct hwmon_channel_info *sbtsi_info[] = { +static const struct hwmon_channel_info * const sbtsi_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX), NULL diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 25fbbd4c9a2b..1bbda3b05532 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -379,7 +379,7 @@ static const struct hwmon_ops sch5627_ops = { .write = sch5627_write, }; -static const struct hwmon_channel_info *sch5627_info[] = { +static const struct hwmon_channel_info * const sch5627_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT, diff --git a/drivers/hwmon/sfctemp.c b/drivers/hwmon/sfctemp.c new file mode 100644 index 000000000000..fb1da93383d7 --- /dev/null +++ b/drivers/hwmon/sfctemp.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk> + * Copyright (C) 2021 Samin Guo <samin.guo@starfivetech.com> + */ + +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/hwmon.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +/* + * TempSensor reset. The RSTN can be de-asserted once the analog core has + * powered up. Trst(min 100ns) + * 0:reset 1:de-assert + */ +#define SFCTEMP_RSTN BIT(0) + +/* + * TempSensor analog core power down. The analog core will be powered up + * Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the + * analog core is powered up. + * 0:power up 1:power down + */ +#define SFCTEMP_PD BIT(1) + +/* + * TempSensor start conversion enable. + * 0:disable 1:enable + */ +#define SFCTEMP_RUN BIT(2) + +/* + * TempSensor conversion value output. + * Temp(C)=DOUT*Y/4094 - K + */ +#define SFCTEMP_DOUT_POS 16 +#define SFCTEMP_DOUT_MSK GENMASK(27, 16) + +/* DOUT to Celcius conversion constants */ +#define SFCTEMP_Y1000 237500L +#define SFCTEMP_Z 4094L +#define SFCTEMP_K1000 81100L + +struct sfctemp { + /* serialize access to hardware register and enabled below */ + struct mutex lock; + void __iomem *regs; + struct clk *clk_sense; + struct clk *clk_bus; + struct reset_control *rst_sense; + struct reset_control *rst_bus; + bool enabled; +}; + +static void sfctemp_power_up(struct sfctemp *sfctemp) +{ + /* make sure we're powered down first */ + writel(SFCTEMP_PD, sfctemp->regs); + udelay(1); + + writel(0, sfctemp->regs); + /* wait t_pu(50us) + t_rst(100ns) */ + usleep_range(60, 200); + + /* de-assert reset */ + writel(SFCTEMP_RSTN, sfctemp->regs); + udelay(1); /* wait t_su(500ps) */ +} + +static void sfctemp_power_down(struct sfctemp *sfctemp) +{ + writel(SFCTEMP_PD, sfctemp->regs); +} + +static void sfctemp_run(struct sfctemp *sfctemp) +{ + writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs); + udelay(1); +} + +static void sfctemp_stop(struct sfctemp *sfctemp) +{ + writel(SFCTEMP_RSTN, sfctemp->regs); +} + +static int sfctemp_enable(struct sfctemp *sfctemp) +{ + int ret = 0; + + mutex_lock(&sfctemp->lock); + if (sfctemp->enabled) + goto done; + + ret = clk_prepare_enable(sfctemp->clk_bus); + if (ret) + goto err; + ret = reset_control_deassert(sfctemp->rst_bus); + if (ret) + goto err_disable_bus; + + ret = clk_prepare_enable(sfctemp->clk_sense); + if (ret) + goto err_assert_bus; + ret = reset_control_deassert(sfctemp->rst_sense); + if (ret) + goto err_disable_sense; + + sfctemp_power_up(sfctemp); + sfctemp_run(sfctemp); + sfctemp->enabled = true; +done: + mutex_unlock(&sfctemp->lock); + return ret; + +err_disable_sense: + clk_disable_unprepare(sfctemp->clk_sense); +err_assert_bus: + reset_control_assert(sfctemp->rst_bus); +err_disable_bus: + clk_disable_unprepare(sfctemp->clk_bus); +err: + mutex_unlock(&sfctemp->lock); + return ret; +} + +static int sfctemp_disable(struct sfctemp *sfctemp) +{ + mutex_lock(&sfctemp->lock); + if (!sfctemp->enabled) + goto done; + + sfctemp_stop(sfctemp); + sfctemp_power_down(sfctemp); + reset_control_assert(sfctemp->rst_sense); + clk_disable_unprepare(sfctemp->clk_sense); + reset_control_assert(sfctemp->rst_bus); + clk_disable_unprepare(sfctemp->clk_bus); + sfctemp->enabled = false; +done: + mutex_unlock(&sfctemp->lock); + return 0; +} + +static void sfctemp_disable_action(void *data) +{ + sfctemp_disable(data); +} + +static int sfctemp_convert(struct sfctemp *sfctemp, long *val) +{ + int ret; + + mutex_lock(&sfctemp->lock); + if (!sfctemp->enabled) { + ret = -ENODATA; + goto out; + } + + /* calculate temperature in milli Celcius */ + *val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS) + * SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000; + + ret = 0; +out: + mutex_unlock(&sfctemp->lock); + return ret; +} + +static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + return 0644; + case hwmon_temp_input: + return 0444; + default: + return 0; + } + default: + return 0; + } +} + +static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct sfctemp *sfctemp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + *val = sfctemp->enabled; + return 0; + case hwmon_temp_input: + return sfctemp_convert(sfctemp, val); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + struct sfctemp *sfctemp = dev_get_drvdata(dev); + + switch (type) { + case hwmon_temp: + switch (attr) { + case hwmon_temp_enable: + if (val == 0) + return sfctemp_disable(sfctemp); + if (val == 1) + return sfctemp_enable(sfctemp); + return -EINVAL; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static const struct hwmon_channel_info *sfctemp_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops sfctemp_hwmon_ops = { + .is_visible = sfctemp_is_visible, + .read = sfctemp_read, + .write = sfctemp_write, +}; + +static const struct hwmon_chip_info sfctemp_chip_info = { + .ops = &sfctemp_hwmon_ops, + .info = sfctemp_info, +}; + +static int sfctemp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device *hwmon_dev; + struct sfctemp *sfctemp; + int ret; + + sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL); + if (!sfctemp) + return -ENOMEM; + + dev_set_drvdata(dev, sfctemp); + mutex_init(&sfctemp->lock); + + sfctemp->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(sfctemp->regs)) + return PTR_ERR(sfctemp->regs); + + sfctemp->clk_sense = devm_clk_get(dev, "sense"); + if (IS_ERR(sfctemp->clk_sense)) + return dev_err_probe(dev, PTR_ERR(sfctemp->clk_sense), + "error getting sense clock\n"); + + sfctemp->clk_bus = devm_clk_get(dev, "bus"); + if (IS_ERR(sfctemp->clk_bus)) + return dev_err_probe(dev, PTR_ERR(sfctemp->clk_bus), + "error getting bus clock\n"); + + sfctemp->rst_sense = devm_reset_control_get_exclusive(dev, "sense"); + if (IS_ERR(sfctemp->rst_sense)) + return dev_err_probe(dev, PTR_ERR(sfctemp->rst_sense), + "error getting sense reset\n"); + + sfctemp->rst_bus = devm_reset_control_get_exclusive(dev, "bus"); + if (IS_ERR(sfctemp->rst_bus)) + return dev_err_probe(dev, PTR_ERR(sfctemp->rst_bus), + "error getting busreset\n"); + + ret = reset_control_assert(sfctemp->rst_sense); + if (ret) + return dev_err_probe(dev, ret, "error asserting sense reset\n"); + + ret = reset_control_assert(sfctemp->rst_bus); + if (ret) + return dev_err_probe(dev, ret, "error asserting bus reset\n"); + + ret = devm_add_action(dev, sfctemp_disable_action, sfctemp); + if (ret) + return ret; + + ret = sfctemp_enable(sfctemp); + if (ret) + return dev_err_probe(dev, ret, "error enabling temperature sensor\n"); + + hwmon_dev = devm_hwmon_device_register_with_info(dev, "sfctemp", sfctemp, + &sfctemp_chip_info, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static const struct of_device_id sfctemp_of_match[] = { + { .compatible = "starfive,jh7100-temp" }, + { .compatible = "starfive,jh7110-temp" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, sfctemp_of_match); + +static struct platform_driver sfctemp_driver = { + .probe = sfctemp_probe, + .driver = { + .name = "sfctemp", + .of_match_table = sfctemp_of_match, + }, +}; +module_platform_driver(sfctemp_driver); + +MODULE_AUTHOR("Emil Renner Berthing"); +MODULE_DESCRIPTION("StarFive JH71x0 temperature sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 13e042927bf8..5bbe09135ab9 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -214,7 +214,7 @@ static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *sht4x_info[] = { +static const struct hwmon_channel_info * const sht4x_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT), diff --git a/drivers/hwmon/sl28cpld-hwmon.c b/drivers/hwmon/sl28cpld-hwmon.c index 9ce4899a81a5..e020f25c9300 100644 --- a/drivers/hwmon/sl28cpld-hwmon.c +++ b/drivers/hwmon/sl28cpld-hwmon.c @@ -67,7 +67,7 @@ static int sl28cpld_hwmon_read(struct device *dev, return 0; } -static const struct hwmon_channel_info *sl28cpld_hwmon_info[] = { +static const struct hwmon_channel_info * const sl28cpld_hwmon_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), NULL }; diff --git a/drivers/hwmon/smpro-hwmon.c b/drivers/hwmon/smpro-hwmon.c index a76c49dd8438..d320adbd47f4 100644 --- a/drivers/hwmon/smpro-hwmon.c +++ b/drivers/hwmon/smpro-hwmon.c @@ -385,7 +385,7 @@ static umode_t smpro_is_visible(const void *data, enum hwmon_sensor_types type, return 0444; } -static const struct hwmon_channel_info *smpro_info[] = { +static const struct hwmon_channel_info * const smpro_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT, diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c index 04fd8505e5d6..d640904939cd 100644 --- a/drivers/hwmon/sparx5-temp.c +++ b/drivers/hwmon/sparx5-temp.c @@ -86,7 +86,7 @@ static umode_t s5_is_visible(const void *_data, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *s5_info[] = { +static const struct hwmon_channel_info * const s5_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), NULL diff --git a/drivers/hwmon/sy7636a-hwmon.c b/drivers/hwmon/sy7636a-hwmon.c index 6dd9c2a0f0e0..ed110884786b 100644 --- a/drivers/hwmon/sy7636a-hwmon.c +++ b/drivers/hwmon/sy7636a-hwmon.c @@ -52,7 +52,7 @@ static const struct hwmon_ops sy7636a_hwmon_ops = { .read = sy7636a_read, }; -static const struct hwmon_channel_info *sy7636a_info[] = { +static const struct hwmon_channel_info * const sy7636a_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), NULL diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 2bf496a62206..e271556efe0b 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -141,7 +141,7 @@ static umode_t tmp102_is_visible(const void *data, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *tmp102_info[] = { +static const struct hwmon_channel_info * const tmp102_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c index 56d5cbf36a45..d257bb91fc69 100644 --- a/drivers/hwmon/tmp103.c +++ b/drivers/hwmon/tmp103.c @@ -119,7 +119,7 @@ static umode_t tmp103_is_visible(const void *data, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *tmp103_info[] = { +static const struct hwmon_channel_info * const tmp103_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index acb4ba750b09..43784c289a9e 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -272,7 +272,7 @@ static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type, } } -static const struct hwmon_channel_info *tmp108_info[] = { +static const struct hwmon_channel_info * const tmp108_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c index 7814f39bd1a3..9213a493a590 100644 --- a/drivers/hwmon/tmp464.c +++ b/drivers/hwmon/tmp464.c @@ -589,7 +589,7 @@ static const struct hwmon_ops tmp464_ops = { .write = tmp464_write, }; -static const struct hwmon_channel_info *tmp464_info[] = { +static const struct hwmon_channel_info * const tmp464_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 7d5f7441aceb..0693eaee054f 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -491,7 +491,7 @@ static umode_t tmp51x_is_visible(const void *_data, return 0; } -static const struct hwmon_channel_info *tmp51x_info[] = { +static const struct hwmon_channel_info * const tmp51x_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST, diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c index 68c77c493270..85a75f551148 100644 --- a/drivers/hwmon/tps23861.c +++ b/drivers/hwmon/tps23861.c @@ -341,7 +341,7 @@ static int tps23861_read_string(struct device *dev, return 0; } -static const struct hwmon_channel_info *tps23861_info[] = { +static const struct hwmon_channel_info * const tps23861_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 4a5e911d26eb..fcd4be7a5a85 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -195,12 +195,6 @@ struct vt1211_data { /* VT1211 logical device numbers */ #define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */ -static inline void superio_outb(int sio_cip, int reg, int val) -{ - outb(reg, sio_cip); - outb(val, sio_cip + 1); -} - static inline int superio_inb(int sio_cip, int reg) { outb(reg, sio_cip); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 939d4c35e713..fe960c0a624f 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1640,7 +1640,7 @@ static const struct hwmon_ops w83627ehf_ops = { .write = w83627ehf_write, }; -static const struct hwmon_channel_info *w83627ehf_info[] = { +static const struct hwmon_channel_info * const w83627ehf_info[] = { HWMON_CHANNEL_INFO(fan, HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN, HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN, diff --git a/drivers/hwmon/w83773g.c b/drivers/hwmon/w83773g.c index 88d11dc5feb9..8dbcd05abd9a 100644 --- a/drivers/hwmon/w83773g.c +++ b/drivers/hwmon/w83773g.c @@ -233,7 +233,7 @@ static umode_t w83773_is_visible(const void *data, enum hwmon_sensor_types type, return 0; } -static const struct hwmon_channel_info *w83773_info[] = { +static const struct hwmon_channel_info * const w83773_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(temp, |