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 | |
parent | 3361e9a4ea957b09c5d6242613360c415194dbb5 (diff) | |
parent | 1c19ac768b8eeb0304c4ed7db66c2bb89c6ad226 (diff) | |
download | linux-4173cf6fb6b7d1b4569cca08af318c4561356fb5.tar.gz linux-4173cf6fb6b7d1b4569cca08af318c4561356fb5.tar.bz2 linux-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
...
110 files changed, 2126 insertions, 572 deletions
diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt index 4509e688623a..48886f0ce415 100644 --- a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt @@ -1,67 +1 @@ -Bindings for a fan connected to the PWM lines - -Required properties: -- compatible : "pwm-fan" -- pwms : the PWM that is used to control the PWM fan -- cooling-levels : PWM duty cycle values in a range from 0 to 255 - which correspond to thermal cooling states - -Optional properties: -- fan-supply : phandle to the regulator that provides power to the fan -- interrupts : This contains an interrupt specifier for each fan - tachometer output connected to an interrupt source. - The output signal must generate a defined number of - interrupts per fan revolution, which require that - it must be self resetting edge interrupts. See - interrupt-controller/interrupts.txt for the format. -- pulses-per-revolution : define the number of pulses per fan revolution for - each tachometer input as an integer (default is 2 - interrupts per revolution). The value must be - greater than zero. - -Example: - fan0: pwm-fan { - compatible = "pwm-fan"; - #cooling-cells = <2>; - pwms = <&pwm 0 10000 0>; - cooling-levels = <0 102 170 230>; - }; - - thermal-zones { - cpu_thermal: cpu-thermal { - thermal-sensors = <&tmu 0>; - polling-delay-passive = <0>; - polling-delay = <0>; - trips { - cpu_alert1: cpu-alert1 { - temperature = <100000>; /* millicelsius */ - hysteresis = <2000>; /* millicelsius */ - type = "passive"; - }; - }; - cooling-maps { - map0 { - trip = <&cpu_alert1>; - cooling-device = <&fan0 0 1>; - }; - }; - }; - -Example 2: - fan0: pwm-fan { - compatible = "pwm-fan"; - pwms = <&pwm 0 40000 0>; - fan-supply = <®_fan>; - interrupt-parent = <&gpio5>; - interrupts = <1 IRQ_TYPE_EDGE_FALLING>; - pulses-per-revolution = <2>; - }; - -Example 3: - fan0: pwm-fan { - compatible = "pwm-fan"; - pwms = <&pwm1 0 25000 0>; - interrupts-extended = <&gpio1 1 IRQ_TYPE_EDGE_FALLING>, - <&gpio2 5 IRQ_TYPE_EDGE_FALLING>; - pulses-per-revolution = <2>, <1>; - }; +This file has moved to pwm-fan.yaml. diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml new file mode 100644 index 000000000000..4e5abf7580cc --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/pwm-fan.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Fan connected to PWM lines + +maintainers: + - Jean Delvare <jdelvare@suse.com> + - Guenter Roeck <linux@roeck-us.net> + +properties: + compatible: + const: pwm-fan + + cooling-levels: + description: PWM duty cycle values corresponding to thermal cooling states. + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + maximum: 255 + + fan-supply: + description: Phandle to the regulator that provides power to the fan. + + interrupts: + description: + This contains an interrupt specifier for each fan tachometer output + connected to an interrupt source. The output signal must generate a + defined number of interrupts per fan revolution, which require that + it must be self resetting edge interrupts. + maxItems: 1 + + pulses-per-revolution: + description: + Define the number of pulses per fan revolution for each tachometer + input as an integer. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 4 + default: 2 + + pwms: + description: The PWM that is used to control the fan. + maxItems: 1 + + "#cooling-cells": true + +required: + - compatible + - pwms + +additionalProperties: false + +examples: + - | + pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <0 102 170 230>; + pwms = <&pwm 0 10000 0>; + #cooling-cells = <2>; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + thermal-sensors = <&tmu 0>; + polling-delay-passive = <0>; + polling-delay = <0>; + + trips { + cpu_alert1: cpu-alert1 { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu_alert1>; + cooling-device = <&fan0 0 1>; + }; + }; + }; + }; + + - | + #include <dt-bindings/interrupt-controller/irq.h> + + pwm-fan { + compatible = "pwm-fan"; + pwms = <&pwm 0 40000 0>; + fan-supply = <®_fan>; + interrupt-parent = <&gpio5>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + pulses-per-revolution = <2>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml b/Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml new file mode 100644 index 000000000000..f5b34528928d --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/starfive,jh71x0-temp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JH71x0 Temperature Sensor + +maintainers: + - Emil Renner Berthing <kernel@esmil.dk> + +description: | + StarFive Technology Co. JH71x0 embedded temperature sensor + +properties: + compatible: + enum: + - starfive,jh7100-temp + - starfive,jh7110-temp + + reg: + maxItems: 1 + + clocks: + minItems: 2 + maxItems: 2 + + clock-names: + items: + - const: "sense" + - const: "bus" + + '#thermal-sensor-cells': + const: 0 + + resets: + minItems: 2 + maxItems: 2 + + reset-names: + items: + - const: "sense" + - const: "bus" + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - reset-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/starfive-jh7100.h> + #include <dt-bindings/reset/starfive-jh7100.h> + + temperature-sensor@124a0000 { + compatible = "starfive,jh7100-temp"; + reg = <0x124a0000 0x10000>; + clocks = <&clkgen JH7100_CLK_TEMP_SENSE>, + <&clkgen JH7100_CLK_TEMP_APB>; + clock-names = "sense", "bus"; + #thermal-sensor-cells = <0>; + resets = <&rstgen JH7100_RSTN_TEMP_SENSE>, + <&rstgen JH7100_RSTN_TEMP_APB>; + reset-names = "sense", "bus"; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml index 47af97bb4ced..8648877d2d01 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml @@ -57,6 +57,10 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 enum: [1, 2, 4, 8] + vs-supply: + description: phandle to the regulator that provides the VS supply typically + in range from 2.7 V to 5.5 V. + required: - compatible - reg @@ -73,5 +77,6 @@ examples: compatible = "ti,ina220"; reg = <0x44>; shunt-resistor = <1000>; + vs-supply = <&vdd_3v0>; }; }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,tmp464.yaml b/Documentation/devicetree/bindings/hwmon/ti,tmp464.yaml index e7493e25a7d2..f9c00cbb2806 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,tmp464.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,tmp464.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: TMP464 and TMP468 temperature sensors maintainers: - - Agathe Porte <agathe.porte@nokia.com> + - Guenter Roeck <linux@roeck-us.net> description: | ±0.0625°C Remote and Local temperature sensor diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index 6f482a254a1d..246863a9bc7e 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -29,6 +29,8 @@ properties: compatible: items: - enum: + # Acbel fsg032 power supply + - acbel,fsg032 # SMBus/I2C Digital Temperature Sensor in 6-Pin SOT with SMBus Alert and Over Temperature Pin - ad,ad7414 # ADM9240: Complete System Hardware Monitor for uProcessor-Based Systems diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index c3fe8c136721..3e29fbd53b6d 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -37,6 +37,8 @@ patternProperties: description: Abracon Corporation "^abt,.*": description: ShenZhen Asia Better Technology Ltd. + "^acbel,.*": + description: Acbel Polytech Inc. "^acer,.*": description: Acer Inc. "^acme,.*": diff --git a/Documentation/hwmon/acbel-fsg032.rst b/Documentation/hwmon/acbel-fsg032.rst new file mode 100644 index 000000000000..f1684b95e103 --- /dev/null +++ b/Documentation/hwmon/acbel-fsg032.rst @@ -0,0 +1,80 @@ +Kernel driver acbel-fsg032 +========================== + +Supported chips: + + * ACBEL FSG032-00xG power supply. + +Author: Lakshmi Yadlapati <lakshmiy@us.ibm.com> + +Description +----------- + +This driver supports ACBEL FSG032-00xG Power Supply. This driver +is a client to the core PMBus driver. + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + +Sysfs entries +------------- + +The following attributes are supported: + +======================= ====================================================== +curr1_crit Critical maximum current. +curr1_crit_alarm Input current critical alarm. +curr1_input Measured output current. +curr1_label "iin" +curr1_max Maximum input current. +curr1_max_alarm Maximum input current high alarm. +curr1_rated_max Maximum rated input current. +curr2_crit Critical maximum current. +curr2_crit_alarm Output current critical alarm. +curr2_input Measured output current. +curr2_label "iout1" +curr2_max Maximum output current. +curr2_max_alarm Output current high alarm. +curr2_rated_max Maximum rated output current. + + +fan1_alarm Fan 1 warning. +fan1_fault Fan 1 fault. +fan1_input Fan 1 speed in RPM. +fan1_target Set fan speed reference. + +in1_alarm Input voltage under-voltage alarm. +in1_input Measured input voltage. +in1_label "vin" +in1_rated_max Maximum rated input voltage. +in1_rated_min Minimum rated input voltage. +in2_crit Critical maximum output voltage. +in2_crit_alarm Output voltage critical high alarm. +in2_input Measured output voltage. +in2_label "vout1" +in2_lcrit Critical minimum output voltage. +in2_lcrit_alarm Output voltage critical low alarm. +in2_rated_max Maximum rated output voltage. +in2_rated_min Minimum rated output voltage. + +power1_alarm Input fault or alarm. +power1_input Measured input power. +power1_label "pin" +power1_max Input power limit. +power1_rated_max Maximum rated input power. +power2_crit Critical output power limit. +power2_crit_alarm Output power crit alarm limit exceeded. +power2_input Measured output power. +power2_label "pout" +power2_max Output power limit. +power2_max_alarm Output power high alarm. +power2_rated_max Maximum rated output power. + +temp[1-3]_input Measured temperature. +temp[1-2]_max Maximum temperature. +temp[1-3]_rated_max Temperature high alarm. +======================= ====================================================== diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 7d0d015b1a52..14b37851af0c 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -12,6 +12,7 @@ Supported devices: * Aquacomputer Octo fan controller * Aquacomputer Quadro fan controller * Aquacomputer High Flow Next sensor +* Aquacomputer Aquastream XT watercooling pump * Aquacomputer Aquastream Ultimate watercooling pump * Aquacomputer Poweradjust 3 fan controller @@ -25,7 +26,8 @@ communicate through proprietary USB HID protocols. The Aquaero devices expose eight physical, eight virtual and four calculated virtual temperature sensors, as well as two flow sensors. The fans expose their -speed (in RPM), power, voltage and current. +speed (in RPM), power, voltage and current. Temperature offsets and fan speeds +can be controlled. For the D5 Next pump, available sensors are pump and fan speed, power, voltage and current, as well as coolant temperature and eight virtual temp sensors. Also @@ -55,6 +57,10 @@ The High Flow Next exposes +5V voltages, water quality, conductivity and flow re A temperature sensor can be connected to it, in which case it provides its reading and an estimation of the dissipated/absorbed power in the liquid cooling loop. +The Aquastream XT pump exposes temperature readings for the coolant, external sensor +and fan IC. It also exposes pump and fan speeds (in RPM), voltages, as well as pump +current. + The Aquastream Ultimate pump exposes coolant temp and an external temp sensor, along with speed, power, voltage and current of both the pump and optionally connected fan. It also exposes pressure and flow speed readings. @@ -75,7 +81,7 @@ Sysfs entries ================ ============================================================== temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius) -temp[1-4]_offset Temperature sensor correction offset (in millidegrees Celsius) +temp[1-8]_offset Temperature sensor correction offset (in millidegrees Celsius) fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h) fan5_pulses Quadro flow sensor pulses power[1-8]_input Pump/fan power (in micro Watts) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index a4039f2f9ca4..c92c1d3839e4 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -8,6 +8,7 @@ Supported boards: * PRIME X570-PRO * Pro WS X570-ACE * ProArt X570-CREATOR WIFI + * ProArt B550-CREATOR * ROG CROSSHAIR VIII DARK HERO * ROG CROSSHAIR VIII HERO (WI-FI) * ROG CROSSHAIR VIII FORMULA @@ -21,6 +22,7 @@ Supported boards: * ROG STRIX X570-E GAMING WIFI II * ROG STRIX X570-F GAMING * ROG STRIX X570-I GAMING + * ROG STRIX Z390-F GAMING * ROG STRIX Z690-A GAMING WIFI D4 * ROG ZENITH II EXTREME * ROG ZENITH II EXTREME ALPHA diff --git a/Documentation/hwmon/ftsteutates.rst b/Documentation/hwmon/ftsteutates.rst index b3bfec36661d..2abd16830c99 100644 --- a/Documentation/hwmon/ftsteutates.rst +++ b/Documentation/hwmon/ftsteutates.rst @@ -36,7 +36,7 @@ correct path to the alarm file:: echo 0 >XXXX_alarm -Specification of the chip can be found here: +Specifications of the chip can be found at the `Kontron FTP Server <http://ftp.kontron.com/>`_ (username = "anonymous", no password required) +under the following path: -- ftp://ftp.ts.fujitsu.com/pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/BMC-Teutates_Specification_V1.21.pdf -- ftp://ftp.ts.fujitsu.com/pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/Fujitsu_mainboards-1-Sensors_HowTo-en-US.pdf + /Services/Software_Tools/Linux_SystemMonitoring_Watchdog_GPIO/BMC-Teutates_Specification_V1.21.pdf diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst index 5451a6d4c874..c2d1e0299d8d 100644 --- a/Documentation/hwmon/hwmon-kernel-api.rst +++ b/Documentation/hwmon/hwmon-kernel-api.rst @@ -19,21 +19,11 @@ also read Documentation/hwmon/submitting-patches.rst. The API ------- -Each hardware monitoring driver must #include <linux/hwmon.h> and, in most +Each hardware monitoring driver must #include <linux/hwmon.h> and, in some cases, <linux/hwmon-sysfs.h>. linux/hwmon.h declares the following register/unregister functions:: struct device * - hwmon_device_register_with_groups(struct device *dev, const char *name, - void *drvdata, - const struct attribute_group **groups); - - struct device * - devm_hwmon_device_register_with_groups(struct device *dev, - const char *name, void *drvdata, - const struct attribute_group **groups); - - struct device * hwmon_device_register_with_info(struct device *dev, const char *name, void *drvdata, const struct hwmon_chip_info *info, @@ -54,46 +44,30 @@ register/unregister functions:: char *devm_hwmon_sanitize_name(struct device *dev, const char *name); -hwmon_device_register_with_groups registers a hardware monitoring device. -The first parameter of this function is a pointer to the parent device. -The name parameter is a pointer to the hwmon device name. The registration -function will create a name sysfs attribute pointing to this name. -The drvdata parameter is the pointer to the local driver data. -hwmon_device_register_with_groups will attach this pointer to the newly -allocated hwmon device. The pointer can be retrieved by the driver using -dev_get_drvdata() on the hwmon device pointer. The groups parameter is -a pointer to a list of sysfs attribute groups. The list must be NULL terminated. -hwmon_device_register_with_groups creates the hwmon device with name attribute -as well as all sysfs attributes attached to the hwmon device. -This function returns a pointer to the newly created hardware monitoring device -or PTR_ERR for failure. - -devm_hwmon_device_register_with_groups is similar to -hwmon_device_register_with_groups. However, it is device managed, meaning the -hwmon device does not have to be removed explicitly by the removal function. - -hwmon_device_register_with_info is the most comprehensive and preferred means -to register a hardware monitoring device. It creates the standard sysfs -attributes in the hardware monitoring core, letting the driver focus on reading -from and writing to the chip instead of having to bother with sysfs attributes. -The parent device parameter as well as the chip parameter must not be NULL. Its -parameters are described in more detail below. +hwmon_device_register_with_info registers a hardware monitoring device. +It creates the standard sysfs attributes in the hardware monitoring core, +letting the driver focus on reading from and writing to the chip instead +of having to bother with sysfs attributes. The parent device parameter +as well as the chip parameter must not be NULL. Its parameters are described +in more detail below. devm_hwmon_device_register_with_info is similar to hwmon_device_register_with_info. However, it is device managed, meaning the hwmon device does not have to be removed explicitly by the removal function. +All other hardware monitoring device registration functions are deprecated +and must not be used in new drivers. + hwmon_device_unregister deregisters a registered hardware monitoring device. The parameter of this function is the pointer to the registered hardware monitoring device structure. This function must be called from the driver remove function if the hardware monitoring device was registered with -hwmon_device_register_with_groups or hwmon_device_register_with_info. +hwmon_device_register_with_info. devm_hwmon_device_unregister does not normally have to be called. It is only needed for error handling, and only needed if the driver probe fails after -the call to devm_hwmon_device_register_with_groups or -hwmon_device_register_with_info and if the automatic (device managed) -removal would be too late. +the call to hwmon_device_register_with_info and if the automatic (device +managed) removal would be too late. All supported hwmon device registration functions only accept valid device names. Device names including invalid characters (whitespace, '*', or '-') @@ -133,7 +107,7 @@ The hwmon_chip_info structure looks as follows:: struct hwmon_chip_info { const struct hwmon_ops *ops; - const struct hwmon_channel_info **info; + const struct hwmon_channel_info * const *info; }; It contains the following fields: @@ -229,7 +203,7 @@ register (HWMON_T_MAX) as well as a maximum temperature hysteresis register .config = lm75_temp_config, }; - static const struct hwmon_channel_info *lm75_info[] = { + static const struct hwmon_channel_info * const lm75_info[] = { &lm75_chip, &lm75_temp, NULL @@ -238,7 +212,7 @@ register (HWMON_T_MAX) as well as a maximum temperature hysteresis register The HWMON_CHANNEL_INFO() macro can and should be used when possible. With this macro, the above example can be simplified to - 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, @@ -351,11 +325,9 @@ Return value: Driver-provided sysfs attributes -------------------------------- -If the hardware monitoring device is registered with -hwmon_device_register_with_info or devm_hwmon_device_register_with_info, -it is most likely not necessary to provide sysfs attributes. Only additional -non-standard sysfs attributes need to be provided when one of those registration -functions is used. +In most situations it should not be necessary for a driver to provide sysfs +attributes since the hardware monitoring core creates those internally. +Only additional non-standard sysfs attributes need to be provided. The header file linux/hwmon-sysfs.h provides a number of useful macros to declare and use hardware monitoring sysfs attributes. diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index f1fe75f596a5..fa1208c62855 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -22,6 +22,7 @@ Hardware Monitoring Kernel Drivers abituguru abituguru3 + acbel-fsg032 acpi_power_meter ad7314 adc128d818 @@ -184,6 +185,7 @@ Hardware Monitoring Kernel Drivers sch5627 sch5636 scpi-hwmon + sfctemp sht15 sht21 sht3x diff --git a/Documentation/hwmon/sfctemp.rst b/Documentation/hwmon/sfctemp.rst new file mode 100644 index 000000000000..9fbd5bb1f356 --- /dev/null +++ b/Documentation/hwmon/sfctemp.rst @@ -0,0 +1,33 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver sfctemp +===================== + +Supported chips: + - StarFive JH7100 + - StarFive JH7110 + +Authors: + - Emil Renner Berthing <kernel@esmil.dk> + +Description +----------- + +This driver adds support for reading the built-in temperature sensor on the +JH7100 and JH7110 RISC-V SoCs by StarFive Technology Co. Ltd. + +``sysfs`` interface +------------------- + +The temperature sensor can be enabled, disabled and queried via the standard +hwmon interface in sysfs under ``/sys/class/hwmon/hwmonX`` for some value of +``X``: + +================ ==== ============================================= +Name Perm Description +================ ==== ============================================= +temp1_enable RW Enable or disable temperature sensor. + Automatically enabled by the driver, + but may be disabled to save power. +temp1_input RO Temperature reading in milli-degrees Celsius. +================ ==== ============================================= diff --git a/Documentation/hwmon/sysfs-interface.rst b/Documentation/hwmon/sysfs-interface.rst index 209626fb2405..f76e9f8cc1ad 100644 --- a/Documentation/hwmon/sysfs-interface.rst +++ b/Documentation/hwmon/sysfs-interface.rst @@ -201,7 +201,7 @@ PWM Pulse width modulation fan control. `pwm[1-*]_enable` - Fan speed control method: + Fan speed control method. `pwm[1-*]_mode` direct current or pulse-width modulation. diff --git a/MAINTAINERS b/MAINTAINERS index c16754961f13..ab13812f591d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18944,6 +18944,14 @@ S: Supported F: Documentation/networking/devlink/sfc.rst F: drivers/net/ethernet/sfc/ +SFCTEMP HWMON DRIVER +M: Emil Renner Berthing <kernel@esmil.dk> +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml +F: Documentation/hwmon/sfctemp.rst +F: drivers/hwmon/sfctemp.c + SFF/SFP/SFP+ MODULE SUPPORT M: Russell King <linux@armlinux.org.uk> L: netdev@vger.kernel.org @@ -21105,7 +21113,6 @@ F: Documentation/hwmon/tmp401.rst F: drivers/hwmon/tmp401.c TMP464 HARDWARE MONITOR DRIVER -M: Agathe Porte <agathe.porte@nokia.com> M: Guenter Roeck <linux@roeck-us.net> L: linux-hwmon@vger.kernel.org S: Maintained 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, diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index c1b62384b6ee..492dd27a5dd8 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -430,7 +430,7 @@ struct hwmon_channel_info { */ struct hwmon_chip_info { const struct hwmon_ops *ops; - const struct hwmon_channel_info **info; + const struct hwmon_channel_info * const *info; }; /* hwmon_device_register() is deprecated */ |