Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'hwmon-for-v6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:
"New drivers:

- Kontron SMARC-sAM67

- GPD device sensors

- MP29502

- MP2869, MP29608, MP29612 and MP29816 series

Added chip support to existing drivers:

- asus-ec-sensors:
Add B650E-I
Add PRIME Z270-A
Add Pro WS WRX90E-SAGE SE
Add ROG STRIX X670E-E GAMING WIFI
Add ROG STRIX X870-I GAMING WIFI
Add ROG STRIX X870E-E GAMING WIFI
Add ROG STRIX Z690-E GAMING WIFI
Add ROG STRIX Z790E GAMING WIFI II
Add STRIX B850-I GAMING WIFI
Add TUF GAMING X670E PLUS WIFI
Add X670E-I GAMING WIFI
Add Z790-I GAMING WIFI

- dell-smm: Add support for Dell OptiPlex 7040

- ina238: Major cleanup, and
Add support for INA700
Add support for INA780

- k10temp:
Add device ID for Strix Halo
Add support for AMD Family 1Ah-based models

- lenovo-ec-sensors: Update P8 supprt

- lm75: Add NXP P3T1750 support

- pmbus/adm1275: Add sq24905c support

- pmbus/isl68137: Add support for Renesas RAA228244 and RAA228246

- pmbus/mp5990: Add support for MP5998

- sht21: Add support for SHT20, SHT25

- sl28cpld: Add sa67mcu compatible

Other notable changes:

- core:
Handle locking internally
Introduce 64-bit energy attribute support

- cros_ec: Register into thermal framework, improve PWM control

- lm75: allow interrupt for ti,tmp75

- mlxreg-fan: Add support for new flavour of capability register

- sbtsi_temp: AMD CPU extended temperature range support

- sht21: Add devicetree support

Various other minor improvements and fixes"

* tag 'hwmon-for-v6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (86 commits)
dt-bindings: hwmon: (lm75) allow interrupt for ti,tmp75
hwmon: (mlxreg-fan) Add support for new flavour of capability register
hwmon: (mlxreg-fan) Separate methods of fan setting coming from different subsystems
hwmon: (cros_ec) register fans into thermal framework cooling devices
hwmon: (cros_ec) add PWM control over fans
platform/chrome: update pwm fan control host commands
hwmon: add SMARC-sAM67 support
dt-bindings: hwmon: sl28cpld: add sa67mcu compatible
hwmon: (asus-ec-sensors) add TUF GAMING X670E PLUS WIFI
hwmon: (dell-smm) Add support for Dell OptiPlex 7040
hwmon: (dell-smm) Add support for automatic fan mode
hwmon: (gpd-fan) complete Kconfig dependencies
hwmon: (asus-ec-sensors) increase timeout for locking ACPI mutex
hwmon: (asus-ec-sensors) add ROG STRIX X870E-E GAMING WIFI
hwmon: (dell-smm) Move clamping of fan speed out of i8k_set_fan()
hwmon: (dell-smm) Remove Dell Precision 490 custom config data
hwmon: (asus-ec-sensors) add ROG STRIX X670E-E GAMING WIFI
hwmon: (gpd-fan) Fix range check for pwm input
hwmon: (pmbus/mp5990) add support for MP5998
dt-bindings: trivial-devices: add mps,mp5998
...

+4283 -594
+9
Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml
··· 18 18 Datasheets: 19 19 https://www.analog.com/en/products/adm1294.html 20 20 21 + The SQ24905C is also a Hot-swap controller compatibility to the ADM1278, 22 + the PMBUS_MFR_MODEL is MC09C 23 + 24 + Datasheets: 25 + https://www.silergy.com/ 26 + download/downloadFile?id=5669&type=product&ftype=note 27 + 21 28 properties: 22 29 compatible: 23 30 enum: ··· 37 30 - adi,adm1281 38 31 - adi,adm1293 39 32 - adi,adm1294 33 + - silergy,mc09c 40 34 41 35 reg: 42 36 maxItems: 1 ··· 104 96 - adi,adm1281 105 97 - adi,adm1293 106 98 - adi,adm1294 99 + - silergy,mc09c 107 100 then: 108 101 properties: 109 102 adi,volt-curr-sample-average:
+1
Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
··· 16 16 properties: 17 17 compatible: 18 18 enum: 19 + - kontron,sa67mcu-hwmon 19 20 - kontron,sl28cpld-fan 20 21 21 22 reg:
+30
Documentation/devicetree/bindings/hwmon/lantiq,cputemp.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/hwmon/lantiq,cputemp.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Lantiq cpu temperature sensor 8 + 9 + maintainers: 10 + - Florian Eckert <fe@dev.tdt.de> 11 + 12 + properties: 13 + compatible: 14 + const: lantiq,cputemp 15 + 16 + reg: 17 + maxItems: 1 18 + 19 + required: 20 + - compatible 21 + - reg 22 + 23 + additionalProperties: false 24 + 25 + examples: 26 + - | 27 + cputemp@103040 { 28 + compatible = "lantiq,cputemp"; 29 + reg = <0x103040 0x4>; 30 + };
+2
Documentation/devicetree/bindings/hwmon/lm75.yaml
··· 28 28 - maxim,max31725 29 29 - maxim,max31726 30 30 - maxim,mcp980x 31 + - nxp,p3t1750 31 32 - nxp,p3t1755 32 33 - nxp,pct2075 33 34 - st,stds75 ··· 70 69 - ti,tmp100 71 70 - ti,tmp101 72 71 - ti,tmp112 72 + - ti,tmp75 73 73 then: 74 74 properties: 75 75 interrupts: false
-10
Documentation/devicetree/bindings/hwmon/ltq-cputemp.txt
··· 1 - Lantiq cpu temperature sensor 2 - 3 - Requires node properties: 4 - - compatible value : 5 - "lantiq,cputemp" 6 - 7 - Example: 8 - cputemp@0 { 9 - compatible = "lantiq,cputemp"; 10 - };
+2
Documentation/devicetree/bindings/hwmon/pmbus/isil,isl68137.yaml
··· 54 54 - renesas,raa228004 55 55 - renesas,raa228006 56 56 - renesas,raa228228 57 + - renesas,raa228244 58 + - renesas,raa228246 57 59 - renesas,raa229001 58 60 - renesas,raa229004 59 61 - renesas,raa229621
+9
Documentation/devicetree/bindings/hwmon/pwm-fan.yaml
··· 31 31 it must be self resetting edge interrupts. 32 32 maxItems: 1 33 33 34 + fan-shutdown-percent: 35 + description: 36 + Fan RPM in percent set during shutdown. This is used to keep the fan 37 + running at fixed RPM after the kernel shut down, which is useful on 38 + hardware that does keep heating itself even after the kernel did shut 39 + down, for example from some sort of management core. 40 + minimum: 0 41 + maximum: 100 42 + 34 43 fan-stop-to-start-percent: 35 44 description: 36 45 Minimum fan RPM in percent to start when stopped.
+34
Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
··· 32 32 - ti,ina237 33 33 - ti,ina238 34 34 - ti,ina260 35 + - ti,ina700 36 + - ti,ina780 35 37 36 38 reg: 37 39 maxItems: 1 ··· 116 114 - ti,ina237 117 115 - ti,ina238 118 116 - ti,ina260 117 + - ti,ina700 118 + - ti,ina780 119 119 then: 120 120 properties: 121 121 ti,maximum-expected-current-microamp: false 122 + 123 + - if: 124 + properties: 125 + compatible: 126 + contains: 127 + enum: 128 + - silergy,sy24655 129 + - ti,ina209 130 + - ti,ina219 131 + - ti,ina220 132 + - ti,ina226 133 + - ti,ina230 134 + - ti,ina231 135 + - ti,ina260 136 + - ti,ina700 137 + - ti,ina780 138 + then: 139 + properties: 140 + ti,shunt-gain: false 141 + 142 + - if: 143 + properties: 144 + compatible: 145 + contains: 146 + enum: 147 + - ti,ina700 148 + - ti,ina780 149 + then: 150 + properties: 151 + shunt-resistor: false 122 152 123 153 unevaluatedProperties: false 124 154
+5
Documentation/devicetree/bindings/hwmon/ti,tmp102.yaml
··· 20 20 reg: 21 21 maxItems: 1 22 22 23 + label: 24 + description: 25 + A descriptive name for this channel, like "ambient" or "psu". 26 + 23 27 "#thermal-sensor-cells": 24 28 const: 1 25 29 ··· 49 45 reg = <0x48>; 50 46 interrupt-parent = <&gpio7>; 51 47 interrupts = <16 IRQ_TYPE_LEVEL_LOW>; 48 + label = "somelabel"; 52 49 vcc-supply = <&supply>; 53 50 #thermal-sensor-cells = <1>; 54 51 };
+15
Documentation/devicetree/bindings/trivial-devices.yaml
··· 293 293 - mps,mp2856 294 294 # Monolithic Power Systems Inc. multi-phase controller mp2857 295 295 - mps,mp2857 296 + # Monolithic Power Systems Inc. multi-phase controller mp2869 297 + - mps,mp2869 296 298 # Monolithic Power Systems Inc. multi-phase controller mp2888 297 299 - mps,mp2888 298 300 # Monolithic Power Systems Inc. multi-phase controller mp2891 299 301 - mps,mp2891 302 + # Monolithic Power Systems Inc. multi-phase controller mp29502 303 + - mps,mp29502 304 + # Monolithic Power Systems Inc. multi-phase controller mp29608 305 + - mps,mp29608 306 + # Monolithic Power Systems Inc. multi-phase controller mp29612 307 + - mps,mp29612 308 + # Monolithic Power Systems Inc. multi-phase controller mp29816 309 + - mps,mp29816 300 310 # Monolithic Power Systems Inc. multi-phase controller mp2993 301 311 - mps,mp2993 302 312 # Monolithic Power Systems Inc. hot-swap protection device ··· 315 305 - mps,mp5920 316 306 # Monolithic Power Systems Inc. multi-phase hot-swap controller mp5990 317 307 - mps,mp5990 308 + # Monolithic Power Systems Inc. multi-phase hot-swap controller mp5998 309 + - mps,mp5998 318 310 # Monolithic Power Systems Inc. digital step-down converter mp9941 319 311 - mps,mp9941 320 312 # Temperature sensor with integrated fan control ··· 374 362 # Sensirion low power multi-pixel gas sensor with I2C interface 375 363 - sensirion,sgpc3 376 364 # Sensirion temperature & humidity sensor with I2C interface 365 + - sensirion,sht20 366 + - sensirion,sht21 367 + - sensirion,sht25 377 368 - sensirion,sht4x 378 369 # Sensortek 3 axis accelerometer 379 370 - sensortek,stk8312
+16 -8
Documentation/hwmon/adm1275.rst
··· 67 67 68 68 Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADM1293_1294.pdf 69 69 70 + * Silergy SQ24905C 71 + 72 + Prefix: 'mc09c' 73 + 74 + Addresses scanned: - 75 + 76 + Datasheet: https://www.silergy.com/download/downloadFile?id=5669&type=product&ftype=note 77 + 70 78 Author: Guenter Roeck <linux@roeck-us.net> 71 79 72 80 ··· 82 74 ----------- 83 75 84 76 This driver supports hardware monitoring for Analog Devices ADM1075, ADM1272, 85 - ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 Hot-Swap 86 - Controller and Digital Power Monitors. 77 + ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, ADM1294, and SQ24905C 78 + Hot-Swap Controller and Digital Power Monitors. 87 79 88 - ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and 89 - ADM1294 are hot-swap controllers that allow a circuit board to be removed from 90 - or inserted into a live backplane. They also feature current and voltage 91 - readback via an integrated 12 bit analog-to-digital converter (ADC), accessed 92 - using a PMBus interface. 80 + ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, 81 + ADM1294 and SQ24905C are hot-swap controllers that allow a circuit board to be 82 + removed from or inserted into a live backplane. They also feature current and 83 + voltage readback via an integrated 12 bit analog-to-digital converter (ADC), 84 + accessed using a PMBus interface. 93 85 94 86 The driver is a client driver to the core PMBus driver. Please see 95 87 Documentation/hwmon/pmbus.rst for details on PMBus client drivers. ··· 168 160 temp1_reset_history Write any value to reset history. 169 161 170 162 Temperature attributes are supported on ADM1272, 171 - ADM1273, ADM1278, and ADM1281. 163 + ADM1273, ADM1278, ADM1281 and SQ24905C. 172 164 ======================= =======================================================
+12
Documentation/hwmon/asus_ec_sensors.rst
··· 8 8 * PRIME X470-PRO 9 9 * PRIME X570-PRO 10 10 * PRIME X670E-PRO WIFI 11 + * PRIME Z270-A 11 12 * Pro WS X570-ACE 13 + * Pro WS WRX90E-SAGE SE 12 14 * ProArt X570-CREATOR WIFI 13 15 * ProArt X670E-CREATOR WIFI 14 16 * ProArt X870E-CREATOR WIFI ··· 27 25 * ROG MAXIMUS Z690 FORMULA 28 26 * ROG STRIX B550-E GAMING 29 27 * ROG STRIX B550-I GAMING 28 + * ROG STRIX B650E-I GAMING WIFI 29 + * ROG STRIX B850-I GAMING WIFI 30 30 * ROG STRIX X570-E GAMING 31 31 * ROG STRIX X570-E GAMING WIFI II 32 32 * ROG STRIX X570-F GAMING 33 33 * ROG STRIX X570-I GAMING 34 + * ROG STRIX X670E-E GAMING WIFI 35 + * ROG STRIX X670E-I GAMING WIFI 36 + * ROG STRIX X870-I GAMING WIFI 37 + * ROG STRIX X870E-E GAMING WIFI 34 38 * ROG STRIX Z390-F GAMING 35 39 * ROG STRIX Z490-F GAMING 36 40 * ROG STRIX Z690-A GAMING WIFI D4 41 + * ROG STRIX Z690-E GAMING WIFI 42 + * ROG STRIX Z790-E GAMING WIFI II 43 + * ROG STRIX Z790-I GAMING WIFI 37 44 * ROG ZENITH II EXTREME 38 45 * ROG ZENITH II EXTREME ALPHA 39 46 * TUF GAMING X670E PLUS 47 + * TUF GAMING X670E PLUS WIFI 40 48 41 49 Authors: 42 50 - Eugene Shalygin <eugene.shalygin@gmail.com>
+6 -1
Documentation/hwmon/cros_ec_hwmon.rst
··· 23 23 24 24 The channel labels exposed via hwmon are retrieved from the EC itself. 25 25 26 - Fan and temperature readings are supported. 26 + Fan and temperature readings are supported. PWM fan control is also supported if 27 + the EC also supports setting fan PWM values and fan mode. Note that EC will 28 + switch fan control mode back to auto when suspended. This driver will restore 29 + the fan state to what they were before suspended when resumed. 30 + If a fan is controllable, this driver will register that fan as a cooling device 31 + in the thermal framework as well.
+2 -2
Documentation/hwmon/crps.rst
··· 43 43 curr1_input Measured input current 44 44 curr1_max Maximum input current 45 45 curr1_max_alarm Input maximum current high alarm 46 - curr1_crit Critial high input current 46 + curr1_crit Critical high input current 47 47 curr1_crit_alarm Input critical current high alarm 48 48 curr1_rated_max Maximum rated input current 49 49 ··· 51 51 curr2_input Measured output current 52 52 curr2_max Maximum output current 53 53 curr2_max_alarm Output maximum current high alarm 54 - curr2_crit Critial high output current 54 + curr2_crit Critical high output current 55 55 curr2_crit_alarm Output critical current high alarm 56 56 curr2_rated_max Maximum rated output current 57 57
+32 -18
Documentation/hwmon/dell-smm-hwmon.rst
··· 38 38 fan[1-4]_max RO Maximal Fan speed in RPM 39 39 fan[1-4]_target RO Expected Fan speed in RPM 40 40 pwm[1-4] RW Control the fan PWM duty-cycle. 41 - pwm1_enable WO Enable or disable automatic BIOS fan 41 + pwm[1-4]_enable RW/WO Enable or disable automatic BIOS fan 42 42 control (not supported on all laptops, 43 43 see below for details). 44 44 temp[1-10]_input RO Temperature reading in milli-degrees ··· 49 49 Due to the nature of the SMM interface, each pwmX attribute controls 50 50 fan number X. 51 51 52 - Disabling automatic BIOS fan control 53 - ------------------------------------ 52 + Enabling/Disabling automatic BIOS fan control 53 + --------------------------------------------- 54 54 55 - On some laptops the BIOS automatically sets fan speed every few 56 - seconds. Therefore the fan speed set by mean of this driver is quickly 57 - overwritten. 55 + There exist two methods for enabling/disabling automatic BIOS fan control: 58 56 59 - There is experimental support for disabling automatic BIOS fan 60 - control, at least on laptops where the corresponding SMM command is 61 - known, by writing the value ``1`` in the attribute ``pwm1_enable`` 62 - (writing ``2`` enables automatic BIOS control again). Even if you have 63 - more than one fan, all of them are set to either enabled or disabled 64 - automatic fan control at the same time and, notwithstanding the name, 65 - ``pwm1_enable`` sets automatic control for all fans. 57 + 1. Separate SMM commands to enable/disable automatic BIOS fan control for all fans. 66 58 67 - If ``pwm1_enable`` is not available, then it means that SMM codes for 68 - enabling and disabling automatic BIOS fan control are not whitelisted 69 - for your hardware. It is possible that codes that work for other 70 - laptops actually work for yours as well, or that you have to discover 71 - new codes. 59 + 2. A special fan state that enables automatic BIOS fan control for a individual fan. 60 + 61 + The driver cannot reliably detect what method should be used on a given 62 + device, so instead the following heuristic is used: 63 + 64 + - use fan state 3 for enabling BIOS fan control if the maximum fan state 65 + setable by the user is smaller than 3 (default setting). 66 + 67 + - use separate SMM commands if device is whitelisted to support them. 68 + 69 + When using the first method, each fan will have a standard ``pwmX_enable`` 70 + sysfs attribute. Writing ``1`` into this attribute will disable automatic 71 + BIOS fan control for the associated fan and set it to maximum speed. Enabling 72 + BIOS fan control again can be achieved by writing ``2`` into this attribute. 73 + Reading this sysfs attributes returns the current setting as reported by 74 + the underlying hardware. 75 + 76 + When using the second method however, only the ``pwm1_enable`` sysfs attribute 77 + will be available to enable/disable automatic BIOS fan control globaly for all 78 + fans available on a given device. Additionally, this sysfs attribute is write-only 79 + as there exists no SMM command for reading the current fan control setting. 80 + 81 + If no ``pwmX_enable`` attributes are available, then it means that the driver 82 + cannot use the first method and the SMM codes for enabling and disabling automatic 83 + BIOS fan control are not whitelisted for your device. It is possible that codes 84 + that work for other laptops actually work for yours as well, or that you have to 85 + discover new codes. 72 86 73 87 Check the list ``i8k_whitelist_fan_control`` in file 74 88 ``drivers/hwmon/dell-smm-hwmon.c`` in the kernel tree: as a first
+78
Documentation/hwmon/gpd-fan.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-or-later 2 + 3 + Kernel driver gpd-fan 4 + ========================= 5 + 6 + Author: 7 + - Cryolitia PukNgae <cryolitia@uniontech.com> 8 + 9 + Description 10 + ------------ 11 + 12 + Handheld devices from Shenzhen GPD Technology Co., Ltd. provide fan readings 13 + and fan control through their embedded controllers. 14 + 15 + Supported devices 16 + ----------------- 17 + 18 + Currently the driver supports the following handhelds: 19 + 20 + - GPD Win Mini (7840U) 21 + - GPD Win Mini (8840U) 22 + - GPD Win Mini (HX370) 23 + - GPD Pocket 4 24 + - GPD Duo 25 + - GPD Win Max 2 (6800U) 26 + - GPD Win Max 2 2023 (7840U) 27 + - GPD Win Max 2 2024 (8840U) 28 + - GPD Win Max 2 2025 (HX370) 29 + - GPD Win 4 (6800U) 30 + - GPD Win 4 (7840U) 31 + 32 + Module parameters 33 + ----------------- 34 + 35 + gpd_fan_board 36 + Force specific which module quirk should be used. 37 + Use it like "gpd_fan_board=wm2". 38 + 39 + - wm2 40 + - GPD Win 4 (7840U) 41 + - GPD Win Max 2 (6800U) 42 + - GPD Win Max 2 2023 (7840U) 43 + - GPD Win Max 2 2024 (8840U) 44 + - GPD Win Max 2 2025 (HX370) 45 + - win4 46 + - GPD Win 4 (6800U) 47 + - win_mini 48 + - GPD Win Mini (7840U) 49 + - GPD Win Mini (8840U) 50 + - GPD Win Mini (HX370) 51 + - GPD Pocket 4 52 + - GPD Duo 53 + 54 + Sysfs entries 55 + ------------- 56 + 57 + The following attributes are supported: 58 + 59 + fan1_input 60 + Read Only. Reads current fan RPM. 61 + 62 + pwm1_enable 63 + Read/Write. Enable manual fan control. Write "0" to disable control and run 64 + at full speed. Write "1" to set to manual, write "2" to let the EC control 65 + decide fan speed. Read this attribute to see current status. 66 + 67 + NB:In consideration of the safety of the device, when setting to manual mode, 68 + the pwm speed will be set to the maximum value (255) by default. You can set 69 + a different value by writing pwm1 later. 70 + 71 + pwm1 72 + Read/Write. Read this attribute to see current duty cycle in the range 73 + [0-255]. When pwm1_enable is set to "1" (manual) write any value in the 74 + range [0-255] to set fan speed. 75 + 76 + NB: Many boards (except listed under wm2 above) don't support reading the 77 + current pwm value in auto mode. That will just return EOPNOTSUPP. In manual 78 + mode it will always return the real value.
+13
Documentation/hwmon/hwmon-kernel-api.rst
··· 42 42 43 43 char *devm_hwmon_sanitize_name(struct device *dev, const char *name); 44 44 45 + void hwmon_lock(struct device *dev); 46 + void hwmon_unlock(struct device *dev); 47 + 45 48 hwmon_device_register_with_info registers a hardware monitoring device. 46 49 It creates the standard sysfs attributes in the hardware monitoring core, 47 50 letting the driver focus on reading from and writing to the chip instead ··· 81 78 devm_hwmon_sanitize_name is the resource managed version of 82 79 hwmon_sanitize_name; the memory will be freed automatically on device 83 80 removal. 81 + 82 + When using ``[devm_]hwmon_device_register_with_info()`` to register the 83 + hardware monitoring device, accesses using the associated access functions 84 + are serialised by the hardware monitoring core. If a driver needs locking 85 + for other functions such as interrupt handlers or for attributes which are 86 + fully implemented in the driver, hwmon_lock() and hwmon_unlock() can be used 87 + to ensure that calls to those functions are serialized. 84 88 85 89 Using devm_hwmon_device_register_with_info() 86 90 -------------------------------------------- ··· 169 159 hwmon_curr Current sensor 170 160 hwmon_power Power sensor 171 161 hwmon_energy Energy sensor 162 + hwmon_energy64 Energy sensor, reported as 64-bit signed value 172 163 hwmon_humidity Humidity sensor 173 164 hwmon_fan Fan speed sensor 174 165 hwmon_pwm PWM control ··· 299 288 The sensor channel number. 300 289 val: 301 290 Pointer to attribute value. 291 + For hwmon_energy64, `'val`' is passed as `long *` but needs 292 + a typecast to `s64 *`. 302 293 303 294 Return value: 304 295 0 on success, a negative error number otherwise.
+51 -13
Documentation/hwmon/ina238.rst
··· 5 5 6 6 Supported chips: 7 7 8 + * Texas Instruments INA228 9 + 10 + Prefix: 'ina228' 11 + 12 + Addresses: I2C 0x40 - 0x4f 13 + 14 + Datasheet: 15 + https://www.ti.com/lit/gpn/ina228 16 + 17 + * Texas Instruments INA237 18 + 19 + Prefix: 'ina237' 20 + 21 + Addresses: I2C 0x40 - 0x4f 22 + 23 + Datasheet: 24 + https://www.ti.com/lit/gpn/ina237 25 + 8 26 * Texas Instruments INA238 9 27 10 28 Prefix: 'ina238' ··· 31 13 32 14 Datasheet: 33 15 https://www.ti.com/lit/gpn/ina238 16 + 17 + * Texas Instruments INA700 18 + 19 + Datasheet: 20 + https://www.ti.com/product/ina700 21 + 22 + * Texas Instruments INA780 23 + 24 + Datasheet: 25 + https://www.ti.com/product/ina780a 34 26 35 27 * Silergy SQ52206 36 28 ··· 57 29 interface. It includes a number of programmable functions including alerts, 58 30 conversion rate, sample averaging and selectable shunt voltage accuracy. 59 31 60 - The shunt value in micro-ohms can be set via platform data or device tree at 61 - compile-time or via the shunt_resistor attribute in sysfs at run-time. Please 62 - refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings 63 - if the device tree is used. 32 + The shunt value in micro-ohms can be set via device properties, either from 33 + platform code or from device tree data. Please refer to 34 + Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings if 35 + device tree is used. 36 + 37 + INA237 is a functionally equivalent variant of INA238 with slightly 38 + different accuracy. INA228 is another variant of INA238 with higher ADC 39 + resolution. This chip also reports the energy. 40 + 41 + INA700 and INA780 are variants of the chip series with built-in shunt resistor. 42 + They also report the energy. 43 + 44 + SQ52206 is a mostly compatible chip from Sylergy. It reports the energy 45 + as well as the peak power consumption. 64 46 65 47 Sysfs entries 66 48 ------------- ··· 91 53 power1_input Power measurement (uW) 92 54 power1_max Maximum power threshold (uW) 93 55 power1_max_alarm Maximum power alarm 56 + power1_input_highest Peak Power (uW) 57 + (SQ52206 only) 94 58 95 59 curr1_input Current measurement (mA) 60 + curr1_min Minimum current threshold (mA) 61 + curr1_min_alarm Minimum current alarm 62 + curr1_max Maximum current threshold (mA) 63 + curr1_max_alarm Maximum current alarm 64 + 65 + energy1_input Energy measurement (uJ) 66 + (SQ52206, INA237, and INA780 only) 96 67 97 68 temp1_input Die temperature measurement (mC) 98 69 temp1_max Maximum die temperature threshold (mC) 99 70 temp1_max_alarm Maximum die temperature alarm 100 - ======================= ======================================================= 101 - 102 - Additional sysfs entries for sq52206 103 - ------------------------------------ 104 - 105 - ======================= ======================================================= 106 - energy1_input Energy measurement (uJ) 107 - 108 - power1_input_highest Peak Power (uW) 109 71 ======================= =======================================================
+4
Documentation/hwmon/index.rst
··· 82 82 gigabyte_waterforce 83 83 gsc-hwmon 84 84 gl518sm 85 + gpd-fan 85 86 gxp-fan-ctrl 86 87 hih6130 87 88 hp-wmi-sensors ··· 174 173 menf21bmc 175 174 mlxreg-fan 176 175 mp2856 176 + mp2869 177 177 mp2888 178 178 mp2891 179 + mp29502 179 180 mp2975 180 181 mp2993 181 182 mp5023 ··· 214 211 q54sj108a2 215 212 qnap-mcu-hwmon 216 213 raspberrypi-hwmon 214 + sa67 217 215 sbrmi 218 216 sbtsi_temp 219 217 sch5627
+20
Documentation/hwmon/isl68137.rst
··· 374 374 375 375 Publicly available (after August 2020 launch) at the Renesas website 376 376 377 + * Renesas RAA228244 378 + 379 + Prefix: 'raa228244' 380 + 381 + Addresses scanned: - 382 + 383 + Datasheet: 384 + 385 + Provided by Renesas upon request and NDA 386 + 387 + * Renesas RAA228246 388 + 389 + Prefix: 'raa228246' 390 + 391 + Addresses scanned: - 392 + 393 + Datasheet: 394 + 395 + Provided by Renesas upon request and NDA 396 + 377 397 * Renesas RAA229001 378 398 379 399 Prefix: 'raa229001'
+4 -2
Documentation/hwmon/lm75.rst
··· 121 121 122 122 https://www.ti.com/product/TMP1075 123 123 124 - * NXP LM75B, P3T1755, PCT2075 124 + * NXP LM75B, P3T1750, P3T1755, PCT2075 125 125 126 - Prefix: 'lm75b', 'p3t1755', 'pct2075' 126 + Prefix: 'lm75b', 'p3t1750', 'p3t1755', 'pct2075' 127 127 128 128 Addresses scanned: none 129 129 130 130 Datasheet: Publicly available at the NXP website 131 131 132 132 https://www.nxp.com/docs/en/data-sheet/LM75B.pdf 133 + 134 + https://www.nxp.com/docs/en/data-sheet/P3T1750DP.pdf 133 135 134 136 https://www.nxp.com/docs/en/data-sheet/P3T1755.pdf 135 137
+175
Documentation/hwmon/mp2869.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + Kernel driver mp2869 4 + ==================== 5 + 6 + Supported chips: 7 + 8 + * MPS mp2869 9 + 10 + Prefix: 'mp2869' 11 + 12 + * MPS mp29608 13 + 14 + Prefix: 'mp29608' 15 + 16 + * MPS mp29612 17 + 18 + Prefix: 'mp29612' 19 + 20 + * MPS mp29816 21 + 22 + Prefix: 'mp29816' 23 + 24 + Author: 25 + 26 + Wensheng Wang <wenswang@yeah.net> 27 + 28 + Description 29 + ----------- 30 + 31 + This driver implements support for Monolithic Power Systems, Inc. (MPS) 32 + MP2869 Dual Loop Digital Multi-phase Controller. 33 + 34 + Device compliant with: 35 + 36 + - PMBus rev 1.3 interface. 37 + 38 + The driver exports the following attributes via the 'sysfs' files 39 + for input voltage: 40 + 41 + **in1_input** 42 + 43 + **in1_label** 44 + 45 + **in1_crit** 46 + 47 + **in1_crit_alarm** 48 + 49 + **in1_lcrit** 50 + 51 + **in1_lcrit_alarm** 52 + 53 + **in1_min** 54 + 55 + **in1_min_alarm** 56 + 57 + The driver provides the following attributes for output voltage: 58 + 59 + **in2_input** 60 + 61 + **in2_label** 62 + 63 + **in2_crit** 64 + 65 + **in2_crit_alarm** 66 + 67 + **in2_lcrit** 68 + 69 + **in2_lcrit_alarm** 70 + 71 + **in3_input** 72 + 73 + **in3_label** 74 + 75 + **in3_crit** 76 + 77 + **in3_crit_alarm** 78 + 79 + **in3_lcrit** 80 + 81 + **in3_lcrit_alarm** 82 + 83 + The driver provides the following attributes for input current: 84 + 85 + **curr1_input** 86 + 87 + **curr1_label** 88 + 89 + **curr2_input** 90 + 91 + **curr2_label** 92 + 93 + The driver provides the following attributes for output current: 94 + 95 + **curr3_input** 96 + 97 + **curr3_label** 98 + 99 + **curr3_crit** 100 + 101 + **curr3_crit_alarm** 102 + 103 + **curr3_max** 104 + 105 + **curr3_max_alarm** 106 + 107 + **curr4_input** 108 + 109 + **curr4_label** 110 + 111 + **curr4_crit** 112 + 113 + **curr4_crit_alarm** 114 + 115 + **curr4_max** 116 + 117 + **curr4_max_alarm** 118 + 119 + The driver provides the following attributes for input power: 120 + 121 + **power1_input** 122 + 123 + **power1_label** 124 + 125 + **power2_input** 126 + 127 + **power2_label** 128 + 129 + The driver provides the following attributes for output power: 130 + 131 + **power3_input** 132 + 133 + **power3_label** 134 + 135 + **power3_input** 136 + 137 + **power3_label** 138 + 139 + **power3_max** 140 + 141 + **power3_max_alarm** 142 + 143 + **power4_input** 144 + 145 + **power4_label** 146 + 147 + **power4_input** 148 + 149 + **power4_label** 150 + 151 + **power4_max** 152 + 153 + **power4_max_alarm** 154 + 155 + The driver provides the following attributes for temperature: 156 + 157 + **temp1_input** 158 + 159 + **temp1_crit** 160 + 161 + **temp1_crit_alarm** 162 + 163 + **temp1_max** 164 + 165 + **temp1_max_alarm** 166 + 167 + **temp2_input** 168 + 169 + **temp2_crit** 170 + 171 + **temp2_crit_alarm** 172 + 173 + **temp2_max** 174 + 175 + **temp2_max_alarm**
+93
Documentation/hwmon/mp29502.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0 2 + 3 + Kernel driver mp29502 4 + ===================== 5 + 6 + Supported chips: 7 + 8 + * MPS mp29502 9 + 10 + Prefix: 'mp29502' 11 + 12 + Author: 13 + 14 + Wensheng Wang <wenswang@yeah.net> 15 + 16 + Description 17 + ----------- 18 + 19 + This driver implements support for Monolithic Power Systems, Inc. (MPS) 20 + MP29502 Digital Multi-phase Controller. 21 + 22 + Device compliant with: 23 + 24 + - PMBus rev 1.3 interface. 25 + 26 + The driver exports the following attributes via the 'sysfs' files 27 + for input voltage: 28 + 29 + **in1_input** 30 + 31 + **in1_label** 32 + 33 + **in1_crit** 34 + 35 + **in1_crit_alarm** 36 + 37 + The driver provides the following attributes for output voltage: 38 + 39 + **in2_input** 40 + 41 + **in2_label** 42 + 43 + **in2_crit** 44 + 45 + **in2_crit_alarm** 46 + 47 + **in2_lcrit** 48 + 49 + **in2_lcrit_alarm** 50 + 51 + The driver provides the following attributes for input current: 52 + 53 + **curr1_input** 54 + 55 + **curr1_label** 56 + 57 + The driver provides the following attributes for output current: 58 + 59 + **curr2_input** 60 + 61 + **curr2_label** 62 + 63 + **curr2_crit** 64 + 65 + **curr2_crit_alarm** 66 + 67 + **curr2_max** 68 + 69 + **curr2_max_alarm** 70 + 71 + The driver provides the following attributes for input power: 72 + 73 + **power1_input** 74 + 75 + **power1_label** 76 + 77 + The driver provides the following attributes for output power: 78 + 79 + **power2_input** 80 + 81 + **power2_label** 82 + 83 + The driver provides the following attributes for temperature: 84 + 85 + **temp1_input** 86 + 87 + **temp1_crit** 88 + 89 + **temp1_crit_alarm** 90 + 91 + **temp1_max** 92 + 93 + **temp1_max_alarm**
+26 -4
Documentation/hwmon/mp5990.rst
··· 9 9 10 10 Prefix: 'mp5990' 11 11 12 - * Datasheet 12 + Datasheet: Publicly available at the MPS website: https://www.monolithicpower.com/en/mp5990.html 13 13 14 - Publicly available at the MPS website : https://www.monolithicpower.com/en/mp5990.html 14 + * MPS MP5998 15 + 16 + Prefix: 'mp5998' 17 + 18 + Datasheet: Not publicly available 15 19 16 20 Author: 17 21 ··· 25 21 ----------- 26 22 27 23 This driver implements support for Monolithic Power Systems, Inc. (MPS) 28 - MP5990 Hot-Swap Controller. 24 + MP5990 and MP5998 Hot-Swap Controller. 29 25 30 26 Device compliant with: 31 27 ··· 57 53 58 54 **in2_alarm** 59 55 60 - The driver provides the following attributes for output current: 56 + The driver provides the following attributes for current: 61 57 62 58 **curr1_input** 63 59 ··· 67 63 68 64 **curr1_max** 69 65 66 + **curr2_input** 67 + 68 + **curr2_label** 69 + 70 + **curr2_max** 71 + 72 + **curr2_max_alarm** 73 + 70 74 The driver provides the following attributes for input power: 71 75 72 76 **power1_input** ··· 82 70 **power1_label** 83 71 84 72 **power1_alarm** 73 + 74 + The driver provides the following attributes for output power: 75 + 76 + **power2_input** 77 + 78 + **power2_label** 79 + 80 + **power2_max** 81 + 82 + **power2_max_alarm** 85 83 86 84 The driver provides the following attributes for temperature: 87 85
+41
Documentation/hwmon/sa67.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-only 2 + 3 + Kernel driver sa67mcu 4 + ===================== 5 + 6 + Supported chips: 7 + 8 + * Kontron sa67mcu 9 + 10 + Prefix: 'sa67mcu' 11 + 12 + Datasheet: not available 13 + 14 + Authors: Michael Walle <mwalle@kernel.org> 15 + 16 + Description 17 + ----------- 18 + 19 + The sa67mcu is a board management controller which also exposes a hardware 20 + monitoring controller. 21 + 22 + The controller has two voltage and one temperature sensor. The values are 23 + hold in two 8 bit registers to form one 16 bit value. Reading the lower byte 24 + will also capture the high byte to make the access atomic. The unit of the 25 + volatge sensors are 1mV and the unit of the temperature sensor is 0.1degC. 26 + 27 + Sysfs entries 28 + ------------- 29 + 30 + The following attributes are supported. 31 + 32 + ======================= ======================================================== 33 + in0_label "VDDIN" 34 + in0_input Measured VDDIN voltage. 35 + 36 + in1_label "VDD_RTC" 37 + in1_input Measured VDD_RTC voltage. 38 + 39 + temp1_input MCU temperature. Roughly the board temperature. 40 + ======================= ======================================================== 41 +
+15 -11
Documentation/hwmon/sht21.rst
··· 3 3 4 4 Supported chips: 5 5 6 + * Sensirion SHT20 7 + 8 + Prefix: 'sht20' 9 + 10 + Addresses scanned: none 11 + 12 + Datasheet: Publicly available at the Sensirion website 13 + 14 + https://www.sensirion.com/file/datasheet_sht20 15 + 6 16 * Sensirion SHT21 7 17 8 18 Prefix: 'sht21' ··· 23 13 24 14 https://www.sensirion.com/file/datasheet_sht21 25 15 26 - 27 - 28 16 * Sensirion SHT25 29 17 30 18 Prefix: 'sht25' ··· 32 24 Datasheet: Publicly available at the Sensirion website 33 25 34 26 https://www.sensirion.com/file/datasheet_sht25 35 - 36 - 37 27 38 28 Author: 39 29 ··· 53 47 sysfs-Interface 54 48 --------------- 55 49 56 - temp1_input 57 - - temperature input 58 - 59 - humidity1_input 60 - - humidity input 61 - eic 62 - - Electronic Identification Code 50 + =================== ============================================================ 51 + temp1_input Temperature input 52 + humidity1_input Humidity input 53 + eic Electronic Identification Code 54 + =================== ============================================================ 63 55 64 56 Notes 65 57 -----
+23 -3
MAINTAINERS
··· 6280 6280 F: tools/testing/selftests/cgroup/test_memcontrol.c 6281 6281 6282 6282 CORETEMP HARDWARE MONITORING DRIVER 6283 - M: Fenghua Yu <fenghua.yu@intel.com> 6284 6283 L: linux-hwmon@vger.kernel.org 6285 - S: Maintained 6284 + S: Orphan 6286 6285 F: Documentation/hwmon/coretemp.rst 6287 6286 F: drivers/hwmon/coretemp.c 6288 6287 ··· 10455 10456 F: include/dt-bindings/clock/google,gs101.h 10456 10457 K: [gG]oogle.?[tT]ensor 10457 10458 10459 + GPD FAN DRIVER 10460 + M: Cryolitia PukNgae <cryolitia@uniontech.com> 10461 + L: linux-hwmon@vger.kernel.org 10462 + S: Maintained 10463 + F: Documentation/hwmon/gpd-fan.rst 10464 + F: drivers/hwmon/gpd-fan.c 10465 + 10458 10466 GPD POCKET FAN DRIVER 10459 10467 M: Hans de Goede <hansg@kernel.org> 10460 10468 L: platform-driver-x86@vger.kernel.org ··· 10758 10752 F: drivers/platform/x86/hdaps.c 10759 10753 10760 10754 HARDWARE MONITORING 10761 - M: Jean Delvare <jdelvare@suse.com> 10762 10755 M: Guenter Roeck <linux@roeck-us.net> 10763 10756 L: linux-hwmon@vger.kernel.org 10764 10757 S: Maintained ··· 17213 17208 F: Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml 17214 17209 F: drivers/video/backlight/mp3309c.c 17215 17210 17211 + MPS MP2869 DRIVER 17212 + M: Wensheng Wang <wenswang@yeah.net> 17213 + L: linux-hwmon@vger.kernel.org 17214 + S: Maintained 17215 + F: Documentation/hwmon/mp2869.rst 17216 + F: drivers/hwmon/pmbus/mp2869.c 17217 + 17216 17218 MPS MP2891 DRIVER 17217 17219 M: Noah Wang <noahwang.wang@outlook.com> 17218 17220 L: linux-hwmon@vger.kernel.org 17219 17221 S: Maintained 17220 17222 F: Documentation/hwmon/mp2891.rst 17221 17223 F: drivers/hwmon/pmbus/mp2891.c 17224 + 17225 + MPS MP29502 DRIVER 17226 + M: Wensheng Wang <wenswang@yeah.net> 17227 + L: linux-hwmon@vger.kernel.org 17228 + S: Maintained 17229 + F: Documentation/hwmon/mp29502.rst 17230 + F: drivers/hwmon/pmbus/mp29502.c 17222 17231 17223 17232 MPS MP2993 DRIVER 17224 17233 M: Noah Wang <noahwang.wang@outlook.com> ··· 23268 23249 F: Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml 23269 23250 F: Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml 23270 23251 F: drivers/gpio/gpio-sl28cpld.c 23252 + F: drivers/hwmon/sa67mcu-hwmon.c 23271 23253 F: drivers/hwmon/sl28cpld-hwmon.c 23272 23254 F: drivers/irqchip/irq-sl28cpld.c 23273 23255 F: drivers/pwm/pwm-sl28cpld.c
+31 -9
drivers/hwmon/Kconfig
··· 769 769 This driver can also be built as a module. If so, the module 770 770 will be called gl520sm. 771 771 772 + config SENSORS_GPD 773 + tristate "GPD handhelds" 774 + depends on X86 && DMI && HAS_IOPORT 775 + help 776 + If you say yes here you get support for fan readings and 777 + control over GPD handheld devices. 778 + 779 + Can also be built as a module. In that case it will be 780 + called gpd-fan. 781 + 772 782 config SENSORS_G760A 773 783 tristate "GMT G760A" 774 784 depends on I2C ··· 1905 1895 This driver can also be built as a module. If so, the module 1906 1896 will be called raspberrypi-hwmon. 1907 1897 1898 + config SENSORS_SA67MCU 1899 + tristate "Kontron sa67mcu hardware monitoring driver" 1900 + depends on MFD_SL28CPLD || COMPILE_TEST 1901 + help 1902 + If you say yes here you get support for the voltage and temperature 1903 + monitor of the sa67 board management controller. 1904 + 1905 + This driver can also be built as a module. If so, the module 1906 + will be called sa67mcu-hwmon. 1907 + 1908 1908 config SENSORS_SL28CPLD 1909 1909 tristate "Kontron sl28cpld hardware monitoring driver" 1910 1910 depends on MFD_SL28CPLD || COMPILE_TEST ··· 1950 1930 tristate "Sensiron humidity and temperature sensors. SHT21 and compat." 1951 1931 depends on I2C 1952 1932 help 1953 - If you say yes here you get support for the Sensiron SHT21, SHT25 1954 - humidity and temperature sensors. 1933 + If you say yes here you get support for the Sensiron SHT20, SHT21, 1934 + SHT25 humidity and temperature sensors. 1955 1935 1956 1936 This driver can also be built as a module. If so, the module 1957 1937 will be called sht21. ··· 2272 2252 will be called ina2xx. 2273 2253 2274 2254 config SENSORS_INA238 2275 - tristate "Texas Instruments INA238" 2255 + tristate "Texas Instruments INA238 and compatibles" 2276 2256 depends on I2C 2277 2257 select REGMAP_I2C 2278 2258 help 2279 - If you say yes here you get support for the INA238 power monitor 2280 - chip. This driver supports voltage, current, power and temperature 2281 - measurements as well as alarm configuration. 2259 + If you say yes here you get support for INA228, INA237, INA238, 2260 + INA700, INA780, and SQ52206 power monitor chips. This driver supports 2261 + voltage, current, power, energy, and temperature measurements as well 2262 + as alarm configuration. 2282 2263 2283 2264 This driver can also be built as a module. If so, the module 2284 2265 will be called ina238. ··· 2694 2673 depends on ACPI_EC 2695 2674 help 2696 2675 If you say yes here you get support for the ACPI embedded controller 2697 - hardware monitoring interface found in ASUS motherboards. The driver 2698 - currently supports B550/X570 boards, although other ASUS boards might 2699 - provide this monitoring interface as well. 2676 + hardware monitoring interface found in some ASUS motherboards. This is 2677 + where such sensors as water flow and temperature, optional fans, and 2678 + additional temperature sensors (T_Sensor, chipset temperatures) 2679 + find themselves. 2700 2680 2701 2681 This driver can also be built as a module. If so, the module 2702 2682 will be called asus_ec_sensors.
+2
drivers/hwmon/Makefile
··· 88 88 obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o 89 89 obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o 90 90 obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o 91 + obj-$(CONFIG_SENSORS_GPD) += gpd-fan.o 91 92 obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o 92 93 obj-$(CONFIG_SENSORS_GXP_FAN_CTRL) += gxp-fan-ctrl.o 93 94 obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o ··· 197 196 obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o 198 197 obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o 199 198 obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o 199 + obj-$(CONFIG_SENSORS_SA67MCU) += sa67mcu-hwmon.o 200 200 obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o 201 201 obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o 202 202 obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
+254 -86
drivers/hwmon/asus-ec-sensors.c
··· 49 49 */ 50 50 #define ASUS_EC_MAX_BANK 3 51 51 52 - #define ACPI_LOCK_DELAY_MS 500 52 + #define ACPI_LOCK_DELAY_MS 800 53 53 54 54 /* ACPI mutex for locking access to the EC for the firmware */ 55 55 #define ASUS_HW_ACCESS_MUTEX_ASMX "\\AMW0.ASMX" 56 56 57 57 #define ASUS_HW_ACCESS_MUTEX_RMTW_ASMX "\\RMTW.ASMX" 58 58 59 + #define ASUS_HW_ACCESS_MUTEX_SB_PC00_LPCB_SIO1_MUT0 "\\_SB.PC00.LPCB.SIO1.MUT0" 60 + 59 61 #define ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0 "\\_SB_.PCI0.SBRG.SIO1.MUT0" 62 + 63 + #define ASUS_HW_ACCESS_MUTEX_SB_PCI0_LPCB_SIO1_MUT0 "\\_SB_.PCI0.LPCB.SIO1.MUT0" 60 64 61 65 #define MAX_IDENTICAL_BOARD_VARIATIONS 3 62 66 ··· 119 115 ec_sensor_fan_cpu_opt, 120 116 /* VRM heat sink fan [RPM] */ 121 117 ec_sensor_fan_vrm_hs, 118 + /* VRM east heat sink fan [RPM] */ 119 + ec_sensor_fan_vrme_hs, 120 + /* VRM west heat sink fan [RPM] */ 121 + ec_sensor_fan_vrmw_hs, 122 122 /* Chipset fan [RPM] */ 123 123 ec_sensor_fan_chipset, 124 124 /* Water flow sensor reading [RPM] */ 125 125 ec_sensor_fan_water_flow, 126 + /* USB4 fan [RPM] */ 127 + ec_sensor_fan_usb4, 128 + /* M.2 fan [RPM] */ 129 + ec_sensor_fan_m2, 126 130 /* CPU current [A] */ 127 131 ec_sensor_curr_cpu, 128 132 /* "Water_In" temperature sensor reading [℃] */ ··· 160 148 #define SENSOR_IN_CPU_CORE BIT(ec_sensor_in_cpu_core) 161 149 #define SENSOR_FAN_CPU_OPT BIT(ec_sensor_fan_cpu_opt) 162 150 #define SENSOR_FAN_VRM_HS BIT(ec_sensor_fan_vrm_hs) 151 + #define SENSOR_FAN_VRME_HS BIT(ec_sensor_fan_vrme_hs) 152 + #define SENSOR_FAN_VRMW_HS BIT(ec_sensor_fan_vrmw_hs) 163 153 #define SENSOR_FAN_CHIPSET BIT(ec_sensor_fan_chipset) 164 154 #define SENSOR_FAN_WATER_FLOW BIT(ec_sensor_fan_water_flow) 155 + #define SENSOR_FAN_USB4 BIT(ec_sensor_fan_usb4) 156 + #define SENSOR_FAN_M2 BIT(ec_sensor_fan_m2) 165 157 #define SENSOR_CURR_CPU BIT(ec_sensor_curr_cpu) 166 158 #define SENSOR_TEMP_WATER_IN BIT(ec_sensor_temp_water_in) 167 159 #define SENSOR_TEMP_WATER_OUT BIT(ec_sensor_temp_water_out) ··· 182 166 family_amd_500_series, 183 167 family_amd_600_series, 184 168 family_amd_800_series, 169 + family_amd_wrx_90, 170 + family_intel_200_series, 185 171 family_intel_300_series, 186 172 family_intel_400_series, 187 - family_intel_600_series 173 + family_intel_600_series, 174 + family_intel_700_series 188 175 }; 189 176 190 177 /* ··· 294 275 EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), 295 276 }; 296 277 278 + static const struct ec_sensor_info sensors_family_amd_wrx_90[] = { 279 + [ec_sensor_temp_cpu_package] = 280 + EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31), 281 + [ec_sensor_fan_cpu_opt] = 282 + EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), 283 + [ec_sensor_fan_vrmw_hs] = 284 + EC_SENSOR("VRMW HS", hwmon_fan, 2, 0x00, 0xb4), 285 + [ec_sensor_fan_usb4] = EC_SENSOR("USB4", hwmon_fan, 2, 0x00, 0xb6), 286 + [ec_sensor_fan_vrme_hs] = 287 + EC_SENSOR("VRME HS", hwmon_fan, 2, 0x00, 0xbc), 288 + [ec_sensor_fan_m2] = EC_SENSOR("M.2", hwmon_fan, 2, 0x00, 0xbe), 289 + [ec_sensor_temp_t_sensor] = 290 + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x01, 0x04), 291 + }; 292 + 293 + static const struct ec_sensor_info sensors_family_intel_200[] = { 294 + [ec_sensor_temp_chipset] = 295 + EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a), 296 + [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b), 297 + [ec_sensor_temp_mb] = 298 + EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c), 299 + [ec_sensor_temp_t_sensor] = 300 + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d), 301 + [ec_sensor_fan_cpu_opt] = 302 + EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xbc), 303 + }; 304 + 297 305 static const struct ec_sensor_info sensors_family_intel_300[] = { 298 306 [ec_sensor_temp_chipset] = 299 307 EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a), ··· 369 323 EC_SENSOR("Water_Block_In", hwmon_temp, 1, 0x01, 0x02), 370 324 }; 371 325 326 + static const struct ec_sensor_info sensors_family_intel_700[] = { 327 + [ec_sensor_temp_t_sensor] = 328 + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x01, 0x09), 329 + [ec_sensor_temp_t_sensor_2] = 330 + EC_SENSOR("T_Sensor 2", hwmon_temp, 1, 0x01, 0x05), 331 + [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33), 332 + [ec_sensor_fan_cpu_opt] = 333 + EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), 334 + }; 335 + 372 336 /* Shortcuts for common combinations */ 373 337 #define SENSOR_SET_TEMP_CHIPSET_CPU_MB \ 374 338 (SENSOR_TEMP_CHIPSET | SENSOR_TEMP_CPU | SENSOR_TEMP_MB) ··· 399 343 enum board_family family; 400 344 }; 401 345 346 + static const struct ec_board_info board_info_crosshair_viii_dark_hero = { 347 + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 348 + SENSOR_TEMP_T_SENSOR | 349 + SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER | 350 + SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW | 351 + SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE, 352 + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 353 + .family = family_amd_500_series, 354 + }; 355 + 356 + static const struct ec_board_info board_info_crosshair_viii_hero = { 357 + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 358 + SENSOR_TEMP_T_SENSOR | 359 + SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER | 360 + SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | 361 + SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | 362 + SENSOR_IN_CPU_CORE, 363 + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 364 + .family = family_amd_500_series, 365 + }; 366 + 367 + static const struct ec_board_info board_info_crosshair_viii_impact = { 368 + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 369 + SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | 370 + SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU | 371 + SENSOR_IN_CPU_CORE, 372 + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 373 + .family = family_amd_500_series, 374 + }; 375 + 376 + static const struct ec_board_info board_info_crosshair_x670e_gene = { 377 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 378 + SENSOR_TEMP_T_SENSOR | 379 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM, 380 + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 381 + .family = family_amd_600_series, 382 + }; 383 + 384 + static const struct ec_board_info board_info_crosshair_x670e_hero = { 385 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 386 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | 387 + SENSOR_SET_TEMP_WATER, 388 + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 389 + .family = family_amd_600_series, 390 + }; 391 + 402 392 static const struct ec_board_info board_info_maximus_vi_hero = { 403 393 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 404 394 SENSOR_TEMP_T_SENSOR | ··· 452 350 SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW, 453 351 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 454 352 .family = family_intel_300_series, 353 + }; 354 + 355 + static const struct ec_board_info board_info_maximus_xi_hero = { 356 + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 357 + SENSOR_TEMP_T_SENSOR | 358 + SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER | 359 + SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW, 360 + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 361 + .family = family_intel_300_series, 362 + }; 363 + 364 + static const struct ec_board_info board_info_maximus_z690_formula = { 365 + .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | 366 + SENSOR_SET_TEMP_WATER | SENSOR_FAN_WATER_FLOW, 367 + .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, 368 + .family = family_intel_600_series, 455 369 }; 456 370 457 371 static const struct ec_board_info board_info_prime_x470_pro = { ··· 494 376 .family = family_amd_600_series, 495 377 }; 496 378 379 + static const struct ec_board_info board_info_prime_z270_a = { 380 + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 381 + SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT, 382 + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_LPCB_SIO1_MUT0, 383 + .family = family_intel_200_series, 384 + }; 385 + 386 + static const struct ec_board_info board_info_pro_art_b550_creator = { 387 + .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 388 + SENSOR_TEMP_T_SENSOR | 389 + SENSOR_FAN_CPU_OPT, 390 + .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 391 + .family = family_amd_500_series, 392 + }; 393 + 497 394 static const struct ec_board_info board_info_pro_art_x570_creator_wifi = { 498 395 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM | 499 396 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT | ··· 529 396 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 530 397 SENSOR_TEMP_MB | SENSOR_TEMP_VRM | 531 398 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT, 532 - .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 399 + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, 533 400 .family = family_amd_800_series, 534 401 }; 535 402 536 - static const struct ec_board_info board_info_pro_art_b550_creator = { 537 - .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 538 - SENSOR_TEMP_T_SENSOR | 539 - SENSOR_FAN_CPU_OPT, 540 - .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 541 - .family = family_amd_500_series, 403 + static const struct ec_board_info board_info_pro_ws_wrx90e_sage_se = { 404 + /* Board also has a nct6798 with 7 more fans and temperatures */ 405 + .sensors = SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_T_SENSOR | 406 + SENSOR_FAN_CPU_OPT | SENSOR_FAN_USB4 | SENSOR_FAN_M2 | 407 + SENSOR_FAN_VRME_HS | SENSOR_FAN_VRMW_HS, 408 + .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, 409 + .family = family_amd_wrx_90, 542 410 }; 543 411 544 412 static const struct ec_board_info board_info_pro_ws_x570_ace = { 545 413 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM | 546 414 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET | 547 415 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE, 548 - .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 549 - .family = family_amd_500_series, 550 - }; 551 - 552 - static const struct ec_board_info board_info_crosshair_x670e_hero = { 553 - .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 554 - SENSOR_TEMP_MB | SENSOR_TEMP_VRM | 555 - SENSOR_SET_TEMP_WATER, 556 - .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 557 - .family = family_amd_600_series, 558 - }; 559 - 560 - static const struct ec_board_info board_info_crosshair_x670e_gene = { 561 - .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 562 - SENSOR_TEMP_T_SENSOR | 563 - SENSOR_TEMP_MB | SENSOR_TEMP_VRM, 564 - .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 565 - .family = family_amd_600_series, 566 - }; 567 - 568 - static const struct ec_board_info board_info_crosshair_viii_dark_hero = { 569 - .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 570 - SENSOR_TEMP_T_SENSOR | 571 - SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER | 572 - SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW | 573 - SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE, 574 - .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 575 - .family = family_amd_500_series, 576 - }; 577 - 578 - static const struct ec_board_info board_info_crosshair_viii_hero = { 579 - .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 580 - SENSOR_TEMP_T_SENSOR | 581 - SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER | 582 - SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | 583 - SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | 584 - SENSOR_IN_CPU_CORE, 585 - .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 586 - .family = family_amd_500_series, 587 - }; 588 - 589 - static const struct ec_board_info board_info_maximus_xi_hero = { 590 - .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 591 - SENSOR_TEMP_T_SENSOR | 592 - SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER | 593 - SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW, 594 - .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 595 - .family = family_intel_300_series, 596 - }; 597 - 598 - static const struct ec_board_info board_info_maximus_z690_formula = { 599 - .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | 600 - SENSOR_SET_TEMP_WATER | SENSOR_FAN_WATER_FLOW, 601 - .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, 602 - .family = family_intel_600_series, 603 - }; 604 - 605 - static const struct ec_board_info board_info_crosshair_viii_impact = { 606 - .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | 607 - SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | 608 - SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU | 609 - SENSOR_IN_CPU_CORE, 610 416 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 611 417 .family = family_amd_500_series, 612 418 }; ··· 565 493 SENSOR_IN_CPU_CORE, 566 494 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX, 567 495 .family = family_amd_500_series, 496 + }; 497 + 498 + static const struct ec_board_info board_info_strix_b650e_i_gaming = { 499 + .sensors = SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR | 500 + SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_IN_CPU_CORE, 501 + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 502 + .family = family_amd_600_series, 503 + }; 504 + 505 + static const struct ec_board_info board_info_strix_b850_i_gaming_wifi = { 506 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 507 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM, 508 + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 509 + .family = family_amd_800_series, 568 510 }; 569 511 570 512 static const struct ec_board_info board_info_strix_x570_e_gaming = { ··· 614 528 .family = family_amd_500_series, 615 529 }; 616 530 531 + static const struct ec_board_info board_info_strix_x670e_e_gaming_wifi = { 532 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 533 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM, 534 + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, 535 + .family = family_amd_600_series, 536 + }; 537 + 538 + static const struct ec_board_info board_info_strix_x670e_i_gaming_wifi = { 539 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 540 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM, 541 + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 542 + .family = family_amd_600_series, 543 + }; 544 + 545 + static const struct ec_board_info board_info_strix_x870_i_gaming_wifi = { 546 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 547 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM, 548 + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, 549 + .family = family_amd_800_series, 550 + }; 551 + 552 + static const struct ec_board_info board_info_strix_x870e_e_gaming_wifi = { 553 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 554 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | 555 + SENSOR_FAN_CPU_OPT, 556 + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, 557 + .family = family_amd_800_series, 558 + }; 559 + 617 560 static const struct ec_board_info board_info_strix_z390_f_gaming = { 618 561 .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM | 619 562 SENSOR_TEMP_T_SENSOR | ··· 669 554 .family = family_intel_600_series, 670 555 }; 671 556 557 + static const struct ec_board_info board_info_strix_z690_e_gaming_wifi = { 558 + .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM, 559 + .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX, 560 + .family = family_intel_600_series, 561 + }; 562 + 563 + static const struct ec_board_info board_info_strix_z790_e_gaming_wifi_ii = { 564 + .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM | 565 + SENSOR_FAN_CPU_OPT, 566 + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PC00_LPCB_SIO1_MUT0, 567 + .family = family_intel_700_series, 568 + }; 569 + 570 + static const struct ec_board_info board_info_strix_z790_i_gaming_wifi = { 571 + .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_T_SENSOR_2 | 572 + SENSOR_TEMP_VRM, 573 + .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PC00_LPCB_SIO1_MUT0, 574 + .family = family_intel_700_series, 575 + }; 576 + 577 + static const struct ec_board_info board_info_tuf_gaming_x670e_plus = { 578 + .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 579 + SENSOR_TEMP_MB | SENSOR_TEMP_VRM | 580 + SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT | 581 + SENSOR_FAN_CPU_OPT, 582 + .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 583 + .family = family_amd_600_series, 584 + }; 585 + 672 586 static const struct ec_board_info board_info_zenith_ii_extreme = { 673 587 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR | 674 588 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER | ··· 708 564 SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3, 709 565 .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0, 710 566 .family = family_amd_500_series, 711 - }; 712 - 713 - static const struct ec_board_info board_info_tuf_gaming_x670e_plus = { 714 - .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | 715 - SENSOR_TEMP_MB | SENSOR_TEMP_VRM | 716 - SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT | 717 - SENSOR_FAN_CPU_OPT, 718 - .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, 719 - .family = family_amd_600_series, 720 567 }; 721 568 722 569 #define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, board_info) \ ··· 729 594 &board_info_prime_x570_pro), 730 595 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X670E-PRO WIFI", 731 596 &board_info_prime_x670e_pro_wifi), 597 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME Z270-A", 598 + &board_info_prime_z270_a), 599 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR", 600 + &board_info_pro_art_b550_creator), 732 601 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X570-CREATOR WIFI", 733 602 &board_info_pro_art_x570_creator_wifi), 734 603 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X670E-CREATOR WIFI", 735 604 &board_info_pro_art_x670E_creator_wifi), 736 605 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI", 737 606 &board_info_pro_art_x870E_creator_wifi), 738 - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR", 739 - &board_info_pro_art_b550_creator), 607 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS WRX90E-SAGE SE", 608 + &board_info_pro_ws_wrx90e_sage_se), 740 609 DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE", 741 610 &board_info_pro_ws_x570_ace), 742 611 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII DARK HERO", ··· 751 612 &board_info_crosshair_viii_hero), 752 613 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO (WI-FI)", 753 614 &board_info_crosshair_viii_hero), 754 - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO", 755 - &board_info_crosshair_x670e_hero), 615 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII IMPACT", 616 + &board_info_crosshair_viii_impact), 756 617 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E GENE", 757 618 &board_info_crosshair_x670e_gene), 619 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO", 620 + &board_info_crosshair_x670e_hero), 758 621 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO", 759 622 &board_info_maximus_xi_hero), 760 623 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)", 761 624 &board_info_maximus_xi_hero), 762 625 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS Z690 FORMULA", 763 626 &board_info_maximus_z690_formula), 764 - DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII IMPACT", 765 - &board_info_crosshair_viii_impact), 766 627 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-E GAMING", 767 628 &board_info_strix_b550_e_gaming), 768 629 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-I GAMING", 769 630 &board_info_strix_b550_i_gaming), 631 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B650E-I GAMING WIFI", 632 + &board_info_strix_b650e_i_gaming), 633 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B850-I GAMING WIFI", 634 + &board_info_strix_b850_i_gaming_wifi), 770 635 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING", 771 636 &board_info_strix_x570_e_gaming), 772 637 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING WIFI II", ··· 779 636 &board_info_strix_x570_f_gaming), 780 637 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-I GAMING", 781 638 &board_info_strix_x570_i_gaming), 639 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X670E-E GAMING WIFI", 640 + &board_info_strix_x670e_e_gaming_wifi), 641 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X670E-I GAMING WIFI", 642 + &board_info_strix_x670e_i_gaming_wifi), 643 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870-I GAMING WIFI", 644 + &board_info_strix_x870_i_gaming_wifi), 645 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-E GAMING WIFI", 646 + &board_info_strix_x870e_e_gaming_wifi), 782 647 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING", 783 648 &board_info_strix_z390_f_gaming), 784 649 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z490-F GAMING", 785 650 &board_info_strix_z490_f_gaming), 786 651 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4", 787 652 &board_info_strix_z690_a_gaming_wifi_d4), 653 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-E GAMING WIFI", 654 + &board_info_strix_z690_e_gaming_wifi), 655 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z790-E GAMING WIFI II", 656 + &board_info_strix_z790_e_gaming_wifi_ii), 657 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z790-I GAMING WIFI", 658 + &board_info_strix_z790_i_gaming_wifi), 788 659 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME", 789 660 &board_info_zenith_ii_extreme), 790 661 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA", 791 662 &board_info_zenith_ii_extreme), 792 663 DMI_EXACT_MATCH_ASUS_BOARD_NAME("TUF GAMING X670E-PLUS", 664 + &board_info_tuf_gaming_x670e_plus), 665 + DMI_EXACT_MATCH_ASUS_BOARD_NAME("TUF GAMING X670E-PLUS WIFI", 793 666 &board_info_tuf_gaming_x670e_plus), 794 667 {}, 795 668 }; ··· 1274 1115 case family_amd_800_series: 1275 1116 ec_data->sensors_info = sensors_family_amd_800; 1276 1117 break; 1118 + case family_amd_wrx_90: 1119 + ec_data->sensors_info = sensors_family_amd_wrx_90; 1120 + break; 1121 + case family_intel_200_series: 1122 + ec_data->sensors_info = sensors_family_intel_200; 1123 + break; 1277 1124 case family_intel_300_series: 1278 1125 ec_data->sensors_info = sensors_family_intel_300; 1279 1126 break; ··· 1288 1123 break; 1289 1124 case family_intel_600_series: 1290 1125 ec_data->sensors_info = sensors_family_intel_600; 1126 + break; 1127 + case family_intel_700_series: 1128 + ec_data->sensors_info = sensors_family_intel_700; 1291 1129 break; 1292 1130 default: 1293 1131 dev_err(dev, "Unknown board family: %d",
+36 -40
drivers/hwmon/coretemp.c
··· 122 122 }; 123 123 124 124 struct tjmax_model { 125 - u8 model; 126 - u8 mask; 125 + u32 vfm; 126 + u8 stepping_mask; 127 127 int tjmax; 128 128 }; 129 129 130 130 #define ANY 0xff 131 131 132 132 static const struct tjmax_model tjmax_model_table[] = { 133 - { 0x1c, 10, 100000 }, /* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */ 134 - { 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others 135 - * Note: Also matches 230 and 330, 136 - * which are covered by tjmax_table 137 - */ 138 - { 0x26, ANY, 90000 }, /* Atom Tunnel Creek (Exx), Lincroft (Z6xx) 139 - * Note: TjMax for E6xxT is 110C, but CPU type 140 - * is undetectable by software 141 - */ 142 - { 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */ 143 - { 0x35, ANY, 90000 }, /* Atom Clover Trail/Cloverview (Z27x0) */ 144 - { 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) 145 - * Also matches S12x0 (stepping 9), covered by 146 - * PCI table 147 - */ 133 + { INTEL_ATOM_BONNELL, 10, 100000 }, /* D4xx, K4xx, N4xx, D5xx, K5xx, N5xx */ 134 + { INTEL_ATOM_BONNELL, ANY, 90000 }, /* Z5xx, N2xx, possibly others 135 + * Note: Also matches 230 and 330, 136 + * which are covered by tjmax_table 137 + */ 138 + { INTEL_ATOM_BONNELL_MID, ANY, 90000 }, /* Atom Tunnel Creek (Exx), Lincroft (Z6xx) 139 + * Note: TjMax for E6xxT is 110C, but CPU type 140 + * is undetectable by software 141 + */ 142 + { INTEL_ATOM_SALTWELL_MID, ANY, 90000 }, /* Atom Medfield (Z2460) */ 143 + { INTEL_ATOM_SALTWELL_TABLET, ANY, 90000 }, /* Atom Clover Trail/Cloverview (Z27x0) */ 144 + { INTEL_ATOM_SALTWELL, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) 145 + * Also matches S12x0 (stepping 9), covered by 146 + * PCI table 147 + */ 148 148 }; 149 149 150 150 static bool is_pkg_temp_data(struct temp_data *tdata) ··· 180 180 } 181 181 pci_dev_put(host_bridge); 182 182 183 + /* 184 + * This is literally looking for "CPU XXX" in the model string. 185 + * Not checking it against the model as well. Just purely a 186 + * string search. 187 + */ 183 188 for (i = 0; i < ARRAY_SIZE(tjmax_table); i++) { 184 189 if (strstr(c->x86_model_id, tjmax_table[i].id)) 185 190 return tjmax_table[i].tjmax; ··· 192 187 193 188 for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) { 194 189 const struct tjmax_model *tm = &tjmax_model_table[i]; 195 - if (c->x86_model == tm->model && 196 - (tm->mask == ANY || c->x86_stepping == tm->mask)) 190 + if (c->x86_vfm == tm->vfm && 191 + (tm->stepping_mask == ANY || 192 + tm->stepping_mask == c->x86_stepping)) 197 193 return tm->tjmax; 198 194 } 199 195 200 196 /* Early chips have no MSR for TjMax */ 201 197 202 - if (c->x86_model == 0xf && c->x86_stepping < 4) 198 + if (c->x86_vfm == INTEL_CORE2_MEROM && c->x86_stepping < 4) 203 199 usemsr_ee = 0; 204 200 205 - if (c->x86_model > 0xe && usemsr_ee) { 201 + if (c->x86_vfm > INTEL_CORE_YONAH && usemsr_ee) { 206 202 u8 platform_id; 207 203 208 204 /* ··· 217 211 "Unable to access MSR 0x17, assuming desktop" 218 212 " CPU\n"); 219 213 usemsr_ee = 0; 220 - } else if (c->x86_model < 0x17 && !(eax & 0x10000000)) { 214 + } else if (c->x86_vfm < INTEL_CORE2_PENRYN && 215 + !(eax & 0x10000000)) { 221 216 /* 222 217 * Trust bit 28 up to Penryn, I could not find any 223 218 * documentation on that; if you happen to know ··· 233 226 * Mobile Penryn CPU seems to be platform ID 7 or 5 234 227 * (guesswork) 235 228 */ 236 - if (c->x86_model == 0x17 && 229 + if (c->x86_vfm == INTEL_CORE2_PENRYN && 237 230 (platform_id == 5 || platform_id == 7)) { 238 231 /* 239 232 * If MSR EE bit is set, set it to 90 degrees C, ··· 265 258 return tjmax; 266 259 } 267 260 268 - static bool cpu_has_tjmax(struct cpuinfo_x86 *c) 269 - { 270 - u8 model = c->x86_model; 271 - 272 - return model > 0xe && 273 - model != 0x1c && 274 - model != 0x26 && 275 - model != 0x27 && 276 - model != 0x35 && 277 - model != 0x36; 278 - } 279 - 280 261 static int get_tjmax(struct temp_data *tdata, struct device *dev) 281 262 { 282 263 struct cpuinfo_x86 *c = &cpu_data(tdata->cpu); ··· 282 287 */ 283 288 err = rdmsr_safe_on_cpu(tdata->cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); 284 289 if (err) { 285 - if (cpu_has_tjmax(c)) 286 - dev_warn(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu); 290 + dev_warn_once(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu); 287 291 } else { 288 292 val = (eax >> 16) & 0xff; 289 293 if (val) ··· 454 460 * Readings might stop update when processor visited too deep sleep, 455 461 * fixed for stepping D0 (6EC). 456 462 */ 457 - if (c->x86_model == 0xe && c->x86_stepping < 0xc && c->microcode < 0x39) { 463 + if (c->x86_vfm == INTEL_CORE_YONAH && c->x86_stepping < 0xc && c->microcode < 0x39) { 458 464 pr_err("Errata AE18 not fixed, update BIOS or microcode of the CPU!\n"); 459 465 return -ENODEV; 460 466 } ··· 574 580 * MSR_IA32_TEMPERATURE_TARGET register. Atoms don't have the register 575 581 * at all. 576 582 */ 577 - if (c->x86_model > 0xe && c->x86_model != 0x1c) 583 + if (c->x86_vfm > INTEL_CORE_YONAH && c->x86_vfm != INTEL_ATOM_BONNELL) 578 584 if (get_ttarget(tdata, &pdev->dev) >= 0) 579 585 tdata->attr_size++; 580 586 ··· 787 793 /* 788 794 * CPUID.06H.EAX[0] indicates whether the CPU has thermal 789 795 * sensors. We check this bit only, all the early CPUs 790 - * without thermal sensors will be filtered out. 796 + * without thermal sensors will be filtered out. This 797 + * includes all the Family 5 and Family 15 (Pentium 4) 798 + * models, since they never set the CPUID bit. 791 799 */ 792 800 if (!x86_match_cpu(coretemp_ids)) 793 801 return -ENODEV;
+313
drivers/hwmon/cros_ec_hwmon.c
··· 7 7 8 8 #include <linux/device.h> 9 9 #include <linux/hwmon.h> 10 + #include <linux/math.h> 10 11 #include <linux/mod_devicetable.h> 11 12 #include <linux/module.h> 12 13 #include <linux/platform_device.h> 13 14 #include <linux/platform_data/cros_ec_commands.h> 14 15 #include <linux/platform_data/cros_ec_proto.h> 16 + #include <linux/thermal.h> 15 17 #include <linux/types.h> 16 18 #include <linux/units.h> 17 19 18 20 #define DRV_NAME "cros-ec-hwmon" 19 21 22 + #define CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION 0 23 + #define CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION 1 24 + #define CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION 2 25 + 20 26 struct cros_ec_hwmon_priv { 21 27 struct cros_ec_device *cros_ec; 22 28 const char *temp_sensor_names[EC_TEMP_SENSOR_ENTRIES + EC_TEMP_SENSOR_B_ENTRIES]; 23 29 u8 usable_fans; 30 + bool fan_control_supported; 31 + u8 manual_fans; /* bits to indicate whether the fan is set to manual */ 32 + u8 manual_fan_pwm[EC_FAN_SPEED_ENTRIES]; 33 + }; 34 + 35 + struct cros_ec_hwmon_cooling_priv { 36 + struct cros_ec_hwmon_priv *hwmon_priv; 37 + u8 index; 24 38 }; 25 39 26 40 static int cros_ec_hwmon_read_fan_speed(struct cros_ec_device *cros_ec, u8 index, u16 *speed) ··· 47 33 return ret; 48 34 49 35 *speed = le16_to_cpu(__speed); 36 + return 0; 37 + } 38 + 39 + static int cros_ec_hwmon_read_pwm_value(struct cros_ec_device *cros_ec, u8 index, u8 *pwm_value) 40 + { 41 + struct ec_params_pwm_get_fan_duty req = { 42 + .fan_idx = index, 43 + }; 44 + struct ec_response_pwm_get_fan_duty resp; 45 + int ret; 46 + 47 + ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION, 48 + EC_CMD_PWM_GET_FAN_DUTY, &req, sizeof(req), &resp, sizeof(resp)); 49 + if (ret < 0) 50 + return ret; 51 + 52 + *pwm_value = (u8)DIV_ROUND_CLOSEST(le32_to_cpu(resp.percent) * 255, 100); 53 + return 0; 54 + } 55 + 56 + static int cros_ec_hwmon_read_pwm_enable(struct cros_ec_device *cros_ec, u8 index, 57 + u8 *control_method) 58 + { 59 + struct ec_params_auto_fan_ctrl_v2 req = { 60 + .cmd = EC_AUTO_FAN_CONTROL_CMD_GET, 61 + .fan_idx = index, 62 + }; 63 + struct ec_response_auto_fan_control resp; 64 + int ret; 65 + 66 + ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION, 67 + EC_CMD_THERMAL_AUTO_FAN_CTRL, &req, sizeof(req), &resp, sizeof(resp)); 68 + if (ret < 0) 69 + return ret; 70 + 71 + *control_method = resp.is_auto ? 2 : 1; 50 72 return 0; 51 73 } 52 74 ··· 125 75 { 126 76 struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev); 127 77 int ret = -EOPNOTSUPP; 78 + u8 control_method; 79 + u8 pwm_value; 128 80 u16 speed; 129 81 u8 temp; 130 82 ··· 143 91 ret = cros_ec_hwmon_read_fan_speed(priv->cros_ec, channel, &speed); 144 92 if (ret == 0) 145 93 *val = cros_ec_hwmon_is_error_fan(speed); 94 + } 95 + } else if (type == hwmon_pwm) { 96 + if (attr == hwmon_pwm_enable) { 97 + ret = cros_ec_hwmon_read_pwm_enable(priv->cros_ec, channel, 98 + &control_method); 99 + if (ret == 0) 100 + *val = control_method; 101 + } else if (attr == hwmon_pwm_input) { 102 + ret = cros_ec_hwmon_read_pwm_value(priv->cros_ec, channel, &pwm_value); 103 + if (ret == 0) 104 + *val = pwm_value; 146 105 } 147 106 } else if (type == hwmon_temp) { 148 107 if (attr == hwmon_temp_input) { ··· 187 124 return -EOPNOTSUPP; 188 125 } 189 126 127 + static int cros_ec_hwmon_set_fan_pwm_val(struct cros_ec_device *cros_ec, u8 index, u8 val) 128 + { 129 + struct ec_params_pwm_set_fan_duty_v1 req = { 130 + .fan_idx = index, 131 + .percent = DIV_ROUND_CLOSEST((uint32_t)val * 100, 255), 132 + }; 133 + int ret; 134 + 135 + ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION, 136 + EC_CMD_PWM_SET_FAN_DUTY, &req, sizeof(req), NULL, 0); 137 + if (ret < 0) 138 + return ret; 139 + return 0; 140 + } 141 + 142 + static int cros_ec_hwmon_write_pwm_input(struct cros_ec_device *cros_ec, u8 index, u8 val) 143 + { 144 + u8 control_method; 145 + int ret; 146 + 147 + ret = cros_ec_hwmon_read_pwm_enable(cros_ec, index, &control_method); 148 + if (ret) 149 + return ret; 150 + if (control_method != 1) 151 + return -EOPNOTSUPP; 152 + 153 + return cros_ec_hwmon_set_fan_pwm_val(cros_ec, index, val); 154 + } 155 + 156 + static int cros_ec_hwmon_write_pwm_enable(struct cros_ec_device *cros_ec, u8 index, u8 val) 157 + { 158 + struct ec_params_auto_fan_ctrl_v2 req = { 159 + .fan_idx = index, 160 + .cmd = EC_AUTO_FAN_CONTROL_CMD_SET, 161 + }; 162 + int ret; 163 + 164 + /* No CrOS EC supports no fan speed control */ 165 + if (val == 0) 166 + return -EOPNOTSUPP; 167 + 168 + req.set_auto = (val != 1) ? true : false; 169 + ret = cros_ec_cmd(cros_ec, CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION, 170 + EC_CMD_THERMAL_AUTO_FAN_CTRL, &req, sizeof(req), NULL, 0); 171 + if (ret < 0) 172 + return ret; 173 + return 0; 174 + } 175 + 176 + static int cros_ec_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, 177 + int channel, long val) 178 + { 179 + struct cros_ec_hwmon_priv *priv = dev_get_drvdata(dev); 180 + 181 + if (type == hwmon_pwm) { 182 + switch (attr) { 183 + case hwmon_pwm_input: 184 + return cros_ec_hwmon_write_pwm_input(priv->cros_ec, channel, val); 185 + case hwmon_pwm_enable: 186 + return cros_ec_hwmon_write_pwm_enable(priv->cros_ec, channel, val); 187 + default: 188 + return -EOPNOTSUPP; 189 + } 190 + } 191 + 192 + return -EOPNOTSUPP; 193 + } 194 + 190 195 static umode_t cros_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, 191 196 u32 attr, int channel) 192 197 { ··· 263 132 if (type == hwmon_fan) { 264 133 if (priv->usable_fans & BIT(channel)) 265 134 return 0444; 135 + } else if (type == hwmon_pwm) { 136 + if (priv->fan_control_supported && priv->usable_fans & BIT(channel)) 137 + return 0644; 266 138 } else if (type == hwmon_temp) { 267 139 if (priv->temp_sensor_names[channel]) 268 140 return 0444; ··· 281 147 HWMON_F_INPUT | HWMON_F_FAULT, 282 148 HWMON_F_INPUT | HWMON_F_FAULT, 283 149 HWMON_F_INPUT | HWMON_F_FAULT), 150 + HWMON_CHANNEL_INFO(pwm, 151 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 152 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 153 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 154 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 284 155 HWMON_CHANNEL_INFO(temp, 285 156 HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL, 286 157 HWMON_T_INPUT | HWMON_T_FAULT | HWMON_T_LABEL, ··· 314 175 NULL 315 176 }; 316 177 178 + static int cros_ec_hwmon_cooling_get_max_state(struct thermal_cooling_device *cdev, 179 + unsigned long *val) 180 + { 181 + *val = 255; 182 + return 0; 183 + } 184 + 185 + static int cros_ec_hwmon_cooling_get_cur_state(struct thermal_cooling_device *cdev, 186 + unsigned long *val) 187 + { 188 + const struct cros_ec_hwmon_cooling_priv *priv = cdev->devdata; 189 + u8 read_val; 190 + int ret; 191 + 192 + ret = cros_ec_hwmon_read_pwm_value(priv->hwmon_priv->cros_ec, priv->index, &read_val); 193 + if (ret) 194 + return ret; 195 + 196 + *val = read_val; 197 + return 0; 198 + } 199 + 200 + static int cros_ec_hwmon_cooling_set_cur_state(struct thermal_cooling_device *cdev, 201 + unsigned long val) 202 + { 203 + const struct cros_ec_hwmon_cooling_priv *priv = cdev->devdata; 204 + 205 + return cros_ec_hwmon_write_pwm_input(priv->hwmon_priv->cros_ec, priv->index, val); 206 + } 207 + 208 + static const struct thermal_cooling_device_ops cros_ec_thermal_cooling_ops = { 209 + .get_max_state = cros_ec_hwmon_cooling_get_max_state, 210 + .get_cur_state = cros_ec_hwmon_cooling_get_cur_state, 211 + .set_cur_state = cros_ec_hwmon_cooling_set_cur_state, 212 + }; 213 + 317 214 static const struct hwmon_ops cros_ec_hwmon_ops = { 318 215 .read = cros_ec_hwmon_read, 319 216 .read_string = cros_ec_hwmon_read_string, 217 + .write = cros_ec_hwmon_write, 320 218 .is_visible = cros_ec_hwmon_is_visible, 321 219 }; 322 220 ··· 409 233 } 410 234 } 411 235 236 + static inline bool is_cros_ec_cmd_available(struct cros_ec_device *cros_ec, 237 + u16 cmd, u8 version) 238 + { 239 + int ret; 240 + 241 + ret = cros_ec_get_cmd_versions(cros_ec, cmd); 242 + return ret >= 0 && (ret & EC_VER_MASK(version)); 243 + } 244 + 245 + static bool cros_ec_hwmon_probe_fan_control_supported(struct cros_ec_device *cros_ec) 246 + { 247 + return is_cros_ec_cmd_available(cros_ec, EC_CMD_PWM_GET_FAN_DUTY, 248 + CROS_EC_HWMON_PWM_GET_FAN_DUTY_CMD_VERSION) && 249 + is_cros_ec_cmd_available(cros_ec, EC_CMD_PWM_SET_FAN_DUTY, 250 + CROS_EC_HWMON_PWM_SET_FAN_DUTY_CMD_VERSION) && 251 + is_cros_ec_cmd_available(cros_ec, EC_CMD_THERMAL_AUTO_FAN_CTRL, 252 + CROS_EC_HWMON_THERMAL_AUTO_FAN_CTRL_CMD_VERSION); 253 + } 254 + 255 + static void cros_ec_hwmon_register_fan_cooling_devices(struct device *dev, 256 + struct cros_ec_hwmon_priv *priv) 257 + { 258 + struct cros_ec_hwmon_cooling_priv *cpriv; 259 + struct thermal_cooling_device *cdev; 260 + const char *type; 261 + size_t i; 262 + 263 + if (!IS_ENABLED(CONFIG_THERMAL)) 264 + return; 265 + 266 + if (!priv->fan_control_supported) 267 + return; 268 + 269 + for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) { 270 + if (!(priv->usable_fans & BIT(i))) 271 + continue; 272 + 273 + cpriv = devm_kzalloc(dev, sizeof(*cpriv), GFP_KERNEL); 274 + if (!cpriv) 275 + continue; 276 + 277 + type = devm_kasprintf(dev, GFP_KERNEL, "%s-fan%zu", dev_name(dev), i); 278 + if (!type) { 279 + dev_warn(dev, "no memory to compose cooling device type for fan %zu\n", i); 280 + continue; 281 + } 282 + 283 + cpriv->hwmon_priv = priv; 284 + cpriv->index = i; 285 + cdev = devm_thermal_of_cooling_device_register(dev, NULL, type, cpriv, 286 + &cros_ec_thermal_cooling_ops); 287 + if (IS_ERR(cdev)) { 288 + dev_warn(dev, "failed to register fan %zu as a cooling device: %pe\n", i, 289 + cdev); 290 + continue; 291 + } 292 + } 293 + } 294 + 412 295 static int cros_ec_hwmon_probe(struct platform_device *pdev) 413 296 { 414 297 struct device *dev = &pdev->dev; ··· 494 259 495 260 cros_ec_hwmon_probe_temp_sensors(dev, priv, thermal_version); 496 261 cros_ec_hwmon_probe_fans(priv); 262 + priv->fan_control_supported = cros_ec_hwmon_probe_fan_control_supported(priv->cros_ec); 263 + cros_ec_hwmon_register_fan_cooling_devices(dev, priv); 497 264 498 265 hwmon_dev = devm_hwmon_device_register_with_info(dev, "cros_ec", priv, 499 266 &cros_ec_hwmon_chip_info, NULL); 267 + platform_set_drvdata(pdev, priv); 500 268 501 269 return PTR_ERR_OR_ZERO(hwmon_dev); 270 + } 271 + 272 + static int cros_ec_hwmon_suspend(struct platform_device *pdev, pm_message_t state) 273 + { 274 + struct cros_ec_hwmon_priv *priv = platform_get_drvdata(pdev); 275 + u8 control_method; 276 + size_t i; 277 + int ret; 278 + 279 + if (!priv->fan_control_supported) 280 + return 0; 281 + 282 + /* EC sets fan control to auto after suspended, store settings before suspending. */ 283 + for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) { 284 + if (!(priv->usable_fans & BIT(i))) 285 + continue; 286 + 287 + ret = cros_ec_hwmon_read_pwm_enable(priv->cros_ec, i, &control_method); 288 + if (ret) { 289 + dev_warn(&pdev->dev, "failed to get mode setting for fan %zu: %d\n", i, 290 + ret); 291 + continue; 292 + } 293 + 294 + if (control_method != 1) { 295 + priv->manual_fans &= ~BIT(i); 296 + continue; 297 + } else { 298 + priv->manual_fans |= BIT(i); 299 + } 300 + 301 + ret = cros_ec_hwmon_read_pwm_value(priv->cros_ec, i, &priv->manual_fan_pwm[i]); 302 + /* 303 + * If storing the value failed, invalidate the stored mode value by setting it 304 + * to auto control. EC will automatically switch to auto mode for that fan after 305 + * suspended. 306 + */ 307 + if (ret) { 308 + dev_warn(&pdev->dev, "failed to get PWM setting for fan %zu: %pe\n", i, 309 + ERR_PTR(ret)); 310 + priv->manual_fans &= ~BIT(i); 311 + continue; 312 + } 313 + } 314 + 315 + return 0; 316 + } 317 + 318 + static int cros_ec_hwmon_resume(struct platform_device *pdev) 319 + { 320 + const struct cros_ec_hwmon_priv *priv = platform_get_drvdata(pdev); 321 + size_t i; 322 + int ret; 323 + 324 + if (!priv->fan_control_supported) 325 + return 0; 326 + 327 + /* EC sets fan control to auto after suspend, restore to settings before suspend. */ 328 + for (i = 0; i < EC_FAN_SPEED_ENTRIES; i++) { 329 + if (!(priv->manual_fans & BIT(i))) 330 + continue; 331 + 332 + /* 333 + * Setting fan PWM value to EC will change the mode to manual for that fan in EC as 334 + * well, so we do not need to issue a separate fan mode to manual call. 335 + */ 336 + ret = cros_ec_hwmon_set_fan_pwm_val(priv->cros_ec, i, priv->manual_fan_pwm[i]); 337 + if (ret) 338 + dev_warn(&pdev->dev, "failed to restore settings for fan %zu: %pe\n", i, 339 + ERR_PTR(ret)); 340 + } 341 + 342 + return 0; 502 343 } 503 344 504 345 static const struct platform_device_id cros_ec_hwmon_id[] = { ··· 585 274 static struct platform_driver cros_ec_hwmon_driver = { 586 275 .driver.name = DRV_NAME, 587 276 .probe = cros_ec_hwmon_probe, 277 + .suspend = pm_ptr(cros_ec_hwmon_suspend), 278 + .resume = pm_ptr(cros_ec_hwmon_resume), 588 279 .id_table = cros_ec_hwmon_id, 589 280 }; 590 281 module_platform_driver(cros_ec_hwmon_driver);
+71 -28
drivers/hwmon/dell-smm-hwmon.c
··· 24 24 #include <linux/init.h> 25 25 #include <linux/kconfig.h> 26 26 #include <linux/kernel.h> 27 + #include <linux/minmax.h> 27 28 #include <linux/module.h> 28 29 #include <linux/mutex.h> 29 30 #include <linux/platform_device.h> ··· 447 446 if (disallow_fan_support) 448 447 return -EINVAL; 449 448 450 - speed = (speed < 0) ? 0 : ((speed > data->i8k_fan_max) ? data->i8k_fan_max : speed); 451 449 regs.ebx = fan | (speed << 8); 452 450 453 451 return dell_smm_call(data->ops, &regs); ··· 637 637 if (copy_from_user(&speed, argp + 1, sizeof(int))) 638 638 return -EFAULT; 639 639 640 + speed = clamp_val(speed, 0, data->i8k_fan_max); 641 + 640 642 mutex_lock(&data->i8k_mutex); 641 643 err = i8k_set_fan(data, val, speed); 642 644 if (err < 0) ··· 764 762 if (ret < 0) 765 763 return ret; 766 764 765 + /* 766 + * A fan state bigger than i8k_fan_max might indicate that 767 + * the fan is currently in automatic mode. 768 + */ 769 + if (ret > cdata->data->i8k_fan_max) 770 + return -ENODATA; 771 + 767 772 *state = ret; 768 773 769 774 return 0; ··· 858 849 859 850 break; 860 851 case hwmon_pwm_enable: 861 - if (auto_fan) 852 + if (auto_fan) { 853 + /* 854 + * The setting affects all fans, so only create a 855 + * single attribute. 856 + */ 857 + if (channel != 1) 858 + return 0; 859 + 862 860 /* 863 861 * There is no command for retrieve the current status 864 862 * from BIOS, and userspace/firmware itself can change ··· 873 857 * Thus we can only provide write-only access for now. 874 858 */ 875 859 return 0200; 860 + } 861 + 862 + if (data->fan[channel] && data->i8k_fan_max < I8K_FAN_AUTO) 863 + return 0644; 876 864 877 865 break; 878 866 default: ··· 946 926 } 947 927 break; 948 928 case hwmon_pwm: 929 + ret = i8k_get_fan_status(data, channel); 930 + if (ret < 0) 931 + return ret; 932 + 949 933 switch (attr) { 950 934 case hwmon_pwm_input: 951 - ret = i8k_get_fan_status(data, channel); 952 - if (ret < 0) 953 - return ret; 935 + /* 936 + * A fan state bigger than i8k_fan_max might indicate that 937 + * the fan is currently in automatic mode. 938 + */ 939 + if (ret > data->i8k_fan_max) 940 + return -ENODATA; 954 941 955 942 *val = clamp_val(ret * data->i8k_pwm_mult, 0, 255); 943 + 944 + return 0; 945 + case hwmon_pwm_enable: 946 + if (ret == I8K_FAN_AUTO) 947 + *val = 2; 948 + else 949 + *val = 1; 956 950 957 951 return 0; 958 952 default: ··· 1054 1020 1055 1021 return 0; 1056 1022 case hwmon_pwm_enable: 1057 - if (!val) 1058 - return -EINVAL; 1059 - 1060 - if (val == 1) 1023 + switch (val) { 1024 + case 1: 1061 1025 enable = false; 1062 - else 1026 + break; 1027 + case 2: 1063 1028 enable = true; 1029 + break; 1030 + default: 1031 + return -EINVAL; 1032 + } 1064 1033 1065 1034 mutex_lock(&data->i8k_mutex); 1066 - err = i8k_enable_fan_auto_mode(data, enable); 1035 + if (auto_fan) { 1036 + err = i8k_enable_fan_auto_mode(data, enable); 1037 + } else { 1038 + /* 1039 + * When putting the fan into manual control mode we have to ensure 1040 + * that the device does not overheat until the userspace fan control 1041 + * software takes over. Because of this we set the fan speed to 1042 + * i8k_fan_max when disabling automatic fan control. 1043 + */ 1044 + if (enable) 1045 + err = i8k_set_fan(data, channel, I8K_FAN_AUTO); 1046 + else 1047 + err = i8k_set_fan(data, channel, data->i8k_fan_max); 1048 + } 1067 1049 mutex_unlock(&data->i8k_mutex); 1068 1050 1069 1051 if (err < 0) ··· 1130 1080 ), 1131 1081 HWMON_CHANNEL_INFO(pwm, 1132 1082 HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 1133 - HWMON_PWM_INPUT, 1134 - HWMON_PWM_INPUT, 1135 - HWMON_PWM_INPUT 1083 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 1084 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, 1085 + HWMON_PWM_INPUT | HWMON_PWM_ENABLE 1136 1086 ), 1137 1087 NULL 1138 1088 }; ··· 1331 1281 }, 1332 1282 }, 1333 1283 { 1284 + .ident = "Dell OptiPlex 7040", 1285 + .matches = { 1286 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1287 + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "OptiPlex 7040"), 1288 + }, 1289 + }, 1290 + { 1334 1291 .ident = "Dell Precision", 1335 1292 .matches = { 1336 1293 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), ··· 1388 1331 1389 1332 enum i8k_configs { 1390 1333 DELL_LATITUDE_D520, 1391 - DELL_PRECISION_490, 1392 1334 DELL_STUDIO, 1393 1335 DELL_XPS, 1394 1336 }; 1395 1337 1396 1338 static const struct i8k_config_data i8k_config_data[] __initconst = { 1397 1339 [DELL_LATITUDE_D520] = { 1398 - .fan_mult = 1, 1399 - .fan_max = I8K_FAN_TURBO, 1400 - }, 1401 - [DELL_PRECISION_490] = { 1402 1340 .fan_mult = 1, 1403 1341 .fan_max = I8K_FAN_TURBO, 1404 1342 }, ··· 1415 1363 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"), 1416 1364 }, 1417 1365 .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], 1418 - }, 1419 - { 1420 - .ident = "Dell Precision 490", 1421 - .matches = { 1422 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 1423 - DMI_MATCH(DMI_PRODUCT_NAME, 1424 - "Precision WorkStation 490"), 1425 - }, 1426 - .driver_data = (void *)&i8k_config_data[DELL_PRECISION_490], 1427 1366 }, 1428 1367 { 1429 1368 .ident = "Dell Studio",
+715
drivers/hwmon/gpd-fan.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + /* Platform driver for GPD devices that expose fan control via hwmon sysfs. 4 + * 5 + * Fan control is provided via pwm interface in the range [0-255]. 6 + * Each model has a different range in the EC, the written value is scaled to 7 + * accommodate for that. 8 + * 9 + * Based on this repo: 10 + * https://github.com/Cryolitia/gpd-fan-driver 11 + * 12 + * Copyright (c) 2024 Cryolitia PukNgae 13 + */ 14 + 15 + #include <linux/acpi.h> 16 + #include <linux/dmi.h> 17 + #include <linux/hwmon.h> 18 + #include <linux/ioport.h> 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/platform_device.h> 22 + 23 + #define DRIVER_NAME "gpdfan" 24 + #define GPD_PWM_CTR_OFFSET 0x1841 25 + 26 + static char *gpd_fan_board = ""; 27 + module_param(gpd_fan_board, charp, 0444); 28 + 29 + // EC read/write locker, protecting a sequence of EC operations 30 + static DEFINE_MUTEX(gpd_fan_sequence_lock); 31 + 32 + enum gpd_board { 33 + win_mini, 34 + win4_6800u, 35 + win_max_2, 36 + duo, 37 + }; 38 + 39 + enum FAN_PWM_ENABLE { 40 + DISABLE = 0, 41 + MANUAL = 1, 42 + AUTOMATIC = 2, 43 + }; 44 + 45 + static struct { 46 + enum FAN_PWM_ENABLE pwm_enable; 47 + u8 pwm_value; 48 + 49 + const struct gpd_fan_drvdata *drvdata; 50 + } gpd_driver_priv; 51 + 52 + struct gpd_fan_drvdata { 53 + const char *board_name; // Board name for module param comparison 54 + const enum gpd_board board; 55 + 56 + const u8 addr_port; 57 + const u8 data_port; 58 + const u16 manual_control_enable; 59 + const u16 rpm_read; 60 + const u16 pwm_write; 61 + const u16 pwm_max; 62 + }; 63 + 64 + static struct gpd_fan_drvdata gpd_win_mini_drvdata = { 65 + .board_name = "win_mini", 66 + .board = win_mini, 67 + 68 + .addr_port = 0x4E, 69 + .data_port = 0x4F, 70 + .manual_control_enable = 0x047A, 71 + .rpm_read = 0x0478, 72 + .pwm_write = 0x047A, 73 + .pwm_max = 244, 74 + }; 75 + 76 + static struct gpd_fan_drvdata gpd_duo_drvdata = { 77 + .board_name = "duo", 78 + .board = duo, 79 + 80 + .addr_port = 0x4E, 81 + .data_port = 0x4F, 82 + .manual_control_enable = 0x047A, 83 + .rpm_read = 0x0478, 84 + .pwm_write = 0x047A, 85 + .pwm_max = 244, 86 + }; 87 + 88 + static struct gpd_fan_drvdata gpd_win4_drvdata = { 89 + .board_name = "win4", 90 + .board = win4_6800u, 91 + 92 + .addr_port = 0x2E, 93 + .data_port = 0x2F, 94 + .manual_control_enable = 0xC311, 95 + .rpm_read = 0xC880, 96 + .pwm_write = 0xC311, 97 + .pwm_max = 127, 98 + }; 99 + 100 + static struct gpd_fan_drvdata gpd_wm2_drvdata = { 101 + .board_name = "wm2", 102 + .board = win_max_2, 103 + 104 + .addr_port = 0x4E, 105 + .data_port = 0x4F, 106 + .manual_control_enable = 0x0275, 107 + .rpm_read = 0x0218, 108 + .pwm_write = 0x1809, 109 + .pwm_max = 184, 110 + }; 111 + 112 + static const struct dmi_system_id dmi_table[] = { 113 + { 114 + // GPD Win Mini 115 + // GPD Win Mini with AMD Ryzen 8840U 116 + .matches = { 117 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 118 + DMI_MATCH(DMI_PRODUCT_NAME, "G1617-01") 119 + }, 120 + .driver_data = &gpd_win_mini_drvdata, 121 + }, 122 + { 123 + // GPD Win Mini 124 + // GPD Win Mini with AMD Ryzen HX370 125 + .matches = { 126 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 127 + DMI_MATCH(DMI_PRODUCT_NAME, "G1617-02") 128 + }, 129 + .driver_data = &gpd_win_mini_drvdata, 130 + }, 131 + { 132 + // GPD Win Mini 133 + // GPD Win Mini with AMD Ryzen HX370 134 + .matches = { 135 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 136 + DMI_MATCH(DMI_PRODUCT_NAME, "G1617-02-L") 137 + }, 138 + .driver_data = &gpd_win_mini_drvdata, 139 + }, 140 + { 141 + // GPD Win 4 with AMD Ryzen 6800U 142 + .matches = { 143 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 144 + DMI_MATCH(DMI_PRODUCT_NAME, "G1618-04"), 145 + DMI_MATCH(DMI_BOARD_VERSION, "Default string"), 146 + }, 147 + .driver_data = &gpd_win4_drvdata, 148 + }, 149 + { 150 + // GPD Win 4 with Ryzen 7840U 151 + .matches = { 152 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 153 + DMI_MATCH(DMI_PRODUCT_NAME, "G1618-04"), 154 + DMI_MATCH(DMI_BOARD_VERSION, "Ver. 1.0"), 155 + }, 156 + // Since 7840U, win4 uses the same drvdata as wm2 157 + .driver_data = &gpd_wm2_drvdata, 158 + }, 159 + { 160 + // GPD Win 4 with Ryzen 7840U (another) 161 + .matches = { 162 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 163 + DMI_MATCH(DMI_PRODUCT_NAME, "G1618-04"), 164 + DMI_MATCH(DMI_BOARD_VERSION, "Ver.1.0"), 165 + }, 166 + .driver_data = &gpd_wm2_drvdata, 167 + }, 168 + { 169 + // GPD Win Max 2 with Ryzen 6800U 170 + // GPD Win Max 2 2023 with Ryzen 7840U 171 + // GPD Win Max 2 2024 with Ryzen 8840U 172 + .matches = { 173 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 174 + DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"), 175 + }, 176 + .driver_data = &gpd_wm2_drvdata, 177 + }, 178 + { 179 + // GPD Win Max 2 with AMD Ryzen HX370 180 + .matches = { 181 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 182 + DMI_MATCH(DMI_PRODUCT_NAME, "G1619-05"), 183 + }, 184 + .driver_data = &gpd_wm2_drvdata, 185 + }, 186 + { 187 + // GPD Duo 188 + .matches = { 189 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 190 + DMI_MATCH(DMI_PRODUCT_NAME, "G1622-01"), 191 + }, 192 + .driver_data = &gpd_duo_drvdata, 193 + }, 194 + { 195 + // GPD Duo (another) 196 + .matches = { 197 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 198 + DMI_MATCH(DMI_PRODUCT_NAME, "G1622-01-L"), 199 + }, 200 + .driver_data = &gpd_duo_drvdata, 201 + }, 202 + { 203 + // GPD Pocket 4 204 + .matches = { 205 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 206 + DMI_MATCH(DMI_PRODUCT_NAME, "G1628-04"), 207 + }, 208 + .driver_data = &gpd_win_mini_drvdata, 209 + }, 210 + { 211 + // GPD Pocket 4 (another) 212 + .matches = { 213 + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 214 + DMI_MATCH(DMI_PRODUCT_NAME, "G1628-04-L"), 215 + }, 216 + .driver_data = &gpd_win_mini_drvdata, 217 + }, 218 + {} 219 + }; 220 + 221 + static const struct gpd_fan_drvdata *gpd_module_drvdata[] = { 222 + &gpd_win_mini_drvdata, &gpd_win4_drvdata, &gpd_wm2_drvdata, NULL 223 + }; 224 + 225 + // Helper functions to handle EC read/write 226 + static void gpd_ecram_read(u16 offset, u8 *val) 227 + { 228 + u16 addr_port = gpd_driver_priv.drvdata->addr_port; 229 + u16 data_port = gpd_driver_priv.drvdata->data_port; 230 + 231 + outb(0x2E, addr_port); 232 + outb(0x11, data_port); 233 + outb(0x2F, addr_port); 234 + outb((u8)((offset >> 8) & 0xFF), data_port); 235 + 236 + outb(0x2E, addr_port); 237 + outb(0x10, data_port); 238 + outb(0x2F, addr_port); 239 + outb((u8)(offset & 0xFF), data_port); 240 + 241 + outb(0x2E, addr_port); 242 + outb(0x12, data_port); 243 + outb(0x2F, addr_port); 244 + *val = inb(data_port); 245 + } 246 + 247 + static void gpd_ecram_write(u16 offset, u8 value) 248 + { 249 + u16 addr_port = gpd_driver_priv.drvdata->addr_port; 250 + u16 data_port = gpd_driver_priv.drvdata->data_port; 251 + 252 + outb(0x2E, addr_port); 253 + outb(0x11, data_port); 254 + outb(0x2F, addr_port); 255 + outb((u8)((offset >> 8) & 0xFF), data_port); 256 + 257 + outb(0x2E, addr_port); 258 + outb(0x10, data_port); 259 + outb(0x2F, addr_port); 260 + outb((u8)(offset & 0xFF), data_port); 261 + 262 + outb(0x2E, addr_port); 263 + outb(0x12, data_port); 264 + outb(0x2F, addr_port); 265 + outb(value, data_port); 266 + } 267 + 268 + static int gpd_generic_read_rpm(void) 269 + { 270 + const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 271 + u8 high, low; 272 + 273 + gpd_ecram_read(drvdata->rpm_read, &high); 274 + gpd_ecram_read(drvdata->rpm_read + 1, &low); 275 + 276 + return (u16)high << 8 | low; 277 + } 278 + 279 + static void gpd_win4_init_ec(void) 280 + { 281 + u8 chip_id, chip_ver; 282 + 283 + gpd_ecram_read(0x2000, &chip_id); 284 + 285 + if (chip_id == 0x55) { 286 + gpd_ecram_read(0x1060, &chip_ver); 287 + gpd_ecram_write(0x1060, chip_ver | 0x80); 288 + } 289 + } 290 + 291 + static int gpd_win4_read_rpm(void) 292 + { 293 + int ret; 294 + 295 + ret = gpd_generic_read_rpm(); 296 + 297 + if (ret == 0) 298 + // Re-init EC when speed is 0 299 + gpd_win4_init_ec(); 300 + 301 + return ret; 302 + } 303 + 304 + static int gpd_wm2_read_rpm(void) 305 + { 306 + for (u16 pwm_ctr_offset = GPD_PWM_CTR_OFFSET; 307 + pwm_ctr_offset <= GPD_PWM_CTR_OFFSET + 2; pwm_ctr_offset++) { 308 + u8 PWMCTR; 309 + 310 + gpd_ecram_read(pwm_ctr_offset, &PWMCTR); 311 + 312 + if (PWMCTR != 0xB8) 313 + gpd_ecram_write(pwm_ctr_offset, 0xB8); 314 + } 315 + 316 + return gpd_generic_read_rpm(); 317 + } 318 + 319 + // Read value for fan1_input 320 + static int gpd_read_rpm(void) 321 + { 322 + switch (gpd_driver_priv.drvdata->board) { 323 + case win_mini: 324 + case duo: 325 + return gpd_generic_read_rpm(); 326 + case win4_6800u: 327 + return gpd_win4_read_rpm(); 328 + case win_max_2: 329 + return gpd_wm2_read_rpm(); 330 + } 331 + 332 + return 0; 333 + } 334 + 335 + static int gpd_wm2_read_pwm(void) 336 + { 337 + const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 338 + u8 var; 339 + 340 + gpd_ecram_read(drvdata->pwm_write, &var); 341 + 342 + // Match gpd_generic_write_pwm(u8) below 343 + return DIV_ROUND_CLOSEST((var - 1) * 255, (drvdata->pwm_max - 1)); 344 + } 345 + 346 + // Read value for pwm1 347 + static int gpd_read_pwm(void) 348 + { 349 + switch (gpd_driver_priv.drvdata->board) { 350 + case win_mini: 351 + case duo: 352 + case win4_6800u: 353 + switch (gpd_driver_priv.pwm_enable) { 354 + case DISABLE: 355 + return 255; 356 + case MANUAL: 357 + return gpd_driver_priv.pwm_value; 358 + case AUTOMATIC: 359 + return -EOPNOTSUPP; 360 + } 361 + break; 362 + case win_max_2: 363 + return gpd_wm2_read_pwm(); 364 + } 365 + return 0; 366 + } 367 + 368 + // PWM value's range in EC is 1 - pwm_max, cast 0 - 255 to it. 369 + static inline u8 gpd_cast_pwm_range(u8 val) 370 + { 371 + const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 372 + 373 + return DIV_ROUND_CLOSEST(val * (drvdata->pwm_max - 1), 255) + 1; 374 + } 375 + 376 + static void gpd_generic_write_pwm(u8 val) 377 + { 378 + const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 379 + u8 pwm_reg; 380 + 381 + pwm_reg = gpd_cast_pwm_range(val); 382 + gpd_ecram_write(drvdata->pwm_write, pwm_reg); 383 + } 384 + 385 + static void gpd_duo_write_pwm(u8 val) 386 + { 387 + const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 388 + u8 pwm_reg; 389 + 390 + pwm_reg = gpd_cast_pwm_range(val); 391 + gpd_ecram_write(drvdata->pwm_write, pwm_reg); 392 + gpd_ecram_write(drvdata->pwm_write + 1, pwm_reg); 393 + } 394 + 395 + // Write value for pwm1 396 + static int gpd_write_pwm(u8 val) 397 + { 398 + if (gpd_driver_priv.pwm_enable != MANUAL) 399 + return -EPERM; 400 + 401 + switch (gpd_driver_priv.drvdata->board) { 402 + case duo: 403 + gpd_duo_write_pwm(val); 404 + break; 405 + case win_mini: 406 + case win4_6800u: 407 + case win_max_2: 408 + gpd_generic_write_pwm(val); 409 + break; 410 + } 411 + 412 + return 0; 413 + } 414 + 415 + static void gpd_win_mini_set_pwm_enable(enum FAN_PWM_ENABLE pwm_enable) 416 + { 417 + switch (pwm_enable) { 418 + case DISABLE: 419 + gpd_generic_write_pwm(255); 420 + break; 421 + case MANUAL: 422 + gpd_generic_write_pwm(gpd_driver_priv.pwm_value); 423 + break; 424 + case AUTOMATIC: 425 + gpd_ecram_write(gpd_driver_priv.drvdata->pwm_write, 0); 426 + break; 427 + } 428 + } 429 + 430 + static void gpd_duo_set_pwm_enable(enum FAN_PWM_ENABLE pwm_enable) 431 + { 432 + switch (pwm_enable) { 433 + case DISABLE: 434 + gpd_duo_write_pwm(255); 435 + break; 436 + case MANUAL: 437 + gpd_duo_write_pwm(gpd_driver_priv.pwm_value); 438 + break; 439 + case AUTOMATIC: 440 + gpd_ecram_write(gpd_driver_priv.drvdata->pwm_write, 0); 441 + break; 442 + } 443 + } 444 + 445 + static void gpd_wm2_set_pwm_enable(enum FAN_PWM_ENABLE enable) 446 + { 447 + const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 448 + 449 + switch (enable) { 450 + case DISABLE: 451 + gpd_generic_write_pwm(255); 452 + gpd_ecram_write(drvdata->manual_control_enable, 1); 453 + break; 454 + case MANUAL: 455 + gpd_generic_write_pwm(gpd_driver_priv.pwm_value); 456 + gpd_ecram_write(drvdata->manual_control_enable, 1); 457 + break; 458 + case AUTOMATIC: 459 + gpd_ecram_write(drvdata->manual_control_enable, 0); 460 + break; 461 + } 462 + } 463 + 464 + // Write value for pwm1_enable 465 + static void gpd_set_pwm_enable(enum FAN_PWM_ENABLE enable) 466 + { 467 + if (enable == MANUAL) 468 + // Set pwm_value to max firstly when switching to manual mode, in 469 + // consideration of device safety. 470 + gpd_driver_priv.pwm_value = 255; 471 + 472 + switch (gpd_driver_priv.drvdata->board) { 473 + case win_mini: 474 + case win4_6800u: 475 + gpd_win_mini_set_pwm_enable(enable); 476 + break; 477 + case duo: 478 + gpd_duo_set_pwm_enable(enable); 479 + break; 480 + case win_max_2: 481 + gpd_wm2_set_pwm_enable(enable); 482 + break; 483 + } 484 + } 485 + 486 + static umode_t gpd_fan_hwmon_is_visible(__always_unused const void *drvdata, 487 + enum hwmon_sensor_types type, u32 attr, 488 + __always_unused int channel) 489 + { 490 + if (type == hwmon_fan && attr == hwmon_fan_input) { 491 + return 0444; 492 + } else if (type == hwmon_pwm) { 493 + switch (attr) { 494 + case hwmon_pwm_enable: 495 + case hwmon_pwm_input: 496 + return 0644; 497 + default: 498 + return 0; 499 + } 500 + } 501 + return 0; 502 + } 503 + 504 + static int gpd_fan_hwmon_read(__always_unused struct device *dev, 505 + enum hwmon_sensor_types type, u32 attr, 506 + __always_unused int channel, long *val) 507 + { 508 + int ret; 509 + 510 + ret = mutex_lock_interruptible(&gpd_fan_sequence_lock); 511 + if (ret) 512 + return ret; 513 + 514 + if (type == hwmon_fan) { 515 + if (attr == hwmon_fan_input) { 516 + ret = gpd_read_rpm(); 517 + 518 + if (ret < 0) 519 + goto OUT; 520 + 521 + *val = ret; 522 + ret = 0; 523 + goto OUT; 524 + } 525 + } else if (type == hwmon_pwm) { 526 + switch (attr) { 527 + case hwmon_pwm_enable: 528 + *val = gpd_driver_priv.pwm_enable; 529 + ret = 0; 530 + goto OUT; 531 + case hwmon_pwm_input: 532 + ret = gpd_read_pwm(); 533 + 534 + if (ret < 0) 535 + goto OUT; 536 + 537 + *val = ret; 538 + ret = 0; 539 + goto OUT; 540 + } 541 + } 542 + 543 + ret = -EOPNOTSUPP; 544 + 545 + OUT: 546 + mutex_unlock(&gpd_fan_sequence_lock); 547 + return ret; 548 + } 549 + 550 + static int gpd_fan_hwmon_write(__always_unused struct device *dev, 551 + enum hwmon_sensor_types type, u32 attr, 552 + __always_unused int channel, long val) 553 + { 554 + int ret; 555 + 556 + ret = mutex_lock_interruptible(&gpd_fan_sequence_lock); 557 + if (ret) 558 + return ret; 559 + 560 + if (type == hwmon_pwm) { 561 + switch (attr) { 562 + case hwmon_pwm_enable: 563 + if (!in_range(val, 0, 3)) { 564 + ret = -EINVAL; 565 + goto OUT; 566 + } 567 + 568 + gpd_driver_priv.pwm_enable = val; 569 + 570 + gpd_set_pwm_enable(gpd_driver_priv.pwm_enable); 571 + ret = 0; 572 + goto OUT; 573 + case hwmon_pwm_input: 574 + if (!in_range(val, 0, 256)) { 575 + ret = -ERANGE; 576 + goto OUT; 577 + } 578 + 579 + gpd_driver_priv.pwm_value = val; 580 + 581 + ret = gpd_write_pwm(val); 582 + goto OUT; 583 + } 584 + } 585 + 586 + ret = -EOPNOTSUPP; 587 + 588 + OUT: 589 + mutex_unlock(&gpd_fan_sequence_lock); 590 + return ret; 591 + } 592 + 593 + static const struct hwmon_ops gpd_fan_ops = { 594 + .is_visible = gpd_fan_hwmon_is_visible, 595 + .read = gpd_fan_hwmon_read, 596 + .write = gpd_fan_hwmon_write, 597 + }; 598 + 599 + static const struct hwmon_channel_info *gpd_fan_hwmon_channel_info[] = { 600 + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), 601 + HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 602 + NULL 603 + }; 604 + 605 + static struct hwmon_chip_info gpd_fan_chip_info = { 606 + .ops = &gpd_fan_ops, 607 + .info = gpd_fan_hwmon_channel_info 608 + }; 609 + 610 + static int gpd_fan_probe(struct platform_device *pdev) 611 + { 612 + struct device *dev = &pdev->dev; 613 + const struct resource *region; 614 + const struct resource *res; 615 + const struct device *hwdev; 616 + 617 + res = platform_get_resource(pdev, IORESOURCE_IO, 0); 618 + if (IS_ERR(res)) 619 + return dev_err_probe(dev, PTR_ERR(res), 620 + "Failed to get platform resource\n"); 621 + 622 + region = devm_request_region(dev, res->start, 623 + resource_size(res), DRIVER_NAME); 624 + if (IS_ERR(region)) 625 + return dev_err_probe(dev, PTR_ERR(region), 626 + "Failed to request region\n"); 627 + 628 + hwdev = devm_hwmon_device_register_with_info(dev, 629 + DRIVER_NAME, 630 + NULL, 631 + &gpd_fan_chip_info, 632 + NULL); 633 + if (IS_ERR(hwdev)) 634 + return dev_err_probe(dev, PTR_ERR(region), 635 + "Failed to register hwmon device\n"); 636 + 637 + return 0; 638 + } 639 + 640 + static void gpd_fan_remove(__always_unused struct platform_device *pdev) 641 + { 642 + gpd_driver_priv.pwm_enable = AUTOMATIC; 643 + gpd_set_pwm_enable(AUTOMATIC); 644 + } 645 + 646 + static struct platform_driver gpd_fan_driver = { 647 + .probe = gpd_fan_probe, 648 + .remove = gpd_fan_remove, 649 + .driver = { 650 + .name = KBUILD_MODNAME, 651 + }, 652 + }; 653 + 654 + static struct platform_device *gpd_fan_platform_device; 655 + 656 + static int __init gpd_fan_init(void) 657 + { 658 + const struct gpd_fan_drvdata *match = NULL; 659 + 660 + for (const struct gpd_fan_drvdata **p = gpd_module_drvdata; *p; p++) { 661 + if (strcmp(gpd_fan_board, (*p)->board_name) == 0) { 662 + match = *p; 663 + break; 664 + } 665 + } 666 + 667 + if (!match) { 668 + const struct dmi_system_id *dmi_match = 669 + dmi_first_match(dmi_table); 670 + if (dmi_match) 671 + match = dmi_match->driver_data; 672 + } 673 + 674 + if (!match) 675 + return -ENODEV; 676 + 677 + gpd_driver_priv.pwm_enable = AUTOMATIC; 678 + gpd_driver_priv.pwm_value = 255; 679 + gpd_driver_priv.drvdata = match; 680 + 681 + struct resource gpd_fan_resources[] = { 682 + { 683 + .start = match->addr_port, 684 + .end = match->data_port, 685 + .flags = IORESOURCE_IO, 686 + }, 687 + }; 688 + 689 + gpd_fan_platform_device = platform_create_bundle(&gpd_fan_driver, 690 + gpd_fan_probe, 691 + gpd_fan_resources, 692 + 1, NULL, 0); 693 + 694 + if (IS_ERR(gpd_fan_platform_device)) { 695 + pr_warn("Failed to create platform device\n"); 696 + return PTR_ERR(gpd_fan_platform_device); 697 + } 698 + 699 + return 0; 700 + } 701 + 702 + static void __exit gpd_fan_exit(void) 703 + { 704 + platform_device_unregister(gpd_fan_platform_device); 705 + platform_driver_unregister(&gpd_fan_driver); 706 + } 707 + 708 + MODULE_DEVICE_TABLE(dmi, dmi_table); 709 + 710 + module_init(gpd_fan_init); 711 + module_exit(gpd_fan_exit); 712 + 713 + MODULE_LICENSE("GPL"); 714 + MODULE_AUTHOR("Cryolitia PukNgae <cryolitia@uniontech.com>"); 715 + MODULE_DESCRIPTION("GPD Devices fan control driver");
+46 -12
drivers/hwmon/hwmon.c
··· 19 19 #include <linux/kstrtox.h> 20 20 #include <linux/list.h> 21 21 #include <linux/module.h> 22 + #include <linux/mutex.h> 22 23 #include <linux/pci.h> 23 24 #include <linux/property.h> 24 25 #include <linux/slab.h> ··· 37 36 const char *label; 38 37 struct device dev; 39 38 const struct hwmon_chip_info *chip; 39 + struct mutex lock; 40 40 struct list_head tzdata; 41 41 struct attribute_group group; 42 42 const struct attribute_group **groups; ··· 167 165 int ret; 168 166 long t; 169 167 168 + guard(mutex)(&hwdev->lock); 169 + 170 170 ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input, 171 171 tdata->index, &t); 172 172 if (ret < 0) ··· 196 192 197 193 if (!info[i]) 198 194 return 0; 195 + 196 + guard(mutex)(&hwdev->lock); 199 197 200 198 if (info[i]->config[tdata->index] & HWMON_T_MIN) { 201 199 err = chip->ops->write(tdata->dev, hwmon_temp, ··· 336 330 * attached to an i2c client device. 337 331 */ 338 332 339 - static DEFINE_MUTEX(hwmon_pec_mutex); 340 - 341 333 static int hwmon_match_device(struct device *dev, const void *data) 342 334 { 343 335 return dev->class == &hwmon_class; ··· 366 362 if (!hdev) 367 363 return -ENODEV; 368 364 369 - mutex_lock(&hwmon_pec_mutex); 370 - 371 365 /* 372 366 * If there is no write function, we assume that chip specific 373 367 * handling is not required. 374 368 */ 375 369 hwdev = to_hwmon_device(hdev); 370 + guard(mutex)(&hwdev->lock); 376 371 if (hwdev->chip->ops->write) { 377 372 err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val); 378 373 if (err && err != -EOPNOTSUPP) 379 - goto unlock; 374 + goto put; 380 375 } 381 376 382 377 if (!val) ··· 384 381 client->flags |= I2C_CLIENT_PEC; 385 382 386 383 err = count; 387 - unlock: 388 - mutex_unlock(&hwmon_pec_mutex); 384 + put: 389 385 put_device(hdev); 390 386 391 387 return err; ··· 428 426 struct device_attribute *devattr, char *buf) 429 427 { 430 428 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 429 + struct hwmon_device *hwdev = to_hwmon_device(dev); 430 + s64 val64; 431 431 long val; 432 432 int ret; 433 433 434 + guard(mutex)(&hwdev->lock); 435 + 434 436 ret = hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, 435 - &val); 437 + (hattr->type == hwmon_energy64) ? (long *)&val64 : &val); 436 438 if (ret < 0) 437 439 return ret; 438 440 439 - trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type), 440 - hattr->name, val); 441 + if (hattr->type != hwmon_energy64) 442 + val64 = val; 441 443 442 - return sprintf(buf, "%ld\n", val); 444 + trace_hwmon_attr_show(hattr->index + hwmon_attr_base(hattr->type), 445 + hattr->name, val64); 446 + 447 + return sprintf(buf, "%lld\n", val64); 443 448 } 444 449 445 450 static ssize_t hwmon_attr_show_string(struct device *dev, ··· 454 445 char *buf) 455 446 { 456 447 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 448 + struct hwmon_device *hwdev = to_hwmon_device(dev); 457 449 enum hwmon_sensor_types type = hattr->type; 458 450 const char *s; 459 451 int ret; 452 + 453 + guard(mutex)(&hwdev->lock); 460 454 461 455 ret = hattr->ops->read_string(dev, hattr->type, hattr->attr, 462 456 hattr->index, &s); ··· 477 465 const char *buf, size_t count) 478 466 { 479 467 struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); 468 + struct hwmon_device *hwdev = to_hwmon_device(dev); 480 469 long val; 481 470 int ret; 482 471 ··· 485 472 if (ret < 0) 486 473 return ret; 487 474 475 + guard(mutex)(&hwdev->lock); 476 + 488 477 ret = hattr->ops->write(dev, hattr->type, hattr->attr, hattr->index, 489 478 val); 490 479 if (ret < 0) 491 480 return ret; 492 481 493 482 trace_hwmon_attr_store(hattr->index + hwmon_attr_base(hattr->type), 494 - hattr->name, val); 483 + hattr->name, (s64)val); 495 484 496 485 return count; 497 486 } ··· 749 734 [hwmon_curr] = hwmon_curr_attr_templates, 750 735 [hwmon_power] = hwmon_power_attr_templates, 751 736 [hwmon_energy] = hwmon_energy_attr_templates, 737 + [hwmon_energy64] = hwmon_energy_attr_templates, 752 738 [hwmon_humidity] = hwmon_humidity_attr_templates, 753 739 [hwmon_fan] = hwmon_fan_attr_templates, 754 740 [hwmon_pwm] = hwmon_pwm_attr_templates, ··· 763 747 [hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates), 764 748 [hwmon_power] = ARRAY_SIZE(hwmon_power_attr_templates), 765 749 [hwmon_energy] = ARRAY_SIZE(hwmon_energy_attr_templates), 750 + [hwmon_energy64] = ARRAY_SIZE(hwmon_energy_attr_templates), 766 751 [hwmon_humidity] = ARRAY_SIZE(hwmon_humidity_attr_templates), 767 752 [hwmon_fan] = ARRAY_SIZE(hwmon_fan_attr_templates), 768 753 [hwmon_pwm] = ARRAY_SIZE(hwmon_pwm_attr_templates), ··· 801 784 return 0; 802 785 } 803 786 EXPORT_SYMBOL_GPL(hwmon_notify_event); 787 + 788 + void hwmon_lock(struct device *dev) 789 + { 790 + struct hwmon_device *hwdev = to_hwmon_device(dev); 791 + 792 + mutex_lock(&hwdev->lock); 793 + } 794 + EXPORT_SYMBOL_GPL(hwmon_lock); 795 + 796 + void hwmon_unlock(struct device *dev) 797 + { 798 + struct hwmon_device *hwdev = to_hwmon_device(dev); 799 + 800 + mutex_unlock(&hwdev->lock); 801 + } 802 + EXPORT_SYMBOL_GPL(hwmon_unlock); 804 803 805 804 static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) 806 805 { ··· 978 945 tdev = tdev->parent; 979 946 hdev->of_node = tdev ? tdev->of_node : NULL; 980 947 hwdev->chip = chip; 948 + mutex_init(&hwdev->lock); 981 949 dev_set_drvdata(hdev, drvdata); 982 950 dev_set_name(hdev, HWMON_ID_FORMAT, id); 983 951 err = device_register(hdev);
+302 -281
drivers/hwmon/ina238.c
··· 16 16 #include <linux/of.h> 17 17 #include <linux/regmap.h> 18 18 19 - #include <linux/platform_data/ina2xx.h> 20 - 21 19 /* INA238 register definitions */ 22 20 #define INA238_CONFIG 0x0 23 21 #define INA238_ADC_CONFIG 0x1 ··· 51 53 52 54 #define INA238_REGISTERS 0x20 53 55 54 - #define INA238_RSHUNT_DEFAULT 10000 /* uOhm */ 56 + #define INA238_RSHUNT_DEFAULT 2500 /* uOhm */ 55 57 56 58 /* Default configuration of device on reset. */ 57 59 #define INA238_CONFIG_DEFAULT 0 ··· 60 62 #define INA238_ADC_CONFIG_DEFAULT 0xfb6a 61 63 /* Configure alerts to be based on averaged value (SLOWALERT) */ 62 64 #define INA238_DIAG_ALERT_DEFAULT 0x2000 65 + #define INA238_DIAG_ALERT_APOL BIT(12) 63 66 /* 64 67 * This driver uses a fixed calibration value in order to scale current/power 65 68 * based on a fixed shunt resistor value. This allows for conversion within the ··· 68 69 * relative to the shunt resistor value within the driver. This is similar to 69 70 * how the ina2xx driver handles current/power scaling. 70 71 * 71 - * The end result of this is that increasing shunt values (from a fixed 20 mOhm 72 - * shunt) increase the effective current/power accuracy whilst limiting the 73 - * range and decreasing shunt values decrease the effective accuracy but 74 - * increase the range. 72 + * To achieve the best possible dynamic range, the value of the shunt voltage 73 + * register should match the value of the current register. With that, the shunt 74 + * voltage of 0x7fff = 32,767 uV = 163,785 uV matches the maximum current, 75 + * and no accuracy is lost. Experiments with a real chip show that this is 76 + * achieved by setting the SHUNT_CAL register to a value of 0x1000 = 4,096. 77 + * Per datasheet, 78 + * SHUNT_CAL = 819.2 x 10^6 x CURRENT_LSB x Rshunt 79 + * = 819,200,000 x CURRENT_LSB x Rshunt 80 + * With SHUNT_CAL set to 4,096, we get 81 + * CURRENT_LSB = 4,096 / (819,200,000 x Rshunt) 82 + * Assuming an Rshunt value of 5 mOhm, we get 83 + * CURRENT_LSB = 4,096 / (819,200,000 x 0.005) = 1mA 84 + * and thus a dynamic range of 1mA ... 32,767mA, which is sufficient for most 85 + * applications. The actual dynamic range is of course determined by the actual 86 + * shunt resistor value. 75 87 * 76 - * The value of the Current register is calculated given the following: 77 - * Current (A) = (shunt voltage register * 5) * calibration / 81920 78 - * 79 - * The maximum shunt voltage is 163.835 mV (0x7fff, ADC_RANGE = 0, gain = 4). 80 - * With the maximum current value of 0x7fff and a fixed shunt value results in 81 - * a calibration value of 16384 (0x4000). 82 - * 83 - * 0x7fff = (0x7fff * 5) * calibration / 81920 84 - * calibration = 0x4000 85 - * 86 - * Equivalent calibration is applied for the Power register (maximum value for 87 - * bus voltage is 102396.875 mV, 0x7fff), where the maximum power that can 88 - * occur is ~16776192 uW (register value 0x147a8): 89 - * 90 - * This scaling means the resulting values for Current and Power registers need 91 - * to be scaled by the difference between the fixed shunt resistor and the 92 - * actual shunt resistor: 93 - * 94 - * shunt = 0x4000 / (819.2 * 10^6) / 0.001 = 20000 uOhms (with 1mA/lsb) 95 - * 96 - * Current (mA) = register value * 20000 / rshunt / 4 * gain 97 - * Power (mW) = 0.2 * register value * 20000 / rshunt / 4 * gain 98 - * (Specific for SQ52206) 99 - * Power (mW) = 0.24 * register value * 20000 / rshunt / 4 * gain 100 - * Energy (uJ) = 16 * 0.24 * register value * 20000 / rshunt / 4 * gain * 1000 88 + * Power and energy values are scaled accordingly. 101 89 */ 102 - #define INA238_CALIBRATION_VALUE 16384 103 - #define INA238_FIXED_SHUNT 20000 90 + #define INA238_CALIBRATION_VALUE 4096 91 + #define INA238_FIXED_SHUNT 5000 104 92 105 - #define INA238_SHUNT_VOLTAGE_LSB 5 /* 5 uV/lsb */ 106 - #define INA238_BUS_VOLTAGE_LSB 3125 /* 3.125 mV/lsb */ 107 - #define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */ 108 - #define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */ 109 - #define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ 110 - #define INA228_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */ 93 + #define INA238_SHUNT_VOLTAGE_LSB 5000 /* 5 uV/lsb, in nV */ 94 + #define INA238_BUS_VOLTAGE_LSB 3125000 /* 3.125 mV/lsb, in nV */ 95 + #define SQ52206_BUS_VOLTAGE_LSB 3750000 /* 3.75 mV/lsb, in nV */ 96 + 97 + #define NUNIT_PER_MUNIT 1000000 /* n[AV] -> m[AV] */ 111 98 112 99 static const struct regmap_config ina238_regmap_config = { 113 100 .max_register = INA238_REGISTERS, ··· 101 116 .val_bits = 16, 102 117 }; 103 118 104 - enum ina238_ids { ina238, ina237, sq52206, ina228 }; 119 + enum ina238_ids { ina228, ina237, ina238, ina700, ina780, sq52206 }; 105 120 106 121 struct ina238_config { 107 122 bool has_20bit_voltage_current; /* vshunt, vbus and current are 20-bit fields */ 108 123 bool has_power_highest; /* chip detection power peak */ 109 124 bool has_energy; /* chip detection energy */ 110 - u8 temp_shift; /* fixed parameters for temp calculate */ 111 - u32 power_calculate_factor; /* fixed parameters for power calculate */ 125 + u8 temp_resolution; /* temperature register resolution in bit */ 112 126 u16 config_default; /* Power-on default state */ 113 - int bus_voltage_lsb; /* use for temperature calculate, uV/lsb */ 114 - int temp_lsb; /* use for temperature calculate */ 127 + u32 power_calculate_factor; /* fixed parameter for power calculation, from datasheet */ 128 + u32 bus_voltage_lsb; /* bus voltage LSB, in nV */ 129 + int current_lsb; /* current LSB, in uA */ 115 130 }; 116 131 117 132 struct ina238_data { ··· 121 136 struct regmap *regmap; 122 137 u32 rshunt; 123 138 int gain; 139 + u32 voltage_lsb[2]; /* shunt, bus voltage LSB, in nV */ 140 + int current_lsb; /* current LSB, in uA */ 141 + int power_lsb; /* power LSB, in uW */ 142 + int energy_lsb; /* energy LSB, in uJ */ 124 143 }; 125 144 126 145 static const struct ina238_config ina238_config[] = { 127 - [ina238] = { 128 - .has_20bit_voltage_current = false, 129 - .has_energy = false, 146 + [ina228] = { 147 + .has_20bit_voltage_current = true, 148 + .has_energy = true, 130 149 .has_power_highest = false, 131 - .temp_shift = 4, 132 150 .power_calculate_factor = 20, 133 151 .config_default = INA238_CONFIG_DEFAULT, 134 152 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 135 - .temp_lsb = INA238_DIE_TEMP_LSB, 153 + .temp_resolution = 16, 136 154 }, 137 155 [ina237] = { 138 156 .has_20bit_voltage_current = false, 139 157 .has_energy = false, 140 158 .has_power_highest = false, 141 - .temp_shift = 4, 142 159 .power_calculate_factor = 20, 143 160 .config_default = INA238_CONFIG_DEFAULT, 144 161 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 145 - .temp_lsb = INA238_DIE_TEMP_LSB, 162 + .temp_resolution = 12, 163 + }, 164 + [ina238] = { 165 + .has_20bit_voltage_current = false, 166 + .has_energy = false, 167 + .has_power_highest = false, 168 + .power_calculate_factor = 20, 169 + .config_default = INA238_CONFIG_DEFAULT, 170 + .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 171 + .temp_resolution = 12, 172 + }, 173 + [ina700] = { 174 + .has_20bit_voltage_current = false, 175 + .has_energy = true, 176 + .has_power_highest = false, 177 + .power_calculate_factor = 20, 178 + .config_default = INA238_CONFIG_DEFAULT, 179 + .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 180 + .temp_resolution = 12, 181 + .current_lsb = 480, 182 + }, 183 + [ina780] = { 184 + .has_20bit_voltage_current = false, 185 + .has_energy = true, 186 + .has_power_highest = false, 187 + .power_calculate_factor = 20, 188 + .config_default = INA238_CONFIG_DEFAULT, 189 + .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 190 + .temp_resolution = 12, 191 + .current_lsb = 2400, 146 192 }, 147 193 [sq52206] = { 148 194 .has_20bit_voltage_current = false, 149 195 .has_energy = true, 150 196 .has_power_highest = true, 151 - .temp_shift = 0, 152 197 .power_calculate_factor = 24, 153 198 .config_default = SQ52206_CONFIG_DEFAULT, 154 199 .bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB, 155 - .temp_lsb = SQ52206_DIE_TEMP_LSB, 156 - }, 157 - [ina228] = { 158 - .has_20bit_voltage_current = true, 159 - .has_energy = true, 160 - .has_power_highest = false, 161 - .temp_shift = 0, 162 - .power_calculate_factor = 20, 163 - .config_default = INA238_CONFIG_DEFAULT, 164 - .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB, 165 - .temp_lsb = INA228_DIE_TEMP_LSB, 200 + .temp_resolution = 16, 166 201 }, 167 202 }; 168 203 ··· 237 232 return 0; 238 233 } 239 234 240 - static int ina228_read_shunt_voltage(struct device *dev, u32 attr, int channel, 241 - long *val) 235 + static int ina228_read_voltage(struct ina238_data *data, int channel, long *val) 242 236 { 243 - struct ina238_data *data = dev_get_drvdata(dev); 244 - int regval; 245 - int err; 237 + int reg = channel ? INA238_BUS_VOLTAGE : INA238_CURRENT; 238 + u32 lsb = data->voltage_lsb[channel]; 239 + u32 factor = NUNIT_PER_MUNIT; 240 + int err, regval; 246 241 247 - err = ina238_read_field_s20(data->client, INA238_SHUNT_VOLTAGE, &regval); 248 - if (err) 249 - return err; 242 + if (data->config->has_20bit_voltage_current) { 243 + err = ina238_read_field_s20(data->client, reg, &regval); 244 + if (err) 245 + return err; 246 + /* Adjust accuracy: LSB in units of 500 pV */ 247 + lsb /= 8; 248 + factor *= 2; 249 + } else { 250 + err = regmap_read(data->regmap, reg, &regval); 251 + if (err) 252 + return err; 253 + regval = (s16)regval; 254 + } 250 255 251 - /* 252 - * gain of 1 -> LSB / 4 253 - * This field has 16 bit on ina238. ina228 adds another 4 bits of 254 - * precision. ina238 conversion factors can still be applied when 255 - * dividing by 16. 256 - */ 257 - *val = (regval * INA238_SHUNT_VOLTAGE_LSB) * data->gain / (1000 * 4) / 16; 258 - return 0; 259 - } 260 - 261 - static int ina228_read_bus_voltage(struct device *dev, u32 attr, int channel, 262 - long *val) 263 - { 264 - struct ina238_data *data = dev_get_drvdata(dev); 265 - int regval; 266 - int err; 267 - 268 - err = ina238_read_field_s20(data->client, INA238_BUS_VOLTAGE, &regval); 269 - if (err) 270 - return err; 271 - 272 - /* 273 - * gain of 1 -> LSB / 4 274 - * This field has 16 bit on ina238. ina228 adds another 4 bits of 275 - * precision. ina238 conversion factors can still be applied when 276 - * dividing by 16. 277 - */ 278 - *val = (regval * data->config->bus_voltage_lsb) / 1000 / 16; 256 + *val = DIV_S64_ROUND_CLOSEST((s64)regval * lsb, factor); 279 257 return 0; 280 258 } 281 259 ··· 266 278 long *val) 267 279 { 268 280 struct ina238_data *data = dev_get_drvdata(dev); 269 - int reg, mask; 281 + int reg, mask = 0; 270 282 int regval; 271 283 int err; 284 + 285 + if (attr == hwmon_in_input) 286 + return ina228_read_voltage(data, channel, val); 272 287 273 288 switch (channel) { 274 289 case 0: 275 290 switch (attr) { 276 - case hwmon_in_input: 277 - if (data->config->has_20bit_voltage_current) 278 - return ina228_read_shunt_voltage(dev, attr, channel, val); 279 - reg = INA238_SHUNT_VOLTAGE; 280 - break; 281 291 case hwmon_in_max: 282 292 reg = INA238_SHUNT_OVER_VOLTAGE; 283 293 break; ··· 296 310 break; 297 311 case 1: 298 312 switch (attr) { 299 - case hwmon_in_input: 300 - if (data->config->has_20bit_voltage_current) 301 - return ina228_read_bus_voltage(dev, attr, channel, val); 302 - reg = INA238_BUS_VOLTAGE; 303 - break; 304 313 case hwmon_in_max: 305 314 reg = INA238_BUS_OVER_VOLTAGE; 306 315 break; ··· 322 341 if (err < 0) 323 342 return err; 324 343 325 - switch (attr) { 326 - case hwmon_in_input: 327 - case hwmon_in_max: 328 - case hwmon_in_min: 329 - /* signed register, value in mV */ 330 - regval = (s16)regval; 331 - if (channel == 0) 332 - /* gain of 1 -> LSB / 4 */ 333 - *val = (regval * INA238_SHUNT_VOLTAGE_LSB) * 334 - data->gain / (1000 * 4); 335 - else 336 - *val = (regval * data->config->bus_voltage_lsb) / 1000; 337 - break; 338 - case hwmon_in_max_alarm: 339 - case hwmon_in_min_alarm: 344 + if (mask) 340 345 *val = !!(regval & mask); 341 - break; 342 - } 346 + else 347 + *val = DIV_S64_ROUND_CLOSEST((s64)(s16)regval * data->voltage_lsb[channel], 348 + NUNIT_PER_MUNIT); 343 349 344 350 return 0; 345 351 } 346 352 347 - static int ina238_write_in(struct device *dev, u32 attr, int channel, 348 - long val) 353 + static int ina238_write_in(struct device *dev, u32 attr, int channel, long val) 349 354 { 350 355 struct ina238_data *data = dev_get_drvdata(dev); 356 + static const int low_limits[2] = {-164, 0}; 357 + static const int high_limits[2] = {164, 150000}; 358 + static const u8 low_regs[2] = {INA238_SHUNT_UNDER_VOLTAGE, INA238_BUS_UNDER_VOLTAGE}; 359 + static const u8 high_regs[2] = {INA238_SHUNT_OVER_VOLTAGE, INA238_BUS_OVER_VOLTAGE}; 351 360 int regval; 352 361 353 - if (attr != hwmon_in_max && attr != hwmon_in_min) 354 - return -EOPNOTSUPP; 362 + /* Initial clamp to avoid overflows */ 363 + val = clamp_val(val, low_limits[channel], high_limits[channel]); 364 + val = DIV_S64_ROUND_CLOSEST((s64)val * NUNIT_PER_MUNIT, data->voltage_lsb[channel]); 365 + /* Final clamp to register limits */ 366 + regval = clamp_val(val, S16_MIN, S16_MAX) & 0xffff; 355 367 356 - /* convert decimal to register value */ 357 - switch (channel) { 358 - case 0: 359 - /* signed value, clamp to max range +/-163 mV */ 360 - regval = clamp_val(val, -163, 163); 361 - regval = (regval * 1000 * 4) / 362 - (INA238_SHUNT_VOLTAGE_LSB * data->gain); 363 - regval = clamp_val(regval, S16_MIN, S16_MAX) & 0xffff; 364 - 365 - switch (attr) { 366 - case hwmon_in_max: 367 - return regmap_write(data->regmap, 368 - INA238_SHUNT_OVER_VOLTAGE, regval); 369 - case hwmon_in_min: 370 - return regmap_write(data->regmap, 371 - INA238_SHUNT_UNDER_VOLTAGE, regval); 372 - default: 373 - return -EOPNOTSUPP; 374 - } 375 - case 1: 376 - /* signed value, positive values only. Clamp to max 102.396 V */ 377 - regval = clamp_val(val, 0, 102396); 378 - regval = (regval * 1000) / data->config->bus_voltage_lsb; 379 - regval = clamp_val(regval, 0, S16_MAX); 380 - 381 - switch (attr) { 382 - case hwmon_in_max: 383 - return regmap_write(data->regmap, 384 - INA238_BUS_OVER_VOLTAGE, regval); 385 - case hwmon_in_min: 386 - return regmap_write(data->regmap, 387 - INA238_BUS_UNDER_VOLTAGE, regval); 388 - default: 389 - return -EOPNOTSUPP; 390 - } 368 + switch (attr) { 369 + case hwmon_in_min: 370 + return regmap_write(data->regmap, low_regs[channel], regval); 371 + case hwmon_in_max: 372 + return regmap_write(data->regmap, high_regs[channel], regval); 391 373 default: 392 374 return -EOPNOTSUPP; 393 375 } 394 376 } 395 377 396 - static int ina238_read_current(struct device *dev, u32 attr, long *val) 378 + static int __ina238_read_curr(struct ina238_data *data, long *val) 379 + { 380 + u32 lsb = data->current_lsb; 381 + int err, regval; 382 + 383 + if (data->config->has_20bit_voltage_current) { 384 + err = ina238_read_field_s20(data->client, INA238_CURRENT, &regval); 385 + if (err) 386 + return err; 387 + lsb /= 16; /* Adjust accuracy */ 388 + } else { 389 + err = regmap_read(data->regmap, INA238_CURRENT, &regval); 390 + if (err) 391 + return err; 392 + regval = (s16)regval; 393 + } 394 + 395 + *val = DIV_S64_ROUND_CLOSEST((s64)regval * lsb, 1000); 396 + return 0; 397 + } 398 + 399 + static int ina238_read_curr(struct device *dev, u32 attr, long *val) 397 400 { 398 401 struct ina238_data *data = dev_get_drvdata(dev); 402 + int reg, mask = 0; 399 403 int regval; 400 404 int err; 401 405 406 + if (attr == hwmon_curr_input) 407 + return __ina238_read_curr(data, val); 408 + 402 409 switch (attr) { 403 - case hwmon_curr_input: 404 - if (data->config->has_20bit_voltage_current) { 405 - err = ina238_read_field_s20(data->client, INA238_CURRENT, &regval); 406 - if (err) 407 - return err; 408 - } else { 409 - err = regmap_read(data->regmap, INA238_CURRENT, &regval); 410 - if (err < 0) 411 - return err; 412 - /* sign-extend */ 413 - regval = (s16)regval; 414 - } 415 - 416 - /* Signed register, fixed 1mA current lsb. result in mA */ 417 - *val = div_s64((s64)regval * INA238_FIXED_SHUNT * data->gain, 418 - data->rshunt * 4); 419 - 420 - /* Account for 4 bit offset */ 421 - if (data->config->has_20bit_voltage_current) 422 - *val /= 16; 410 + case hwmon_curr_min: 411 + reg = INA238_SHUNT_UNDER_VOLTAGE; 412 + break; 413 + case hwmon_curr_min_alarm: 414 + reg = INA238_DIAG_ALERT; 415 + mask = INA238_DIAG_ALERT_SHNTUL; 416 + break; 417 + case hwmon_curr_max: 418 + reg = INA238_SHUNT_OVER_VOLTAGE; 419 + break; 420 + case hwmon_curr_max_alarm: 421 + reg = INA238_DIAG_ALERT; 422 + mask = INA238_DIAG_ALERT_SHNTOL; 423 423 break; 424 424 default: 425 425 return -EOPNOTSUPP; 426 426 } 427 427 428 + err = regmap_read(data->regmap, reg, &regval); 429 + if (err < 0) 430 + return err; 431 + 432 + if (mask) 433 + *val = !!(regval & mask); 434 + else 435 + *val = DIV_S64_ROUND_CLOSEST((s64)(s16)regval * data->current_lsb, 1000); 436 + 428 437 return 0; 438 + } 439 + 440 + static int ina238_write_curr(struct device *dev, u32 attr, long val) 441 + { 442 + struct ina238_data *data = dev_get_drvdata(dev); 443 + int regval; 444 + 445 + /* Set baseline range to avoid over/underflows */ 446 + val = clamp_val(val, -1000000, 1000000); 447 + /* Scale */ 448 + val = DIV_ROUND_CLOSEST(val * 1000, data->current_lsb); 449 + /* Clamp to register size */ 450 + regval = clamp_val(val, S16_MIN, S16_MAX) & 0xffff; 451 + 452 + switch (attr) { 453 + case hwmon_curr_min: 454 + return regmap_write(data->regmap, INA238_SHUNT_UNDER_VOLTAGE, 455 + regval); 456 + case hwmon_curr_max: 457 + return regmap_write(data->regmap, INA238_SHUNT_OVER_VOLTAGE, 458 + regval); 459 + default: 460 + return -EOPNOTSUPP; 461 + } 429 462 } 430 463 431 464 static int ina238_read_power(struct device *dev, u32 attr, long *val) ··· 455 460 if (err) 456 461 return err; 457 462 458 - /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */ 459 - power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * 460 - data->config->power_calculate_factor, 4 * 100 * data->rshunt); 463 + power = (long long)regval * data->power_lsb; 461 464 /* Clamp value to maximum value of long */ 462 465 *val = clamp_val(power, 0, LONG_MAX); 463 466 break; ··· 464 471 if (err) 465 472 return err; 466 473 467 - /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */ 468 - power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain * 469 - data->config->power_calculate_factor, 4 * 100 * data->rshunt); 474 + power = (long long)regval * data->power_lsb; 470 475 /* Clamp value to maximum value of long */ 471 476 *val = clamp_val(power, 0, LONG_MAX); 472 477 break; ··· 477 486 * Truncated 24-bit compare register, lower 8-bits are 478 487 * truncated. Same conversion to/from uW as POWER register. 479 488 */ 480 - power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT * data->gain * 481 - data->config->power_calculate_factor, 4 * 100 * data->rshunt); 489 + power = ((long long)regval << 8) * data->power_lsb; 482 490 /* Clamp value to maximum value of long */ 483 491 *val = clamp_val(power, 0, LONG_MAX); 484 492 break; ··· 495 505 return 0; 496 506 } 497 507 498 - static int ina238_write_power(struct device *dev, u32 attr, long val) 508 + static int ina238_write_power_max(struct device *dev, long val) 499 509 { 500 510 struct ina238_data *data = dev_get_drvdata(dev); 501 - long regval; 502 - 503 - if (attr != hwmon_power_max) 504 - return -EOPNOTSUPP; 505 511 506 512 /* 507 513 * Unsigned postive values. Compared against the 24-bit power register, ··· 505 519 * register. 506 520 * The first clamp_val() is to establish a baseline to avoid overflows. 507 521 */ 508 - regval = clamp_val(val, 0, LONG_MAX / 2); 509 - regval = div_u64(regval * 4 * 100 * data->rshunt, data->config->power_calculate_factor * 510 - 1000ULL * INA238_FIXED_SHUNT * data->gain); 511 - regval = clamp_val(regval >> 8, 0, U16_MAX); 522 + val = clamp_val(val, 0, LONG_MAX / 2); 523 + val = DIV_ROUND_CLOSEST(val, data->power_lsb); 524 + val = clamp_val(val >> 8, 0, U16_MAX); 512 525 513 - return regmap_write(data->regmap, INA238_POWER_LIMIT, regval); 526 + return regmap_write(data->regmap, INA238_POWER_LIMIT, val); 527 + } 528 + 529 + static int ina238_temp_from_reg(s16 regval, u8 resolution) 530 + { 531 + return ((regval >> (16 - resolution)) * 1000) >> (resolution - 9); 514 532 } 515 533 516 534 static int ina238_read_temp(struct device *dev, u32 attr, long *val) ··· 528 538 err = regmap_read(data->regmap, INA238_DIE_TEMP, &regval); 529 539 if (err) 530 540 return err; 531 - /* Signed, result in mC */ 532 - *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * 533 - (s64)data->config->temp_lsb, 10000); 541 + *val = ina238_temp_from_reg(regval, data->config->temp_resolution); 534 542 break; 535 543 case hwmon_temp_max: 536 544 err = regmap_read(data->regmap, INA238_TEMP_LIMIT, &regval); 537 545 if (err) 538 546 return err; 539 547 /* Signed, result in mC */ 540 - *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) * 541 - (s64)data->config->temp_lsb, 10000); 548 + *val = ina238_temp_from_reg(regval, data->config->temp_resolution); 542 549 break; 543 550 case hwmon_temp_max_alarm: 544 551 err = regmap_read(data->regmap, INA238_DIAG_ALERT, &regval); ··· 551 564 return 0; 552 565 } 553 566 554 - static int ina238_write_temp(struct device *dev, u32 attr, long val) 567 + static u16 ina238_temp_to_reg(long val, u8 resolution) 568 + { 569 + int fraction = 1000 - DIV_ROUND_CLOSEST(1000, BIT(resolution - 9)); 570 + 571 + val = clamp_val(val, -255000 - fraction, 255000 + fraction); 572 + 573 + return (DIV_ROUND_CLOSEST(val << (resolution - 9), 1000) << (16 - resolution)) & 0xffff; 574 + } 575 + 576 + static int ina238_write_temp_max(struct device *dev, long val) 555 577 { 556 578 struct ina238_data *data = dev_get_drvdata(dev); 557 579 int regval; 558 580 559 - if (attr != hwmon_temp_max) 560 - return -EOPNOTSUPP; 561 - 562 - /* Signed */ 563 - val = clamp_val(val, -40000, 125000); 564 - regval = div_s64(val * 10000, data->config->temp_lsb) << data->config->temp_shift; 565 - regval = clamp_val(regval, S16_MIN, S16_MAX) & (0xffff << data->config->temp_shift); 566 - 581 + regval = ina238_temp_to_reg(val, data->config->temp_resolution); 567 582 return regmap_write(data->regmap, INA238_TEMP_LIMIT, regval); 568 583 } 569 584 570 - static ssize_t energy1_input_show(struct device *dev, 571 - struct device_attribute *da, char *buf) 585 + static int ina238_read_energy(struct device *dev, s64 *energy) 572 586 { 573 587 struct ina238_data *data = dev_get_drvdata(dev); 574 - int ret; 575 588 u64 regval; 576 - u64 energy; 589 + int ret; 577 590 578 591 ret = ina238_read_reg40(data->client, SQ52206_ENERGY, &regval); 579 592 if (ret) 580 593 return ret; 581 594 582 595 /* result in uJ */ 583 - energy = div_u64(regval * INA238_FIXED_SHUNT * data->gain * 16 * 10 * 584 - data->config->power_calculate_factor, 4 * data->rshunt); 585 - 586 - return sysfs_emit(buf, "%llu\n", energy); 596 + *energy = regval * data->energy_lsb; 597 + return 0; 587 598 } 588 599 589 600 static int ina238_read(struct device *dev, enum hwmon_sensor_types type, ··· 591 606 case hwmon_in: 592 607 return ina238_read_in(dev, attr, channel, val); 593 608 case hwmon_curr: 594 - return ina238_read_current(dev, attr, val); 609 + return ina238_read_curr(dev, attr, val); 595 610 case hwmon_power: 596 611 return ina238_read_power(dev, attr, val); 612 + case hwmon_energy64: 613 + return ina238_read_energy(dev, (s64 *)val); 597 614 case hwmon_temp: 598 615 return ina238_read_temp(dev, attr, val); 599 616 default: ··· 616 629 case hwmon_in: 617 630 err = ina238_write_in(dev, attr, channel, val); 618 631 break; 632 + case hwmon_curr: 633 + err = ina238_write_curr(dev, attr, val); 634 + break; 619 635 case hwmon_power: 620 - err = ina238_write_power(dev, attr, val); 636 + err = ina238_write_power_max(dev, val); 621 637 break; 622 638 case hwmon_temp: 623 - err = ina238_write_temp(dev, attr, val); 639 + err = ina238_write_temp_max(dev, val); 624 640 break; 625 641 default: 626 642 err = -EOPNOTSUPP; ··· 640 650 { 641 651 const struct ina238_data *data = drvdata; 642 652 bool has_power_highest = data->config->has_power_highest; 653 + bool has_energy = data->config->has_energy; 643 654 644 655 switch (type) { 645 656 case hwmon_in: ··· 658 667 case hwmon_curr: 659 668 switch (attr) { 660 669 case hwmon_curr_input: 670 + case hwmon_curr_max_alarm: 671 + case hwmon_curr_min_alarm: 661 672 return 0444; 673 + case hwmon_curr_max: 674 + case hwmon_curr_min: 675 + return 0644; 662 676 default: 663 677 return 0; 664 678 } ··· 681 685 default: 682 686 return 0; 683 687 } 688 + case hwmon_energy64: 689 + /* hwmon_energy_input */ 690 + if (has_energy) 691 + return 0444; 692 + return 0; 684 693 case hwmon_temp: 685 694 switch (attr) { 686 695 case hwmon_temp_input: ··· 713 712 INA238_HWMON_IN_CONFIG), 714 713 HWMON_CHANNEL_INFO(curr, 715 714 /* 0: current through shunt */ 716 - HWMON_C_INPUT), 715 + HWMON_C_INPUT | HWMON_C_MIN | HWMON_C_MIN_ALARM | 716 + HWMON_C_MAX | HWMON_C_MAX_ALARM), 717 717 HWMON_CHANNEL_INFO(power, 718 718 /* 0: power */ 719 719 HWMON_P_INPUT | HWMON_P_MAX | 720 720 HWMON_P_MAX_ALARM | HWMON_P_INPUT_HIGHEST), 721 + HWMON_CHANNEL_INFO(energy64, 722 + HWMON_E_INPUT), 721 723 HWMON_CHANNEL_INFO(temp, 722 724 /* 0: die temperature */ 723 725 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_ALARM), ··· 738 734 .info = ina238_info, 739 735 }; 740 736 741 - /* energy attributes are 5 bytes wide so we need u64 */ 742 - static DEVICE_ATTR_RO(energy1_input); 743 - 744 - static struct attribute *ina238_attrs[] = { 745 - &dev_attr_energy1_input.attr, 746 - NULL, 747 - }; 748 - ATTRIBUTE_GROUPS(ina238); 749 - 750 737 static int ina238_probe(struct i2c_client *client) 751 738 { 752 - struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev); 753 739 struct device *dev = &client->dev; 754 740 struct device *hwmon_dev; 755 741 struct ina238_data *data; ··· 765 771 return PTR_ERR(data->regmap); 766 772 } 767 773 768 - /* load shunt value */ 769 - data->rshunt = INA238_RSHUNT_DEFAULT; 770 - if (device_property_read_u32(dev, "shunt-resistor", &data->rshunt) < 0 && pdata) 771 - data->rshunt = pdata->shunt_uohms; 772 - if (data->rshunt == 0) { 773 - dev_err(dev, "invalid shunt resister value %u\n", data->rshunt); 774 - return -EINVAL; 775 - } 776 - 777 - /* load shunt gain value */ 778 - if (device_property_read_u32(dev, "ti,shunt-gain", &data->gain) < 0) 779 - data->gain = 4; /* Default of ADCRANGE = 0 */ 780 - if (data->gain != 1 && data->gain != 2 && data->gain != 4) { 781 - dev_err(dev, "invalid shunt gain value %u\n", data->gain); 782 - return -EINVAL; 783 - } 784 - 785 774 /* Setup CONFIG register */ 786 775 config = data->config->config_default; 787 - if (chip == sq52206) { 788 - if (data->gain == 1) 789 - config |= SQ52206_CONFIG_ADCRANGE_HIGH; /* ADCRANGE = 10/11 is /1 */ 790 - else if (data->gain == 2) 791 - config |= SQ52206_CONFIG_ADCRANGE_LOW; /* ADCRANGE = 01 is /2 */ 792 - } else if (data->gain == 1) { 793 - config |= INA238_CONFIG_ADCRANGE; /* ADCRANGE = 1 is /1 */ 776 + if (data->config->current_lsb) { 777 + data->voltage_lsb[0] = INA238_SHUNT_VOLTAGE_LSB; 778 + data->current_lsb = data->config->current_lsb; 779 + } else { 780 + /* load shunt value */ 781 + if (device_property_read_u32(dev, "shunt-resistor", &data->rshunt) < 0) 782 + data->rshunt = INA238_RSHUNT_DEFAULT; 783 + if (data->rshunt == 0) { 784 + dev_err(dev, "invalid shunt resister value %u\n", data->rshunt); 785 + return -EINVAL; 786 + } 787 + 788 + /* load shunt gain value */ 789 + if (device_property_read_u32(dev, "ti,shunt-gain", &data->gain) < 0) 790 + data->gain = 4; /* Default of ADCRANGE = 0 */ 791 + if (data->gain != 1 && data->gain != 2 && data->gain != 4) { 792 + dev_err(dev, "invalid shunt gain value %u\n", data->gain); 793 + return -EINVAL; 794 + } 795 + 796 + /* Setup SHUNT_CALIBRATION register with fixed value */ 797 + ret = regmap_write(data->regmap, INA238_SHUNT_CALIBRATION, 798 + INA238_CALIBRATION_VALUE); 799 + if (ret < 0) { 800 + dev_err(dev, "error configuring the device: %d\n", ret); 801 + return -ENODEV; 802 + } 803 + if (chip == sq52206) { 804 + if (data->gain == 1) /* ADCRANGE = 10/11 is /1 */ 805 + config |= SQ52206_CONFIG_ADCRANGE_HIGH; 806 + else if (data->gain == 2) /* ADCRANGE = 01 is /2 */ 807 + config |= SQ52206_CONFIG_ADCRANGE_LOW; 808 + } else if (data->gain == 1) { /* ADCRANGE = 1 is /1 */ 809 + config |= INA238_CONFIG_ADCRANGE; 810 + } 811 + data->voltage_lsb[0] = INA238_SHUNT_VOLTAGE_LSB * data->gain / 4; 812 + data->current_lsb = DIV_U64_ROUND_CLOSEST(250ULL * INA238_FIXED_SHUNT * data->gain, 813 + data->rshunt); 794 814 } 815 + 795 816 ret = regmap_write(data->regmap, INA238_CONFIG, config); 796 817 if (ret < 0) { 797 818 dev_err(dev, "error configuring the device: %d\n", ret); ··· 821 812 return -ENODEV; 822 813 } 823 814 824 - /* Setup SHUNT_CALIBRATION register with fixed value */ 825 - ret = regmap_write(data->regmap, INA238_SHUNT_CALIBRATION, 826 - INA238_CALIBRATION_VALUE); 815 + /* Setup alert/alarm configuration */ 816 + config = INA238_DIAG_ALERT_DEFAULT; 817 + if (device_property_read_bool(dev, "ti,alert-polarity-active-high")) 818 + config |= INA238_DIAG_ALERT_APOL; 819 + 820 + ret = regmap_write(data->regmap, INA238_DIAG_ALERT, config); 827 821 if (ret < 0) { 828 822 dev_err(dev, "error configuring the device: %d\n", ret); 829 823 return -ENODEV; 830 824 } 831 825 832 - /* Setup alert/alarm configuration */ 833 - ret = regmap_write(data->regmap, INA238_DIAG_ALERT, 834 - INA238_DIAG_ALERT_DEFAULT); 835 - if (ret < 0) { 836 - dev_err(dev, "error configuring the device: %d\n", ret); 837 - return -ENODEV; 838 - } 826 + data->voltage_lsb[1] = data->config->bus_voltage_lsb; 827 + 828 + data->power_lsb = DIV_ROUND_CLOSEST(data->current_lsb * 829 + data->config->power_calculate_factor, 830 + 100); 831 + 832 + data->energy_lsb = data->power_lsb * 16; 839 833 840 834 hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, 841 - &ina238_chip_info, 842 - data->config->has_energy ? 843 - ina238_groups : NULL); 835 + &ina238_chip_info, NULL); 844 836 if (IS_ERR(hwmon_dev)) 845 837 return PTR_ERR(hwmon_dev); 846 838 847 - dev_info(dev, "power monitor %s (Rshunt = %u uOhm, gain = %u)\n", 848 - client->name, data->rshunt, data->gain); 839 + if (data->rshunt) 840 + dev_info(dev, "power monitor %s (Rshunt = %u uOhm, gain = %u)\n", 841 + client->name, data->rshunt, data->gain); 849 842 850 843 return 0; 851 844 } ··· 856 845 { "ina228", ina228 }, 857 846 { "ina237", ina237 }, 858 847 { "ina238", ina238 }, 848 + { "ina700", ina700 }, 849 + { "ina780", ina780 }, 859 850 { "sq52206", sq52206 }, 860 851 { } 861 852 }; ··· 875 862 { 876 863 .compatible = "ti,ina238", 877 864 .data = (void *)ina238 865 + }, 866 + { 867 + .compatible = "ti,ina700", 868 + .data = (void *)ina700 869 + }, 870 + { 871 + .compatible = "ti,ina780", 872 + .data = (void *)ina780 878 873 }, 879 874 { 880 875 .compatible = "silergy,sq52206",
+10
drivers/hwmon/k10temp.c
··· 84 84 */ 85 85 #define AMD_I3255_STR "3255" 86 86 87 + /* 88 + * PCI Device IDs for AMD's Family 1Ah-based SOCs. 89 + * Defining locally as IDs are not shared. 90 + */ 91 + #define PCI_DEVICE_ID_AMD_1AH_M50H_DF_F3 0x12cb 92 + #define PCI_DEVICE_ID_AMD_1AH_M90H_DF_F3 0x127b 93 + 87 94 struct k10temp_data { 88 95 struct pci_dev *pdev; 89 96 void (*read_htcreg)(struct pci_dev *pdev, u32 *regval); ··· 563 556 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M78H_DF_F3) }, 564 557 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M00H_DF_F3) }, 565 558 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M20H_DF_F3) }, 559 + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M50H_DF_F3) }, 566 560 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M60H_DF_F3) }, 561 + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M70H_DF_F3) }, 562 + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_1AH_M90H_DF_F3) }, 567 563 { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, 568 564 {} 569 565 };
+30 -4
drivers/hwmon/lenovo-ec-sensors.c
··· 66 66 LENOVO_P8, 67 67 }; 68 68 69 - static int px_temp_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; 69 + static int px_temp_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 31, 32}; 70 70 71 71 static const char * const lenovo_px_ec_temp_label[] = { 72 72 "CPU1", ··· 84 84 "PCI_Z3", 85 85 "PCI_Z4", 86 86 "AMB", 87 + "PSU1", 88 + "PSU2", 87 89 }; 88 90 89 - static int gen_temp_map[] = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; 91 + static int p8_temp_map[] = {0, 1, 2, 8, 9, 13, 14, 15, 16, 17, 19, 20, 33}; 92 + 93 + static const char * const lenovo_p8_ec_temp_label[] = { 94 + "CPU1", 95 + "CPU_DIMM_BANK1", 96 + "CPU_DIMM_BANK2", 97 + "M2_Z2R", 98 + "M2_Z3R", 99 + "DIMM_RIGHT", 100 + "DIMM_LEFT", 101 + "PCI_Z1", 102 + "PCI_Z2", 103 + "PCI_Z3", 104 + "AMB", 105 + "REAR_VR", 106 + "PSU", 107 + }; 108 + 109 + static int gen_temp_map[] = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 31}; 90 110 91 111 static const char * const lenovo_gen_ec_temp_label[] = { 92 112 "CPU1", ··· 121 101 "PCI_Z3", 122 102 "PCI_Z4", 123 103 "AMB", 104 + "PSU", 124 105 }; 125 106 126 107 static int px_fan_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; ··· 314 293 HWMON_T_INPUT | HWMON_T_LABEL, 315 294 HWMON_T_INPUT | HWMON_T_LABEL, 316 295 HWMON_T_INPUT | HWMON_T_LABEL, 296 + HWMON_T_INPUT | HWMON_T_LABEL, 297 + HWMON_T_INPUT | HWMON_T_LABEL, 317 298 HWMON_T_INPUT | HWMON_T_LABEL), 318 299 HWMON_CHANNEL_INFO(fan, 319 300 HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX, ··· 339 316 340 317 static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p8[] = { 341 318 HWMON_CHANNEL_INFO(temp, 319 + HWMON_T_INPUT | HWMON_T_LABEL, 342 320 HWMON_T_INPUT | HWMON_T_LABEL, 343 321 HWMON_T_INPUT | HWMON_T_LABEL, 344 322 HWMON_T_INPUT | HWMON_T_LABEL, ··· 383 359 HWMON_T_INPUT | HWMON_T_LABEL, 384 360 HWMON_T_INPUT | HWMON_T_LABEL, 385 361 HWMON_T_INPUT | HWMON_T_LABEL, 362 + HWMON_T_INPUT | HWMON_T_LABEL, 386 363 HWMON_T_INPUT | HWMON_T_LABEL), 387 364 HWMON_CHANNEL_INFO(fan, 388 365 HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX, ··· 402 377 403 378 static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p5[] = { 404 379 HWMON_CHANNEL_INFO(temp, 380 + HWMON_T_INPUT | HWMON_T_LABEL, 405 381 HWMON_T_INPUT | HWMON_T_LABEL, 406 382 HWMON_T_INPUT | HWMON_T_LABEL, 407 383 HWMON_T_INPUT | HWMON_T_LABEL, ··· 571 545 break; 572 546 case 3: 573 547 ec_data->fan_labels = p8_ec_fan_label; 574 - ec_data->temp_labels = lenovo_gen_ec_temp_label; 548 + ec_data->temp_labels = lenovo_p8_ec_temp_label; 575 549 ec_data->fan_map = p8_fan_map; 576 - ec_data->temp_map = gen_temp_map; 550 + ec_data->temp_map = p8_temp_map; 577 551 lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p8; 578 552 break; 579 553 default:
+13
drivers/hwmon/lm75.c
··· 39 39 max6626, 40 40 max31725, 41 41 mcp980x, 42 + p3t1750, 42 43 p3t1755, 43 44 pct2075, 44 45 stds75, ··· 222 221 [tcn75] = { 223 222 .default_resolution = 9, 224 223 .default_sample_time = MSEC_PER_SEC / 18, 224 + }, 225 + [p3t1750] = { 226 + .clr_mask = 1 << 1 | 1 << 7, /* disable SMBAlert and one-shot */ 227 + .default_resolution = 12, 228 + .default_sample_time = 55, 229 + .num_sample_times = 4, 230 + .sample_times = (unsigned int []){ 28, 55, 110, 220 }, 225 231 }, 226 232 [p3t1755] = { 227 233 .clr_mask = 1 << 1 | 1 << 7, /* disable SMBAlert and one-shot */ ··· 813 805 { "max31725", max31725, }, 814 806 { "max31726", max31725, }, 815 807 { "mcp980x", mcp980x, }, 808 + { "p3t1750", p3t1750, }, 816 809 { "p3t1755", p3t1755, }, 817 810 { "pct2075", pct2075, }, 818 811 { "stds75", stds75, }, ··· 924 915 { 925 916 .compatible = "maxim,mcp980x", 926 917 .data = (void *)mcp980x 918 + }, 919 + { 920 + .compatible = "nxp,p3t1750", 921 + .data = (void *)p3t1750 927 922 }, 928 923 { 929 924 .compatible = "nxp,p3t1755",
+1 -2
drivers/hwmon/ltc4282.c
··· 1693 1693 1694 1694 st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); 1695 1695 if (!st) 1696 - return dev_err_probe(dev, -ENOMEM, 1697 - "Failed to allocate memory\n"); 1696 + return -ENOMEM; 1698 1697 1699 1698 st->map = devm_regmap_init_i2c(i2c, &ltc4282_regmap_config); 1700 1699 if (IS_ERR(st->map))
+31 -11
drivers/hwmon/mlxreg-fan.c
··· 63 63 * @reg: register offset; 64 64 * @mask: fault mask; 65 65 * @prsnt: present register offset; 66 + * @shift: tacho presence bit shift; 66 67 */ 67 68 struct mlxreg_fan_tacho { 68 69 bool connected; 69 70 u32 reg; 70 71 u32 mask; 71 72 u32 prsnt; 73 + u32 shift; 72 74 }; 73 75 74 76 /* ··· 115 113 int divider; 116 114 }; 117 115 118 - static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, 119 - unsigned long state); 116 + static int _mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, 117 + unsigned long state, bool thermal); 120 118 121 119 static int 122 120 mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, ··· 145 143 /* 146 144 * Map channel to presence bit - drawer can be equipped with 147 145 * one or few FANs, while presence is indicated per drawer. 146 + * Shift channel value if necessary to align with register value. 148 147 */ 149 - if (BIT(channel / fan->tachos_per_drwr) & regval) { 148 + if (BIT(rol32(channel, tacho->shift) / fan->tachos_per_drwr) & 149 + regval) { 150 150 /* FAN is not connected - return zero for FAN speed. */ 151 151 *val = 0; 152 152 return 0; ··· 228 224 * last thermal state. 229 225 */ 230 226 if (pwm->last_hwmon_state >= pwm->last_thermal_state) 231 - return mlxreg_fan_set_cur_state(pwm->cdev, 232 - pwm->last_hwmon_state); 227 + return _mlxreg_fan_set_cur_state(pwm->cdev, 228 + pwm->last_hwmon_state, 229 + false); 233 230 return 0; 234 231 } 235 232 return regmap_write(fan->regmap, pwm->reg, val); ··· 362 357 return 0; 363 358 } 364 359 365 - static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, 366 - unsigned long state) 367 - 360 + static int _mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, 361 + unsigned long state, bool thermal) 368 362 { 369 363 struct mlxreg_fan_pwm *pwm = cdev->devdata; 370 364 struct mlxreg_fan *fan = pwm->fan; ··· 373 369 return -EINVAL; 374 370 375 371 /* Save thermal state. */ 376 - pwm->last_thermal_state = state; 372 + if (thermal) 373 + pwm->last_thermal_state = state; 377 374 378 375 state = max_t(unsigned long, state, pwm->last_hwmon_state); 379 376 err = regmap_write(fan->regmap, pwm->reg, ··· 384 379 return err; 385 380 } 386 381 return 0; 382 + } 383 + 384 + static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, 385 + unsigned long state) 386 + 387 + { 388 + return _mlxreg_fan_set_cur_state(cdev, state, true); 387 389 } 388 390 389 391 static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = { ··· 412 400 return err; 413 401 } 414 402 415 - return !!(regval & data->bit); 403 + return data->slot ? (data->slot <= regval ? 1 : 0) : !!(regval & data->bit); 416 404 } 417 405 418 406 static int mlxreg_pwm_connect_verify(struct mlxreg_fan *fan, ··· 549 537 return err; 550 538 } 551 539 552 - drwr_avail = hweight32(regval); 540 + /* 541 + * The number of drawers could be specified in registers by counters for newer 542 + * systems, or by bitmasks for older systems. In case the data is provided by 543 + * counter, it is indicated through 'version' field. 544 + */ 545 + if (pdata->version) 546 + drwr_avail = regval; 547 + else 548 + drwr_avail = hweight32(regval); 553 549 if (!tacho_avail || !drwr_avail || tacho_avail < drwr_avail) { 554 550 dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n", 555 551 drwr_avail, tacho_avail);
+2 -1
drivers/hwmon/nct6775-platform.c
··· 167 167 168 168 static inline int nct6775_asuswmi_read(u8 bank, u8 reg, u8 *val) 169 169 { 170 - u32 ret, tmp = 0; 170 + u32 tmp = 0; 171 + int ret; 171 172 172 173 ret = nct6775_asuswmi_evaluate_method(ASUSWMI_METHODID_RHWM, bank, 173 174 reg, 0, &tmp);
+1 -7
drivers/hwmon/nzxt-smart2.c
··· 721 721 return init_device(drvdata, drvdata->update_interval); 722 722 } 723 723 724 - static void mutex_fini(void *lock) 725 - { 726 - mutex_destroy(lock); 727 - } 728 - 729 724 static int nzxt_smart2_hid_probe(struct hid_device *hdev, 730 725 const struct hid_device_id *id) 731 726 { ··· 736 741 737 742 init_waitqueue_head(&drvdata->wq); 738 743 739 - mutex_init(&drvdata->mutex); 740 - ret = devm_add_action_or_reset(&hdev->dev, mutex_fini, &drvdata->mutex); 744 + ret = devm_mutex_init(&hdev->dev, &drvdata->mutex); 741 745 if (ret) 742 746 return ret; 743 747
+20 -1
drivers/hwmon/pmbus/Kconfig
··· 52 52 help 53 53 If you say yes here you get hardware monitoring support for Analog 54 54 Devices ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, 55 - ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors. 55 + ADM1293, ADM1294 and SQ24905C Hot-Swap Controller and 56 + Digital Power Monitors. 56 57 57 58 This driver can also be built as a module. If so, the module will 58 59 be called adm1275. ··· 374 373 This driver can also be built as a module. If so, the module will 375 374 be called mp2856. 376 375 376 + config SENSORS_MP2869 377 + tristate "MPS MP2869" 378 + help 379 + If you say yes here you get hardware monitoring support for MPS 380 + MP2869 Dual Loop Digital Multi-Phase Controller. 381 + 382 + This driver can also be built as a module. If so, the module will 383 + be called mp2869. 384 + 377 385 config SENSORS_MP2888 378 386 tristate "MPS MP2888" 379 387 help ··· 400 390 401 391 This driver can also be built as a module. If so, the module will 402 392 be called mp2891. 393 + 394 + config SENSORS_MP29502 395 + tristate "MPS MP29502" 396 + help 397 + If you say yes here you get hardware monitoring support for MPS 398 + MP29502 Dual Loop Digital Multi-Phase Controller. 399 + 400 + This driver can also be built as a module. If so, the module will 401 + be called mp29502. 403 402 404 403 config SENSORS_MP2975 405 404 tristate "MPS MP2975"
+2
drivers/hwmon/pmbus/Makefile
··· 37 37 obj-$(CONFIG_SENSORS_MAX34440) += max34440.o 38 38 obj-$(CONFIG_SENSORS_MAX8688) += max8688.o 39 39 obj-$(CONFIG_SENSORS_MP2856) += mp2856.o 40 + obj-$(CONFIG_SENSORS_MP2869) += mp2869.o 40 41 obj-$(CONFIG_SENSORS_MP2888) += mp2888.o 41 42 obj-$(CONFIG_SENSORS_MP2891) += mp2891.o 43 + obj-$(CONFIG_SENSORS_MP29502) += mp29502.o 42 44 obj-$(CONFIG_SENSORS_MP2975) += mp2975.o 43 45 obj-$(CONFIG_SENSORS_MP2993) += mp2993.o 44 46 obj-$(CONFIG_SENSORS_MP5023) += mp5023.o
+8 -3
drivers/hwmon/pmbus/adm1275.c
··· 18 18 #include <linux/log2.h> 19 19 #include "pmbus.h" 20 20 21 - enum chips { adm1075, adm1272, adm1273, adm1275, adm1276, adm1278, adm1281, adm1293, adm1294 }; 21 + enum chips { adm1075, adm1272, adm1273, adm1275, adm1276, adm1278, adm1281, 22 + adm1293, adm1294, sq24905c }; 22 23 23 24 #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) 24 25 #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) ··· 487 486 { "adm1281", adm1281 }, 488 487 { "adm1293", adm1293 }, 489 488 { "adm1294", adm1294 }, 489 + { "mc09c", sq24905c }, 490 490 { } 491 491 }; 492 492 MODULE_DEVICE_TABLE(i2c, adm1275_id); ··· 534 532 dev_err(&client->dev, "Failed to read Manufacturer ID\n"); 535 533 return ret; 536 534 } 537 - if (ret != 3 || strncmp(block_buffer, "ADI", 3)) { 535 + if ((ret != 3 || strncmp(block_buffer, "ADI", 3)) && 536 + (ret != 2 || strncmp(block_buffer, "SY", 2))) { 538 537 dev_err(&client->dev, "Unsupported Manufacturer ID\n"); 539 538 return -ENODEV; 540 539 } ··· 561 558 562 559 if (mid->driver_data == adm1272 || mid->driver_data == adm1273 || 563 560 mid->driver_data == adm1278 || mid->driver_data == adm1281 || 564 - mid->driver_data == adm1293 || mid->driver_data == adm1294) 561 + mid->driver_data == adm1293 || mid->driver_data == adm1294 || 562 + mid->driver_data == sq24905c) 565 563 config_read_fn = i2c_smbus_read_word_data; 566 564 else 567 565 config_read_fn = i2c_smbus_read_byte_data; ··· 712 708 break; 713 709 case adm1278: 714 710 case adm1281: 711 + case sq24905c: 715 712 data->have_vout = true; 716 713 data->have_pin_max = true; 717 714 data->have_temp_max = true;
+6
drivers/hwmon/pmbus/isl68137.c
··· 61 61 raa228004, 62 62 raa228006, 63 63 raa228228, 64 + raa228244, 65 + raa228246, 64 66 raa229001, 65 67 raa229004, 66 68 raa229621, ··· 466 464 {"raa228004", raa_dmpvr2_hv}, 467 465 {"raa228006", raa_dmpvr2_hv}, 468 466 {"raa228228", raa_dmpvr2_2rail_nontc}, 467 + {"raa228244", raa_dmpvr2_2rail_nontc}, 468 + {"raa228246", raa_dmpvr2_2rail_nontc}, 469 469 {"raa229001", raa_dmpvr2_2rail}, 470 470 {"raa229004", raa_dmpvr2_2rail}, 471 471 {"raa229621", raa_dmpvr2_2rail}, ··· 516 512 { .compatible = "renesas,raa228004", .data = (void *)raa_dmpvr2_hv }, 517 513 { .compatible = "renesas,raa228006", .data = (void *)raa_dmpvr2_hv }, 518 514 { .compatible = "renesas,raa228228", .data = (void *)raa_dmpvr2_2rail_nontc }, 515 + { .compatible = "renesas,raa228244", .data = (void *)raa_dmpvr2_2rail_nontc }, 516 + { .compatible = "renesas,raa228246", .data = (void *)raa_dmpvr2_2rail_nontc }, 519 517 { .compatible = "renesas,raa229001", .data = (void *)raa_dmpvr2_2rail }, 520 518 { .compatible = "renesas,raa229004", .data = (void *)raa_dmpvr2_2rail }, 521 519 { .compatible = "renesas,raa229621", .data = (void *)raa_dmpvr2_2rail },
+659
drivers/hwmon/pmbus/mp2869.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP2869) 4 + */ 5 + 6 + #include <linux/bitfield.h> 7 + #include <linux/i2c.h> 8 + #include <linux/module.h> 9 + #include <linux/of_device.h> 10 + #include "pmbus.h" 11 + 12 + /* 13 + * Vender specific registers, the register MFR_SVI3_IOUT_PRT(0x67), 14 + * READ_PIN_EST(0x94)and READ_IIN_EST(0x95) redefine the standard 15 + * PMBUS register. The MFR_VOUT_LOOP_CTRL(0x29) is used to identify 16 + * the vout scale and the MFR_SVI3_IOUT_PRT(0x67) is used to identify 17 + * the iout scale. The READ_PIN_EST(0x94) is used to read input power 18 + * per rail. The MP2891 does not have standard READ_IIN register(0x89), 19 + * the iin telemetry can be obtained through the vendor redefined 20 + * register READ_IIN_EST(0x95). 21 + */ 22 + #define MFR_SVI3_IOUT_PRT 0x67 23 + #define MFR_READ_PIN_EST 0x94 24 + #define MFR_READ_IIN_EST 0x95 25 + #define MFR_TSNS_FLT_SET 0xBB 26 + 27 + #define MP2869_VIN_OV_FAULT_GAIN 4 28 + #define MP2869_READ_VOUT_DIV 1024 29 + #define MP2869_READ_IOUT_DIV 32 30 + #define MP2869_OVUV_LIMIT_SCALE 10 31 + #define MP2869_OVUV_DELTA_SCALE 50 32 + #define MP2869_TEMP_LIMIT_OFFSET 40 33 + #define MP2869_IOUT_LIMIT_UINT 8 34 + #define MP2869_POUT_OP_GAIN 2 35 + 36 + #define MP2869_PAGE_NUM 2 37 + 38 + #define MP2869_RAIL1_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \ 39 + PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | \ 40 + PMBUS_HAVE_TEMP | PMBUS_HAVE_PIN | \ 41 + PMBUS_HAVE_IIN | \ 42 + PMBUS_HAVE_STATUS_VOUT | \ 43 + PMBUS_HAVE_STATUS_IOUT | \ 44 + PMBUS_HAVE_STATUS_TEMP | \ 45 + PMBUS_HAVE_STATUS_INPUT) 46 + 47 + #define MP2869_RAIL2_FUNC (PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | \ 48 + PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | \ 49 + PMBUS_HAVE_PIN | PMBUS_HAVE_IIN | \ 50 + PMBUS_HAVE_STATUS_VOUT | \ 51 + PMBUS_HAVE_STATUS_IOUT | \ 52 + PMBUS_HAVE_STATUS_TEMP | \ 53 + PMBUS_HAVE_STATUS_INPUT) 54 + 55 + struct mp2869_data { 56 + struct pmbus_driver_info info; 57 + bool mfr_thwn_flt_en; 58 + int vout_scale[MP2869_PAGE_NUM]; 59 + int iout_scale[MP2869_PAGE_NUM]; 60 + }; 61 + 62 + static const int mp2869_vout_sacle[8] = {6400, 5120, 2560, 2048, 1024, 63 + 4, 2, 1}; 64 + static const int mp2869_iout_sacle[8] = {32, 1, 2, 4, 8, 16, 32, 64}; 65 + 66 + #define to_mp2869_data(x) container_of(x, struct mp2869_data, info) 67 + 68 + static u16 mp2869_reg2data_linear11(u16 word) 69 + { 70 + s16 exponent; 71 + s32 mantissa; 72 + s64 val; 73 + 74 + exponent = ((s16)word) >> 11; 75 + mantissa = ((s16)((word & 0x7ff) << 5)) >> 5; 76 + val = mantissa; 77 + 78 + if (exponent >= 0) 79 + val <<= exponent; 80 + else 81 + val >>= -exponent; 82 + 83 + return val; 84 + } 85 + 86 + static int 87 + mp2869_identify_thwn_flt(struct i2c_client *client, struct pmbus_driver_info *info, 88 + int page) 89 + { 90 + struct mp2869_data *data = to_mp2869_data(info); 91 + int ret; 92 + 93 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 94 + if (ret < 0) 95 + return ret; 96 + 97 + ret = i2c_smbus_read_word_data(client, MFR_TSNS_FLT_SET); 98 + if (ret < 0) 99 + return ret; 100 + 101 + data->mfr_thwn_flt_en = FIELD_GET(GENMASK(13, 13), ret); 102 + 103 + return 0; 104 + } 105 + 106 + static int 107 + mp2869_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 108 + int page) 109 + { 110 + struct mp2869_data *data = to_mp2869_data(info); 111 + int ret; 112 + 113 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 114 + if (ret < 0) 115 + return ret; 116 + 117 + ret = i2c_smbus_read_word_data(client, PMBUS_VOUT_SCALE_LOOP); 118 + if (ret < 0) 119 + return ret; 120 + 121 + /* 122 + * The output voltage is equal to the READ_VOUT(0x8B) register value multiply 123 + * by vout_scale. 124 + * Obtain vout scale from the register PMBUS_VOUT_SCALE_LOOP, bits 12-10 125 + * PMBUS_VOUT_SCALE_LOOP[12:10]: 126 + * 000b - 6.25mV/LSB, 001b - 5mV/LSB, 010b - 2.5mV/LSB, 011b - 2mV/LSB 127 + * 100b - 1mV/Lsb, 101b - (1/256)mV/LSB, 110b - (1/512)mV/LSB, 128 + * 111b - (1/1024)mV/LSB 129 + */ 130 + data->vout_scale[page] = mp2869_vout_sacle[FIELD_GET(GENMASK(12, 10), ret)]; 131 + 132 + return 0; 133 + } 134 + 135 + static int 136 + mp2869_identify_iout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 137 + int page) 138 + { 139 + struct mp2869_data *data = to_mp2869_data(info); 140 + int ret; 141 + 142 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 143 + if (ret < 0) 144 + return ret; 145 + 146 + ret = i2c_smbus_read_word_data(client, MFR_SVI3_IOUT_PRT); 147 + if (ret < 0) 148 + return ret; 149 + 150 + /* 151 + * The output current is equal to the READ_IOUT(0x8C) register value 152 + * multiply by iout_scale. 153 + * Obtain iout_scale from the register MFR_SVI3_IOUT_PRT[2:0]. 154 + * The value is selected as below: 155 + * 000b - 1A/LSB, 001b - (1/32)A/LSB, 010b - (1/16)A/LSB, 156 + * 011b - (1/8)A/LSB, 100b - (1/4)A/LSB, 101b - (1/2)A/LSB 157 + * 110b - 1A/LSB, 111b - 2A/LSB 158 + */ 159 + data->iout_scale[page] = mp2869_iout_sacle[FIELD_GET(GENMASK(2, 0), ret)]; 160 + 161 + return 0; 162 + } 163 + 164 + static int mp2869_read_byte_data(struct i2c_client *client, int page, int reg) 165 + { 166 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 167 + struct mp2869_data *data = to_mp2869_data(info); 168 + int ret; 169 + 170 + switch (reg) { 171 + case PMBUS_VOUT_MODE: 172 + /* 173 + * The calculation of vout in this driver is based on direct format. 174 + * As a result, the format of vout is enforced to direct. 175 + */ 176 + ret = PB_VOUT_MODE_DIRECT; 177 + break; 178 + case PMBUS_STATUS_BYTE: 179 + /* 180 + * If the tsns digital fault is enabled, the TEMPERATURE flag 181 + * of PMBUS_STATUS_BYTE should come from STATUS_MFR_SPECIFIC 182 + * register bit1. 183 + */ 184 + if (!data->mfr_thwn_flt_en) 185 + return -ENODATA; 186 + 187 + ret = pmbus_read_byte_data(client, page, reg); 188 + if (ret < 0) 189 + return ret; 190 + 191 + ret = (ret & ~GENMASK(2, 2)) | 192 + FIELD_PREP(GENMASK(2, 2), 193 + FIELD_GET(GENMASK(1, 1), 194 + pmbus_read_byte_data(client, page, 195 + PMBUS_STATUS_MFR_SPECIFIC))); 196 + break; 197 + case PMBUS_STATUS_TEMPERATURE: 198 + /* 199 + * If the tsns digital fault is enabled, the OT Fault and OT Warning 200 + * flag of PMBUS_STATUS_TEMPERATURE should come from STATUS_MFR_SPECIFIC 201 + * register bit1. 202 + */ 203 + if (!data->mfr_thwn_flt_en) 204 + return -ENODATA; 205 + 206 + ret = pmbus_read_byte_data(client, page, reg); 207 + if (ret < 0) 208 + return ret; 209 + 210 + ret = (ret & ~GENMASK(7, 6)) | 211 + FIELD_PREP(GENMASK(6, 6), 212 + FIELD_GET(GENMASK(1, 1), 213 + pmbus_read_byte_data(client, page, 214 + PMBUS_STATUS_MFR_SPECIFIC))) | 215 + FIELD_PREP(GENMASK(7, 7), 216 + FIELD_GET(GENMASK(1, 1), 217 + pmbus_read_byte_data(client, page, 218 + PMBUS_STATUS_MFR_SPECIFIC))); 219 + break; 220 + default: 221 + ret = -ENODATA; 222 + break; 223 + } 224 + 225 + return ret; 226 + } 227 + 228 + static int mp2869_read_word_data(struct i2c_client *client, int page, int phase, 229 + int reg) 230 + { 231 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 232 + struct mp2869_data *data = to_mp2869_data(info); 233 + int ret; 234 + 235 + switch (reg) { 236 + case PMBUS_STATUS_WORD: 237 + /* 238 + * If the tsns digital fault is enabled, the OT Fault flag 239 + * of PMBUS_STATUS_WORD should come from STATUS_MFR_SPECIFIC 240 + * register bit1. 241 + */ 242 + if (!data->mfr_thwn_flt_en) 243 + return -ENODATA; 244 + 245 + ret = pmbus_read_word_data(client, page, phase, reg); 246 + if (ret < 0) 247 + return ret; 248 + 249 + ret = (ret & ~GENMASK(2, 2)) | 250 + FIELD_PREP(GENMASK(2, 2), 251 + FIELD_GET(GENMASK(1, 1), 252 + pmbus_read_byte_data(client, page, 253 + PMBUS_STATUS_MFR_SPECIFIC))); 254 + break; 255 + case PMBUS_READ_VIN: 256 + /* 257 + * The MP2869 PMBUS_READ_VIN[10:0] is the vin value, the vin scale is 258 + * 31.25mV/LSB. And the vin scale is set to 31.25mV/Lsb(using r/m/b scale) 259 + * in MP2869 pmbus_driver_info struct, so the word data bit0-bit10 can be 260 + * returned to pmbus core directly. 261 + */ 262 + ret = pmbus_read_word_data(client, page, phase, reg); 263 + if (ret < 0) 264 + return ret; 265 + 266 + ret = FIELD_GET(GENMASK(10, 0), ret); 267 + break; 268 + case PMBUS_READ_IIN: 269 + /* 270 + * The MP2869 redefine the standard 0x95 register as iin telemetry 271 + * per rail. 272 + */ 273 + ret = pmbus_read_word_data(client, page, phase, MFR_READ_IIN_EST); 274 + if (ret < 0) 275 + return ret; 276 + 277 + break; 278 + case PMBUS_READ_PIN: 279 + /* 280 + * The MP2869 redefine the standard 0x94 register as pin telemetry 281 + * per rail. The MP2869 MFR_READ_PIN_EST register is linear11 format, 282 + * but the pin scale is set to 1W/Lsb(using r/m/b scale). As a result, 283 + * the pin read from MP2869 should be converted to W, then return 284 + * the result to pmbus core. 285 + */ 286 + ret = pmbus_read_word_data(client, page, phase, MFR_READ_PIN_EST); 287 + if (ret < 0) 288 + return ret; 289 + 290 + ret = mp2869_reg2data_linear11(ret); 291 + break; 292 + case PMBUS_READ_VOUT: 293 + ret = pmbus_read_word_data(client, page, phase, reg); 294 + if (ret < 0) 295 + return ret; 296 + 297 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * data->vout_scale[page], 298 + MP2869_READ_VOUT_DIV); 299 + break; 300 + case PMBUS_READ_IOUT: 301 + ret = pmbus_read_word_data(client, page, phase, reg); 302 + if (ret < 0) 303 + return ret; 304 + 305 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(10, 0)) * data->iout_scale[page], 306 + MP2869_READ_IOUT_DIV); 307 + break; 308 + case PMBUS_READ_POUT: 309 + /* 310 + * The MP2869 PMBUS_READ_POUT register is linear11 format, but the pout 311 + * scale is set to 1W/Lsb(using r/m/b scale). As a result, the pout read 312 + * from MP2869 should be converted to W, then return the result to pmbus 313 + * core. 314 + */ 315 + ret = pmbus_read_word_data(client, page, phase, reg); 316 + if (ret < 0) 317 + return ret; 318 + 319 + ret = mp2869_reg2data_linear11(ret); 320 + break; 321 + case PMBUS_READ_TEMPERATURE_1: 322 + ret = pmbus_read_word_data(client, page, phase, reg); 323 + if (ret < 0) 324 + return ret; 325 + 326 + ret = FIELD_GET(GENMASK(10, 0), ret); 327 + break; 328 + case PMBUS_VOUT_OV_FAULT_LIMIT: 329 + ret = pmbus_read_word_data(client, page, phase, reg); 330 + if (ret < 0) 331 + return ret; 332 + 333 + if (FIELD_GET(GENMASK(12, 9), ret)) 334 + ret = FIELD_GET(GENMASK(8, 0), ret) * MP2869_OVUV_LIMIT_SCALE + 335 + (FIELD_GET(GENMASK(12, 9), ret) + 1) * MP2869_OVUV_DELTA_SCALE; 336 + else 337 + ret = FIELD_GET(GENMASK(8, 0), ret) * MP2869_OVUV_LIMIT_SCALE; 338 + break; 339 + case PMBUS_VOUT_UV_FAULT_LIMIT: 340 + ret = pmbus_read_word_data(client, page, phase, reg); 341 + if (ret < 0) 342 + return ret; 343 + 344 + if (FIELD_GET(GENMASK(12, 9), ret)) 345 + ret = FIELD_GET(GENMASK(8, 0), ret) * MP2869_OVUV_LIMIT_SCALE - 346 + (FIELD_GET(GENMASK(12, 9), ret) + 1) * MP2869_OVUV_DELTA_SCALE; 347 + else 348 + ret = FIELD_GET(GENMASK(8, 0), ret) * MP2869_OVUV_LIMIT_SCALE; 349 + break; 350 + case PMBUS_OT_FAULT_LIMIT: 351 + case PMBUS_OT_WARN_LIMIT: 352 + /* 353 + * The scale of MP2869 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT 354 + * is 1°C/LSB and they have 40°C offset. 355 + */ 356 + ret = pmbus_read_word_data(client, page, phase, reg); 357 + if (ret < 0) 358 + return ret; 359 + 360 + ret = (ret & GENMASK(7, 0)) - MP2869_TEMP_LIMIT_OFFSET; 361 + break; 362 + case PMBUS_VIN_OV_FAULT_LIMIT: 363 + ret = pmbus_read_word_data(client, page, phase, reg); 364 + if (ret < 0) 365 + return ret; 366 + 367 + ret = (ret & GENMASK(7, 0)) * MP2869_VIN_OV_FAULT_GAIN; 368 + break; 369 + case PMBUS_VIN_UV_WARN_LIMIT: 370 + case PMBUS_VIN_UV_FAULT_LIMIT: 371 + ret = pmbus_read_word_data(client, page, phase, reg); 372 + if (ret < 0) 373 + return ret; 374 + 375 + ret = FIELD_GET(GENMASK(9, 0), ret); 376 + break; 377 + case PMBUS_IOUT_OC_FAULT_LIMIT: 378 + case PMBUS_IOUT_OC_WARN_LIMIT: 379 + ret = pmbus_read_word_data(client, page, phase, reg); 380 + if (ret < 0) 381 + return ret; 382 + 383 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(7, 0)) * data->iout_scale[page] * 384 + MP2869_IOUT_LIMIT_UINT, MP2869_READ_IOUT_DIV); 385 + break; 386 + case PMBUS_POUT_OP_WARN_LIMIT: 387 + ret = pmbus_read_word_data(client, page, phase, reg); 388 + if (ret < 0) 389 + return ret; 390 + 391 + ret = (ret & GENMASK(7, 0)) * MP2869_POUT_OP_GAIN; 392 + break; 393 + default: 394 + ret = -EINVAL; 395 + break; 396 + } 397 + 398 + return ret; 399 + } 400 + 401 + static int mp2869_write_word_data(struct i2c_client *client, int page, int reg, 402 + u16 word) 403 + { 404 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 405 + struct mp2869_data *data = to_mp2869_data(info); 406 + int ret; 407 + 408 + switch (reg) { 409 + case PMBUS_VOUT_UV_FAULT_LIMIT: 410 + /* 411 + * The MP2869 PMBUS_VOUT_UV_FAULT_LIMIT[8:0] is the limit value, 412 + * and bit9-bit15 should not be changed. 413 + */ 414 + ret = pmbus_read_word_data(client, page, 0xff, reg); 415 + if (ret < 0) 416 + return ret; 417 + 418 + if (FIELD_GET(GENMASK(12, 9), ret)) 419 + ret = pmbus_write_word_data(client, page, reg, 420 + (ret & ~GENMASK(8, 0)) | 421 + FIELD_PREP(GENMASK(8, 0), 422 + DIV_ROUND_CLOSEST(word + 423 + (FIELD_GET(GENMASK(12, 9), 424 + ret) + 1) * 425 + MP2869_OVUV_DELTA_SCALE, 426 + MP2869_OVUV_LIMIT_SCALE))); 427 + else 428 + ret = pmbus_write_word_data(client, page, reg, 429 + (ret & ~GENMASK(8, 0)) | 430 + FIELD_PREP(GENMASK(8, 0), 431 + DIV_ROUND_CLOSEST(word, 432 + MP2869_OVUV_LIMIT_SCALE))); 433 + break; 434 + case PMBUS_VOUT_OV_FAULT_LIMIT: 435 + /* 436 + * The MP2869 PMBUS_VOUT_OV_FAULT_LIMIT[8:0] is the limit value, 437 + * and bit9-bit15 should not be changed. 438 + */ 439 + ret = pmbus_read_word_data(client, page, 0xff, reg); 440 + if (ret < 0) 441 + return ret; 442 + 443 + if (FIELD_GET(GENMASK(12, 9), ret)) 444 + ret = pmbus_write_word_data(client, page, reg, 445 + (ret & ~GENMASK(8, 0)) | 446 + FIELD_PREP(GENMASK(8, 0), 447 + DIV_ROUND_CLOSEST(word - 448 + (FIELD_GET(GENMASK(12, 9), 449 + ret) + 1) * 450 + MP2869_OVUV_DELTA_SCALE, 451 + MP2869_OVUV_LIMIT_SCALE))); 452 + else 453 + ret = pmbus_write_word_data(client, page, reg, 454 + (ret & ~GENMASK(8, 0)) | 455 + FIELD_PREP(GENMASK(8, 0), 456 + DIV_ROUND_CLOSEST(word, 457 + MP2869_OVUV_LIMIT_SCALE))); 458 + break; 459 + case PMBUS_OT_FAULT_LIMIT: 460 + case PMBUS_OT_WARN_LIMIT: 461 + /* 462 + * If the tsns digital fault is enabled, the PMBUS_OT_FAULT_LIMIT and 463 + * PMBUS_OT_WARN_LIMIT can not be written. 464 + */ 465 + if (data->mfr_thwn_flt_en) 466 + return -EINVAL; 467 + 468 + /* 469 + * The MP2869 scale of MP2869 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT 470 + * have 40°C offset. The bit0-bit7 is the limit value, and bit8-bit15 471 + * should not be changed. 472 + */ 473 + ret = pmbus_read_word_data(client, page, 0xff, reg); 474 + if (ret < 0) 475 + return ret; 476 + 477 + ret = pmbus_write_word_data(client, page, reg, 478 + (ret & ~GENMASK(7, 0)) | 479 + FIELD_PREP(GENMASK(7, 0), 480 + word + MP2869_TEMP_LIMIT_OFFSET)); 481 + break; 482 + case PMBUS_VIN_OV_FAULT_LIMIT: 483 + /* 484 + * The MP2869 PMBUS_VIN_OV_FAULT_LIMIT[7:0] is the limit value, and bit8-bit15 485 + * should not be changed. The scale of PMBUS_VIN_OV_FAULT_LIMIT is 125mV/Lsb, 486 + * but the vin scale is set to 31.25mV/Lsb(using r/m/b scale), so the word data 487 + * should divide by MP2869_VIN_OV_FAULT_GAIN(4) 488 + */ 489 + ret = pmbus_read_word_data(client, page, 0xff, reg); 490 + if (ret < 0) 491 + return ret; 492 + 493 + ret = pmbus_write_word_data(client, page, reg, 494 + (ret & ~GENMASK(7, 0)) | 495 + FIELD_PREP(GENMASK(7, 0), 496 + DIV_ROUND_CLOSEST(word, 497 + MP2869_VIN_OV_FAULT_GAIN))); 498 + break; 499 + case PMBUS_VIN_UV_WARN_LIMIT: 500 + case PMBUS_VIN_UV_FAULT_LIMIT: 501 + /* 502 + * The PMBUS_VIN_UV_LIMIT[9:0] is the limit value, and bit10-bit15 should 503 + * not be changed. The scale of PMBUS_VIN_UV_LIMIT is 31.25mV/Lsb, and the 504 + * vin scale is set to 31.25mV/Lsb(using r/m/b scale), so the word data can 505 + * be written directly. 506 + */ 507 + ret = pmbus_read_word_data(client, page, 0xff, reg); 508 + if (ret < 0) 509 + return ret; 510 + 511 + ret = pmbus_write_word_data(client, page, reg, 512 + (ret & ~GENMASK(9, 0)) | 513 + FIELD_PREP(GENMASK(9, 0), 514 + word)); 515 + break; 516 + case PMBUS_IOUT_OC_FAULT_LIMIT: 517 + case PMBUS_IOUT_OC_WARN_LIMIT: 518 + ret = pmbus_write_word_data(client, page, reg, 519 + DIV_ROUND_CLOSEST(word * MP2869_READ_IOUT_DIV, 520 + MP2869_IOUT_LIMIT_UINT * 521 + data->iout_scale[page])); 522 + break; 523 + case PMBUS_POUT_OP_WARN_LIMIT: 524 + /* 525 + * The POUT_OP_WARN_LIMIT[11:0] is the limit value, and bit12-bit15 should 526 + * not be changed. The scale of POUT_OP_WARN_LIMIT is 2W/Lsb. 527 + */ 528 + ret = pmbus_read_word_data(client, page, 0xff, reg); 529 + if (ret < 0) 530 + return ret; 531 + 532 + ret = pmbus_write_word_data(client, page, reg, 533 + (ret & ~GENMASK(11, 0)) | 534 + FIELD_PREP(GENMASK(11, 0), 535 + DIV_ROUND_CLOSEST(word, 536 + MP2869_POUT_OP_GAIN))); 537 + break; 538 + default: 539 + ret = -EINVAL; 540 + break; 541 + } 542 + 543 + return ret; 544 + } 545 + 546 + static int mp2869_identify(struct i2c_client *client, struct pmbus_driver_info *info) 547 + { 548 + int ret; 549 + 550 + /* Identify whether tsns digital fault is enable */ 551 + ret = mp2869_identify_thwn_flt(client, info, 1); 552 + if (ret < 0) 553 + return 0; 554 + 555 + /* Identify vout scale for rail1. */ 556 + ret = mp2869_identify_vout_scale(client, info, 0); 557 + if (ret < 0) 558 + return ret; 559 + 560 + /* Identify vout scale for rail2. */ 561 + ret = mp2869_identify_vout_scale(client, info, 1); 562 + if (ret < 0) 563 + return ret; 564 + 565 + /* Identify iout scale for rail 1. */ 566 + ret = mp2869_identify_iout_scale(client, info, 0); 567 + if (ret < 0) 568 + return ret; 569 + 570 + /* Identify iout scale for rail 2. */ 571 + return mp2869_identify_iout_scale(client, info, 1); 572 + } 573 + 574 + static const struct pmbus_driver_info mp2869_info = { 575 + .pages = MP2869_PAGE_NUM, 576 + .format[PSC_VOLTAGE_IN] = direct, 577 + .format[PSC_CURRENT_IN] = linear, 578 + .format[PSC_CURRENT_OUT] = direct, 579 + .format[PSC_TEMPERATURE] = direct, 580 + .format[PSC_POWER] = direct, 581 + .format[PSC_VOLTAGE_OUT] = direct, 582 + 583 + .m[PSC_VOLTAGE_IN] = 32, 584 + .R[PSC_VOLTAGE_IN] = 0, 585 + .b[PSC_VOLTAGE_IN] = 0, 586 + 587 + .m[PSC_VOLTAGE_OUT] = 1, 588 + .R[PSC_VOLTAGE_OUT] = 3, 589 + .b[PSC_VOLTAGE_OUT] = 0, 590 + 591 + .m[PSC_CURRENT_OUT] = 1, 592 + .R[PSC_CURRENT_OUT] = 0, 593 + .b[PSC_CURRENT_OUT] = 0, 594 + 595 + .m[PSC_TEMPERATURE] = 1, 596 + .R[PSC_TEMPERATURE] = 0, 597 + .b[PSC_TEMPERATURE] = 0, 598 + 599 + .m[PSC_POWER] = 1, 600 + .R[PSC_POWER] = 0, 601 + .b[PSC_POWER] = 0, 602 + 603 + .func[0] = MP2869_RAIL1_FUNC, 604 + .func[1] = MP2869_RAIL2_FUNC, 605 + .read_word_data = mp2869_read_word_data, 606 + .write_word_data = mp2869_write_word_data, 607 + .read_byte_data = mp2869_read_byte_data, 608 + .identify = mp2869_identify, 609 + }; 610 + 611 + static int mp2869_probe(struct i2c_client *client) 612 + { 613 + struct pmbus_driver_info *info; 614 + struct mp2869_data *data; 615 + 616 + data = devm_kzalloc(&client->dev, sizeof(struct mp2869_data), 617 + GFP_KERNEL); 618 + if (!data) 619 + return -ENOMEM; 620 + 621 + memcpy(&data->info, &mp2869_info, sizeof(*info)); 622 + info = &data->info; 623 + 624 + return pmbus_do_probe(client, info); 625 + } 626 + 627 + static const struct i2c_device_id mp2869_id[] = { 628 + {"mp2869", 0}, 629 + {"mp29608", 1}, 630 + {"mp29612", 2}, 631 + {"mp29816", 3}, 632 + {} 633 + }; 634 + MODULE_DEVICE_TABLE(i2c, mp2869_id); 635 + 636 + static const struct of_device_id __maybe_unused mp2869_of_match[] = { 637 + {.compatible = "mps,mp2869", .data = (void *)0}, 638 + {.compatible = "mps,mp29608", .data = (void *)1}, 639 + {.compatible = "mps,mp29612", .data = (void *)2}, 640 + {.compatible = "mps,mp29816", .data = (void *)3}, 641 + {} 642 + }; 643 + MODULE_DEVICE_TABLE(of, mp2869_of_match); 644 + 645 + static struct i2c_driver mp2869_driver = { 646 + .driver = { 647 + .name = "mp2869", 648 + .of_match_table = mp2869_of_match, 649 + }, 650 + .probe = mp2869_probe, 651 + .id_table = mp2869_id, 652 + }; 653 + 654 + module_i2c_driver(mp2869_driver); 655 + 656 + MODULE_AUTHOR("Wensheng Wang <wenswang@yeah.net>"); 657 + MODULE_DESCRIPTION("PMBus driver for MPS MP2869"); 658 + MODULE_LICENSE("GPL"); 659 + MODULE_IMPORT_NS("PMBUS");
+670
drivers/hwmon/pmbus/mp29502.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Hardware monitoring driver for MPS Multi-phase Digital VR Controllers(MP29502) 4 + */ 5 + 6 + #include <linux/bitfield.h> 7 + #include <linux/i2c.h> 8 + #include <linux/module.h> 9 + #include <linux/of_device.h> 10 + #include "pmbus.h" 11 + 12 + #define MFR_VOUT_SCALE_LOOP 0x29 13 + #define MFR_SVI3_IOUT_PRT 0x67 14 + #define MFR_READ_PIN_EST 0x94 15 + #define MFR_READ_IIN_EST 0x95 16 + #define MFR_VOUT_PROT1 0x3D 17 + #define MFR_VOUT_PROT2 0x51 18 + #define MFR_SLOPE_CNT_SET 0xA8 19 + #define MFR_TSNS_FLT_SET 0xBB 20 + 21 + #define MP29502_VIN_OV_GAIN 4 22 + #define MP29502_TEMP_LIMIT_OFFSET 40 23 + #define MP29502_READ_VOUT_DIV 1024 24 + #define MP29502_READ_IOUT_DIV 32 25 + #define MP29502_IOUT_LIMIT_UINT 8 26 + #define MP29502_OVUV_LIMIT_SCALE 10 27 + #define MP28502_VOUT_OV_GAIN 512 28 + #define MP28502_VOUT_OV_SCALE 40 29 + #define MP29502_VOUT_UV_OFFSET 36 30 + #define MP29502_PIN_GAIN 2 31 + #define MP29502_IIN_DIV 2 32 + 33 + #define MP29502_PAGE_NUM 1 34 + 35 + #define MP29502_RAIL_FUNC (PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | \ 36 + PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | \ 37 + PMBUS_HAVE_TEMP | PMBUS_HAVE_PIN | \ 38 + PMBUS_HAVE_IIN | \ 39 + PMBUS_HAVE_STATUS_VOUT | \ 40 + PMBUS_HAVE_STATUS_IOUT | \ 41 + PMBUS_HAVE_STATUS_TEMP | \ 42 + PMBUS_HAVE_STATUS_INPUT) 43 + 44 + struct mp29502_data { 45 + struct pmbus_driver_info info; 46 + int vout_scale; 47 + int vout_bottom_div; 48 + int vout_top_div; 49 + int ovp_div; 50 + int iout_scale; 51 + }; 52 + 53 + #define to_mp29502_data(x) container_of(x, struct mp29502_data, info) 54 + 55 + static u16 mp29502_reg2data_linear11(u16 word) 56 + { 57 + s16 exponent; 58 + s32 mantissa; 59 + s64 val; 60 + 61 + exponent = ((s16)word) >> 11; 62 + mantissa = ((s16)((word & 0x7ff) << 5)) >> 5; 63 + val = mantissa; 64 + 65 + if (exponent >= 0) 66 + val <<= exponent; 67 + else 68 + val >>= -exponent; 69 + 70 + return val; 71 + } 72 + 73 + static int 74 + mp29502_identify_vout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 75 + int page) 76 + { 77 + struct mp29502_data *data = to_mp29502_data(info); 78 + int ret; 79 + 80 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 81 + if (ret < 0) 82 + return ret; 83 + 84 + ret = i2c_smbus_read_word_data(client, MFR_VOUT_SCALE_LOOP); 85 + if (ret < 0) 86 + return ret; 87 + 88 + switch (FIELD_GET(GENMASK(12, 10), ret)) { 89 + case 0: 90 + data->vout_scale = 6400; 91 + break; 92 + case 1: 93 + data->vout_scale = 5120; 94 + break; 95 + case 2: 96 + data->vout_scale = 2560; 97 + break; 98 + case 3: 99 + data->vout_scale = 2048; 100 + break; 101 + case 4: 102 + data->vout_scale = 1024; 103 + break; 104 + case 5: 105 + data->vout_scale = 4; 106 + break; 107 + case 6: 108 + data->vout_scale = 2; 109 + break; 110 + case 7: 111 + data->vout_scale = 1; 112 + break; 113 + default: 114 + data->vout_scale = 1; 115 + break; 116 + } 117 + 118 + return 0; 119 + } 120 + 121 + static int 122 + mp29502_identify_vout_divider(struct i2c_client *client, struct pmbus_driver_info *info, 123 + int page) 124 + { 125 + struct mp29502_data *data = to_mp29502_data(info); 126 + int ret; 127 + 128 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 129 + if (ret < 0) 130 + return ret; 131 + 132 + ret = i2c_smbus_read_word_data(client, MFR_VOUT_PROT1); 133 + if (ret < 0) 134 + return ret; 135 + 136 + data->vout_bottom_div = FIELD_GET(GENMASK(11, 0), ret); 137 + 138 + ret = i2c_smbus_read_word_data(client, MFR_VOUT_PROT2); 139 + if (ret < 0) 140 + return ret; 141 + 142 + data->vout_top_div = FIELD_GET(GENMASK(14, 0), ret); 143 + 144 + return 0; 145 + } 146 + 147 + static int 148 + mp29502_identify_ovp_divider(struct i2c_client *client, struct pmbus_driver_info *info, 149 + int page) 150 + { 151 + struct mp29502_data *data = to_mp29502_data(info); 152 + int ret; 153 + 154 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 155 + if (ret < 0) 156 + return ret; 157 + 158 + ret = i2c_smbus_read_word_data(client, MFR_SLOPE_CNT_SET); 159 + if (ret < 0) 160 + return ret; 161 + 162 + data->ovp_div = FIELD_GET(GENMASK(9, 0), ret); 163 + 164 + return 0; 165 + } 166 + 167 + static int 168 + mp29502_identify_iout_scale(struct i2c_client *client, struct pmbus_driver_info *info, 169 + int page) 170 + { 171 + struct mp29502_data *data = to_mp29502_data(info); 172 + int ret; 173 + 174 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); 175 + if (ret < 0) 176 + return ret; 177 + 178 + ret = i2c_smbus_read_word_data(client, MFR_SVI3_IOUT_PRT); 179 + if (ret < 0) 180 + return ret; 181 + 182 + switch (ret & GENMASK(2, 0)) { 183 + case 0: 184 + case 6: 185 + data->iout_scale = 32; 186 + break; 187 + case 1: 188 + data->iout_scale = 1; 189 + break; 190 + case 2: 191 + data->iout_scale = 2; 192 + break; 193 + case 3: 194 + data->iout_scale = 4; 195 + break; 196 + case 4: 197 + data->iout_scale = 8; 198 + break; 199 + case 5: 200 + data->iout_scale = 16; 201 + break; 202 + default: 203 + data->iout_scale = 64; 204 + break; 205 + } 206 + 207 + return 0; 208 + } 209 + 210 + static int mp29502_read_vout_ov_limit(struct i2c_client *client, struct mp29502_data *data) 211 + { 212 + int ret; 213 + int ov_value; 214 + 215 + /* 216 + * This is because the vout ov fault limit value comes from 217 + * page1 MFR_TSNS_FLT_SET reg, and other telemetry and limit 218 + * value comes from page0 reg. So the page should be set to 219 + * 0 after the reading of vout ov limit. 220 + */ 221 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 1); 222 + if (ret < 0) 223 + return ret; 224 + 225 + ret = i2c_smbus_read_word_data(client, MFR_TSNS_FLT_SET); 226 + if (ret < 0) 227 + return ret; 228 + 229 + ov_value = DIV_ROUND_CLOSEST(FIELD_GET(GENMASK(12, 7), ret) * 230 + MP28502_VOUT_OV_GAIN * MP28502_VOUT_OV_SCALE, 231 + data->ovp_div); 232 + 233 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 234 + if (ret < 0) 235 + return ret; 236 + 237 + return ov_value; 238 + } 239 + 240 + static int mp29502_write_vout_ov_limit(struct i2c_client *client, u16 word, 241 + struct mp29502_data *data) 242 + { 243 + int ret; 244 + 245 + /* 246 + * This is because the vout ov fault limit value comes from 247 + * page1 MFR_TSNS_FLT_SET reg, and other telemetry and limit 248 + * value comes from page0 reg. So the page should be set to 249 + * 0 after the writing of vout ov limit. 250 + */ 251 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 1); 252 + if (ret < 0) 253 + return ret; 254 + 255 + ret = i2c_smbus_read_word_data(client, MFR_TSNS_FLT_SET); 256 + if (ret < 0) 257 + return ret; 258 + 259 + ret = i2c_smbus_write_word_data(client, MFR_TSNS_FLT_SET, 260 + (ret & ~GENMASK(12, 7)) | 261 + FIELD_PREP(GENMASK(12, 7), 262 + DIV_ROUND_CLOSEST(word * data->ovp_div, 263 + MP28502_VOUT_OV_GAIN * MP28502_VOUT_OV_SCALE))); 264 + 265 + return i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 266 + } 267 + 268 + static int mp29502_read_byte_data(struct i2c_client *client, int page, int reg) 269 + { 270 + int ret; 271 + 272 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 273 + if (ret < 0) 274 + return ret; 275 + 276 + switch (reg) { 277 + case PMBUS_VOUT_MODE: 278 + ret = PB_VOUT_MODE_DIRECT; 279 + break; 280 + default: 281 + ret = -ENODATA; 282 + break; 283 + } 284 + 285 + return ret; 286 + } 287 + 288 + static int mp29502_read_word_data(struct i2c_client *client, int page, 289 + int phase, int reg) 290 + { 291 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 292 + struct mp29502_data *data = to_mp29502_data(info); 293 + int ret; 294 + 295 + switch (reg) { 296 + case PMBUS_STATUS_WORD: 297 + ret = -ENODATA; 298 + break; 299 + case PMBUS_READ_VIN: 300 + /* 301 + * The MP29502 PMBUS_READ_VIN[10:0] is the vin value, the vin scale is 302 + * 125mV/LSB. And the vin scale is set to 125mV/Lsb(using r/m/b scale) 303 + * in MP29502 pmbus_driver_info struct, so the word data bit0-bit10 can 304 + * be returned to pmbus core directly. 305 + */ 306 + ret = pmbus_read_word_data(client, page, phase, reg); 307 + if (ret < 0) 308 + return ret; 309 + 310 + ret = FIELD_GET(GENMASK(10, 0), ret); 311 + break; 312 + case PMBUS_READ_VOUT: 313 + /* 314 + * The MP29502 PMBUS_READ_VOUT[11:0] is the vout value, and vout 315 + * value is calculated based on vout scale and vout divider. 316 + */ 317 + ret = pmbus_read_word_data(client, page, phase, reg); 318 + if (ret < 0) 319 + return ret; 320 + 321 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(11, 0)) * 322 + data->vout_scale * 323 + (data->vout_bottom_div + 324 + 4 * data->vout_top_div), 325 + MP29502_READ_VOUT_DIV * 326 + data->vout_bottom_div); 327 + break; 328 + case PMBUS_READ_IIN: 329 + /* 330 + * The MP29502 MFR_READ_IIN_EST register is linear11 format, and the 331 + * exponent is not a constant value. But the iin scale is set to 332 + * 1A/Lsb(using r/m/b scale). As a result, the iin read from MP29502 333 + * should be calculated to A, then return the result to pmbus core. 334 + */ 335 + ret = pmbus_read_word_data(client, page, phase, MFR_READ_IIN_EST); 336 + if (ret < 0) 337 + return ret; 338 + 339 + ret = DIV_ROUND_CLOSEST(mp29502_reg2data_linear11(ret), 340 + MP29502_IIN_DIV); 341 + break; 342 + case PMBUS_READ_PIN: 343 + /* 344 + * The MP29502 MFR_READ_PIN_EST register is linear11 format, and the 345 + * exponent is not a constant value. But the pin scale is set to 346 + * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP29502 347 + * should be calculated to W, then return the result to pmbus core. 348 + */ 349 + ret = pmbus_read_word_data(client, page, phase, MFR_READ_PIN_EST); 350 + if (ret < 0) 351 + return ret; 352 + 353 + ret = mp29502_reg2data_linear11(ret) * MP29502_PIN_GAIN; 354 + break; 355 + case PMBUS_READ_POUT: 356 + /* 357 + * The MP29502 PMBUS_READ_POUT register is linear11 format, and the 358 + * exponent is not a constant value. But the pout scale is set to 359 + * 1W/Lsb(using r/m/b scale). As a result, the pout read from MP29502 360 + * should be calculated to W, then return the result to pmbus core. 361 + * And the pout is calculated based on vout divider. 362 + */ 363 + ret = pmbus_read_word_data(client, page, phase, reg); 364 + if (ret < 0) 365 + return ret; 366 + 367 + ret = DIV_ROUND_CLOSEST(mp29502_reg2data_linear11(ret) * 368 + (data->vout_bottom_div + 369 + 4 * data->vout_top_div), 370 + data->vout_bottom_div); 371 + break; 372 + case PMBUS_READ_IOUT: 373 + ret = pmbus_read_word_data(client, page, phase, reg); 374 + if (ret < 0) 375 + return ret; 376 + 377 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(10, 0)) * data->iout_scale, 378 + MP29502_READ_IOUT_DIV); 379 + break; 380 + case PMBUS_READ_TEMPERATURE_1: 381 + ret = pmbus_read_word_data(client, page, phase, reg); 382 + if (ret < 0) 383 + return ret; 384 + 385 + ret = FIELD_GET(GENMASK(10, 0), ret); 386 + break; 387 + case PMBUS_VIN_OV_FAULT_LIMIT: 388 + /* 389 + * The MP29502 PMBUS_VIN_OV_FAULT_LIMIT is 500mV/Lsb, but 390 + * the vin scale is set to 125mV/Lsb(using r/m/b scale), 391 + * so the word data should multiply by 4. 392 + */ 393 + ret = pmbus_read_word_data(client, page, phase, reg); 394 + if (ret < 0) 395 + return ret; 396 + 397 + ret = FIELD_GET(GENMASK(7, 0), ret) * MP29502_VIN_OV_GAIN; 398 + break; 399 + case PMBUS_VIN_UV_WARN_LIMIT: 400 + case PMBUS_VIN_UV_FAULT_LIMIT: 401 + /* 402 + * The MP29502 PMBUS_VIN_UV_WARN_LIMIT and PMBUS_VIN_UV_FAULT_LIMIT 403 + * scale is 125mV/Lsb, but the vin scale is set to 125mV/Lsb(using 404 + * r/m/b scale), so the word data bit0-bit9 can be returned to pmbus 405 + * core directly. 406 + */ 407 + ret = pmbus_read_word_data(client, page, phase, reg); 408 + if (ret < 0) 409 + return ret; 410 + 411 + ret = FIELD_GET(GENMASK(9, 0), ret); 412 + break; 413 + case PMBUS_VOUT_OV_FAULT_LIMIT: 414 + /* 415 + * The MP29502 vout ov fault limit value comes from 416 + * page1 MFR_TSNS_FLT_SET[12:7]. 417 + */ 418 + ret = mp29502_read_vout_ov_limit(client, data); 419 + if (ret < 0) 420 + return ret; 421 + 422 + break; 423 + case PMBUS_VOUT_UV_FAULT_LIMIT: 424 + ret = pmbus_read_word_data(client, page, phase, reg); 425 + if (ret < 0) 426 + return ret; 427 + 428 + ret = DIV_ROUND_CLOSEST((FIELD_GET(GENMASK(8, 0), ret) * 429 + MP29502_OVUV_LIMIT_SCALE - 430 + MP29502_VOUT_UV_OFFSET) * 431 + (data->vout_bottom_div + 432 + 4 * data->vout_top_div), 433 + data->vout_bottom_div); 434 + break; 435 + case PMBUS_IOUT_OC_FAULT_LIMIT: 436 + case PMBUS_IOUT_OC_WARN_LIMIT: 437 + ret = pmbus_read_word_data(client, page, phase, reg); 438 + if (ret < 0) 439 + return ret; 440 + 441 + ret = DIV_ROUND_CLOSEST((ret & GENMASK(7, 0)) * 442 + data->iout_scale * 443 + MP29502_IOUT_LIMIT_UINT, 444 + MP29502_READ_IOUT_DIV); 445 + break; 446 + case PMBUS_OT_FAULT_LIMIT: 447 + case PMBUS_OT_WARN_LIMIT: 448 + /* 449 + * The scale of MP29502 PMBUS_OT_FAULT_LIMIT and PMBUS_OT_WARN_LIMIT 450 + * is 1°C/LSB and they have 40°C offset. 451 + */ 452 + ret = pmbus_read_word_data(client, page, phase, reg); 453 + if (ret < 0) 454 + return ret; 455 + 456 + ret = (ret & GENMASK(7, 0)) - MP29502_TEMP_LIMIT_OFFSET; 457 + break; 458 + default: 459 + ret = -EINVAL; 460 + break; 461 + } 462 + 463 + return ret; 464 + } 465 + 466 + static int mp29502_write_word_data(struct i2c_client *client, int page, int reg, 467 + u16 word) 468 + { 469 + const struct pmbus_driver_info *info = pmbus_get_driver_info(client); 470 + struct mp29502_data *data = to_mp29502_data(info); 471 + int ret; 472 + 473 + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); 474 + if (ret < 0) 475 + return ret; 476 + 477 + switch (reg) { 478 + case PMBUS_VIN_OV_FAULT_LIMIT: 479 + /* 480 + * The PMBUS_VIN_OV_FAULT_LIMIT[7:0] is the limit value, 481 + * and bit8-bit15 should not be changed. The scale of 482 + * PMBUS_VIN_OV_FAULT_LIMIT is 500mV/Lsb, but the vin 483 + * scale is set to 125mV/Lsb(using r/m/b scale), so 484 + * the word data should divide by 4. 485 + */ 486 + ret = pmbus_read_word_data(client, page, 0xff, reg); 487 + if (ret < 0) 488 + return ret; 489 + 490 + ret = pmbus_write_word_data(client, page, reg, 491 + (ret & ~GENMASK(7, 0)) | 492 + FIELD_PREP(GENMASK(7, 0), 493 + DIV_ROUND_CLOSEST(word, 494 + MP29502_VIN_OV_GAIN))); 495 + break; 496 + case PMBUS_VIN_UV_WARN_LIMIT: 497 + case PMBUS_VIN_UV_FAULT_LIMIT: 498 + /* 499 + * The PMBUS_VIN_UV_WARN_LIMIT[9:0] and PMBUS_VIN_UV_FAULT_LIMIT[9:0] 500 + * are the limit value, and bit10-bit15 should not be changed. 501 + */ 502 + ret = pmbus_read_word_data(client, page, 0xff, reg); 503 + if (ret < 0) 504 + return ret; 505 + 506 + ret = pmbus_write_word_data(client, page, reg, 507 + (ret & ~GENMASK(9, 0)) | 508 + FIELD_PREP(GENMASK(9, 0), 509 + word)); 510 + break; 511 + case PMBUS_VOUT_OV_FAULT_LIMIT: 512 + ret = mp29502_write_vout_ov_limit(client, word, data); 513 + if (ret < 0) 514 + return ret; 515 + 516 + break; 517 + case PMBUS_VOUT_UV_FAULT_LIMIT: 518 + ret = pmbus_read_word_data(client, page, 0xff, reg); 519 + if (ret < 0) 520 + return ret; 521 + 522 + ret = pmbus_write_word_data(client, page, reg, 523 + (ret & ~GENMASK(8, 0)) | 524 + FIELD_PREP(GENMASK(8, 0), 525 + DIV_ROUND_CLOSEST(word * 526 + data->vout_bottom_div + 527 + MP29502_VOUT_UV_OFFSET * 528 + (data->vout_bottom_div + 529 + 4 * data->vout_top_div), 530 + MP29502_OVUV_LIMIT_SCALE * 531 + (data->vout_bottom_div + 532 + 4 * data->vout_top_div)))); 533 + break; 534 + case PMBUS_IOUT_OC_FAULT_LIMIT: 535 + case PMBUS_IOUT_OC_WARN_LIMIT: 536 + ret = pmbus_write_word_data(client, page, reg, 537 + DIV_ROUND_CLOSEST(word * 538 + MP29502_READ_IOUT_DIV, 539 + MP29502_IOUT_LIMIT_UINT * 540 + data->iout_scale)); 541 + break; 542 + case PMBUS_OT_FAULT_LIMIT: 543 + case PMBUS_OT_WARN_LIMIT: 544 + /* 545 + * The PMBUS_OT_FAULT_LIMIT[7:0] and PMBUS_OT_WARN_LIMIT[7:0] 546 + * are the limit value, and bit8-bit15 should not be changed. 547 + */ 548 + ret = pmbus_read_word_data(client, page, 0xff, reg); 549 + if (ret < 0) 550 + return ret; 551 + 552 + ret = pmbus_write_word_data(client, page, reg, 553 + (ret & ~GENMASK(7, 0)) | 554 + FIELD_PREP(GENMASK(7, 0), 555 + word + MP29502_TEMP_LIMIT_OFFSET)); 556 + break; 557 + default: 558 + ret = -EINVAL; 559 + break; 560 + } 561 + 562 + return ret; 563 + } 564 + 565 + static int mp29502_identify(struct i2c_client *client, struct pmbus_driver_info *info) 566 + { 567 + int ret; 568 + 569 + /* Identify vout scale */ 570 + ret = mp29502_identify_vout_scale(client, info, 0); 571 + if (ret < 0) 572 + return ret; 573 + 574 + /* Identify vout divider. */ 575 + ret = mp29502_identify_vout_divider(client, info, 1); 576 + if (ret < 0) 577 + return ret; 578 + 579 + /* Identify ovp divider. */ 580 + ret = mp29502_identify_ovp_divider(client, info, 1); 581 + if (ret < 0) 582 + return ret; 583 + 584 + /* Identify iout scale */ 585 + return mp29502_identify_iout_scale(client, info, 0); 586 + } 587 + 588 + static const struct pmbus_driver_info mp29502_info = { 589 + .pages = MP29502_PAGE_NUM, 590 + .format[PSC_VOLTAGE_IN] = direct, 591 + .format[PSC_TEMPERATURE] = direct, 592 + .format[PSC_CURRENT_IN] = direct, 593 + .format[PSC_CURRENT_OUT] = direct, 594 + .format[PSC_VOLTAGE_OUT] = direct, 595 + .format[PSC_POWER] = direct, 596 + 597 + .m[PSC_VOLTAGE_IN] = 8, 598 + .R[PSC_VOLTAGE_IN] = 0, 599 + .b[PSC_VOLTAGE_IN] = 0, 600 + 601 + .m[PSC_VOLTAGE_OUT] = 1, 602 + .R[PSC_VOLTAGE_OUT] = 3, 603 + .b[PSC_VOLTAGE_OUT] = 0, 604 + 605 + .m[PSC_TEMPERATURE] = 1, 606 + .R[PSC_TEMPERATURE] = 0, 607 + .b[PSC_TEMPERATURE] = 0, 608 + 609 + .m[PSC_CURRENT_IN] = 1, 610 + .R[PSC_CURRENT_IN] = 0, 611 + .b[PSC_CURRENT_IN] = 0, 612 + 613 + .m[PSC_CURRENT_OUT] = 1, 614 + .R[PSC_CURRENT_OUT] = 0, 615 + .b[PSC_CURRENT_OUT] = 0, 616 + 617 + .m[PSC_POWER] = 1, 618 + .R[PSC_POWER] = 0, 619 + .b[PSC_POWER] = 0, 620 + 621 + .func[0] = MP29502_RAIL_FUNC, 622 + .read_word_data = mp29502_read_word_data, 623 + .read_byte_data = mp29502_read_byte_data, 624 + .write_word_data = mp29502_write_word_data, 625 + .identify = mp29502_identify, 626 + }; 627 + 628 + static int mp29502_probe(struct i2c_client *client) 629 + { 630 + struct pmbus_driver_info *info; 631 + struct mp29502_data *data; 632 + 633 + data = devm_kzalloc(&client->dev, sizeof(struct mp29502_data), 634 + GFP_KERNEL); 635 + if (!data) 636 + return -ENOMEM; 637 + 638 + memcpy(&data->info, &mp29502_info, sizeof(*info)); 639 + info = &data->info; 640 + 641 + return pmbus_do_probe(client, info); 642 + } 643 + 644 + static const struct i2c_device_id mp29502_id[] = { 645 + {"mp29502", 0}, 646 + {} 647 + }; 648 + MODULE_DEVICE_TABLE(i2c, mp29502_id); 649 + 650 + static const struct of_device_id __maybe_unused mp29502_of_match[] = { 651 + {.compatible = "mps,mp29502"}, 652 + {} 653 + }; 654 + MODULE_DEVICE_TABLE(of, mp29502_of_match); 655 + 656 + static struct i2c_driver mp29502_driver = { 657 + .driver = { 658 + .name = "mp29502", 659 + .of_match_table = mp29502_of_match, 660 + }, 661 + .probe = mp29502_probe, 662 + .id_table = mp29502_id, 663 + }; 664 + 665 + module_i2c_driver(mp29502_driver); 666 + 667 + MODULE_AUTHOR("Wensheng Wang <wenswang@yeah.net"); 668 + MODULE_DESCRIPTION("PMBus driver for MPS MP29502"); 669 + MODULE_LICENSE("GPL"); 670 + MODULE_IMPORT_NS("PMBUS");
+59 -8
drivers/hwmon/pmbus/mp5990.c
··· 8 8 #include <linux/of_device.h> 9 9 #include "pmbus.h" 10 10 11 + enum chips { mp5990, mp5998 }; 12 + 11 13 #define MP5990_EFUSE_CFG (0xC4) 12 14 #define MP5990_VOUT_FORMAT BIT(9) 13 15 ··· 112 110 .read_word_data = mp5990_read_word_data, 113 111 }; 114 112 113 + static struct pmbus_driver_info mp5998_info = { 114 + .pages = 1, 115 + .format[PSC_VOLTAGE_IN] = direct, 116 + .format[PSC_VOLTAGE_OUT] = direct, 117 + .format[PSC_CURRENT_IN] = direct, 118 + .format[PSC_CURRENT_OUT] = direct, 119 + .format[PSC_POWER] = direct, 120 + .format[PSC_TEMPERATURE] = direct, 121 + .m[PSC_VOLTAGE_IN] = 64, 122 + .b[PSC_VOLTAGE_IN] = 0, 123 + .R[PSC_VOLTAGE_IN] = 0, 124 + .m[PSC_VOLTAGE_OUT] = 64, 125 + .b[PSC_VOLTAGE_OUT] = 0, 126 + .R[PSC_VOLTAGE_OUT] = 0, 127 + .m[PSC_CURRENT_IN] = 16, 128 + .b[PSC_CURRENT_IN] = 0, 129 + .R[PSC_CURRENT_IN] = 0, 130 + .m[PSC_CURRENT_OUT] = 16, 131 + .b[PSC_CURRENT_OUT] = 0, 132 + .R[PSC_CURRENT_OUT] = 0, 133 + .m[PSC_POWER] = 2, 134 + .b[PSC_POWER] = 0, 135 + .R[PSC_POWER] = 0, 136 + .m[PSC_TEMPERATURE] = 1, 137 + .b[PSC_TEMPERATURE] = 0, 138 + .R[PSC_TEMPERATURE] = 0, 139 + .func[0] = 140 + PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | 141 + PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | 142 + PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_IOUT | 143 + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, 144 + .read_byte_data = mp5990_read_byte_data, 145 + .read_word_data = mp5990_read_word_data, 146 + }; 147 + 148 + static const struct i2c_device_id mp5990_id[] = { 149 + {"mp5990", mp5990}, 150 + {"mp5998", mp5998}, 151 + { } 152 + }; 153 + MODULE_DEVICE_TABLE(i2c, mp5990_id); 154 + 115 155 static int mp5990_probe(struct i2c_client *client) 116 156 { 117 157 struct pmbus_driver_info *info; 118 158 struct mp5990_data *data; 159 + enum chips chip; 119 160 int ret; 120 161 121 162 data = devm_kzalloc(&client->dev, sizeof(struct mp5990_data), ··· 166 121 if (!data) 167 122 return -ENOMEM; 168 123 169 - memcpy(&data->info, &mp5990_info, sizeof(*info)); 124 + if (client->dev.of_node) 125 + chip = (uintptr_t)of_device_get_match_data(&client->dev); 126 + else 127 + chip = i2c_match_id(mp5990_id, client)->driver_data; 128 + 129 + if (chip == mp5990) 130 + memcpy(&data->info, &mp5990_info, sizeof(*info)); 131 + else 132 + memcpy(&data->info, &mp5998_info, sizeof(*info)); 170 133 info = &data->info; 171 134 172 135 /* Read Vout Config */ ··· 193 140 data->info.format[PSC_VOLTAGE_OUT] = linear; 194 141 data->info.format[PSC_CURRENT_OUT] = linear; 195 142 data->info.format[PSC_POWER] = linear; 143 + if (chip == mp5998) 144 + data->info.format[PSC_CURRENT_IN] = linear; 145 + 196 146 ret = i2c_smbus_read_word_data(client, PMBUS_READ_VOUT); 197 147 if (ret < 0) { 198 148 dev_err(&client->dev, "Can't get vout exponent."); ··· 209 153 } 210 154 211 155 static const struct of_device_id mp5990_of_match[] = { 212 - { .compatible = "mps,mp5990" }, 156 + { .compatible = "mps,mp5990", .data = (void *)mp5990 }, 157 + { .compatible = "mps,mp5998", .data = (void *)mp5998 }, 213 158 {} 214 159 }; 215 - 216 - static const struct i2c_device_id mp5990_id[] = { 217 - {"mp5990"}, 218 - { } 219 - }; 220 - MODULE_DEVICE_TABLE(i2c, mp5990_id); 221 160 222 161 static struct i2c_driver mp5990_driver = { 223 162 .driver = {
+15 -3
drivers/hwmon/pwm-fan.c
··· 64 64 65 65 u64 pwm_duty_cycle_from_stopped; 66 66 u32 pwm_usec_from_stopped; 67 + u8 pwm_shutdown; 67 68 }; 68 69 69 70 /* This handler assumes self resetting edge triggered interrupt. */ ··· 485 484 struct pwm_fan_ctx *ctx = __ctx; 486 485 487 486 timer_delete_sync(&ctx->rpm_timer); 488 - /* Switch off everything */ 489 - ctx->enable_mode = pwm_disable_reg_disable; 490 - pwm_fan_power_off(ctx, true); 487 + if (ctx->pwm_shutdown) { 488 + ctx->enable_mode = pwm_enable_reg_enable; 489 + __set_pwm(ctx, ctx->pwm_shutdown); 490 + } else { 491 + /* Switch off everything */ 492 + ctx->enable_mode = pwm_disable_reg_disable; 493 + pwm_fan_power_off(ctx, true); 494 + } 491 495 } 492 496 493 497 static int pwm_fan_probe(struct platform_device *pdev) ··· 504 498 int ret; 505 499 const struct hwmon_channel_info **channels; 506 500 u32 initial_pwm, pwm_min_from_stopped = 0; 501 + u32 pwm_shutdown_percent = 0; 507 502 u32 *fan_channel_config; 508 503 int channel_count = 1; /* We always have a PWM channel. */ 509 504 int i; ··· 654 647 655 648 channels[1] = &ctx->fan_channel; 656 649 } 650 + 651 + ret = device_property_read_u32(dev, "fan-shutdown-percent", 652 + &pwm_shutdown_percent); 653 + if (!ret && pwm_shutdown_percent) 654 + ctx->pwm_shutdown = (clamp(pwm_shutdown_percent, 0, 100) * 255) / 100; 657 655 658 656 ret = device_property_read_u32(dev, "fan-stop-to-start-percent", 659 657 &pwm_min_from_stopped);
+161
drivers/hwmon/sa67mcu-hwmon.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * sl67mcu hardware monitoring driver 4 + * 5 + * Copyright 2025 Kontron Europe GmbH 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/hwmon.h> 10 + #include <linux/kernel.h> 11 + #include <linux/mod_devicetable.h> 12 + #include <linux/module.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/property.h> 15 + #include <linux/regmap.h> 16 + 17 + #define SA67MCU_VOLTAGE(n) (0x00 + ((n) * 2)) 18 + #define SA67MCU_TEMP(n) (0x04 + ((n) * 2)) 19 + 20 + struct sa67mcu_hwmon { 21 + struct regmap *regmap; 22 + u32 offset; 23 + }; 24 + 25 + static int sa67mcu_hwmon_read(struct device *dev, 26 + enum hwmon_sensor_types type, u32 attr, 27 + int channel, long *input) 28 + { 29 + struct sa67mcu_hwmon *hwmon = dev_get_drvdata(dev); 30 + unsigned int offset; 31 + u8 reg[2]; 32 + int ret; 33 + 34 + switch (type) { 35 + case hwmon_in: 36 + switch (attr) { 37 + case hwmon_in_input: 38 + offset = hwmon->offset + SA67MCU_VOLTAGE(channel); 39 + break; 40 + default: 41 + return -EOPNOTSUPP; 42 + } 43 + break; 44 + case hwmon_temp: 45 + switch (attr) { 46 + case hwmon_temp_input: 47 + offset = hwmon->offset + SA67MCU_TEMP(channel); 48 + break; 49 + default: 50 + return -EOPNOTSUPP; 51 + } 52 + break; 53 + default: 54 + return -EOPNOTSUPP; 55 + } 56 + 57 + /* Reading the low byte will capture the value */ 58 + ret = regmap_bulk_read(hwmon->regmap, offset, reg, ARRAY_SIZE(reg)); 59 + if (ret) 60 + return ret; 61 + 62 + *input = reg[1] << 8 | reg[0]; 63 + 64 + /* Temperatures are s16 and in 0.1degC steps. */ 65 + if (type == hwmon_temp) 66 + *input = sign_extend32(*input, 15) * 100; 67 + 68 + return 0; 69 + } 70 + 71 + static const struct hwmon_channel_info * const sa67mcu_hwmon_info[] = { 72 + HWMON_CHANNEL_INFO(in, 73 + HWMON_I_INPUT | HWMON_I_LABEL, 74 + HWMON_I_INPUT | HWMON_I_LABEL), 75 + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), 76 + NULL 77 + }; 78 + 79 + static const char *const sa67mcu_hwmon_in_labels[] = { 80 + "VDDIN", 81 + "VDD_RTC", 82 + }; 83 + 84 + static int sa67mcu_hwmon_read_string(struct device *dev, 85 + enum hwmon_sensor_types type, u32 attr, 86 + int channel, const char **str) 87 + { 88 + switch (type) { 89 + case hwmon_in: 90 + switch (attr) { 91 + case hwmon_in_label: 92 + *str = sa67mcu_hwmon_in_labels[channel]; 93 + return 0; 94 + default: 95 + return -EOPNOTSUPP; 96 + } 97 + default: 98 + return -EOPNOTSUPP; 99 + } 100 + } 101 + 102 + static const struct hwmon_ops sa67mcu_hwmon_ops = { 103 + .visible = 0444, 104 + .read = sa67mcu_hwmon_read, 105 + .read_string = sa67mcu_hwmon_read_string, 106 + }; 107 + 108 + static const struct hwmon_chip_info sa67mcu_hwmon_chip_info = { 109 + .ops = &sa67mcu_hwmon_ops, 110 + .info = sa67mcu_hwmon_info, 111 + }; 112 + 113 + static int sa67mcu_hwmon_probe(struct platform_device *pdev) 114 + { 115 + struct sa67mcu_hwmon *hwmon; 116 + struct device *hwmon_dev; 117 + int ret; 118 + 119 + if (!pdev->dev.parent) 120 + return -ENODEV; 121 + 122 + hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL); 123 + if (!hwmon) 124 + return -ENOMEM; 125 + 126 + hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL); 127 + if (!hwmon->regmap) 128 + return -ENODEV; 129 + 130 + ret = device_property_read_u32(&pdev->dev, "reg", &hwmon->offset); 131 + if (ret) 132 + return -EINVAL; 133 + 134 + hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, 135 + "sa67mcu_hwmon", hwmon, 136 + &sa67mcu_hwmon_chip_info, 137 + NULL); 138 + if (IS_ERR(hwmon_dev)) 139 + dev_err(&pdev->dev, "failed to register as hwmon device"); 140 + 141 + return PTR_ERR_OR_ZERO(hwmon_dev); 142 + } 143 + 144 + static const struct of_device_id sa67mcu_hwmon_of_match[] = { 145 + { .compatible = "kontron,sa67mcu-hwmon", }, 146 + {} 147 + }; 148 + MODULE_DEVICE_TABLE(of, sa67mcu_hwmon_of_match); 149 + 150 + static struct platform_driver sa67mcu_hwmon_driver = { 151 + .probe = sa67mcu_hwmon_probe, 152 + .driver = { 153 + .name = "sa67mcu-hwmon", 154 + .of_match_table = sa67mcu_hwmon_of_match, 155 + }, 156 + }; 157 + module_platform_driver(sa67mcu_hwmon_driver); 158 + 159 + MODULE_DESCRIPTION("sa67mcu Hardware Monitoring Driver"); 160 + MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>"); 161 + MODULE_LICENSE("GPL");
+31 -15
drivers/hwmon/sbtsi_temp.c
··· 14 14 #include <linux/module.h> 15 15 #include <linux/mutex.h> 16 16 #include <linux/of.h> 17 + #include <linux/bitfield.h> 17 18 18 19 /* 19 20 * SB-TSI registers only support SMBus byte data access. "_INT" registers are ··· 30 29 #define SBTSI_REG_TEMP_HIGH_DEC 0x13 /* RW */ 31 30 #define SBTSI_REG_TEMP_LOW_DEC 0x14 /* RW */ 32 31 32 + /* 33 + * Bit for reporting value with temperature measurement range. 34 + * bit == 0: Use default temperature range (0C to 255.875C). 35 + * bit == 1: Use extended temperature range (-49C to +206.875C). 36 + */ 37 + #define SBTSI_CONFIG_EXT_RANGE_SHIFT 2 38 + /* 39 + * ReadOrder bit specifies the reading order of integer and decimal part of 40 + * CPU temperature for atomic reads. If bit == 0, reading integer part triggers 41 + * latching of the decimal part, so integer part should be read first. 42 + * If bit == 1, read order should be reversed. 43 + */ 33 44 #define SBTSI_CONFIG_READ_ORDER_SHIFT 5 45 + 46 + #define SBTSI_TEMP_EXT_RANGE_ADJ 49000 34 47 35 48 #define SBTSI_TEMP_MIN 0 36 49 #define SBTSI_TEMP_MAX 255875 ··· 53 38 struct sbtsi_data { 54 39 struct i2c_client *client; 55 40 struct mutex lock; 41 + bool ext_range_mode; 42 + bool read_order; 56 43 }; 57 44 58 45 /* ··· 91 74 { 92 75 struct sbtsi_data *data = dev_get_drvdata(dev); 93 76 s32 temp_int, temp_dec; 94 - int err; 95 77 96 78 switch (attr) { 97 79 case hwmon_temp_input: 98 - /* 99 - * ReadOrder bit specifies the reading order of integer and 100 - * decimal part of CPU temp for atomic reads. If bit == 0, 101 - * reading integer part triggers latching of the decimal part, 102 - * so integer part should be read first. If bit == 1, read 103 - * order should be reversed. 104 - */ 105 - err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG); 106 - if (err < 0) 107 - return err; 108 - 109 80 mutex_lock(&data->lock); 110 - if (err & BIT(SBTSI_CONFIG_READ_ORDER_SHIFT)) { 81 + if (data->read_order) { 111 82 temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC); 112 83 temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT); 113 84 } else { ··· 127 122 return temp_dec; 128 123 129 124 *val = sbtsi_reg_to_mc(temp_int, temp_dec); 125 + if (data->ext_range_mode) 126 + *val -= SBTSI_TEMP_EXT_RANGE_ADJ; 130 127 131 128 return 0; 132 129 } ··· 153 146 return -EINVAL; 154 147 } 155 148 149 + if (data->ext_range_mode) 150 + val += SBTSI_TEMP_EXT_RANGE_ADJ; 156 151 val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX); 157 152 sbtsi_mc_to_reg(val, &temp_int, &temp_dec); 158 153 ··· 212 203 struct device *dev = &client->dev; 213 204 struct device *hwmon_dev; 214 205 struct sbtsi_data *data; 206 + int err; 215 207 216 208 data = devm_kzalloc(dev, sizeof(struct sbtsi_data), GFP_KERNEL); 217 209 if (!data) ··· 221 211 data->client = client; 222 212 mutex_init(&data->lock); 223 213 224 - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, &sbtsi_chip_info, 225 - NULL); 214 + err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG); 215 + if (err < 0) 216 + return err; 217 + data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), err); 218 + data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err); 219 + 220 + hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data, 221 + &sbtsi_chip_info, NULL); 226 222 227 223 return PTR_ERR_OR_ZERO(hwmon_dev); 228 224 }
+1 -3
drivers/hwmon/sch56xx-common.c
··· 544 544 545 545 watchdog_set_drvdata(&data->wddev, data); 546 546 err = devm_watchdog_register_device(parent, &data->wddev); 547 - if (err) { 548 - pr_err("Registering watchdog chardev: %d\n", err); 547 + if (err) 549 548 devm_kfree(parent, data); 550 - } 551 549 } 552 550 EXPORT_SYMBOL(sch56xx_watchdog_register); 553 551
+14 -1
drivers/hwmon/sht21.c
··· 275 275 276 276 /* Device ID table */ 277 277 static const struct i2c_device_id sht21_id[] = { 278 + { "sht20" }, 278 279 { "sht21" }, 280 + { "sht25" }, 279 281 { } 280 282 }; 281 283 MODULE_DEVICE_TABLE(i2c, sht21_id); 282 284 285 + static const struct of_device_id sht21_of_match[] = { 286 + { .compatible = "sensirion,sht20" }, 287 + { .compatible = "sensirion,sht21" }, 288 + { .compatible = "sensirion,sht25" }, 289 + { } 290 + }; 291 + MODULE_DEVICE_TABLE(of, sht21_of_match); 292 + 283 293 static struct i2c_driver sht21_driver = { 284 - .driver.name = "sht21", 294 + .driver = { 295 + .name = "sht21", 296 + .of_match_table = sht21_of_match, 297 + }, 285 298 .probe = sht21_probe, 286 299 .id_table = sht21_id, 287 300 };
+1
drivers/hwmon/sy7636a-hwmon.c
··· 104 104 105 105 MODULE_DESCRIPTION("SY7636A sensor driver"); 106 106 MODULE_LICENSE("GPL"); 107 + MODULE_ALIAS("platform:sy7636a-temperature");
+21 -1
drivers/hwmon/tmp102.c
··· 53 53 #define CONVERSION_TIME_MS 35 /* in milli-seconds */ 54 54 55 55 struct tmp102 { 56 + const char *label; 56 57 struct regmap *regmap; 57 58 u16 config_orig; 58 59 unsigned long ready_time; ··· 69 68 static inline u16 tmp102_mC_to_reg(int val) 70 69 { 71 70 return (val * 128) / 1000; 71 + } 72 + 73 + static int tmp102_read_string(struct device *dev, enum hwmon_sensor_types type, 74 + u32 attr, int channel, const char **str) 75 + { 76 + struct tmp102 *tmp102 = dev_get_drvdata(dev); 77 + 78 + *str = tmp102->label; 79 + 80 + return 0; 72 81 } 73 82 74 83 static int tmp102_read(struct device *dev, enum hwmon_sensor_types type, ··· 139 128 static umode_t tmp102_is_visible(const void *data, enum hwmon_sensor_types type, 140 129 u32 attr, int channel) 141 130 { 131 + const struct tmp102 *tmp102 = data; 132 + 142 133 if (type != hwmon_temp) 143 134 return 0; 144 135 145 136 switch (attr) { 146 137 case hwmon_temp_input: 147 138 return 0444; 139 + case hwmon_temp_label: 140 + if (tmp102->label) 141 + return 0444; 142 + return 0; 148 143 case hwmon_temp_max_hyst: 149 144 case hwmon_temp_max: 150 145 return 0644; ··· 163 146 HWMON_CHANNEL_INFO(chip, 164 147 HWMON_C_REGISTER_TZ), 165 148 HWMON_CHANNEL_INFO(temp, 166 - HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST), 149 + HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX | HWMON_T_MAX_HYST), 167 150 NULL 168 151 }; 169 152 170 153 static const struct hwmon_ops tmp102_hwmon_ops = { 171 154 .is_visible = tmp102_is_visible, 155 + .read_string = tmp102_read_string, 172 156 .read = tmp102_read, 173 157 .write = tmp102_write, 174 158 }; ··· 230 212 tmp102 = devm_kzalloc(dev, sizeof(*tmp102), GFP_KERNEL); 231 213 if (!tmp102) 232 214 return -ENOMEM; 215 + 216 + of_property_read_string(dev->of_node, "label", &tmp102->label); 233 217 234 218 i2c_set_clientdata(client, tmp102); 235 219
+4
include/linux/hwmon.h
··· 24 24 hwmon_curr, 25 25 hwmon_power, 26 26 hwmon_energy, 27 + hwmon_energy64, 27 28 hwmon_humidity, 28 29 hwmon_fan, 29 30 hwmon_pwm, ··· 491 490 492 491 char *hwmon_sanitize_name(const char *name); 493 492 char *devm_hwmon_sanitize_name(struct device *dev, const char *name); 493 + 494 + void hwmon_lock(struct device *dev); 495 + void hwmon_unlock(struct device *dev); 494 496 495 497 /** 496 498 * hwmon_is_bad_char - Is the char invalid in a hwmon name
+28 -1
include/linux/platform_data/cros_ec_commands.h
··· 1825 1825 uint16_t duty; /* Duty cycle, EC_PWM_MAX_DUTY = 100% */ 1826 1826 } __ec_align2; 1827 1827 1828 + #define EC_CMD_PWM_GET_FAN_DUTY 0x0027 1829 + 1830 + struct ec_params_pwm_get_fan_duty { 1831 + uint8_t fan_idx; 1832 + } __ec_align1; 1833 + 1834 + struct ec_response_pwm_get_fan_duty { 1835 + uint32_t percent; /* Percentage of duty cycle, ranging from 0 ~ 100 */ 1836 + } __ec_align4; 1837 + 1828 1838 /*****************************************************************************/ 1829 1839 /* 1830 1840 * Lightbar commands. This looks worse than it is. Since we only use one HOST ··· 3137 3127 3138 3128 /****************************************************************************/ 3139 3129 3140 - /* Toggle automatic fan control */ 3130 + /* Set or get fan control mode */ 3141 3131 #define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x0052 3132 + 3133 + enum ec_auto_fan_ctrl_cmd { 3134 + EC_AUTO_FAN_CONTROL_CMD_SET = 0, 3135 + EC_AUTO_FAN_CONTROL_CMD_GET, 3136 + }; 3142 3137 3143 3138 /* Version 1 of input params */ 3144 3139 struct ec_params_auto_fan_ctrl_v1 { 3145 3140 uint8_t fan_idx; 3141 + } __ec_align1; 3142 + 3143 + /* Version 2 of input params */ 3144 + struct ec_params_auto_fan_ctrl_v2 { 3145 + uint8_t fan_idx; 3146 + uint8_t cmd; /* enum ec_auto_fan_ctrl_cmd */ 3147 + uint8_t set_auto; /* only used with EC_AUTO_FAN_CONTROL_CMD_SET - bool 3148 + */ 3149 + } __ec_align4; 3150 + 3151 + struct ec_response_auto_fan_control { 3152 + uint8_t is_auto; /* bool */ 3146 3153 } __ec_align1; 3147 3154 3148 3155 /* Get/Set TMP006 calibration data */
+5 -5
include/trace/events/hwmon.h
··· 9 9 10 10 DECLARE_EVENT_CLASS(hwmon_attr_class, 11 11 12 - TP_PROTO(int index, const char *attr_name, long val), 12 + TP_PROTO(int index, const char *attr_name, long long val), 13 13 14 14 TP_ARGS(index, attr_name, val), 15 15 16 16 TP_STRUCT__entry( 17 17 __field(int, index) 18 18 __string(attr_name, attr_name) 19 - __field(long, val) 19 + __field(long long, val) 20 20 ), 21 21 22 22 TP_fast_assign( ··· 25 25 __entry->val = val; 26 26 ), 27 27 28 - TP_printk("index=%d, attr_name=%s, val=%ld", 28 + TP_printk("index=%d, attr_name=%s, val=%lld", 29 29 __entry->index, __get_str(attr_name), __entry->val) 30 30 ); 31 31 32 32 DEFINE_EVENT(hwmon_attr_class, hwmon_attr_show, 33 33 34 - TP_PROTO(int index, const char *attr_name, long val), 34 + TP_PROTO(int index, const char *attr_name, long long val), 35 35 36 36 TP_ARGS(index, attr_name, val) 37 37 ); 38 38 39 39 DEFINE_EVENT(hwmon_attr_class, hwmon_attr_store, 40 40 41 - TP_PROTO(int index, const char *attr_name, long val), 41 + TP_PROTO(int index, const char *attr_name, long long val), 42 42 43 43 TP_ARGS(index, attr_name, val) 44 44 );
+2
include/uapi/linux/i8k.h
··· 36 36 #define I8K_FAN_LOW 1 37 37 #define I8K_FAN_HIGH 2 38 38 #define I8K_FAN_TURBO 3 39 + /* Many machines treat this mode as some sort of automatic mode */ 40 + #define I8K_FAN_AUTO 3 39 41 #define I8K_FAN_MAX I8K_FAN_TURBO 40 42 41 43 #define I8K_VOL_UP 1