mirror of https://github.com/torvalds/linux.git
hwmon updates for v6.19
* New drivers
- Driver for Apple Silicon SMC
- Driver for TSC1641 I2C power monitor
- Driver for MPS MP9945
- Driver for MAX17616
- Driver for MP2925 and MP2929
* Added support for new devices to existing drivers
- dell-smm: Add Dell G5 5505 to fan control whitelist
- aspeed-g6-pwm-tach: Support for AST2700
- asus-ec-sensors: Support for ROG STRIX X470-I GAMING,
ROG STRIX X870-F GAMING WIFI, ROG STRIX X870E-H GAMING WIFI7,
and Pro WS TRX50-SAGE WIFI
- k10temp: Support for AMD Steam Deck APU ID
- pmbus/isl68137: Support for raa229141
- aht10: Support for dht20
- adt7410: Support for ADT7422
- peci: Support for Intel Emerald Rapids
- nct6775: Support for ASUS ROG STRIX X870E-H GAMING WIFI7
- pmbus/max34440: Support for ADPM12200
- ntc-thermistor: Support for Murata ncp18wm474
* Infrastructure updates
- Utilize subsystem locking in various drivers
- ltc4282, ltc2947: Use the new energy64 attribute
* Bug fixes
- Various drivers: Fixes to avoid TOCTOU, mostly in macro functions
evaluating parameters multiple times, as well as missing locks
- max6697: Fix regmap leak on probe failure
- sy7636a: Fix regulator_enable resource leak on error path
- asus-ec-sensors: Correct Pro WS TRX50-SAGE WIFI entry
* Other changes and improvements
- w83781d, lm78: Drop REALLY_SLOW_IO
- Fix broken datasheet links in various drivers
* Various other minor fixes and improvements
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmkt7bIACgkQyx8mb86f
mYGV4w/9FGzFpNuC2nWEF9DvAgv2NmdEpx9Om/VUxMJ9gaWxUbKuQkO/Ac52SH3R
9zESbdiBYphDNXnCT2SSsS5+lT3WSBqoSKaiKZR706KjC3UDu6yKug6d4Ku9rXNX
OCfW6uhb+xrs47w0FG4ZJ38UVO0bV70ceLbo3glPm4YL9GXxRSWzbUxPJCbN65cU
lo2TFSAvf52jczjBjvgHnKGi0CMkil68G1Vx4OhvnAa+DW6BqDvJgpUPHPcb6HmB
n7k7mVME8MGL+i4OON9iPQd+wJ3BAALnLr5SSbz3Y8vxNNfTWSOYbEMgOFTi+zdi
CLtFxEqQmDbbP93Za5lSZP0x2CQtgxFd8y7X5BmheNwTs/06FxMmBc2/oFVjHDtv
gUQml/HREtNwwIc+OdSESRPSNvNM1YYO5FXczezE70IypWvpPUPLJHBXzh8dOhMl
WUddo6H5GzV2IKWyiuPCzMWCKIkzzCebklWA7VL0BcPao28JUVYtEiInf/6k7Xwt
OLrmKwT8OT7TkZdKXUXDqquGbsAwBmco66K7GWMuH60XTyn80ilTUZ+GrJiR3rNI
GvNexGBA+qv4xSV7ilSHjJh0vdXzdv0zHghqG67tti+nApI3+9oSRYmdCIaf+y0i
k5msMjtvWC1xCPxTyyjLIKIjKwR/8SmGw7C8MvEFEnPbLbepr4M=
=NviP
-----END PGP SIGNATURE-----
Merge tag 'hwmon-for-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
"New drivers:
- Apple Silicon SMC
- TSC1641 I2C power monitor
- MPS MP9945
- MAX17616
- MP2925 and MP2929
Added support for new devices to existing drivers:
- dell-smm: Add Dell G5 5505 to fan control whitelist
- aspeed-g6-pwm-tach: Support for AST2700
- asus-ec-sensors: Support for ROG STRIX X470-I GAMING, ROG STRIX
X870-F GAMING WIFI, ROG STRIX X870E-H GAMING WIFI7, and Pro WS
TRX50-SAGE WIFI
- k10temp: Support for AMD Steam Deck APU ID
- pmbus/isl68137: Support for raa229141
- aht10: Support for dht20
- adt7410: Support for ADT7422
- peci: Support for Intel Emerald Rapids
- nct6775: Support for ASUS ROG STRIX X870E-H GAMING WIFI7
- pmbus/max34440: Support for ADPM12200
- ntc-thermistor: Support for Murata ncp18wm474
Infrastructure updates:
- Utilize subsystem locking in various drivers
- ltc4282, ltc2947: Use the new energy64 attribute
Bug fixes:
- Various drivers: Fixes to avoid TOCTOU, mostly in macro functions
evaluating parameters multiple times, as well as missing locks
- max6697: Fix regmap leak on probe failure
- sy7636a: Fix regulator_enable resource leak on error path
- asus-ec-sensors: Correct Pro WS TRX50-SAGE WIFI entry
Other changes and improvements:
- w83781d, lm78: Drop REALLY_SLOW_IO
- Fix broken datasheet links in various drivers
And various other minor fixes and improvements"
* tag 'hwmon-for-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (110 commits)
hwmon: (dell-smm) Add Dell G5 5505 to fan control whitelist
hwmon: (max16065) Use local variable to avoid TOCTOU
hwmon: (w83l786ng) Convert macros to functions to avoid TOCTOU
hwmon: (max6697) fix regmap leak on probe failure
hwmon/w83781d: Drop REALLY_SLOW_IO setting
hwmon/lm78: Drop REALLY_SLOW_IO setting
hwmon: sy7636a: Fix regulator_enable resource leak on error path
hwmon: (adm1026) Convert macros to functions to avoid TOCTOU
hwmon: (adm1029) Add locking to avoid TOCTOU
hwmon: (lm87) Convert macros to functions to avoid TOCTOU
hwmon: (asus-ec-sensors) correct Pro WS TRX50-SAGE WIFI entry
hwmon: (vt8231) Convert macros to functions to avoid TOCTOU
hwmon: (emc2103) Add locking to avoid TOCTOU
hwmon: (aspeed-g6-pwm-tach): Add AST2700 compatible string
dt-bindings: hwmon: Add AST2700 compatible
hwmon: (asus-ec-sensors) add ROG STRIX X470-I GAMING
hwmon: (vt1211) Convert macros to functions to avoid TOCTOU
hwmon: (k10temp) Add AMD Steam Deck APU ID
hwmon: Add Apple Silicon SMC hwmon driver
Documentation/hwmon: Fix broken datasheet links for zl6100
...
This commit is contained in:
commit
02892f90a9
|
|
@ -0,0 +1,30 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/apm,xgene-slimpro-hwmon.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: APM X-Gene SLIMpro hwmon
|
||||
|
||||
maintainers:
|
||||
- Khuong Dinh <khuong@os.amperecomputing.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: apm,xgene-slimpro-hwmon
|
||||
|
||||
mboxes:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mboxes
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
hwmon {
|
||||
compatible = "apm,xgene-slimpro-hwmon";
|
||||
mboxes = <&mailbox 7>;
|
||||
};
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
APM X-Gene hwmon driver
|
||||
|
||||
APM X-Gene SOC sensors are accessed over the "SLIMpro" mailbox.
|
||||
|
||||
Required properties :
|
||||
- compatible : should be "apm,xgene-slimpro-hwmon"
|
||||
- mboxes : use the label reference for the mailbox as the first parameter.
|
||||
The second parameter is the channel number.
|
||||
|
||||
Example :
|
||||
hwmonslimpro {
|
||||
compatible = "apm,xgene-slimpro-hwmon";
|
||||
mboxes = <&mailbox 7>;
|
||||
};
|
||||
|
|
@ -18,8 +18,11 @@ description: |
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- aspeed,ast2600-pwm-tach
|
||||
oneOf:
|
||||
- items:
|
||||
- const: aspeed,ast2700-pwm-tach
|
||||
- const: aspeed,ast2600-pwm-tach
|
||||
- const: aspeed,ast2600-pwm-tach
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
Bindings for the Maxim MAX31785 Intelligent Fan Controller
|
||||
==========================================================
|
||||
|
||||
Reference:
|
||||
|
||||
https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
|
||||
|
||||
The Maxim MAX31785 is a PMBus device providing closed-loop, multi-channel fan
|
||||
management with temperature and remote voltage sensing. Various fan control
|
||||
features are provided, including PWM frequency control, temperature hysteresis,
|
||||
dual tachometer measurements, and fan health monitoring.
|
||||
|
||||
Required properties:
|
||||
- compatible : One of "maxim,max31785" or "maxim,max31785a"
|
||||
- reg : I2C address, one of 0x52, 0x53, 0x54, 0x55.
|
||||
|
||||
Example:
|
||||
|
||||
fans@52 {
|
||||
compatible = "maxim,max31785";
|
||||
reg = <0x52>;
|
||||
};
|
||||
|
|
@ -20,7 +20,11 @@ description: >
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
const: maxim,max31790
|
||||
enum:
|
||||
- maxim,max31785
|
||||
- maxim,max31785a
|
||||
- maxim,max31785b
|
||||
- maxim,max31790
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
@ -31,11 +35,17 @@ properties:
|
|||
resets:
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
"#pwm-cells":
|
||||
const: 1
|
||||
|
||||
patternProperties:
|
||||
"^fan-[0-9]+$":
|
||||
"^fan@[0-9]+$":
|
||||
$ref: fan-common.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
@ -56,13 +66,17 @@ examples:
|
|||
reg = <0x20>;
|
||||
clocks = <&sys_clk>;
|
||||
resets = <&reset 0>;
|
||||
#address-cells = <1>;
|
||||
#pwm-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fan-0 {
|
||||
fan@0 {
|
||||
reg = <0x0>;
|
||||
pwms = <&pwm_provider 1>;
|
||||
};
|
||||
|
||||
fan-1 {
|
||||
fan@1 {
|
||||
reg = <0x1>;
|
||||
pwms = <&pwm_provider 2>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ properties:
|
|||
- const: murata,ncp15wl333
|
||||
- const: murata,ncp03wf104
|
||||
- const: murata,ncp15xh103
|
||||
- const: murata,ncp18wm474
|
||||
- const: samsung,1404-001221
|
||||
# Deprecated "ntc," compatible strings
|
||||
- const: ntc,ncp15wb473
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/pmbus/adi,max17616.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices MAX17616/MAX17616A Current-Limiter with PMBus Interface
|
||||
|
||||
maintainers:
|
||||
- Kim Seer Paller <kimseer.paller@analog.com>
|
||||
|
||||
description: |
|
||||
The MAX17616/MAX17616A is a 3V to 80V, 7A current-limiter with overvoltage,
|
||||
surge, undervoltage, reverse polarity, and loss of ground protection. It allows
|
||||
monitoring of input/output voltage, output current and temperature through the
|
||||
PMBus serial interface.
|
||||
Datasheet:
|
||||
https://www.analog.com/en/products/max17616.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,max17616
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vcc-supply: true
|
||||
|
||||
interrupts:
|
||||
description: Fault condition signal provided on SMBALERT pin.
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vcc-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hwmon@16 {
|
||||
compatible = "adi,max17616";
|
||||
reg = <0x16>;
|
||||
vcc-supply = <&vcc>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/st,tsc1641.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ST Microelectronics TSC1641 I2C power monitor
|
||||
|
||||
maintainers:
|
||||
- Igor Reznichenko <igor@reznichenko.net>
|
||||
|
||||
description: |
|
||||
TSC1641 is a 60 V, 16-bit high-precision power monitor with I2C and
|
||||
MIPI I3C interface
|
||||
|
||||
Datasheets:
|
||||
https://www.st.com/resource/en/datasheet/tsc1641.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: st,tsc1641
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: Optional alert interrupt.
|
||||
maxItems: 1
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
description: Shunt resistor value in micro-ohms. Since device has internal
|
||||
16-bit RSHUNT register with 10 uOhm LSB, the maximum value is capped at
|
||||
655.35 mOhm.
|
||||
minimum: 100
|
||||
default: 1000
|
||||
maximum: 655350
|
||||
|
||||
st,alert-polarity-active-high:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description: Default value is 0 which configures the normal polarity of the
|
||||
ALERT pin, being active low open-drain. Setting this to 1 configures the
|
||||
polarity of the ALERT pin to be inverted and active high open-drain.
|
||||
Specify this property to set the alert polarity to active-high.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
power-sensor@40 {
|
||||
compatible = "st,tsc1641";
|
||||
reg = <0x40>;
|
||||
shunt-resistor-micro-ohms = <1000>;
|
||||
st,alert-polarity-active-high;
|
||||
};
|
||||
};
|
||||
|
|
@ -43,8 +43,14 @@ properties:
|
|||
- adi,ad5110
|
||||
# Temperature sensor with integrated fan control
|
||||
- adi,adm1027
|
||||
# Analog Devices ADT7410 High Accuracy Digital Temperature Sensor
|
||||
- adi,adt7410
|
||||
# Analog Devices ADT7411 Temperature Sensor and 8-channel ADC
|
||||
- adi,adt7411
|
||||
# Analog Devices ADT7420 High Accuracy Digital Temperature Sensor
|
||||
- adi,adt7420
|
||||
# Analog Devices ADT7422 High Accuracy Digital Temperature Sensor
|
||||
- adi,adt7422
|
||||
# Temperature sensor with integrated fan control
|
||||
- adi,adt7463
|
||||
# Temperature sensor with integrated fan control
|
||||
|
|
@ -299,6 +305,10 @@ properties:
|
|||
- mps,mp2888
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2891
|
||||
- mps,mp2891
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2925
|
||||
- mps,mp2925
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp2929
|
||||
- mps,mp2929
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp29502
|
||||
- mps,mp29502
|
||||
# Monolithic Power Systems Inc. multi-phase controller mp29608
|
||||
|
|
@ -319,6 +329,8 @@ properties:
|
|||
- mps,mp5998
|
||||
# Monolithic Power Systems Inc. digital step-down converter mp9941
|
||||
- mps,mp9941
|
||||
# Monolithic Power Systems Inc. digital step-down converter mp9945
|
||||
- mps,mp9945
|
||||
# Temperature sensor with integrated fan control
|
||||
- national,lm63
|
||||
# Temperature sensor with integrated fan control
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@ Supported chips:
|
|||
|
||||
English: http://www.aosong.com/userfiles/files/media/Data%20Sheet%20AHT20.pdf
|
||||
|
||||
* Aosong DHT20
|
||||
|
||||
Prefix: 'dht20'
|
||||
|
||||
Addresses scanned: None
|
||||
|
||||
Datasheet: https://www.digikey.co.nz/en/htmldatasheets/production/9184855/0/0/1/101020932
|
||||
|
||||
Author: Johannes Cornelis Draaijer <jcdra1@gmail.com>
|
||||
|
||||
|
||||
|
|
@ -33,7 +41,7 @@ The address of this i2c device may only be 0x38
|
|||
Special Features
|
||||
----------------
|
||||
|
||||
AHT20 has additional CRC8 support which is sent as the last byte of the sensor
|
||||
AHT20, DHT20 has additional CRC8 support which is sent as the last byte of the sensor
|
||||
values.
|
||||
|
||||
Usage Notes
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Supported boards:
|
|||
* PRIME X570-PRO
|
||||
* PRIME X670E-PRO WIFI
|
||||
* PRIME Z270-A
|
||||
* Pro WS TRX50-SAGE WIFI
|
||||
* Pro WS X570-ACE
|
||||
* Pro WS WRX90E-SAGE SE
|
||||
* ProArt X570-CREATOR WIFI
|
||||
|
|
@ -29,14 +30,17 @@ Supported boards:
|
|||
* ROG STRIX B550-I GAMING
|
||||
* ROG STRIX B650E-I GAMING WIFI
|
||||
* ROG STRIX B850-I GAMING WIFI
|
||||
* ROG STRIX X470-I GAMING
|
||||
* ROG STRIX X570-E GAMING
|
||||
* ROG STRIX X570-E GAMING WIFI II
|
||||
* ROG STRIX X570-F GAMING
|
||||
* ROG STRIX X570-I GAMING
|
||||
* ROG STRIX X670E-E GAMING WIFI
|
||||
* ROG STRIX X670E-I GAMING WIFI
|
||||
* ROG STRIX X870-F GAMING WIFI
|
||||
* ROG STRIX X870-I GAMING WIFI
|
||||
* ROG STRIX X870E-E GAMING WIFI
|
||||
* ROG STRIX X870E-H GAMING WIFI7
|
||||
* ROG STRIX Z390-F GAMING
|
||||
* ROG STRIX Z490-F GAMING
|
||||
* ROG STRIX Z690-A GAMING WIFI D4
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available from www.maximintegrated.com
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS1621.pdf
|
||||
|
||||
* Dallas Semiconductor DS1625
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available from www.datasheetarchive.com
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS1620.pdf
|
||||
|
||||
* Maxim Integrated DS1631
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available from www.maximintegrated.com
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS1631-DS1731.pdf
|
||||
|
||||
* Maxim Integrated DS1721
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available from www.maximintegrated.com
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS1721.pdf
|
||||
|
||||
* Maxim Integrated DS1731
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available from www.maximintegrated.com
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/DS1631-DS1731.pdf
|
||||
|
||||
Authors:
|
||||
- Christian W. Zuckschwerdt <zany@triq.net>
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ Hardware Monitoring Kernel Drivers
|
|||
ltc4261
|
||||
ltc4282
|
||||
ltc4286
|
||||
macsmc-hwmon
|
||||
max127
|
||||
max15301
|
||||
max16064
|
||||
|
|
@ -151,6 +152,7 @@ Hardware Monitoring Kernel Drivers
|
|||
max1619
|
||||
max16601
|
||||
max1668
|
||||
max17616
|
||||
max197
|
||||
max20730
|
||||
max20751
|
||||
|
|
@ -177,6 +179,7 @@ Hardware Monitoring Kernel Drivers
|
|||
mp2869
|
||||
mp2888
|
||||
mp2891
|
||||
mp2925
|
||||
mp29502
|
||||
mp2975
|
||||
mp2993
|
||||
|
|
@ -184,6 +187,7 @@ Hardware Monitoring Kernel Drivers
|
|||
mp5920
|
||||
mp5990
|
||||
mp9941
|
||||
mp9945
|
||||
mpq8785
|
||||
nct6683
|
||||
nct6775
|
||||
|
|
@ -253,6 +257,7 @@ Hardware Monitoring Kernel Drivers
|
|||
tps40422
|
||||
tps53679
|
||||
tps546d24
|
||||
tsc1641
|
||||
twl4030-madc-hwmon
|
||||
ucd9000
|
||||
ucd9200
|
||||
|
|
|
|||
|
|
@ -414,6 +414,16 @@ Supported chips:
|
|||
|
||||
Publicly available (after August 2020 launch) at the Renesas website
|
||||
|
||||
* Renesas RAA229141
|
||||
|
||||
Prefix: 'raa229141'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
|
||||
Provided by Renesas upon request and NDA
|
||||
|
||||
Authors:
|
||||
- Maxim Sloyko <maxims@google.com>
|
||||
- Robert Lippert <rlippert@google.com>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Supported chips:
|
|||
|
||||
Datasheets:
|
||||
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX6604.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6604.pdf
|
||||
|
||||
* Microchip MCP9804, MCP9805, MCP9808, MCP98242, MCP98243, MCP98244, MCP9843
|
||||
|
||||
|
|
|
|||
|
|
@ -23,15 +23,17 @@ Supported chips:
|
|||
|
||||
http://www.national.com/
|
||||
|
||||
* Dallas Semiconductor (now Maxim) DS75, DS1775, DS7505
|
||||
* Dallas Semiconductor (now Analog Devices) DS75, DS1775, DS7505
|
||||
|
||||
Prefixes: 'ds75', 'ds1775', 'ds7505'
|
||||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheets:
|
||||
|
||||
https://www.maximintegrated.com/
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/DS75.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/DS1775.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/DS7505.pdf
|
||||
|
||||
* Maxim MAX6625, MAX6626, MAX31725, MAX31726
|
||||
|
||||
|
|
@ -39,9 +41,10 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheets:
|
||||
|
||||
http://www.maxim-ic.com/
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6625-MAX6626.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31725-MAX31726.pdf
|
||||
|
||||
* Microchip (TelCom) TCN75
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
Datasheet: Publicly available at the TI website
|
||||
|
||||
https://www.ti.com/lit/ds/symlink/lm84.pdf
|
||||
|
||||
* National Semiconductor LM90
|
||||
|
||||
|
|
@ -17,9 +19,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
Datasheet: Publicly available at the TI website
|
||||
|
||||
http://www.national.com/pf/LM/LM90.html
|
||||
https://www.ti.com/lit/ds/symlink/lm90.pdf
|
||||
|
||||
* National Semiconductor LM89
|
||||
|
||||
|
|
@ -27,9 +29,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
Datasheet: Publicly available at the TI website
|
||||
|
||||
http://www.national.com/mpf/LM/LM89.html
|
||||
https://www.ti.com/lit/ds/symlink/lm89.pdf
|
||||
|
||||
* National Semiconductor LM99
|
||||
|
||||
|
|
@ -37,9 +39,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
Datasheet: Publicly available at the TI website
|
||||
|
||||
http://www.national.com/pf/LM/LM99.html
|
||||
https://www.ti.com/lit/ds/symlink/lm99.pdf
|
||||
|
||||
* National Semiconductor LM86
|
||||
|
||||
|
|
@ -47,9 +49,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: Publicly available at the National Semiconductor website
|
||||
Datasheet: Publicly available at the TI website
|
||||
|
||||
http://www.national.com/mpf/LM/LM86.html
|
||||
https://www.ti.com/lit/ds/symlink/lm86.pdf
|
||||
|
||||
* Analog Devices ADM1020
|
||||
|
||||
|
|
@ -57,7 +59,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
Datasheet: Publicly available at the DigiKey website
|
||||
|
||||
https://media.digikey.com/pdf/Data%20Sheets/Analog%20Devices%20PDFs/ADM1020.pdf
|
||||
|
||||
* Analog Devices ADM1021
|
||||
|
||||
|
|
@ -65,7 +69,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
Datasheet: Publicly available at the DigiKey website
|
||||
|
||||
https://media.digikey.com/pdf/Data%20Sheets/Analog%20Devices%20PDFs/ADM1021.pdf
|
||||
|
||||
* Analog Devices ADM1021A/ADM1023
|
||||
|
||||
|
|
@ -75,15 +81,18 @@ Supported chips:
|
|||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
https://media.digikey.com/pdf/Data%20Sheets/Analog%20Devices%20PDFs/ADM1021A.pdf
|
||||
https://media.digikey.com/pdf/Data%20Sheets/Analog%20Devices%20PDFs/ADM1023.pdf
|
||||
|
||||
* Analog Devices ADM1032
|
||||
|
||||
Prefix: 'adm1032'
|
||||
|
||||
Addresses scanned: I2C 0x4c and 0x4d
|
||||
|
||||
Datasheet: Publicly available at the ON Semiconductor website
|
||||
Datasheet: Publicly available at the DigiKey website
|
||||
|
||||
https://www.onsemi.com/PowerSolutions/product.do?id=ADM1032
|
||||
https://www.digikey.com/htmldatasheets/production/53140/0/0/1/ADM1032.pdf
|
||||
|
||||
* Analog Devices ADT7461
|
||||
|
||||
|
|
@ -111,9 +120,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4b and 0x4c
|
||||
|
||||
Datasheet: Publicly available at the ON Semiconductor website
|
||||
Datasheet: Publicly available at the DigiKey website
|
||||
|
||||
https://www.onsemi.com/PowerSolutions/product.do?id=ADT7481
|
||||
https://www.digikey.com/htmldatasheets/production/234607/0/0/1/ADT7481.pdf
|
||||
|
||||
* Analog Devices ADT7482
|
||||
|
||||
|
|
@ -191,7 +200,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX1617.pdf
|
||||
|
||||
* Maxim MAX1617A
|
||||
|
||||
|
|
@ -199,7 +210,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX1617A.pdf
|
||||
|
||||
* Maxim MAX6642
|
||||
|
||||
|
|
@ -207,9 +220,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x48-0x4f
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6642.pdf
|
||||
|
||||
* Maxim MAX6646
|
||||
|
||||
|
|
@ -217,9 +230,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4d
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6646-MAX6649.pdf
|
||||
|
||||
* Maxim MAX6647
|
||||
|
||||
|
|
@ -227,9 +240,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6646-MAX6649.pdf
|
||||
|
||||
* Maxim MAX6648
|
||||
|
||||
|
|
@ -237,9 +250,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3500
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6648-MAX6692.pdf
|
||||
|
||||
* Maxim MAX6649
|
||||
|
||||
|
|
@ -247,9 +260,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3497
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX1617.pdf
|
||||
|
||||
* Maxim MAX6654
|
||||
|
||||
|
|
@ -259,9 +272,9 @@ Supported chips:
|
|||
|
||||
0x4c, 0x4d and 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
https://www.maximintegrated.com/en/products/sensors/MAX6654.html
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6654.pdf
|
||||
|
||||
* Maxim MAX6657
|
||||
|
||||
|
|
@ -269,9 +282,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6657-MAX6659.pdf
|
||||
|
||||
* Maxim MAX6658
|
||||
|
||||
|
|
@ -279,9 +292,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6657-MAX6659.pdf
|
||||
|
||||
* Maxim MAX6659
|
||||
|
||||
|
|
@ -289,9 +302,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c, 0x4d, 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6657-MAX6659.pdf
|
||||
|
||||
* Maxim MAX6680
|
||||
|
||||
|
|
@ -301,9 +314,9 @@ Supported chips:
|
|||
|
||||
0x4c, 0x4d and 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6680-MAX6681.pdf
|
||||
|
||||
* Maxim MAX6681
|
||||
|
||||
|
|
@ -313,9 +326,9 @@ Supported chips:
|
|||
|
||||
0x4c, 0x4d and 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6680-MAX6681.pdf
|
||||
|
||||
* Maxim MAX6692
|
||||
|
||||
|
|
@ -323,9 +336,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3500
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6648-MAX6692.pdf
|
||||
|
||||
* Maxim MAX6695
|
||||
|
||||
|
|
@ -333,9 +346,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/datasheet/index.mvp/id/4199
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6695-MAX6696.pdf
|
||||
|
||||
* Maxim MAX6696
|
||||
|
||||
|
|
@ -345,9 +358,9 @@ Supported chips:
|
|||
|
||||
0x4c, 0x4d and 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
|
||||
http://www.maxim-ic.com/datasheet/index.mvp/id/4199
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6695-MAX6696.pdf
|
||||
|
||||
* Winbond/Nuvoton W83L771W/G
|
||||
|
||||
|
|
@ -355,7 +368,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x4c
|
||||
|
||||
Datasheet: No longer available
|
||||
Datasheet: Publicly available at the DigiKey website
|
||||
|
||||
https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/1128/W83L771W%2CW83L771G.pdf
|
||||
|
||||
* Winbond/Nuvoton W83L771AWG/ASG
|
||||
|
||||
|
|
@ -381,7 +396,7 @@ Supported chips:
|
|||
|
||||
Datasheet: Publicly available at Nuvoton website
|
||||
|
||||
https://www.nuvoton.com/resource-files/Nuvoton_NCT7717U_Datasheet_V111.pdf
|
||||
https://www.nuvoton.com/resource-files/Nuvoton_NCT7717U_Datasheet_V111.pdf
|
||||
|
||||
* Nuvoton NCT7718
|
||||
|
||||
|
|
@ -391,7 +406,7 @@ Supported chips:
|
|||
|
||||
Datasheet: Publicly available at Nuvoton website
|
||||
|
||||
https://www.nuvoton.com/resource-files/Nuvoton_NCT7718W_Datasheet_V11.pdf
|
||||
https://www.nuvoton.com/resource-files/Nuvoton_NCT7718W_Datasheet_V11.pdf
|
||||
|
||||
* Philips/NXP SA56004X
|
||||
|
||||
|
|
@ -401,7 +416,7 @@ Supported chips:
|
|||
|
||||
Datasheet: Publicly available at NXP website
|
||||
|
||||
http://ics.nxp.com/products/interface/datasheet/sa56004x.pdf
|
||||
https://www.nxp.com/docs/en/data-sheet/SA56004X.pdf
|
||||
|
||||
* GMT G781
|
||||
|
||||
|
|
@ -437,7 +452,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheets: Publicly available at the Philips website
|
||||
Datasheets: Publicly available at the DigiKey website
|
||||
|
||||
https://www.digikey.com/htmldatasheets/production/97606/0/0/1/ne1617.pdf
|
||||
|
||||
* Philips NE1618
|
||||
|
||||
|
|
@ -445,7 +462,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheets: Publicly available at the Philips website
|
||||
Datasheets: Publicly available at the DigiKey website
|
||||
|
||||
https://media.digikey.com/pdf/Data%20Sheets/NXP%20PDFs/NE1618.pdf
|
||||
|
||||
* Genesys Logic GL523SM
|
||||
|
||||
|
|
@ -453,7 +472,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet:
|
||||
Datasheet: No longer available at Genesys Logic website
|
||||
|
||||
* TI THMC10
|
||||
|
||||
|
|
@ -461,7 +480,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the TI website
|
||||
Datasheet: No longer available at the TI website
|
||||
|
||||
* Onsemi MC1066
|
||||
|
||||
|
|
@ -469,7 +488,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
|
||||
|
||||
Datasheet: Publicly available at the Onsemi website
|
||||
Datasheet: No longer available at the Onsemi website
|
||||
|
||||
Author: Jean Delvare <jdelvare@suse.de>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
Kernel driver macsmc-hwmon
|
||||
==========================
|
||||
|
||||
Supported hardware
|
||||
|
||||
* Apple Silicon Macs (M1 and up)
|
||||
|
||||
Author: James Calligeros <jcalligeros99@gmail.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
macsmc-hwmon exposes the Apple System Management controller's
|
||||
temperature, voltage, current and power sensors, as well as
|
||||
fan speed and control capabilities, via hwmon.
|
||||
|
||||
Because each Apple Silicon Mac exposes a different set of sensors
|
||||
(e.g. the MacBooks expose battery telemetry that is not present on
|
||||
the desktop Macs), sensors present on any given machine are described
|
||||
via Devicetree. The driver picks these up and registers them with
|
||||
hwmon when probed.
|
||||
|
||||
Manual fan speed is supported via the fan_control module parameter. This
|
||||
is disabled by default and marked as unsafe, as it cannot be proven that
|
||||
the system will fail safe if overheating due to manual fan control being
|
||||
used.
|
||||
|
||||
sysfs interface
|
||||
---------------
|
||||
|
||||
currX_input
|
||||
Ammeter value
|
||||
|
||||
currX_label
|
||||
Ammeter label
|
||||
|
||||
fanX_input
|
||||
Current fan speed
|
||||
|
||||
fanX_label
|
||||
Fan label
|
||||
|
||||
fanX_min
|
||||
Minimum possible fan speed
|
||||
|
||||
fanX_max
|
||||
Maximum possible fan speed
|
||||
|
||||
fanX_target
|
||||
Current fan setpoint
|
||||
|
||||
inX_input
|
||||
Voltmeter value
|
||||
|
||||
inX_label
|
||||
Voltmeter label
|
||||
|
||||
powerX_input
|
||||
Power meter value
|
||||
|
||||
powerX_label
|
||||
Power meter label
|
||||
|
||||
tempX_input
|
||||
Temperature sensor value
|
||||
|
||||
tempX_label
|
||||
Temperature sensor label
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ Supported chips:
|
|||
|
||||
Prefix: 'max127'
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX127-MAX128.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max127-max128.pdf
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX15301.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max15301.pdf
|
||||
|
||||
* Maxim MAX15303
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX16064.pdf
|
||||
Datasheet: https://www.digikey.com/en/htmldatasheets/production/701833/0/0/1/max16064
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ Supported chips:
|
|||
|
||||
Datasheet:
|
||||
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX16065-MAX16066.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/max16065-max16066.pdf
|
||||
|
||||
* Maxim MAX16067
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ Supported chips:
|
|||
|
||||
Datasheet:
|
||||
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX16067.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/max16067.pdf
|
||||
|
||||
* Maxim MAX16068
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ Supported chips:
|
|||
|
||||
Datasheet:
|
||||
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX16068.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/max16068.pdf
|
||||
|
||||
* Maxim MAX16070/MAX16071
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ Supported chips:
|
|||
|
||||
Datasheet:
|
||||
|
||||
http://datasheets.maxim-ic.com/en/ds/MAX16070-MAX16071.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/max16070-max16071.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e
|
||||
|
||||
Datasheet: Publicly available at the Maxim website
|
||||
Datasheet:
|
||||
|
||||
http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX1619.pdf
|
||||
|
||||
Authors:
|
||||
- Oleksij Rempel <bug-track@fisher-privat.net>,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX16602.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max16602.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e
|
||||
|
||||
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX1668-MAX1989.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX1668-MAX1989.pdf
|
||||
|
||||
Author:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver max17616
|
||||
======================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Analog Devices MAX17616/MAX17616A
|
||||
|
||||
Prefix: 'max17616'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max17616-max17616a.pdf
|
||||
|
||||
Author:
|
||||
|
||||
- Kim Seer Paller <kimseer.paller@analog.com>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver supports hardware monitoring for Analog Devices MAX17616/MAX17616A
|
||||
Current-Limiter with OV/Surge, UV, Reverse Polarity, Loss of Ground Protection
|
||||
with PMBus Interface.
|
||||
|
||||
The MAX17616/MAX17616A is a 3V to 80V, 7A current-limiter with overvoltage,
|
||||
surge, undervoltage, reverse polarity, and loss of ground protection. Through
|
||||
the PMBus interface, the device can monitor input/output voltages, output current
|
||||
and temperature.
|
||||
|
||||
The driver is a client driver to the core PMBus driver. Please see
|
||||
Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
This driver does not auto-detect devices. You will have to instantiate
|
||||
the devices explicitly. Please see Documentation/i2c/instantiating-devices.rst
|
||||
for details.
|
||||
|
||||
Platform data support
|
||||
---------------------
|
||||
|
||||
The driver supports standard PMBus driver platform data.
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
================= ========================================
|
||||
in1_label "vin"
|
||||
in1_input Measured input voltage
|
||||
in1_alarm Input voltage alarm
|
||||
in2_label "vout1"
|
||||
in2_input Measured output voltage
|
||||
curr1_label "iout1"
|
||||
curr1_input Measured output current.
|
||||
curr1_alarm Output current alarm
|
||||
temp1_input Measured temperature
|
||||
temp1_alarm Chip temperature alarm
|
||||
================= ========================================
|
||||
|
|
@ -11,13 +11,13 @@ Supported chips:
|
|||
|
||||
Prefix: 'max197'
|
||||
|
||||
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX197.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX197.pdf
|
||||
|
||||
* Maxim MAX199
|
||||
|
||||
Prefix: 'max199'
|
||||
|
||||
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX199.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX199.pdf
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX20710.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max20710.pdf
|
||||
|
||||
* Maxim MAX20730
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX20730.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max20730.pdf
|
||||
|
||||
* Maxim MAX20734
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX20734.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max20734.pdf
|
||||
|
||||
* Maxim MAX20743
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX20743.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max20743.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31722-MAX31723.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max31722-max31723.pdf
|
||||
|
||||
* Maxim Integrated MAX31723
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31722-MAX31723.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max31722-max31723.pdf
|
||||
|
||||
Author: Tiberiu Breana <tiberiu.a.breana@intel.com>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: 0x1c, 0x1d, 0x1e, 0x1f, 0x4c, 0x4d, 0x4e, 0x4f
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31730.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max31730.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max31785.pdf
|
||||
|
||||
Author: Andrew Jeffery <andrew@aj.id.au>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://pdfserv.maximintegrated.com/en/ds/MAX31790.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31790.pdf
|
||||
|
||||
Author: Il Han <corone.il.han@gmail.com>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x40 - 0x5f
|
||||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf
|
||||
|
||||
* Maxim MAX31828
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x40 - 0x5f
|
||||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf
|
||||
|
||||
* Maxim MAX31829
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x40 - 0x5f
|
||||
|
||||
Datasheet: Publicly available at the Analog Devices website
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf
|
||||
|
||||
|
||||
Authors:
|
||||
|
|
|
|||
|
|
@ -11,13 +11,21 @@ Supported chips:
|
|||
|
||||
Datasheet: -
|
||||
|
||||
* ADI ADPM12200
|
||||
|
||||
Prefixes: 'adpm12200'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: -
|
||||
|
||||
* Maxim MAX34440
|
||||
|
||||
Prefixes: 'max34440'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX34440.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max34440.pdf
|
||||
|
||||
* Maxim MAX34441
|
||||
|
||||
|
|
@ -27,7 +35,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX34441.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max34441.pdf
|
||||
|
||||
* Maxim MAX34446
|
||||
|
||||
|
|
@ -37,7 +45,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX34446.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max34446.pdf
|
||||
|
||||
* Maxim MAX34451
|
||||
|
||||
|
|
@ -47,7 +55,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX34451.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max34451.pdf
|
||||
|
||||
* Maxim MAX34460
|
||||
|
||||
|
|
@ -57,7 +65,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX34460.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max34460.pdf
|
||||
|
||||
* Maxim MAX34461
|
||||
|
||||
|
|
@ -67,7 +75,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX34461.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max34461.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
|
@ -79,10 +87,11 @@ This driver supports multiple devices: hardware monitoring for Maxim MAX34440
|
|||
PMBus 6-Channel Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply
|
||||
Manager and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data
|
||||
Logger; PMBus Voltage Monitor and Sequencers for MAX34451, MAX34460, and
|
||||
MAX34461; PMBus DC/DC Power Module ADPM12160. The MAX34451 supports monitoring
|
||||
voltage or current of 12 channels based on GIN pins. The MAX34460 supports 12
|
||||
voltage channels, and the MAX34461 supports 16 voltage channels. The ADPM1260
|
||||
also monitors both input and output of voltage and current.
|
||||
MAX34461; PMBus DC/DC Power Module ADPM12160, and ADPM12200. The MAX34451
|
||||
supports monitoring voltage or current of 12 channels based on GIN pins. The
|
||||
MAX34460 supports 12 voltage channels, and the MAX34461 supports 16 voltage
|
||||
channels. The ADPM12160, and ADPM12200 also monitors both input and output
|
||||
of voltage and current.
|
||||
|
||||
The driver is a client driver to the core PMBus driver. Please see
|
||||
Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
|
||||
|
|
@ -140,7 +149,8 @@ in[1-6]_reset_history Write any value to reset history.
|
|||
.. note::
|
||||
|
||||
- MAX34446 only supports in[1-4].
|
||||
- ADPM12160 only supports in[1-2]. Label is "vin1" and "vout1" respectively.
|
||||
- ADPM12160, and ADPM12200 only supports in[1-2]. Label is "vin1"
|
||||
and "vout1" respectively.
|
||||
|
||||
Curr
|
||||
~~~~
|
||||
|
|
@ -162,7 +172,8 @@ curr[1-6]_reset_history Write any value to reset history.
|
|||
|
||||
- in6 and curr6 attributes only exist for MAX34440.
|
||||
- MAX34446 only supports curr[1-4].
|
||||
- For ADPM12160, curr[1] is "iin1" and curr[2-6] are "iout[1-5].
|
||||
- For ADPM12160, and ADPM12200, curr[1] is "iin1" and curr[2-6]
|
||||
are "iout[1-5]".
|
||||
|
||||
Power
|
||||
~~~~~
|
||||
|
|
@ -198,7 +209,7 @@ temp[1-8]_reset_history Write any value to reset history.
|
|||
.. note::
|
||||
- temp7 and temp8 attributes only exist for MAX34440.
|
||||
- MAX34446 only supports temp[1-3].
|
||||
- ADPM12160 only supports temp[1].
|
||||
- ADPM12160, and ADPM12200 only supports temp[1].
|
||||
|
||||
|
||||
.. note::
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: I2C 0x2c, 0x2e, 0x2f
|
||||
|
||||
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6639-max6639f.pdf
|
||||
|
||||
Authors:
|
||||
- He Changqing <hechangqing@semptian.com>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6650-MAX6651.pdf
|
||||
|
||||
* Maxim MAX6651
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/MAX6650-MAX6651.pdf
|
||||
|
||||
Authors:
|
||||
- Hans J. Koch <hjk@hansjkoch.de>
|
||||
|
|
|
|||
|
|
@ -7,61 +7,61 @@ Supported chips:
|
|||
|
||||
Prefix: 'max6581'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6581.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6581.pdf
|
||||
|
||||
* Maxim MAX6602
|
||||
|
||||
Prefix: 'max6602'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6602.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6602.pdf
|
||||
|
||||
* Maxim MAX6622
|
||||
|
||||
Prefix: 'max6622'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6622.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6622.pdf
|
||||
|
||||
* Maxim MAX6636
|
||||
|
||||
Prefix: 'max6636'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6636.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6636.pdf
|
||||
|
||||
* Maxim MAX6689
|
||||
|
||||
Prefix: 'max6689'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6689.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6689.pdf
|
||||
|
||||
* Maxim MAX6693
|
||||
|
||||
Prefix: 'max6693'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6693.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6693.pdf
|
||||
|
||||
* Maxim MAX6694
|
||||
|
||||
Prefix: 'max6694'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6694.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6694.pdf
|
||||
|
||||
* Maxim MAX6697
|
||||
|
||||
Prefix: 'max6697'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6697.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6697.pdf
|
||||
|
||||
* Maxim MAX6698
|
||||
|
||||
Prefix: 'max6698'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6698.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6698.pdf
|
||||
|
||||
* Maxim MAX6699
|
||||
|
||||
Prefix: 'max6699'
|
||||
|
||||
Datasheet: http://datasheets.maximintegrated.com/en/ds/MAX6699.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max6699.pdf
|
||||
|
||||
Author:
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Not available
|
||||
Datasheet:
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/max77505.pdf
|
||||
|
||||
Authors:
|
||||
- Dzmitry Sankouski <dsankouski@gmail.com>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: http://datasheets.maxim-ic.com/en/ds/MAX8688.pdf
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max8688.pdf
|
||||
|
||||
Author: Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,151 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver mp2925
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* MPS mp2925
|
||||
|
||||
Prefix: 'mp2925'
|
||||
|
||||
* MPS mp2929
|
||||
|
||||
Prefix: 'mp2929'
|
||||
|
||||
Author:
|
||||
|
||||
Wensheng Wang <wenswang@yeah.net>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Monolithic Power Systems, Inc. (MPS)
|
||||
MP2925 Dual Loop Digital Multi-phase Controller.
|
||||
|
||||
Device compliant with:
|
||||
|
||||
- PMBus rev 1.3 interface.
|
||||
|
||||
The driver exports the following attributes via the 'sysfs' files
|
||||
for input voltage:
|
||||
|
||||
**in1_input**
|
||||
|
||||
**in1_label**
|
||||
|
||||
**in1_crit**
|
||||
|
||||
**in1_crit_alarm**
|
||||
|
||||
**in1_lcrit**
|
||||
|
||||
**in1_lcrit_alarm**
|
||||
|
||||
**in1_max**
|
||||
|
||||
**in1_max_alarm**
|
||||
|
||||
**in1_min**
|
||||
|
||||
**in1_min_alarm**
|
||||
|
||||
The driver provides the following attributes for output voltage:
|
||||
|
||||
**in2_input**
|
||||
|
||||
**in2_label**
|
||||
|
||||
**in2_crit**
|
||||
|
||||
**in2_crit_alarm**
|
||||
|
||||
**in2_lcrit**
|
||||
|
||||
**in2_lcrit_alarm**
|
||||
|
||||
**in3_input**
|
||||
|
||||
**in3_label**
|
||||
|
||||
**in3_crit**
|
||||
|
||||
**in3_crit_alarm**
|
||||
|
||||
**in3_lcrit**
|
||||
|
||||
**in3_lcrit_alarm**
|
||||
|
||||
The driver provides the following attributes for input current:
|
||||
|
||||
**curr1_input**
|
||||
|
||||
**curr1_label**
|
||||
|
||||
The driver provides the following attributes for output current:
|
||||
|
||||
**curr2_input**
|
||||
|
||||
**curr2_label**
|
||||
|
||||
**curr2_crit**
|
||||
|
||||
**curr2_crit_alarm**
|
||||
|
||||
**curr2_max**
|
||||
|
||||
**curr2_max_alarm**
|
||||
|
||||
**curr3_input**
|
||||
|
||||
**curr3_label**
|
||||
|
||||
**curr3_crit**
|
||||
|
||||
**curr3_crit_alarm**
|
||||
|
||||
**curr3_max**
|
||||
|
||||
**curr3_max_alarm**
|
||||
|
||||
The driver provides the following attributes for input power:
|
||||
|
||||
**power1_input**
|
||||
|
||||
**power1_label**
|
||||
|
||||
**power2_input**
|
||||
|
||||
**power2_label**
|
||||
|
||||
The driver provides the following attributes for output power:
|
||||
|
||||
**power3_input**
|
||||
|
||||
**power3_label**
|
||||
|
||||
**power4_input**
|
||||
|
||||
**power4_label**
|
||||
|
||||
The driver provides the following attributes for temperature:
|
||||
|
||||
**temp1_input**
|
||||
|
||||
**temp1_crit**
|
||||
|
||||
**temp1_crit_alarm**
|
||||
|
||||
**temp1_max**
|
||||
|
||||
**temp1_max_alarm**
|
||||
|
||||
**temp2_input**
|
||||
|
||||
**temp2_crit**
|
||||
|
||||
**temp2_crit_alarm**
|
||||
|
||||
**temp2_max**
|
||||
|
||||
**temp2_max_alarm**
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver mp9945
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* MPS mp9945
|
||||
|
||||
Prefix: 'mp9945'
|
||||
|
||||
Author:
|
||||
|
||||
Cosmo Chou <chou.cosmo@gmail.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for Monolithic Power Systems, Inc. (MPS)
|
||||
MP9945 Digital Single-phase Controller.
|
||||
|
||||
Device compliant with:
|
||||
|
||||
- PMBus rev 1.3 interface.
|
||||
|
||||
The driver exports the following attributes via the 'sysfs' files
|
||||
for input voltage:
|
||||
|
||||
**in1_input**
|
||||
|
||||
**in1_label**
|
||||
|
||||
**in1_crit**
|
||||
|
||||
**in1_crit_alarm**
|
||||
|
||||
**in1_lcrit**
|
||||
|
||||
**in1_lcrit_alarm**
|
||||
|
||||
**in1_max**
|
||||
|
||||
**in1_max_alarm**
|
||||
|
||||
**in1_min**
|
||||
|
||||
**in1_min_alarm**
|
||||
|
||||
The driver provides the following attributes for output voltage:
|
||||
|
||||
**in2_input**
|
||||
|
||||
**in2_label**
|
||||
|
||||
**in2_crit**
|
||||
|
||||
**in2_crit_alarm**
|
||||
|
||||
**in2_lcrit**
|
||||
|
||||
**in2_lcrit_alarm**
|
||||
|
||||
**in2_min**
|
||||
|
||||
**in2_min_alarm**
|
||||
|
||||
The driver provides the following attributes for input current:
|
||||
|
||||
**curr1_input**
|
||||
|
||||
**curr1_label**
|
||||
|
||||
**curr1_max**
|
||||
|
||||
**curr1_max_alarm**
|
||||
|
||||
The driver provides the following attributes for output current:
|
||||
|
||||
**curr2_input**
|
||||
|
||||
**curr2_label**
|
||||
|
||||
**curr2_crit**
|
||||
|
||||
**curr2_crit_alarm**
|
||||
|
||||
**curr2_max**
|
||||
|
||||
**curr2_max_alarm**
|
||||
|
||||
The driver provides the following attributes for input power:
|
||||
|
||||
**power1_input**
|
||||
|
||||
**power1_label**
|
||||
|
||||
The driver provides the following attributes for output power:
|
||||
|
||||
**power2_input**
|
||||
|
||||
**power2_label**
|
||||
|
||||
**power2_max**
|
||||
|
||||
**power2_max_alarm**
|
||||
|
||||
The driver provides the following attributes for temperature:
|
||||
|
||||
**temp1_input**
|
||||
|
||||
**temp1_crit**
|
||||
|
||||
**temp1_crit_alarm**
|
||||
|
||||
**temp1_max**
|
||||
|
||||
**temp1_max_alarm**
|
||||
|
|
@ -74,7 +74,7 @@ Supported chips:
|
|||
|
||||
Datasheet:
|
||||
|
||||
Not published
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX20796.pdf
|
||||
|
||||
* Generic PMBus devices
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ the Silergy SY7636A PMIC.
|
|||
The following sensors are supported
|
||||
|
||||
* Temperature
|
||||
- SoC on-die temperature in milli-degree C
|
||||
- Temperature of external NTC in milli-degree C
|
||||
|
||||
sysfs-Interface
|
||||
---------------
|
||||
|
||||
temp0_input
|
||||
- SoC on-die temperature (milli-degree C)
|
||||
- Temperature of external NTC (milli-degree C)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
Kernel driver tsc1641
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* ST TSC1641
|
||||
|
||||
Prefix: 'tsc1641'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet:
|
||||
https://www.st.com/resource/en/datasheet/tsc1641.pdf
|
||||
|
||||
Author:
|
||||
- Igor Reznichenko <igor@reznichenko.net>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The TSC1641 is a high-precision current, voltage, power, and temperature
|
||||
monitoring analog front-end (AFE). It monitors bidirectional current into a
|
||||
shunt resistor and load voltage up to 60 V in a synchronized way. Digital bus
|
||||
interface is I2C/SMbus. The TSC1641 allows the assertion of several alerts
|
||||
regarding the voltage, current, power and temperature.
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
The TSC1641 driver requires the value of the external shunt resistor to
|
||||
correctly compute current and power measurements. The resistor value, in
|
||||
micro-ohms, should be provided either through the device tree property
|
||||
"shunt-resistor-micro-ohms" or via writable sysfs attribute "shunt_resistor".
|
||||
Please refer to the Documentation/devicetree/bindings/hwmon/st,tsc1641.yaml
|
||||
for bindings if the device tree is used.
|
||||
|
||||
Supported range of shunt resistor values is from 100 uOhm to 655.35 mOhm, in
|
||||
10 uOhm steps.
|
||||
When selecting the value keep in mind device maximum DC power measurement is
|
||||
1600W. See datasheet p.22 for ST recommendations on selecting shunt value.
|
||||
|
||||
If the shunt resistor value is not specified in the device tree, the driver
|
||||
initializes it to 1000 uOhm by default. Users may configure the correct shunt
|
||||
resistor value at runtime by writing to the "shunt_resistor" sysfs attribute.
|
||||
|
||||
The driver only supports continuous operating mode.
|
||||
Measurement ranges:
|
||||
|
||||
================ ===============================================================
|
||||
Current Bidirectional, dependent on shunt
|
||||
Bus voltage 0-60V
|
||||
Maximum DC power 1600W
|
||||
Temperature -40C to +125C
|
||||
================ ===============================================================
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
==================== ===========================================================
|
||||
in0_input bus voltage (mV)
|
||||
in0_max bus voltage max alarm limit (mV)
|
||||
in0_max_alarm bus voltage max alarm limit exceeded
|
||||
in0_min bus voltage min alarm limit (mV)
|
||||
in0_min_alarm bus voltage min alarm limit exceeded
|
||||
|
||||
curr1_input current measurement (mA)
|
||||
curr1_max current max alarm limit (mA)
|
||||
curr1_max_alarm current max alarm limit exceeded
|
||||
curr1_min current min alarm limit (mA)
|
||||
curr1_min_alarm current min alarm limit exceeded
|
||||
|
||||
power1_input power measurement (uW)
|
||||
power1_max power max alarm limit (uW)
|
||||
power1_max_alarm power max alarm limit exceeded
|
||||
|
||||
shunt_resistor shunt resistor value (uOhms)
|
||||
|
||||
temp1_input temperature measurement (mdegC)
|
||||
temp1_max temperature max alarm limit (mdegC)
|
||||
temp1_max_alarm temperature max alarm limit exceeded
|
||||
|
||||
update_interval data conversion time (1 - 33ms), longer conversion time
|
||||
corresponds to higher effective resolution in bits
|
||||
==================== ===========================================================
|
||||
|
|
@ -9,7 +9,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2004-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2004-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL2005
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2005-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2005-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL2006
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2006-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2006-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL2008
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2008-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2008-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL2105
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2105-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2105-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL2106
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2106-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl2106-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL6100
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl6100-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl6100-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL6105
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ Supported chips:
|
|||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl6105-datasheet.pdf
|
||||
Datasheet: https://www.renesas.com/us/en/document/dst/zl6105-datasheet
|
||||
|
||||
* Renesas / Intersil / Zilker Labs ZL8802
|
||||
|
||||
|
|
|
|||
33
MAINTAINERS
33
MAINTAINERS
|
|
@ -2468,12 +2468,14 @@ F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml
|
|||
F: Documentation/devicetree/bindings/spi/apple,spi.yaml
|
||||
F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml
|
||||
F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
|
||||
F: Documentation/hwmon/macsmc-hwmon.rst
|
||||
F: arch/arm64/boot/dts/apple/
|
||||
F: drivers/bluetooth/hci_bcm4377.c
|
||||
F: drivers/clk/clk-apple-nco.c
|
||||
F: drivers/cpufreq/apple-soc-cpufreq.c
|
||||
F: drivers/dma/apple-admac.c
|
||||
F: drivers/gpio/gpio-macsmc.c
|
||||
F: drivers/hwmon/macsmc-hwmon.c
|
||||
F: drivers/pmdomain/apple/
|
||||
F: drivers/i2c/busses/i2c-pasemi-core.c
|
||||
F: drivers/i2c/busses/i2c-pasemi-platform.c
|
||||
|
|
@ -15228,6 +15230,15 @@ S: Maintained
|
|||
F: Documentation/hwmon/max15301.rst
|
||||
F: drivers/hwmon/pmbus/max15301.c
|
||||
|
||||
MAX17616 HARDWARE MONITOR DRIVER
|
||||
M: Kim Seer Paller <kimseer.paller@analog.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/hwmon/pmbus/adi,max17616.yaml
|
||||
F: Documentation/hwmon/max17616.rst
|
||||
F: drivers/hwmon/pmbus/max17616.c
|
||||
|
||||
MAX2175 SDR TUNER DRIVER
|
||||
M: Ramesh Shanmugasundaram <rashanmu@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
@ -17545,6 +17556,13 @@ S: Maintained
|
|||
F: Documentation/hwmon/mp2891.rst
|
||||
F: drivers/hwmon/pmbus/mp2891.c
|
||||
|
||||
MPS MP2925 DRIVER
|
||||
M: Noah Wang <wenswang@yeah.net>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/mp2925.rst
|
||||
F: drivers/hwmon/pmbus/mp2925.c
|
||||
|
||||
MPS MP29502 DRIVER
|
||||
M: Wensheng Wang <wenswang@yeah.net>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
|
|
@ -17566,6 +17584,13 @@ S: Maintained
|
|||
F: Documentation/hwmon/mp9941.rst
|
||||
F: drivers/hwmon/pmbus/mp9941.c
|
||||
|
||||
MPS MP9945 DRIVER
|
||||
M: Cosmo Chou <chou.cosmo@gmail.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/mp9945.rst
|
||||
F: drivers/hwmon/pmbus/mp9945.c
|
||||
|
||||
MR800 AVERMEDIA USB FM RADIO DRIVER
|
||||
M: Alexey Klimov <alexey.klimov@linaro.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
@ -24493,6 +24518,14 @@ S: Maintained
|
|||
F: Documentation/hwmon/stpddc60.rst
|
||||
F: drivers/hwmon/pmbus/stpddc60.c
|
||||
|
||||
ST TSC1641 DRIVER
|
||||
M: Igor Reznichenko <igor@reznichenko.net>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/hwmon/st,tsc1641.yaml
|
||||
F: Documentation/hwmon/tsc1641.rst
|
||||
F: drivers/hwmon/tsc1641.c
|
||||
|
||||
ST VD55G1 DRIVER
|
||||
M: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
|
||||
M: Sylvain Petinot <sylvain.petinot@foss.st.com>
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ config SENSORS_ADT7X10
|
|||
select REGMAP
|
||||
help
|
||||
This module contains common code shared by the ADT7310/ADT7320 and
|
||||
ADT7410/ADT7420 temperature monitoring chip drivers.
|
||||
ADT7410/ADT7420/ADT7422 temperature monitoring chip drivers.
|
||||
|
||||
If built as a module, the module will be called adt7x10.
|
||||
|
||||
|
|
@ -191,12 +191,12 @@ config SENSORS_ADT7310
|
|||
will be called adt7310.
|
||||
|
||||
config SENSORS_ADT7410
|
||||
tristate "Analog Devices ADT7410/ADT7420"
|
||||
tristate "Analog Devices ADT7410/ADT7420/ADT7422"
|
||||
depends on I2C
|
||||
select SENSORS_ADT7X10
|
||||
help
|
||||
If you say yes here you get support for the Analog Devices
|
||||
ADT7410 and ADT7420 temperature monitoring chips.
|
||||
ADT7410, ADT7420 and ADT7422 temperature monitoring chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called adt7410.
|
||||
|
|
@ -245,12 +245,12 @@ config SENSORS_ADT7475
|
|||
will be called adt7475.
|
||||
|
||||
config SENSORS_AHT10
|
||||
tristate "Aosong AHT10, AHT20"
|
||||
tristate "Aosong AHT10, AHT20, DHT20"
|
||||
depends on I2C
|
||||
select CRC8
|
||||
help
|
||||
If you say yes here, you get support for the Aosong AHT10 and AHT20
|
||||
temperature and humidity sensors
|
||||
If you say yes here, you get support for the Aosong AHT10, AHT20 and
|
||||
DHT20 temperature and humidity sensors
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called aht10.
|
||||
|
|
@ -1174,6 +1174,18 @@ config SENSORS_LTQ_CPUTEMP
|
|||
If you say yes here you get support for the temperature
|
||||
sensor inside your CPU.
|
||||
|
||||
config SENSORS_MACSMC_HWMON
|
||||
tristate "Apple SMC (Apple Silicon)"
|
||||
depends on MFD_MACSMC && OF
|
||||
help
|
||||
This driver enables hwmon support for current, power, temperature,
|
||||
and voltage sensors, as well as fan speed reporting and control
|
||||
on Apple Silicon devices. Say Y here if you have an Apple Silicon
|
||||
device.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called macsmc-hwmon.
|
||||
|
||||
config SENSORS_MAX1111
|
||||
tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
|
||||
depends on SPI_MASTER
|
||||
|
|
@ -2434,6 +2446,18 @@ config SENSORS_TMP513
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called tmp513.
|
||||
|
||||
config SENSORS_TSC1641
|
||||
tristate "ST Microelectronics TSC1641 Power Monitor"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for TSC1641 power monitor chip.
|
||||
The TSC1641 driver is configured for the default configuration of
|
||||
the part except temperature is enabled by default.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tsc1641.
|
||||
|
||||
config SENSORS_VEXPRESS
|
||||
tristate "Versatile Express"
|
||||
depends on VEXPRESS_CONFIG
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o
|
|||
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
|
||||
obj-$(CONFIG_SENSORS_LTC4282) += ltc4282.o
|
||||
obj-$(CONFIG_SENSORS_LTQ_CPUTEMP) += ltq-cputemp.o
|
||||
obj-$(CONFIG_SENSORS_MACSMC_HWMON) += macsmc-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
|
||||
obj-$(CONFIG_SENSORS_MAX127) += max127.o
|
||||
obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
|
||||
|
|
@ -233,6 +234,7 @@ obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
|
|||
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
|
||||
obj-$(CONFIG_SENSORS_TMP464) += tmp464.o
|
||||
obj-$(CONFIG_SENSORS_TMP513) += tmp513.o
|
||||
obj-$(CONFIG_SENSORS_TSC1641) += tsc1641.o
|
||||
obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
|
||||
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
|
||||
|
|
|
|||
|
|
@ -197,8 +197,16 @@ static int adm1026_scaling[] = { /* .001 Volts */
|
|||
#define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \
|
||||
clamp_val(1350000 / ((val) * (div)), \
|
||||
1, 254))
|
||||
#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 0xff ? 0 : \
|
||||
1350000 / ((val) * (div)))
|
||||
|
||||
static int fan_from_reg(int val, int div)
|
||||
{
|
||||
if (val == 0)
|
||||
return -1;
|
||||
if (val == 0xff)
|
||||
return 0;
|
||||
return 1350000 / (val * div);
|
||||
}
|
||||
|
||||
#define DIV_FROM_REG(val) (1 << (val))
|
||||
#define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
|
||||
|
||||
|
|
@ -656,7 +664,7 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *attr,
|
|||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr],
|
||||
data->fan_div[nr]));
|
||||
}
|
||||
static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr,
|
||||
|
|
@ -665,7 +673,7 @@ static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr,
|
|||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct adm1026_data *data = adm1026_update_device(dev);
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
|
||||
return sprintf(buf, "%d\n", fan_from_reg(data->fan_min[nr],
|
||||
data->fan_div[nr]));
|
||||
}
|
||||
static ssize_t fan_min_store(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -171,14 +171,17 @@ fan_show(struct device *dev, struct device_attribute *devattr, char *buf)
|
|||
struct adm1029_data *data = adm1029_update_device(dev);
|
||||
u16 val;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (data->fan[attr->index] == 0 ||
|
||||
(data->fan_div[attr->index] & 0xC0) == 0 ||
|
||||
data->fan[attr->index] == 255) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])
|
||||
/ data->fan[attr->index];
|
||||
mutex_unlock(&data->update_lock);
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-vid.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
|
|
@ -125,7 +124,6 @@ static inline unsigned int AOUT_FROM_REG(u8 reg)
|
|||
struct adm9240_data {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct mutex update_lock;
|
||||
|
||||
u8 fan_div[2]; /* rw fan1_div, read-only accessor */
|
||||
u8 vrm; /* -- vrm set on startup, no accessor */
|
||||
|
|
@ -170,8 +168,6 @@ static int adm9240_fan_min_write(struct adm9240_data *data, int channel, long va
|
|||
u8 fan_min;
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (!val) {
|
||||
fan_min = 255;
|
||||
new_div = data->fan_div[channel];
|
||||
|
|
@ -206,8 +202,6 @@ static int adm9240_fan_min_write(struct adm9240_data *data, int channel, long va
|
|||
}
|
||||
err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(channel), fan_min);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -501,23 +495,17 @@ static int adm9240_fan_read(struct device *dev, u32 attr, int channel, long *val
|
|||
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
mutex_lock(&data->update_lock);
|
||||
err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), ®val);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
if (regval == 255 && data->fan_div[channel] < 3) {
|
||||
/* adjust fan clock divider on overflow */
|
||||
err = adm9240_write_fan_div(data, channel,
|
||||
++data->fan_div[channel]);
|
||||
if (err) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
*val = FAN_FROM_REG(regval, BIT(data->fan_div[channel]));
|
||||
mutex_unlock(&data->update_lock);
|
||||
break;
|
||||
case hwmon_fan_div:
|
||||
*val = BIT(data->fan_div[channel]);
|
||||
|
|
@ -791,7 +779,6 @@ static int adm9240_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
data->dev = dev;
|
||||
mutex_init(&data->update_lock);
|
||||
data->regmap = devm_regmap_init_i2c(client, &adm9240_regmap_config);
|
||||
if (IS_ERR(data->regmap))
|
||||
return PTR_ERR(data->regmap);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
@ -90,14 +91,24 @@ static int adt7410_i2c_probe(struct i2c_client *client)
|
|||
static const struct i2c_device_id adt7410_ids[] = {
|
||||
{ "adt7410" },
|
||||
{ "adt7420" },
|
||||
{ "adt7422" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adt7410_ids);
|
||||
|
||||
static const struct of_device_id adt7410_of_match[] = {
|
||||
{ .compatible = "adi,adt7410" },
|
||||
{ .compatible = "adi,adt7420" },
|
||||
{ .compatible = "adi,adt7422" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adt7410_of_match);
|
||||
|
||||
static struct i2c_driver adt7410_driver = {
|
||||
.driver = {
|
||||
.name = "adt7410",
|
||||
.pm = pm_sleep_ptr(&adt7x10_dev_pm_ops),
|
||||
.of_match_table = adt7410_of_match,
|
||||
},
|
||||
.probe = adt7410_i2c_probe,
|
||||
.id_table = adt7410_ids,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
|
|
@ -99,8 +98,6 @@ static const u8 adt7411_in_alarm_bits[] = {
|
|||
};
|
||||
|
||||
struct adt7411_data {
|
||||
struct mutex device_lock; /* for "atomic" device accesses */
|
||||
struct mutex update_lock;
|
||||
unsigned long next_update;
|
||||
long vref_cached;
|
||||
struct i2c_client *client;
|
||||
|
|
@ -110,55 +107,41 @@ struct adt7411_data {
|
|||
/*
|
||||
* When reading a register containing (up to 4) lsb, all associated
|
||||
* msb-registers get locked by the hardware. After _one_ of those msb is read,
|
||||
* _all_ are unlocked. In order to use this locking correctly, reading lsb/msb
|
||||
* is protected here with a mutex, too.
|
||||
* _all_ are unlocked.
|
||||
*/
|
||||
static int adt7411_read_10_bit(struct i2c_client *client, u8 lsb_reg,
|
||||
u8 msb_reg, u8 lsb_shift)
|
||||
u8 msb_reg, u8 lsb_shift)
|
||||
{
|
||||
struct adt7411_data *data = i2c_get_clientdata(client);
|
||||
int val, tmp;
|
||||
|
||||
mutex_lock(&data->device_lock);
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, lsb_reg);
|
||||
if (val < 0)
|
||||
goto exit_unlock;
|
||||
return val;
|
||||
|
||||
tmp = (val >> lsb_shift) & 3;
|
||||
val = i2c_smbus_read_byte_data(client, msb_reg);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
if (val >= 0)
|
||||
val = (val << 2) | tmp;
|
||||
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->device_lock);
|
||||
|
||||
val = (val << 2) | tmp;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit,
|
||||
bool flag)
|
||||
bool flag)
|
||||
{
|
||||
struct adt7411_data *data = i2c_get_clientdata(client);
|
||||
int ret, val;
|
||||
|
||||
mutex_lock(&data->device_lock);
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
return ret;
|
||||
|
||||
if (flag)
|
||||
val = ret | bit;
|
||||
else
|
||||
val = ret & ~bit;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, reg, val);
|
||||
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->device_lock);
|
||||
return ret;
|
||||
return i2c_smbus_write_byte_data(client, reg, val);
|
||||
}
|
||||
|
||||
static ssize_t adt7411_show_bit(struct device *dev,
|
||||
|
|
@ -186,12 +169,11 @@ static ssize_t adt7411_set_bit(struct device *dev,
|
|||
if (ret || flag > 1)
|
||||
return -EINVAL;
|
||||
|
||||
hwmon_lock(dev);
|
||||
ret = adt7411_modify_bit(client, s_attr2->index, s_attr2->nr, flag);
|
||||
|
||||
/* force update */
|
||||
mutex_lock(&data->update_lock);
|
||||
data->next_update = jiffies;
|
||||
mutex_unlock(&data->update_lock);
|
||||
hwmon_unlock(dev);
|
||||
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
|
|
@ -294,10 +276,9 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel,
|
|||
int reg, lsb_reg, lsb_shift;
|
||||
int nr = channel - 1;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = adt7411_update_vref(dev);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
return ret;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_in_input:
|
||||
|
|
@ -307,7 +288,7 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel,
|
|||
ADT7411_REG_EXT_TEMP_AIN1_MSB + nr,
|
||||
lsb_shift);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
return ret;
|
||||
*val = ret * data->vref_cached / 1024;
|
||||
ret = 0;
|
||||
break;
|
||||
|
|
@ -318,7 +299,7 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel,
|
|||
: ADT7411_REG_IN_HIGH(channel);
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
return ret;
|
||||
*val = ret * data->vref_cached / 256;
|
||||
ret = 0;
|
||||
break;
|
||||
|
|
@ -329,8 +310,6 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel,
|
|||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -457,10 +436,9 @@ static int adt7411_write_in_chan(struct device *dev, u32 attr, int channel,
|
|||
struct i2c_client *client = data->client;
|
||||
int ret, reg;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = adt7411_update_vref(dev);
|
||||
if (ret < 0)
|
||||
goto exit_unlock;
|
||||
return ret;
|
||||
val = clamp_val(val, 0, 255 * data->vref_cached / 256);
|
||||
val = DIV_ROUND_CLOSEST(val * 256, data->vref_cached);
|
||||
|
||||
|
|
@ -472,13 +450,10 @@ static int adt7411_write_in_chan(struct device *dev, u32 attr, int channel,
|
|||
reg = ADT7411_REG_IN_HIGH(channel);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit_unlock;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, reg, val);
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -679,8 +654,6 @@ static int adt7411_probe(struct i2c_client *client)
|
|||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->client = client;
|
||||
mutex_init(&data->device_lock);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
ret = adt7411_init_device(data);
|
||||
if (ret < 0)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
@ -55,7 +54,6 @@
|
|||
/* Each client has this additional data */
|
||||
struct adt7x10_data {
|
||||
struct regmap *regmap;
|
||||
struct mutex update_lock;
|
||||
u8 config;
|
||||
u8 oldconfig;
|
||||
bool valid; /* true if temperature valid */
|
||||
|
|
@ -137,17 +135,13 @@ static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val)
|
|||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (index == adt7x10_temperature && !data->valid) {
|
||||
/* wait for valid temperature */
|
||||
ret = adt7x10_temp_ready(data->regmap);
|
||||
if (ret) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
data->valid = true;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], ®val);
|
||||
if (ret)
|
||||
|
|
@ -159,13 +153,8 @@ static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val)
|
|||
|
||||
static int adt7x10_temp_write(struct adt7x10_data *data, int index, long temp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[index],
|
||||
ADT7X10_TEMP_TO_REG(temp));
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
return regmap_write(data->regmap, ADT7X10_REG_TEMP[index],
|
||||
ADT7X10_TEMP_TO_REG(temp));
|
||||
}
|
||||
|
||||
static int adt7x10_hyst_read(struct adt7x10_data *data, int index, long *val)
|
||||
|
|
@ -197,22 +186,17 @@ static int adt7x10_hyst_write(struct adt7x10_data *data, long hyst)
|
|||
unsigned int regval;
|
||||
int limit, ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* convert absolute hysteresis value to a 4 bit delta value */
|
||||
ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, ®val);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
return ret;
|
||||
|
||||
limit = ADT7X10_REG_TO_TEMP(data, regval);
|
||||
|
||||
hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
|
||||
regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
|
||||
ADT7X10_T_HYST_MASK);
|
||||
ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval);
|
||||
abort:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
return regmap_write(data->regmap, ADT7X10_T_HYST, regval);
|
||||
}
|
||||
|
||||
static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val)
|
||||
|
|
@ -344,7 +328,6 @@ int adt7x10_probe(struct device *dev, const char *name, int irq,
|
|||
data->regmap = regmap;
|
||||
|
||||
dev_set_drvdata(dev, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* configure as specified */
|
||||
ret = regmap_read(regmap, ADT7X10_CONFIG, &config);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
#define AHT10_CMD_MEAS 0b10101100
|
||||
#define AHT10_CMD_RST 0b10111010
|
||||
|
||||
#define DHT20_CMD_INIT 0x71
|
||||
|
||||
/*
|
||||
* Flags in the answer byte/command
|
||||
*/
|
||||
|
|
@ -48,11 +50,12 @@
|
|||
|
||||
#define AHT10_MAX_POLL_INTERVAL_LEN 30
|
||||
|
||||
enum aht10_variant { aht10, aht20 };
|
||||
enum aht10_variant { aht10, aht20, dht20};
|
||||
|
||||
static const struct i2c_device_id aht10_id[] = {
|
||||
{ "aht10", aht10 },
|
||||
{ "aht20", aht20 },
|
||||
{ "dht20", dht20 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, aht10_id);
|
||||
|
|
@ -60,8 +63,6 @@ MODULE_DEVICE_TABLE(i2c, aht10_id);
|
|||
/**
|
||||
* struct aht10_data - All the data required to operate an AHT10/AHT20 chip
|
||||
* @client: the i2c client associated with the AHT10/AHT20
|
||||
* @lock: a mutex that is used to prevent parallel access to the
|
||||
* i2c client
|
||||
* @min_poll_interval: the minimum poll interval
|
||||
* While the poll rate limit is not 100% necessary,
|
||||
* the datasheet recommends that a measurement
|
||||
|
|
@ -77,21 +78,18 @@ MODULE_DEVICE_TABLE(i2c, aht10_id);
|
|||
* AHT10/AHT20
|
||||
* @crc8: crc8 support flag
|
||||
* @meas_size: measurements data size
|
||||
* @init_cmd: Initialization command
|
||||
*/
|
||||
|
||||
struct aht10_data {
|
||||
struct i2c_client *client;
|
||||
/*
|
||||
* Prevent simultaneous access to the i2c
|
||||
* client and previous_poll_time
|
||||
*/
|
||||
struct mutex lock;
|
||||
ktime_t min_poll_interval;
|
||||
ktime_t previous_poll_time;
|
||||
int temperature;
|
||||
int humidity;
|
||||
bool crc8;
|
||||
unsigned int meas_size;
|
||||
u8 init_cmd;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -101,13 +99,13 @@ struct aht10_data {
|
|||
*/
|
||||
static int aht10_init(struct aht10_data *data)
|
||||
{
|
||||
const u8 cmd_init[] = {AHT10_CMD_INIT, AHT10_CAL_ENABLED | AHT10_MODE_CYC,
|
||||
const u8 cmd_init[] = {data->init_cmd, AHT10_CAL_ENABLED | AHT10_MODE_CYC,
|
||||
0x00};
|
||||
int res;
|
||||
u8 status;
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
res = i2c_master_send(client, cmd_init, 3);
|
||||
res = i2c_master_send(client, cmd_init, sizeof(cmd_init));
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
|
|
@ -168,32 +166,24 @@ static int aht10_read_values(struct aht10_data *data)
|
|||
u8 raw_data[AHT20_MEAS_SIZE];
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
if (!aht10_polltime_expired(data)) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (!aht10_polltime_expired(data))
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas));
|
||||
if (res < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA);
|
||||
|
||||
res = i2c_master_recv(client, raw_data, data->meas_size);
|
||||
if (res != data->meas_size) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (res >= 0)
|
||||
return -ENODATA;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (data->crc8 && crc8_check(raw_data, data->meas_size)) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (data->crc8 && crc8_check(raw_data, data->meas_size))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
hum = ((u32)raw_data[1] << 12u) |
|
||||
((u32)raw_data[2] << 4u) |
|
||||
|
|
@ -210,7 +200,6 @@ static int aht10_read_values(struct aht10_data *data)
|
|||
data->humidity = hum;
|
||||
data->previous_poll_time = ktime_get_boottime();
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -352,14 +341,20 @@ static int aht10_probe(struct i2c_client *client)
|
|||
data->meas_size = AHT20_MEAS_SIZE;
|
||||
data->crc8 = true;
|
||||
crc8_populate_msb(crc8_table, AHT20_CRC8_POLY);
|
||||
data->init_cmd = AHT10_CMD_INIT;
|
||||
break;
|
||||
case dht20:
|
||||
data->meas_size = AHT20_MEAS_SIZE;
|
||||
data->crc8 = true;
|
||||
crc8_populate_msb(crc8_table, AHT20_CRC8_POLY);
|
||||
data->init_cmd = DHT20_CMD_INIT;
|
||||
break;
|
||||
default:
|
||||
data->meas_size = AHT10_MEAS_SIZE;
|
||||
data->init_cmd = AHT10_CMD_INIT;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_init(&data->lock);
|
||||
|
||||
res = aht10_init(data);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
|
|
@ -551,7 +550,6 @@ struct aqc_data {
|
|||
struct hid_device *hdev;
|
||||
struct device *hwmon_dev;
|
||||
struct dentry *debugfs;
|
||||
struct mutex mutex; /* Used for locking access when reading and writing PWM values */
|
||||
enum kinds kind;
|
||||
const char *name;
|
||||
|
||||
|
|
@ -662,7 +660,6 @@ static void aqc_delay_ctrl_report(struct aqc_data *priv)
|
|||
}
|
||||
}
|
||||
|
||||
/* Expects the mutex to be locked */
|
||||
static int aqc_get_ctrl_data(struct aqc_data *priv)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -680,7 +677,6 @@ static int aqc_get_ctrl_data(struct aqc_data *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Expects the mutex to be locked */
|
||||
static int aqc_send_ctrl_data(struct aqc_data *priv)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -721,11 +717,9 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int ty
|
|||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
ret = aqc_get_ctrl_data(priv);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
return ret;
|
||||
|
||||
switch (type) {
|
||||
case AQC_BE16:
|
||||
|
|
@ -737,9 +731,6 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int ty
|
|||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unlock_and_return:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -747,11 +738,9 @@ static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, in
|
|||
{
|
||||
int ret, i;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
ret = aqc_get_ctrl_data(priv);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
switch (types[i]) {
|
||||
|
|
@ -762,18 +751,11 @@ static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, in
|
|||
priv->buffer[offsets[i]] = (u8)vals[i];
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
|
||||
ret = aqc_send_ctrl_data(priv);
|
||||
|
||||
unlock_and_return:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
return aqc_send_ctrl_data(priv);
|
||||
}
|
||||
|
||||
static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val, int type)
|
||||
|
|
@ -953,13 +935,11 @@ static int aqc_legacy_read(struct aqc_data *priv)
|
|||
{
|
||||
int ret, i, sensor_value;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
memset(priv->buffer, 0x00, priv->buffer_size);
|
||||
ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer,
|
||||
priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
return ret;
|
||||
|
||||
/* Temperature sensor readings */
|
||||
for (i = 0; i < priv->num_temp_sensors; i++) {
|
||||
|
|
@ -1020,10 +1000,7 @@ static int aqc_legacy_read(struct aqc_data *priv)
|
|||
}
|
||||
|
||||
priv->updated = jiffies;
|
||||
|
||||
unlock_and_return:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
|
|
@ -1870,8 +1847,6 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
goto fail_and_close;
|
||||
}
|
||||
|
||||
mutex_init(&priv->mutex);
|
||||
|
||||
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, priv->name, priv,
|
||||
&aqc_chip_info, NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -528,6 +528,9 @@ static const struct of_device_id aspeed_pwm_tach_match[] = {
|
|||
{
|
||||
.compatible = "aspeed,ast2600-pwm-tach",
|
||||
},
|
||||
{
|
||||
.compatible = "aspeed,ast2700-pwm-tach",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match);
|
||||
|
|
|
|||
|
|
@ -113,15 +113,19 @@ enum ec_sensors {
|
|||
ec_sensor_temp_t_sensor,
|
||||
/* VRM temperature [℃] */
|
||||
ec_sensor_temp_vrm,
|
||||
/* VRM east (right) temperature [℃] */
|
||||
ec_sensor_temp_vrme,
|
||||
/* VRM west (left) temperature [℃] */
|
||||
ec_sensor_temp_vrmw,
|
||||
/* CPU Core voltage [mV] */
|
||||
ec_sensor_in_cpu_core,
|
||||
/* CPU_Opt fan [RPM] */
|
||||
ec_sensor_fan_cpu_opt,
|
||||
/* VRM heat sink fan [RPM] */
|
||||
ec_sensor_fan_vrm_hs,
|
||||
/* VRM east heat sink fan [RPM] */
|
||||
/* VRM east (right) heat sink fan [RPM] */
|
||||
ec_sensor_fan_vrme_hs,
|
||||
/* VRM west heat sink fan [RPM] */
|
||||
/* VRM west (left) heat sink fan [RPM] */
|
||||
ec_sensor_fan_vrmw_hs,
|
||||
/* Chipset fan [RPM] */
|
||||
ec_sensor_fan_chipset,
|
||||
|
|
@ -157,6 +161,8 @@ enum ec_sensors {
|
|||
#define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb)
|
||||
#define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor)
|
||||
#define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm)
|
||||
#define SENSOR_TEMP_VRME BIT(ec_sensor_temp_vrme)
|
||||
#define SENSOR_TEMP_VRMW BIT(ec_sensor_temp_vrmw)
|
||||
#define SENSOR_IN_CPU_CORE BIT(ec_sensor_in_cpu_core)
|
||||
#define SENSOR_FAN_CPU_OPT BIT(ec_sensor_fan_cpu_opt)
|
||||
#define SENSOR_FAN_VRM_HS BIT(ec_sensor_fan_vrm_hs)
|
||||
|
|
@ -182,6 +188,7 @@ enum board_family {
|
|||
family_amd_500_series,
|
||||
family_amd_600_series,
|
||||
family_amd_800_series,
|
||||
family_amd_trx_50,
|
||||
family_amd_wrx_90,
|
||||
family_intel_200_series,
|
||||
family_intel_300_series,
|
||||
|
|
@ -294,6 +301,19 @@ static const struct ec_sensor_info sensors_family_amd_800[] = {
|
|||
EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
|
||||
};
|
||||
|
||||
static const struct ec_sensor_info sensors_family_amd_trx_50[] = {
|
||||
[ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x30),
|
||||
[ec_sensor_temp_cpu_package] =
|
||||
EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31),
|
||||
[ec_sensor_temp_vrme] = EC_SENSOR("VRM_E", hwmon_temp, 1, 0x00, 0x33),
|
||||
[ec_sensor_temp_vrmw] = EC_SENSOR("VRM_W", hwmon_temp, 1, 0x00, 0x34),
|
||||
[ec_sensor_fan_cpu_opt] = EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
|
||||
[ec_sensor_fan_vrmw_hs] = EC_SENSOR("VRM_E HS", hwmon_fan, 2, 0x00, 0xb4),
|
||||
[ec_sensor_fan_vrme_hs] = EC_SENSOR("VRM_W HS", hwmon_fan, 2, 0x00, 0xbc),
|
||||
[ec_sensor_temp_t_sensor] =
|
||||
EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x01, 0x04),
|
||||
};
|
||||
|
||||
static const struct ec_sensor_info sensors_family_amd_wrx_90[] = {
|
||||
[ec_sensor_temp_cpu_package] =
|
||||
EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31),
|
||||
|
|
@ -533,6 +553,15 @@ static const struct ec_board_info board_info_pro_art_x870E_creator_wifi = {
|
|||
.family = family_amd_800_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_pro_ws_trx50_sage_wifi = {
|
||||
/* Board also has a nct6798 */
|
||||
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_VRME |
|
||||
SENSOR_TEMP_VRMW | SENSOR_FAN_CPU_OPT | SENSOR_FAN_VRME_HS |
|
||||
SENSOR_FAN_VRMW_HS | SENSOR_TEMP_T_SENSOR,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
|
||||
.family = family_amd_trx_50,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_pro_ws_wrx90e_sage_se = {
|
||||
/* Board also has a nct6798 with 7 more fans and temperatures */
|
||||
.sensors = SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_T_SENSOR |
|
||||
|
|
@ -581,6 +610,14 @@ static const struct ec_board_info board_info_strix_b850_i_gaming_wifi = {
|
|||
.family = family_amd_800_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_x470_i_gaming = {
|
||||
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
|
||||
SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
|
||||
SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
|
||||
.family = family_amd_400_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_x570_e_gaming = {
|
||||
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
|
||||
SENSOR_TEMP_T_SENSOR |
|
||||
|
|
@ -628,6 +665,13 @@ static const struct ec_board_info board_info_strix_x670e_i_gaming_wifi = {
|
|||
.family = family_amd_600_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_x870_f_gaming_wifi = {
|
||||
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
|
||||
SENSOR_TEMP_MB | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,
|
||||
.family = family_amd_800_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_x870_i_gaming_wifi = {
|
||||
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
|
||||
SENSOR_TEMP_MB | SENSOR_TEMP_VRM,
|
||||
|
|
@ -643,6 +687,14 @@ static const struct ec_board_info board_info_strix_x870e_e_gaming_wifi = {
|
|||
.family = family_amd_800_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_x870e_h_gaming_wifi7 = {
|
||||
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
|
||||
SENSOR_TEMP_MB | SENSOR_TEMP_VRM | SENSOR_TEMP_T_SENSOR |
|
||||
SENSOR_FAN_CPU_OPT,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,
|
||||
.family = family_amd_800_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_z390_f_gaming = {
|
||||
.sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
|
||||
SENSOR_TEMP_T_SENSOR |
|
||||
|
|
@ -739,6 +791,8 @@ static const struct dmi_system_id dmi_table[] = {
|
|||
&board_info_pro_art_x670E_creator_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI",
|
||||
&board_info_pro_art_x870E_creator_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS TRX50-SAGE WIFI",
|
||||
&board_info_pro_ws_trx50_sage_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS WRX90E-SAGE SE",
|
||||
&board_info_pro_ws_wrx90e_sage_se),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE",
|
||||
|
|
@ -771,6 +825,8 @@ static const struct dmi_system_id dmi_table[] = {
|
|||
&board_info_strix_b650e_i_gaming),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B850-I GAMING WIFI",
|
||||
&board_info_strix_b850_i_gaming_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X470-I GAMING",
|
||||
&board_info_strix_x470_i_gaming),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING",
|
||||
&board_info_strix_x570_e_gaming),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING WIFI II",
|
||||
|
|
@ -783,10 +839,14 @@ static const struct dmi_system_id dmi_table[] = {
|
|||
&board_info_strix_x670e_e_gaming_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X670E-I GAMING WIFI",
|
||||
&board_info_strix_x670e_i_gaming_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870-F GAMING WIFI",
|
||||
&board_info_strix_x870_f_gaming_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870-I GAMING WIFI",
|
||||
&board_info_strix_x870_i_gaming_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-E GAMING WIFI",
|
||||
&board_info_strix_x870e_e_gaming_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-H GAMING WIFI7",
|
||||
&board_info_strix_x870e_h_gaming_wifi7),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING",
|
||||
&board_info_strix_z390_f_gaming),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z490-F GAMING",
|
||||
|
|
@ -1274,6 +1334,9 @@ static int asus_ec_probe(struct platform_device *pdev)
|
|||
case family_amd_800_series:
|
||||
ec_data->sensors_info = sensors_family_amd_800;
|
||||
break;
|
||||
case family_amd_trx_50:
|
||||
ec_data->sensors_info = sensors_family_amd_trx_50;
|
||||
break;
|
||||
case family_amd_wrx_90:
|
||||
ec_data->sensors_info = sensors_family_amd_wrx_90;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -81,10 +81,6 @@ static const char *const rog_ryujin_speed_label[] = {
|
|||
struct rog_ryujin_data {
|
||||
struct hid_device *hdev;
|
||||
struct device *hwmon_dev;
|
||||
/* For locking access to buffer */
|
||||
struct mutex buffer_lock;
|
||||
/* For queueing multiple readers */
|
||||
struct mutex status_report_request_mutex;
|
||||
/* For reinitializing the completions below */
|
||||
spinlock_t status_report_request_lock;
|
||||
struct completion cooler_status_received;
|
||||
|
|
@ -153,18 +149,10 @@ static umode_t rog_ryujin_is_visible(const void *data,
|
|||
/* Writes the command to the device with the rest of the report filled with zeroes */
|
||||
static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->buffer_lock);
|
||||
|
||||
memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00);
|
||||
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
|
||||
|
||||
mutex_unlock(&priv->buffer_lock);
|
||||
return ret;
|
||||
return hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
|
||||
}
|
||||
|
||||
/* Assumes priv->status_report_request_mutex is locked */
|
||||
static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length,
|
||||
struct completion *status_completion)
|
||||
{
|
||||
|
|
@ -196,14 +184,11 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i
|
|||
|
||||
static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
|
||||
{
|
||||
int ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
int ret;
|
||||
|
||||
if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) {
|
||||
/* Data is up to date */
|
||||
goto unlock_and_return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve cooler status */
|
||||
|
|
@ -211,36 +196,30 @@ static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
|
|||
rog_ryujin_execute_cmd(priv, get_cooler_status_cmd, GET_CMD_LENGTH,
|
||||
&priv->cooler_status_received);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
return ret;
|
||||
|
||||
/* Retrieve controller status (speeds) */
|
||||
ret =
|
||||
rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH,
|
||||
&priv->controller_status_received);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
return ret;
|
||||
|
||||
/* Retrieve cooler duty */
|
||||
ret =
|
||||
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
|
||||
&priv->cooler_duty_received);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
return ret;
|
||||
|
||||
/* Retrieve controller duty */
|
||||
ret =
|
||||
rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH,
|
||||
&priv->controller_duty_received);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
|
||||
priv->updated = jiffies;
|
||||
|
||||
unlock_and_return:
|
||||
mutex_unlock(&priv->status_report_request_mutex);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->updated = jiffies;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -303,14 +282,11 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
|
|||
* Retrieve cooler duty since both pump and internal fan are set
|
||||
* together, then write back with one of them modified.
|
||||
*/
|
||||
ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret =
|
||||
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
|
||||
&priv->cooler_duty_received);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
return ret;
|
||||
|
||||
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH);
|
||||
|
||||
|
|
@ -329,11 +305,7 @@ static int rog_ryujin_write_fixed_duty(struct rog_ryujin_data *priv, int channel
|
|||
set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
|
||||
}
|
||||
|
||||
ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
|
||||
unlock_and_return:
|
||||
mutex_unlock(&priv->status_report_request_mutex);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set);
|
||||
} else {
|
||||
/*
|
||||
* Controller fan duty (channel == 2). No need to retrieve current
|
||||
|
|
@ -538,8 +510,6 @@ static int rog_ryujin_probe(struct hid_device *hdev, const struct hid_device_id
|
|||
goto fail_and_close;
|
||||
}
|
||||
|
||||
mutex_init(&priv->status_report_request_mutex);
|
||||
mutex_init(&priv->buffer_lock);
|
||||
spin_lock_init(&priv->status_report_request_lock);
|
||||
init_completion(&priv->cooler_status_received);
|
||||
init_completion(&priv->controller_status_received);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ struct cc2_data {
|
|||
struct completion complete;
|
||||
struct device *hwmon;
|
||||
struct i2c_client *client;
|
||||
struct mutex dev_access_lock; /* device access lock */
|
||||
struct regulator *regulator;
|
||||
const char *name;
|
||||
int irq_ready;
|
||||
|
|
@ -558,8 +557,6 @@ static int cc2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
{
|
||||
struct cc2_data *data = dev_get_drvdata(dev);
|
||||
|
||||
guard(mutex)(&data->dev_access_lock);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
return cc2_measurement(data, type, val);
|
||||
|
|
@ -600,8 +597,6 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
if (val < 0 || val > CC2_RH_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
guard(mutex)(&data->dev_access_lock);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_humidity_min:
|
||||
cmd = CC2_W_ALARM_L_ON;
|
||||
|
|
@ -708,8 +703,6 @@ static int cc2_probe(struct i2c_client *client)
|
|||
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
mutex_init(&data->dev_access_lock);
|
||||
|
||||
data->client = client;
|
||||
|
||||
data->regulator = devm_regulator_get_exclusive(dev, "vdd");
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
#define CTL_GET_TMP 0x11 /*
|
||||
* send: byte 1 is channel, rest zero
|
||||
* rcv: returns temp for channel in centi-degree celsius
|
||||
* in bytes 1 and 2
|
||||
* in bytes 1 and 2 as a two's complement value
|
||||
* returns 0x11 in byte 0 if no sensor is connected
|
||||
*/
|
||||
#define CTL_GET_VOLT 0x12 /*
|
||||
|
|
@ -90,10 +90,10 @@ struct ccp_device {
|
|||
u8 *cmd_buffer;
|
||||
u8 *buffer;
|
||||
int buffer_recv_size; /* number of received bytes in buffer */
|
||||
int target[6];
|
||||
int target[NUM_FANS];
|
||||
DECLARE_BITMAP(temp_cnct, NUM_TEMP_SENSORS);
|
||||
DECLARE_BITMAP(fan_cnct, NUM_FANS);
|
||||
char fan_label[6][LABEL_LENGTH];
|
||||
char fan_label[NUM_FANS][LABEL_LENGTH];
|
||||
u8 firmware_ver[3];
|
||||
u8 bootloader_ver[2];
|
||||
};
|
||||
|
|
@ -258,7 +258,7 @@ static int ccp_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
ret = get_data(ccp, CTL_GET_TMP, channel, true);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret * 10;
|
||||
*val = (s16)ret * 10;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -9,11 +9,9 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
|
|
@ -124,7 +122,6 @@ struct corsairpsu_data {
|
|||
struct device *hwmon_dev;
|
||||
struct dentry *debugfs;
|
||||
struct completion wait_completion;
|
||||
struct mutex lock; /* for locking access to cmd_buffer */
|
||||
u8 *cmd_buffer;
|
||||
char vendor[REPLY_SIZE];
|
||||
char product[REPLY_SIZE];
|
||||
|
|
@ -220,7 +217,6 @@ static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, voi
|
|||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
switch (cmd) {
|
||||
case PSU_CMD_RAIL_VOLTS_HCRIT:
|
||||
case PSU_CMD_RAIL_VOLTS_LCRIT:
|
||||
|
|
@ -230,17 +226,13 @@ static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, voi
|
|||
case PSU_CMD_RAIL_WATTS:
|
||||
ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL);
|
||||
if (ret < 0)
|
||||
goto cmd_fail;
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = corsairpsu_usb_cmd(priv, 3, cmd, 0, data);
|
||||
|
||||
cmd_fail:
|
||||
mutex_unlock(&priv->lock);
|
||||
return ret;
|
||||
return corsairpsu_usb_cmd(priv, 3, cmd, 0, data);
|
||||
}
|
||||
|
||||
static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, long *val)
|
||||
|
|
@ -797,7 +789,6 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
|
|||
|
||||
priv->hdev = hdev;
|
||||
hid_set_drvdata(hdev, priv);
|
||||
mutex_init(&priv->lock);
|
||||
init_completion(&priv->wait_completion);
|
||||
|
||||
hid_device_io_start(hdev);
|
||||
|
|
|
|||
|
|
@ -1533,6 +1533,15 @@ static const struct i8k_fan_control_data i8k_fan_control_data[] __initconst = {
|
|||
};
|
||||
|
||||
static const struct dmi_system_id i8k_whitelist_fan_control[] __initconst = {
|
||||
{
|
||||
.ident = "Dell G5 5505",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G5 5505"),
|
||||
|
||||
},
|
||||
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
|
||||
},
|
||||
{
|
||||
.ident = "Dell Latitude 5480",
|
||||
.matches = {
|
||||
|
|
|
|||
|
|
@ -102,7 +102,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_driver.h>
|
||||
|
|
@ -110,7 +109,6 @@
|
|||
|
||||
struct drivetemp_data {
|
||||
struct list_head list; /* list of instantiated devices */
|
||||
struct mutex lock; /* protect data buffer accesses */
|
||||
struct scsi_device *sdev; /* SCSI device */
|
||||
struct device *dev; /* instantiating device */
|
||||
struct device *hwdev; /* hardware monitoring device */
|
||||
|
|
@ -462,9 +460,7 @@ static int drivetemp_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
case hwmon_temp_input:
|
||||
case hwmon_temp_lowest:
|
||||
case hwmon_temp_highest:
|
||||
mutex_lock(&st->lock);
|
||||
err = st->get_temp(st, attr, val);
|
||||
mutex_unlock(&st->lock);
|
||||
break;
|
||||
case hwmon_temp_lcrit:
|
||||
*val = st->temp_lcrit;
|
||||
|
|
@ -566,7 +562,6 @@ static int drivetemp_add(struct device *dev)
|
|||
|
||||
st->sdev = sdev;
|
||||
st->dev = dev;
|
||||
mutex_init(&st->lock);
|
||||
|
||||
if (drivetemp_identify(st)) {
|
||||
err = -ENODEV;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
|
|
@ -30,7 +29,6 @@ enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 };
|
|||
struct thermal_data {
|
||||
enum emc1403_chip chip;
|
||||
struct regmap *regmap;
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
|
@ -268,8 +266,8 @@ static s8 emc1403_temp_regs_low[][4] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __emc1403_get_temp(struct thermal_data *data, int channel,
|
||||
enum emc1403_reg_map map, long *val)
|
||||
static int emc1403_get_temp(struct thermal_data *data, int channel,
|
||||
enum emc1403_reg_map map, long *val)
|
||||
{
|
||||
unsigned int regvalh;
|
||||
unsigned int regvall = 0;
|
||||
|
|
@ -295,38 +293,23 @@ static int __emc1403_get_temp(struct thermal_data *data, int channel,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int emc1403_get_temp(struct thermal_data *data, int channel,
|
||||
enum emc1403_reg_map map, long *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
ret = __emc1403_get_temp(data, channel, map, val);
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int emc1403_get_hyst(struct thermal_data *data, int channel,
|
||||
enum emc1403_reg_map map, long *val)
|
||||
{
|
||||
int hyst, ret;
|
||||
long limit;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
ret = __emc1403_get_temp(data, channel, map, &limit);
|
||||
ret = emc1403_get_temp(data, channel, map, &limit);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
return ret;
|
||||
ret = regmap_read(data->regmap, 0x21, &hyst);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
return ret;
|
||||
if (map == temp_min)
|
||||
*val = limit + hyst * 1000;
|
||||
else
|
||||
*val = limit - hyst * 1000;
|
||||
unlock:
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emc1403_temp_read(struct thermal_data *data, u32 attr, int channel, long *val)
|
||||
|
|
@ -451,20 +434,16 @@ static int emc1403_set_hyst(struct thermal_data *data, long val)
|
|||
else
|
||||
val = clamp_val(val, 0, 255000);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
ret = __emc1403_get_temp(data, 0, temp_crit, &limit);
|
||||
ret = emc1403_get_temp(data, 0, temp_crit, &limit);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
hyst = limit - val;
|
||||
if (data->chip == emc1428)
|
||||
hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 127);
|
||||
else
|
||||
hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255);
|
||||
ret = regmap_write(data->regmap, 0x21, hyst);
|
||||
unlock:
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
return regmap_write(data->regmap, 0x21, hyst);
|
||||
}
|
||||
|
||||
static int emc1403_set_temp(struct thermal_data *data, int channel,
|
||||
|
|
@ -478,7 +457,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel,
|
|||
regh = emc1403_temp_regs[channel][map];
|
||||
regl = emc1403_temp_regs_low[channel][map];
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
if (regl >= 0) {
|
||||
if (data->chip == emc1428)
|
||||
val = clamp_val(val, -128000, 127875);
|
||||
|
|
@ -487,7 +465,7 @@ static int emc1403_set_temp(struct thermal_data *data, int channel,
|
|||
regval = DIV_ROUND_CLOSEST(val, 125);
|
||||
ret = regmap_write(data->regmap, regh, (regval >> 3) & 0xff);
|
||||
if (ret < 0)
|
||||
goto unlock;
|
||||
return ret;
|
||||
ret = regmap_write(data->regmap, regl, (regval & 0x07) << 5);
|
||||
} else {
|
||||
if (data->chip == emc1428)
|
||||
|
|
@ -497,8 +475,6 @@ static int emc1403_set_temp(struct thermal_data *data, int channel,
|
|||
regval = DIV_ROUND_CLOSEST(val, 1000);
|
||||
ret = regmap_write(data->regmap, regh, regval);
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&data->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -695,8 +671,6 @@ static int emc1403_probe(struct i2c_client *client)
|
|||
if (IS_ERR(data->regmap))
|
||||
return PTR_ERR(data->regmap);
|
||||
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
|
||||
client->name, data,
|
||||
&emc1403_chip_info,
|
||||
|
|
|
|||
|
|
@ -277,8 +277,10 @@ fan1_input_show(struct device *dev, struct device_attribute *da, char *buf)
|
|||
{
|
||||
struct emc2103_data *data = emc2103_update_device(dev);
|
||||
int rpm = 0;
|
||||
mutex_lock(&data->update_lock);
|
||||
if (data->fan_tach != 0)
|
||||
rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_tach;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
|
||||
|
|
@ -363,10 +365,12 @@ fan1_target_show(struct device *dev, struct device_attribute *da, char *buf)
|
|||
struct emc2103_data *data = emc2103_update_device(dev);
|
||||
int rpm = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* high byte of 0xff indicates disabled so return 0 */
|
||||
if ((data->fan_target != 0) && ((data->fan_target & 0x1fe0) != 0x1fe0))
|
||||
rpm = (FAN_RPM_FACTOR * data->fan_multiplier)
|
||||
/ data->fan_target;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
|
|
@ -62,10 +61,6 @@ enum WATCHDOG_RESOLUTION {
|
|||
|
||||
struct fts_data {
|
||||
struct i2c_client *client;
|
||||
/* update sensor data lock */
|
||||
struct mutex update_lock;
|
||||
/* read/write register lock */
|
||||
struct mutex access_lock;
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
struct watchdog_device wdd;
|
||||
enum WATCHDOG_RESOLUTION resolution;
|
||||
|
|
@ -98,21 +93,15 @@ static int fts_read_byte(struct i2c_client *client, unsigned short reg)
|
|||
{
|
||||
int ret;
|
||||
unsigned char page = reg >> 8;
|
||||
struct fts_data *data = dev_get_drvdata(&client->dev);
|
||||
|
||||
mutex_lock(&data->access_lock);
|
||||
|
||||
dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page);
|
||||
ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
|
||||
reg &= 0xFF;
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
dev_dbg(&client->dev, "read - reg: 0x%.02x: val: 0x%.02x\n", reg, ret);
|
||||
|
||||
error:
|
||||
mutex_unlock(&data->access_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -121,22 +110,16 @@ static int fts_write_byte(struct i2c_client *client, unsigned short reg,
|
|||
{
|
||||
int ret;
|
||||
unsigned char page = reg >> 8;
|
||||
struct fts_data *data = dev_get_drvdata(&client->dev);
|
||||
|
||||
mutex_lock(&data->access_lock);
|
||||
|
||||
dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page);
|
||||
ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
|
||||
reg &= 0xFF;
|
||||
dev_dbg(&client->dev,
|
||||
"write - reg: 0x%.02x: val: 0x%.02x\n", reg, value);
|
||||
ret = i2c_smbus_write_byte_data(client, reg, value);
|
||||
|
||||
error:
|
||||
mutex_unlock(&data->access_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -145,44 +128,40 @@ static int fts_write_byte(struct i2c_client *client, unsigned short reg,
|
|||
/*****************************************************************************/
|
||||
static int fts_update_device(struct fts_data *data)
|
||||
{
|
||||
int i;
|
||||
int err = 0;
|
||||
int i, err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
if (!time_after(jiffies, data->last_updated + 2 * HZ) && data->valid)
|
||||
goto exit;
|
||||
return 0;
|
||||
|
||||
err = fts_read_byte(data->client, FTS_DEVICE_STATUS_REG);
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
|
||||
data->valid = !!(err & 0x02); /* Data not ready yet */
|
||||
if (unlikely(!data->valid)) {
|
||||
err = -EAGAIN;
|
||||
goto exit;
|
||||
}
|
||||
if (unlikely(!data->valid))
|
||||
return -EAGAIN;
|
||||
|
||||
err = fts_read_byte(data->client, FTS_FAN_PRESENT_REG);
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
data->fan_present = err;
|
||||
|
||||
err = fts_read_byte(data->client, FTS_FAN_EVENT_REG);
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
data->fan_alarm = err;
|
||||
|
||||
for (i = 0; i < FTS_NO_FAN_SENSORS; i++) {
|
||||
if (data->fan_present & BIT(i)) {
|
||||
err = fts_read_byte(data->client, FTS_REG_FAN_INPUT(i));
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
data->fan_input[i] = err;
|
||||
|
||||
err = fts_read_byte(data->client,
|
||||
FTS_REG_FAN_SOURCE(i));
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
data->fan_source[i] = err;
|
||||
} else {
|
||||
data->fan_input[i] = 0;
|
||||
|
|
@ -192,27 +171,24 @@ static int fts_update_device(struct fts_data *data)
|
|||
|
||||
err = fts_read_byte(data->client, FTS_SENSOR_EVENT_REG);
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
data->temp_alarm = err;
|
||||
|
||||
for (i = 0; i < FTS_NO_TEMP_SENSORS; i++) {
|
||||
err = fts_read_byte(data->client, FTS_REG_TEMP_INPUT(i));
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
data->temp_input[i] = err;
|
||||
}
|
||||
|
||||
for (i = 0; i < FTS_NO_VOLT_SENSORS; i++) {
|
||||
err = fts_read_byte(data->client, FTS_REG_VOLT(i));
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
return err;
|
||||
data->volt[i] = err;
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
err = 0;
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -470,18 +446,14 @@ static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
if (val)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(channel));
|
||||
if (ret >= 0)
|
||||
ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel),
|
||||
ret | 0x1);
|
||||
if (ret >= 0)
|
||||
data->valid = false;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel),
|
||||
ret | 0x1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->valid = false;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -493,18 +465,14 @@ static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
if (val)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(channel));
|
||||
if (ret >= 0)
|
||||
ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel),
|
||||
ret | 0x1);
|
||||
if (ret >= 0)
|
||||
data->valid = false;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel),
|
||||
ret | 0x1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
data->valid = false;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -648,8 +616,6 @@ static int fts_probe(struct i2c_client *client)
|
|||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&data->update_lock);
|
||||
mutex_init(&data->access_lock);
|
||||
data->client = client;
|
||||
dev_set_drvdata(&client->dev, data);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,6 @@
|
|||
static char *gpd_fan_board = "";
|
||||
module_param(gpd_fan_board, charp, 0444);
|
||||
|
||||
// EC read/write locker, protecting a sequence of EC operations
|
||||
static DEFINE_MUTEX(gpd_fan_sequence_lock);
|
||||
|
||||
enum gpd_board {
|
||||
win_mini,
|
||||
win4_6800u,
|
||||
|
|
@ -481,87 +478,60 @@ static int gpd_fan_hwmon_read(__always_unused struct device *dev,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&gpd_fan_sequence_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (type == hwmon_fan) {
|
||||
if (attr == hwmon_fan_input) {
|
||||
ret = gpd_read_rpm();
|
||||
|
||||
if (ret < 0)
|
||||
goto OUT;
|
||||
return ret;
|
||||
|
||||
*val = ret;
|
||||
ret = 0;
|
||||
goto OUT;
|
||||
return 0;
|
||||
}
|
||||
} else if (type == hwmon_pwm) {
|
||||
switch (attr) {
|
||||
case hwmon_pwm_enable:
|
||||
*val = gpd_driver_priv.pwm_enable;
|
||||
ret = 0;
|
||||
goto OUT;
|
||||
return 0;
|
||||
case hwmon_pwm_input:
|
||||
ret = gpd_read_pwm();
|
||||
|
||||
if (ret < 0)
|
||||
goto OUT;
|
||||
return ret;
|
||||
|
||||
*val = ret;
|
||||
ret = 0;
|
||||
goto OUT;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret = -EOPNOTSUPP;
|
||||
|
||||
OUT:
|
||||
mutex_unlock(&gpd_fan_sequence_lock);
|
||||
return ret;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int gpd_fan_hwmon_write(__always_unused struct device *dev,
|
||||
enum hwmon_sensor_types type, u32 attr,
|
||||
__always_unused int channel, long val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mutex_lock_interruptible(&gpd_fan_sequence_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (type == hwmon_pwm) {
|
||||
switch (attr) {
|
||||
case hwmon_pwm_enable:
|
||||
if (!in_range(val, 0, 3)) {
|
||||
ret = -EINVAL;
|
||||
goto OUT;
|
||||
}
|
||||
if (!in_range(val, 0, 3))
|
||||
return -EINVAL;
|
||||
|
||||
gpd_driver_priv.pwm_enable = val;
|
||||
|
||||
gpd_set_pwm_enable(gpd_driver_priv.pwm_enable);
|
||||
ret = 0;
|
||||
goto OUT;
|
||||
return 0;
|
||||
case hwmon_pwm_input:
|
||||
if (!in_range(val, 0, 256)) {
|
||||
ret = -ERANGE;
|
||||
goto OUT;
|
||||
}
|
||||
if (!in_range(val, 0, 256))
|
||||
return -EINVAL;
|
||||
|
||||
gpd_driver_priv.pwm_value = val;
|
||||
|
||||
ret = gpd_write_pwm(val);
|
||||
goto OUT;
|
||||
return gpd_write_pwm(val);
|
||||
}
|
||||
}
|
||||
|
||||
ret = -EOPNOTSUPP;
|
||||
|
||||
OUT:
|
||||
mutex_unlock(&gpd_fan_sequence_lock);
|
||||
return ret;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct hwmon_ops gpd_fan_ops = {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
|
||||
struct hs3001_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex i2c_lock; /* lock for sending i2c commands */
|
||||
u32 wait_time; /* in us */
|
||||
int temperature; /* in milli degree */
|
||||
u32 humidity; /* in milli % */
|
||||
|
|
@ -112,12 +111,9 @@ static int hs3001_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->i2c_lock);
|
||||
ret = i2c_master_send(client, NULL, 0);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->i2c_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sensor needs some time to process measurement depending on
|
||||
|
|
@ -126,8 +122,6 @@ static int hs3001_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
fsleep(data->wait_time);
|
||||
|
||||
ret = hs3001_data_fetch_command(client, data);
|
||||
mutex_unlock(&data->i2c_lock);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -211,8 +205,6 @@ static int hs3001_probe(struct i2c_client *client)
|
|||
data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION +
|
||||
HS3001_14BIT_RESOLUTION);
|
||||
|
||||
mutex_init(&data->i2c_lock);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev,
|
||||
client->name,
|
||||
data,
|
||||
|
|
|
|||
|
|
@ -8,13 +8,10 @@
|
|||
#include <linux/bitops.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
/* Register definitions from datasheet */
|
||||
#define REG_TSTHRCATA 0xE2
|
||||
|
|
|
|||
|
|
@ -117,7 +117,6 @@ struct ina238_config {
|
|||
struct ina238_data {
|
||||
const struct ina238_config *config;
|
||||
struct i2c_client *client;
|
||||
struct mutex config_lock;
|
||||
struct regmap *regmap;
|
||||
u32 rshunt;
|
||||
int gain;
|
||||
|
|
@ -607,31 +606,18 @@ static int ina238_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
static int ina238_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
struct ina238_data *data = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->config_lock);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_in:
|
||||
err = ina238_write_in(dev, attr, channel, val);
|
||||
break;
|
||||
return ina238_write_in(dev, attr, channel, val);
|
||||
case hwmon_curr:
|
||||
err = ina238_write_curr(dev, attr, val);
|
||||
break;
|
||||
return ina238_write_curr(dev, attr, val);
|
||||
case hwmon_power:
|
||||
err = ina238_write_power_max(dev, val);
|
||||
break;
|
||||
return ina238_write_power_max(dev, val);
|
||||
case hwmon_temp:
|
||||
err = ina238_write_temp_max(dev, val);
|
||||
break;
|
||||
return ina238_write_temp_max(dev, val);
|
||||
default:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->config_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static umode_t ina238_is_visible(const void *drvdata,
|
||||
|
|
@ -757,8 +743,6 @@ static int ina238_probe(struct i2c_client *client)
|
|||
/* set the device type */
|
||||
data->config = &ina238_config[chip];
|
||||
|
||||
mutex_init(&data->config_lock);
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, &ina238_regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
dev_err(dev, "failed to allocate register map\n");
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ struct ina2xx_data {
|
|||
long rshunt;
|
||||
long current_lsb_uA;
|
||||
long power_lsb_uW;
|
||||
struct mutex config_lock;
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
|
@ -390,22 +389,19 @@ static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg,
|
|||
int regval;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->config_lock);
|
||||
ret = regmap_read(regmap, INA226_MASK_ENABLE, ®val);
|
||||
if (ret)
|
||||
goto abort;
|
||||
return ret;
|
||||
|
||||
if (regval & mask) {
|
||||
ret = regmap_read(regmap, INA226_ALERT_LIMIT, ®val);
|
||||
if (ret)
|
||||
goto abort;
|
||||
return ret;
|
||||
*val = ina2xx_get_value(data, reg, regval);
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
abort:
|
||||
mutex_unlock(&data->config_lock);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, long val)
|
||||
|
|
@ -421,23 +417,20 @@ static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg,
|
|||
* due to register write sequence. Then, only enable the alert
|
||||
* if the value is non-zero.
|
||||
*/
|
||||
mutex_lock(&data->config_lock);
|
||||
ret = regmap_update_bits(regmap, INA226_MASK_ENABLE,
|
||||
INA226_ALERT_CONFIG_MASK, 0);
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(regmap, INA226_ALERT_LIMIT,
|
||||
ina226_alert_to_reg(data, reg, val));
|
||||
if (ret < 0)
|
||||
goto abort;
|
||||
return ret;
|
||||
|
||||
if (val)
|
||||
ret = regmap_update_bits(regmap, INA226_MASK_ENABLE,
|
||||
INA226_ALERT_CONFIG_MASK, mask);
|
||||
abort:
|
||||
mutex_unlock(&data->config_lock);
|
||||
return ret;
|
||||
return regmap_update_bits(regmap, INA226_MASK_ENABLE,
|
||||
INA226_ALERT_CONFIG_MASK, mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ina2xx_chip_read(struct device *dev, u32 attr, long *val)
|
||||
|
|
@ -859,9 +852,9 @@ static ssize_t shunt_resistor_store(struct device *dev,
|
|||
if (status < 0)
|
||||
return status;
|
||||
|
||||
mutex_lock(&data->config_lock);
|
||||
hwmon_lock(dev);
|
||||
status = ina2xx_set_shunt(data, val);
|
||||
mutex_unlock(&data->config_lock);
|
||||
hwmon_unlock(dev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
return count;
|
||||
|
|
@ -951,7 +944,6 @@ static int ina2xx_probe(struct i2c_client *client)
|
|||
data->client = client;
|
||||
data->config = &ina2xx_config[chip];
|
||||
data->chip = chip;
|
||||
mutex_init(&data->config_lock);
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
@ -115,7 +114,6 @@ struct ina3221_input {
|
|||
* @regmap: Register map of the device
|
||||
* @fields: Register fields of the device
|
||||
* @inputs: Array of channel input source specific structures
|
||||
* @lock: mutex lock to serialize sysfs attribute accesses
|
||||
* @reg_config: Register value of INA3221_CONFIG
|
||||
* @summation_shunt_resistor: equivalent shunt resistor value for summation
|
||||
* @summation_channel_control: Value written to SCC field in INA3221_MASK_ENABLE
|
||||
|
|
@ -126,7 +124,6 @@ struct ina3221_data {
|
|||
struct regmap *regmap;
|
||||
struct regmap_field *fields[F_MAX_FIELDS];
|
||||
struct ina3221_input inputs[INA3221_NUM_CHANNELS];
|
||||
struct mutex lock;
|
||||
u32 reg_config;
|
||||
int summation_shunt_resistor;
|
||||
u32 summation_channel_control;
|
||||
|
|
@ -530,11 +527,8 @@ static int ina3221_write_enable(struct device *dev, int channel, bool enable)
|
|||
static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct ina3221_data *ina = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ina->lock);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_chip:
|
||||
ret = ina3221_read_chip(dev, attr, val);
|
||||
|
|
@ -550,20 +544,14 @@ static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&ina->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ina3221_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
struct ina3221_data *ina = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ina->lock);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_chip:
|
||||
ret = ina3221_write_chip(dev, attr, val);
|
||||
|
|
@ -579,9 +567,6 @@ static int ina3221_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&ina->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -886,7 +871,6 @@ static int ina3221_probe(struct i2c_client *client)
|
|||
}
|
||||
|
||||
ina->pm_dev = dev;
|
||||
mutex_init(&ina->lock);
|
||||
dev_set_drvdata(dev, ina);
|
||||
|
||||
/* Enable PM runtime -- status is suspended by default */
|
||||
|
|
@ -925,7 +909,6 @@ static int ina3221_probe(struct i2c_client *client)
|
|||
/* pm_runtime_put_noidle() will decrease the PM refcount until 0 */
|
||||
for (i = 0; i < INA3221_NUM_CHANNELS; i++)
|
||||
pm_runtime_put_noidle(ina->pm_dev);
|
||||
mutex_destroy(&ina->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -941,8 +924,6 @@ static void ina3221_remove(struct i2c_client *client)
|
|||
/* pm_runtime_put_noidle() will decrease the PM refcount until 0 */
|
||||
for (i = 0; i < INA3221_NUM_CHANNELS; i++)
|
||||
pm_runtime_put_noidle(ina->pm_dev);
|
||||
|
||||
mutex_destroy(&ina->lock);
|
||||
}
|
||||
|
||||
static int ina3221_suspend(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
|
|
@ -179,7 +178,6 @@ static struct jc42_chips jc42_chips[] = {
|
|||
|
||||
/* Each client has this additional data */
|
||||
struct jc42_data {
|
||||
struct mutex update_lock; /* protect register access */
|
||||
struct regmap *regmap;
|
||||
bool extended; /* true if extended range supported */
|
||||
bool valid;
|
||||
|
|
@ -216,8 +214,6 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
unsigned int regval;
|
||||
int ret, temp, hyst;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val);
|
||||
|
|
@ -295,8 +291,6 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -308,8 +302,6 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
int diff, hyst;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_min:
|
||||
ret = regmap_write(data->regmap, JC42_REG_TEMP_LOWER,
|
||||
|
|
@ -356,8 +348,6 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -498,7 +488,6 @@ static int jc42_probe(struct i2c_client *client)
|
|||
return PTR_ERR(data->regmap);
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
ret = regmap_read(data->regmap, JC42_REG_CAP, &cap);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ static bool force;
|
|||
module_param(force, bool, 0444);
|
||||
MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
|
||||
|
||||
/* Provide lock for writing to NB_SMU_IND_ADDR */
|
||||
static DEFINE_MUTEX(nb_smu_ind_mutex);
|
||||
|
||||
#ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3
|
||||
#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3
|
||||
#endif
|
||||
|
|
@ -84,6 +81,12 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
|
|||
*/
|
||||
#define AMD_I3255_STR "3255"
|
||||
|
||||
/*
|
||||
* PCI Device IDs for AMD's Family 17h-based SOCs.
|
||||
* Defining locally as IDs are not shared.
|
||||
*/
|
||||
#define PCI_DEVICE_ID_AMD_17H_M90H_DF_F3 0x1663
|
||||
|
||||
/*
|
||||
* PCI Device IDs for AMD's Family 1Ah-based SOCs.
|
||||
* Defining locally as IDs are not shared.
|
||||
|
|
@ -137,12 +140,10 @@ static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
|
|||
static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
|
||||
unsigned int base, int offset, u32 *val)
|
||||
{
|
||||
mutex_lock(&nb_smu_ind_mutex);
|
||||
pci_bus_write_config_dword(pdev->bus, devfn,
|
||||
base, offset);
|
||||
pci_bus_read_config_dword(pdev->bus, devfn,
|
||||
base + 4, val);
|
||||
mutex_unlock(&nb_smu_ind_mutex);
|
||||
}
|
||||
|
||||
static void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval)
|
||||
|
|
@ -553,6 +554,7 @@ static const struct pci_device_id k10temp_id_table[] = {
|
|||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M40H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M90H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_MA0H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) },
|
||||
|
|
|
|||
|
|
@ -843,17 +843,18 @@ static int __init lm78_isa_found(unsigned short address)
|
|||
}
|
||||
}
|
||||
|
||||
#define REALLY_SLOW_IO
|
||||
/*
|
||||
* We need the timeouts for at least some LM78-like
|
||||
* chips. But only if we read 'undefined' registers.
|
||||
* There used to be a "#define REALLY_SLOW_IO" to enforce that, but
|
||||
* this has been without any effect since more than a decade, so it
|
||||
* has been dropped.
|
||||
*/
|
||||
val = inb_p(address + 1);
|
||||
if (inb_p(address + 2) != val
|
||||
|| inb_p(address + 3) != val
|
||||
|| inb_p(address + 7) != val)
|
||||
goto release;
|
||||
#undef REALLY_SLOW_IO
|
||||
|
||||
/*
|
||||
* We should be able to change the 7 LSB of the address port. The
|
||||
|
|
|
|||
|
|
@ -116,8 +116,14 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
|
|||
(((val) < 0 ? (val) - 500 : \
|
||||
(val) + 500) / 1000))
|
||||
|
||||
#define FAN_FROM_REG(reg, div) ((reg) == 255 || (reg) == 0 ? 0 : \
|
||||
(1350000 + (reg)*(div) / 2) / ((reg) * (div)))
|
||||
static int fan_from_reg(int reg, int div)
|
||||
{
|
||||
if (reg == 255 || reg == 0)
|
||||
return 0;
|
||||
|
||||
return (1350000 + reg * div / 2) / (reg * div);
|
||||
}
|
||||
|
||||
#define FAN_TO_REG(val, div) ((val) * (div) * 255 <= 1350000 ? 255 : \
|
||||
(1350000 + (val)*(div) / 2) / ((val) * (div)))
|
||||
|
||||
|
|
@ -465,7 +471,7 @@ static ssize_t fan_input_show(struct device *dev,
|
|||
struct lm87_data *data = lm87_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
|
||||
return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr],
|
||||
FAN_DIV_FROM_REG(data->fan_div[nr])));
|
||||
}
|
||||
|
||||
|
|
@ -475,7 +481,7 @@ static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr,
|
|||
struct lm87_data *data = lm87_update_device(dev);
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
|
||||
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
|
||||
return sprintf(buf, "%d\n", fan_from_reg(data->fan_min[nr],
|
||||
FAN_DIV_FROM_REG(data->fan_div[nr])));
|
||||
}
|
||||
|
||||
|
|
@ -534,7 +540,7 @@ static ssize_t fan_div_store(struct device *dev,
|
|||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
min = FAN_FROM_REG(data->fan_min[nr],
|
||||
min = fan_from_reg(data->fan_min[nr],
|
||||
FAN_DIV_FROM_REG(data->fan_div[nr]));
|
||||
|
||||
switch (val) {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@
|
|||
#include <linux/hwmon.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -735,7 +734,6 @@ struct lm90_data {
|
|||
struct hwmon_channel_info temp_info;
|
||||
const struct hwmon_channel_info *info[3];
|
||||
struct hwmon_chip_info chip;
|
||||
struct mutex update_lock;
|
||||
struct delayed_work alert_work;
|
||||
struct work_struct report_work;
|
||||
bool valid; /* true if register values are valid */
|
||||
|
|
@ -1226,9 +1224,9 @@ static int lm90_update_alarms(struct lm90_data *data, bool force)
|
|||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
hwmon_lock(data->hwmon_dev);
|
||||
err = lm90_update_alarms_locked(data, force);
|
||||
mutex_unlock(&data->update_lock);
|
||||
hwmon_unlock(data->hwmon_dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1519,9 +1517,7 @@ static int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val)
|
|||
int err;
|
||||
u16 bit;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = lm90_update_device(dev);
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -1590,11 +1586,9 @@ static int lm90_temp_write(struct device *dev, u32 attr, int channel, long val)
|
|||
struct lm90_data *data = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
err = lm90_update_device(dev);
|
||||
if (err)
|
||||
goto error;
|
||||
return err;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_min:
|
||||
|
|
@ -1624,9 +1618,6 @@ static int lm90_temp_write(struct device *dev, u32 attr, int channel, long val)
|
|||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
error:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1662,9 +1653,7 @@ static int lm90_chip_read(struct device *dev, u32 attr, int channel, long *val)
|
|||
struct lm90_data *data = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = lm90_update_device(dev);
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -1710,11 +1699,9 @@ static int lm90_chip_write(struct device *dev, u32 attr, int channel, long val)
|
|||
struct i2c_client *client = data->client;
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
err = lm90_update_device(dev);
|
||||
if (err)
|
||||
goto error;
|
||||
return err;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_chip_update_interval:
|
||||
|
|
@ -1728,9 +1715,6 @@ static int lm90_chip_write(struct device *dev, u32 attr, int channel, long val)
|
|||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
error:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -2793,7 +2777,6 @@ static int lm90_probe(struct i2c_client *client)
|
|||
|
||||
data->client = client;
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
INIT_DELAYED_WORK(&data->alert_work, lm90_alert_work);
|
||||
INIT_WORK(&data->report_work, lm90_report_alarms);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
@ -78,7 +77,6 @@ static inline u8 ALARMS_FROM_REG(s16 reg)
|
|||
/* Client data (each client gets its own) */
|
||||
struct lm92_data {
|
||||
struct regmap *regmap;
|
||||
struct mutex update_lock;
|
||||
int resolution;
|
||||
};
|
||||
|
||||
|
|
@ -199,15 +197,11 @@ static int lm92_temp_write(struct lm92_data *data, u32 attr, long val)
|
|||
break;
|
||||
case hwmon_temp_crit_hyst:
|
||||
val = clamp_val(val, -120000, 220000);
|
||||
mutex_lock(&data->update_lock);
|
||||
err = regmap_read(regmap, LM92_REG_TEMP_CRIT, &temp);
|
||||
if (err)
|
||||
goto unlock;
|
||||
return err;
|
||||
val = TEMP_TO_REG(TEMP_FROM_REG(temp) - val, data->resolution);
|
||||
err = regmap_write(regmap, LM92_REG_TEMP_HYST, val);
|
||||
unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return err;
|
||||
return regmap_write(regmap, LM92_REG_TEMP_HYST, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -396,7 +390,6 @@ static int lm92_probe(struct i2c_client *client)
|
|||
|
||||
data->regmap = regmap;
|
||||
data->resolution = (unsigned long)i2c_get_match_data(client);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the chipset */
|
||||
err = lm92_init_client(regmap);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
|
|
@ -54,7 +53,6 @@ static const unsigned short normal_i2c[] = {
|
|||
/* Client data (each client gets its own) */
|
||||
struct lm95234_data {
|
||||
struct regmap *regmap;
|
||||
struct mutex update_lock;
|
||||
enum chips type;
|
||||
};
|
||||
|
||||
|
|
@ -107,19 +105,14 @@ static ssize_t lm95234_hyst_set(struct lm95234_data *data, long val)
|
|||
u32 tcrit;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
ret = regmap_read(data->regmap, LM95234_REG_TCRIT1(0), &tcrit);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
val = DIV_ROUND_CLOSEST(clamp_val(val, -255000, 255000), 1000);
|
||||
val = clamp_val((int)tcrit - val, 0, 31);
|
||||
|
||||
ret = regmap_write(data->regmap, LM95234_REG_TCRIT_HYST, val);
|
||||
unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
return regmap_write(data->regmap, LM95234_REG_TCRIT_HYST, val);
|
||||
}
|
||||
|
||||
static int lm95234_crit_reg(int channel)
|
||||
|
|
@ -526,7 +519,6 @@ static int lm95234_probe(struct i2c_client *client)
|
|||
return PTR_ERR(regmap);
|
||||
|
||||
data->regmap = regmap;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the LM95234 chip */
|
||||
err = lm95234_init_client(dev, regmap);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define DEVNAME "lm95241"
|
||||
|
|
@ -75,7 +74,6 @@ static const u8 lm95241_reg_address[] = {
|
|||
/* Client data (each client gets its own) */
|
||||
struct lm95241_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
unsigned long interval; /* in milli-seconds */
|
||||
bool valid; /* false until following fields are valid */
|
||||
|
|
@ -102,8 +100,6 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
|
|||
struct lm95241_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated
|
||||
+ msecs_to_jiffies(data->interval)) ||
|
||||
!data->valid) {
|
||||
|
|
@ -120,9 +116,6 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
|
|||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
@ -204,8 +197,6 @@ static int lm95241_write_chip(struct device *dev, u32 attr, int channel,
|
|||
u8 config;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_chip_update_interval:
|
||||
config = data->config & ~CFG_CRMASK;
|
||||
|
|
@ -231,7 +222,6 @@ static int lm95241_write_chip(struct device *dev, u32 attr, int channel,
|
|||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -242,8 +232,6 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel,
|
|||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_min:
|
||||
if (channel == 1) {
|
||||
|
|
@ -313,9 +301,6 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel,
|
|||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -443,7 +428,6 @@ static int lm95241_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the LM95241 chip */
|
||||
lm95241_init_client(client, data);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/hwmon.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
@ -86,7 +85,6 @@ static const unsigned short normal_i2c[] = {
|
|||
/* Client data (each client gets its own) */
|
||||
struct lm95245_data {
|
||||
struct regmap *regmap;
|
||||
struct mutex update_lock;
|
||||
int interval; /* in msecs */
|
||||
};
|
||||
|
||||
|
|
@ -279,20 +277,16 @@ static int lm95245_write_temp(struct device *dev, u32 attr, int channel,
|
|||
ret = regmap_write(regmap, reg, val);
|
||||
return ret;
|
||||
case hwmon_temp_crit_hyst:
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = regmap_read(regmap, LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT,
|
||||
®val);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
/* Clamp to reasonable range to prevent overflow */
|
||||
val = clamp_val(val, -1000000, 1000000);
|
||||
val = regval - val / 1000;
|
||||
val = clamp_val(val, 0, 31);
|
||||
ret = regmap_write(regmap, LM95245_REG_RW_COMMON_HYSTERESIS,
|
||||
val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
case hwmon_temp_offset:
|
||||
val = clamp_val(val, -128000, 127875);
|
||||
|
|
@ -332,14 +326,10 @@ static int lm95245_write_chip(struct device *dev, u32 attr, int channel,
|
|||
long val)
|
||||
{
|
||||
struct lm95245_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_chip_update_interval:
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = lm95245_set_conversion_rate(data, val);
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
return lm95245_set_conversion_rate(data, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -542,8 +532,6 @@ static int lm95245_probe(struct i2c_client *client)
|
|||
if (IS_ERR(data->regmap))
|
||||
return PTR_ERR(data->regmap);
|
||||
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the LM95245 chip */
|
||||
ret = lm95245_init_client(data);
|
||||
if (ret < 0)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/mfd/lochnagar.h>
|
||||
#include <linux/mfd/lochnagar2_regs.h>
|
||||
|
|
@ -42,9 +41,6 @@ struct lochnagar_hwmon {
|
|||
struct regmap *regmap;
|
||||
|
||||
long power_nsamples[ARRAY_SIZE(lochnagar_chan_names)];
|
||||
|
||||
/* Lock to ensure only a single sensor is read at a time */
|
||||
struct mutex sensor_lock;
|
||||
};
|
||||
|
||||
enum lochnagar_measure_mode {
|
||||
|
|
@ -178,26 +174,20 @@ static int read_sensor(struct device *dev, int chan,
|
|||
u32 data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&priv->sensor_lock);
|
||||
|
||||
ret = do_measurement(regmap, chan, mode, nsamples);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to perform measurement: %d\n", ret);
|
||||
goto error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_data(regmap, chan, &data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to read measurement: %d\n", ret);
|
||||
goto error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = float_to_long(data, precision);
|
||||
|
||||
error:
|
||||
mutex_unlock(&priv->sensor_lock);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int read_power(struct device *dev, int chan, long *val)
|
||||
|
|
@ -378,8 +368,6 @@ static int lochnagar_hwmon_probe(struct platform_device *pdev)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&priv->sensor_lock);
|
||||
|
||||
priv->regmap = dev_get_regmap(dev->parent, NULL);
|
||||
if (!priv->regmap) {
|
||||
dev_err(dev, "No register map found\n");
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
@ -120,12 +120,6 @@
|
|||
struct ltc2947_data {
|
||||
struct regmap *map;
|
||||
struct device *dev;
|
||||
/*
|
||||
* The mutex is needed because the device has 2 memory pages. When
|
||||
* reading/writing the correct page needs to be set so that, the
|
||||
* complete sequence select_page->read/write needs to be protected.
|
||||
*/
|
||||
struct mutex lock;
|
||||
u32 lsb_energy;
|
||||
bool gpio_out;
|
||||
};
|
||||
|
|
@ -181,13 +175,9 @@ static int ltc2947_val_read(struct ltc2947_data *st, const u8 reg,
|
|||
int ret;
|
||||
u64 __val = 0;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page);
|
||||
if (ret) {
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(st->dev, "Read val, reg:%02X, p:%d sz:%zu\n", reg, page,
|
||||
size);
|
||||
|
|
@ -207,8 +197,6 @@ static int ltc2947_val_read(struct ltc2947_data *st, const u8 reg,
|
|||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -242,13 +230,10 @@ static int ltc2947_val_write(struct ltc2947_data *st, const u8 reg,
|
|||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
/* set device on correct page */
|
||||
ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page);
|
||||
if (ret) {
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(st->dev, "Write val, r:%02X, p:%d, sz:%zu, val:%016llX\n",
|
||||
reg, page, size, val);
|
||||
|
|
@ -265,8 +250,6 @@ static int ltc2947_val_write(struct ltc2947_data *st, const u8 reg,
|
|||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -295,11 +278,9 @@ static int ltc2947_alarm_read(struct ltc2947_data *st, const u8 reg,
|
|||
|
||||
memset(alarms, 0, sizeof(alarms));
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, LTC2947_PAGE0);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
dev_dbg(st->dev, "Read alarm, reg:%02X, mask:%02X\n", reg, mask);
|
||||
/*
|
||||
|
|
@ -310,31 +291,11 @@ static int ltc2947_alarm_read(struct ltc2947_data *st, const u8 reg,
|
|||
ret = regmap_bulk_read(st->map, LTC2947_REG_STATUS, alarms,
|
||||
sizeof(alarms));
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
/* get the alarm */
|
||||
*val = !!(alarms[offset] & mask);
|
||||
unlock:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ltc2947_show_value(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct ltc2947_data *st = dev_get_drvdata(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
int ret;
|
||||
s64 val = 0;
|
||||
|
||||
ret = ltc2947_val_read(st, attr->index, LTC2947_PAGE0, 6, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* value in microJoule. st->lsb_energy was multiplied by 10E9 */
|
||||
val = div_s64(val * st->lsb_energy, 1000);
|
||||
|
||||
return sprintf(buf, "%lld\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltc2947_read_temp(struct device *dev, const u32 attr, long *val,
|
||||
|
|
@ -588,6 +549,23 @@ static int ltc2947_read_in(struct device *dev, const u32 attr, long *val,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ltc2947_read_energy(struct device *dev, s64 *val, const int channel)
|
||||
{
|
||||
int reg = channel ? LTC2947_REG_ENERGY2 : LTC2947_REG_ENERGY1;
|
||||
struct ltc2947_data *st = dev_get_drvdata(dev);
|
||||
s64 __val = 0;
|
||||
int ret;
|
||||
|
||||
ret = ltc2947_val_read(st, reg, LTC2947_PAGE0, 6, &__val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* value in microJoule. st->lsb_energy was multiplied by 10E9 */
|
||||
*val = DIV_S64_ROUND_CLOSEST(__val * st->lsb_energy, 1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltc2947_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
|
|
@ -600,6 +578,8 @@ static int ltc2947_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
return ltc2947_read_power(dev, attr, val);
|
||||
case hwmon_temp:
|
||||
return ltc2947_read_temp(dev, attr, val, channel);
|
||||
case hwmon_energy64:
|
||||
return ltc2947_read_energy(dev, (s64 *)val, channel);
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
|
@ -897,6 +877,8 @@ static umode_t ltc2947_is_visible(const void *data,
|
|||
return ltc2947_power_is_visible(attr);
|
||||
case hwmon_temp:
|
||||
return ltc2947_temp_is_visible(attr);
|
||||
case hwmon_energy64:
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -929,6 +911,9 @@ static const struct hwmon_channel_info * const ltc2947_info[] = {
|
|||
HWMON_T_LABEL,
|
||||
HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MIN | HWMON_T_LABEL),
|
||||
HWMON_CHANNEL_INFO(energy64,
|
||||
HWMON_E_INPUT,
|
||||
HWMON_E_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -944,19 +929,6 @@ static const struct hwmon_chip_info ltc2947_chip_info = {
|
|||
.info = ltc2947_info,
|
||||
};
|
||||
|
||||
/* energy attributes are 6bytes wide so we need u64 */
|
||||
static SENSOR_DEVICE_ATTR(energy1_input, 0444, ltc2947_show_value, NULL,
|
||||
LTC2947_REG_ENERGY1);
|
||||
static SENSOR_DEVICE_ATTR(energy2_input, 0444, ltc2947_show_value, NULL,
|
||||
LTC2947_REG_ENERGY2);
|
||||
|
||||
static struct attribute *ltc2947_attrs[] = {
|
||||
&sensor_dev_attr_energy1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_energy2_input.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ltc2947);
|
||||
|
||||
static int ltc2947_setup(struct ltc2947_data *st)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -1107,15 +1079,13 @@ int ltc2947_core_probe(struct regmap *map, const char *name)
|
|||
st->map = map;
|
||||
st->dev = dev;
|
||||
dev_set_drvdata(dev, st);
|
||||
mutex_init(&st->lock);
|
||||
|
||||
ret = ltc2947_setup(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hwmon = devm_hwmon_device_register_with_info(dev, name, st,
|
||||
<c2947_chip_info,
|
||||
ltc2947_groups);
|
||||
<c2947_chip_info, NULL);
|
||||
return PTR_ERR_OR_ZERO(hwmon);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ltc2947_core_probe);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/platform_data/ltc4245.h>
|
||||
|
||||
|
|
@ -51,7 +50,6 @@ enum ltc4245_cmd {
|
|||
struct ltc4245_data {
|
||||
struct i2c_client *client;
|
||||
|
||||
struct mutex update_lock;
|
||||
bool valid;
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
|
|
@ -132,10 +130,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
|
|||
s32 val;
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
|
||||
/* Read control registers -- 0x00 to 0x07 */
|
||||
for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
|
||||
val = i2c_smbus_read_byte_data(client, i);
|
||||
|
|
@ -161,8 +156,6 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
|
|||
data->valid = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
@ -454,7 +447,6 @@ static int ltc4245_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
data->use_extra_gpios = ltc4245_use_extra_gpios(client);
|
||||
|
||||
/* Initialize the LTC4245 chip */
|
||||
|
|
|
|||
|
|
@ -12,13 +12,11 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/string.h>
|
||||
|
|
@ -132,8 +130,6 @@ struct ltc4282_cache {
|
|||
|
||||
struct ltc4282_state {
|
||||
struct regmap *map;
|
||||
/* Protect against multiple accesses to the device registers */
|
||||
struct mutex lock;
|
||||
struct clk_hw clk_hw;
|
||||
/*
|
||||
* Used to cache values for VDD/VSOURCE depending which will be used
|
||||
|
|
@ -282,14 +278,12 @@ static int __ltc4282_read_alarm(struct ltc4282_state *st, u32 reg, u32 mask,
|
|||
static int ltc4282_read_alarm(struct ltc4282_state *st, u32 reg, u32 mask,
|
||||
long *val)
|
||||
{
|
||||
guard(mutex)(&st->lock);
|
||||
return __ltc4282_read_alarm(st, reg, mask, val);
|
||||
}
|
||||
|
||||
static int ltc4282_vdd_source_read_in(struct ltc4282_state *st, u32 channel,
|
||||
long *val)
|
||||
{
|
||||
guard(mutex)(&st->lock);
|
||||
if (!st->in0_1_cache[channel].en)
|
||||
return -ENODATA;
|
||||
|
||||
|
|
@ -301,7 +295,6 @@ static int ltc4282_vdd_source_read_hist(struct ltc4282_state *st, u32 reg,
|
|||
{
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
if (!st->in0_1_cache[channel].en) {
|
||||
*val = *cached;
|
||||
return 0;
|
||||
|
|
@ -318,7 +311,6 @@ static int ltc4282_vdd_source_read_hist(struct ltc4282_state *st, u32 reg,
|
|||
static int ltc4282_vdd_source_read_lim(struct ltc4282_state *st, u32 reg,
|
||||
u32 channel, u32 *cached, long *val)
|
||||
{
|
||||
guard(mutex)(&st->lock);
|
||||
if (!st->in0_1_cache[channel].en)
|
||||
return ltc4282_read_voltage_byte_cached(st, reg, st->vfs_out,
|
||||
val, cached);
|
||||
|
|
@ -329,7 +321,6 @@ static int ltc4282_vdd_source_read_lim(struct ltc4282_state *st, u32 reg,
|
|||
static int ltc4282_vdd_source_read_alm(struct ltc4282_state *st, u32 mask,
|
||||
u32 channel, long *val)
|
||||
{
|
||||
guard(mutex)(&st->lock);
|
||||
if (!st->in0_1_cache[channel].en) {
|
||||
/*
|
||||
* Do this otherwise alarms can get confused because we clear
|
||||
|
|
@ -413,9 +404,7 @@ static int ltc4282_read_in(struct ltc4282_state *st, u32 attr, long *val,
|
|||
channel,
|
||||
&st->in0_1_cache[channel].in_min_raw, val);
|
||||
case hwmon_in_enable:
|
||||
scoped_guard(mutex, &st->lock) {
|
||||
*val = st->in0_1_cache[channel].en;
|
||||
}
|
||||
*val = st->in0_1_cache[channel].en;
|
||||
return 0;
|
||||
case hwmon_in_fault:
|
||||
/*
|
||||
|
|
@ -541,7 +530,7 @@ static int ltc4282_read_power_byte(const struct ltc4282_state *st, u32 reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ltc4282_read_energy(const struct ltc4282_state *st, u64 *val)
|
||||
static int ltc4282_read_energy(const struct ltc4282_state *st, s64 *val)
|
||||
{
|
||||
u64 temp, energy;
|
||||
__be64 raw;
|
||||
|
|
@ -613,10 +602,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
case hwmon_power:
|
||||
return ltc4282_read_power(st, attr, val);
|
||||
case hwmon_energy:
|
||||
scoped_guard(mutex, &st->lock) {
|
||||
*val = st->energy_en;
|
||||
}
|
||||
*val = st->energy_en;
|
||||
return 0;
|
||||
case hwmon_energy64:
|
||||
if (st->energy_en)
|
||||
return ltc4282_read_energy(st, (s64 *)val);
|
||||
return -ENODATA;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
|
@ -683,7 +674,6 @@ static int __ltc4282_in_write_history(const struct ltc4282_state *st, u32 reg,
|
|||
static int ltc4282_in_write_history(struct ltc4282_state *st, u32 reg,
|
||||
long lowest, long highest, u32 fs)
|
||||
{
|
||||
guard(mutex)(&st->lock);
|
||||
return __ltc4282_in_write_history(st, reg, lowest, highest, fs);
|
||||
}
|
||||
|
||||
|
|
@ -691,8 +681,6 @@ static int ltc4282_power_reset_hist(struct ltc4282_state *st)
|
|||
{
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
ret = ltc4282_write_power_word(st, LTC4282_POWER_LOWEST,
|
||||
st->power_max);
|
||||
if (ret)
|
||||
|
|
@ -798,7 +786,6 @@ static int ltc4282_vdd_source_write_lim(struct ltc4282_state *st, u32 reg,
|
|||
{
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
if (st->in0_1_cache[channel].en)
|
||||
ret = ltc4282_write_voltage_byte(st, reg, st->vfs_out, val);
|
||||
else
|
||||
|
|
@ -816,7 +803,6 @@ static int ltc4282_vdd_source_reset_hist(struct ltc4282_state *st, int channel)
|
|||
if (channel == LTC4282_CHAN_VDD)
|
||||
lowest = st->vdd;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
if (st->in0_1_cache[channel].en) {
|
||||
ret = __ltc4282_in_write_history(st, LTC4282_VSOURCE_LOWEST,
|
||||
lowest, 0, st->vfs_out);
|
||||
|
|
@ -856,7 +842,6 @@ static int ltc4282_vdd_source_enable(struct ltc4282_state *st, int channel,
|
|||
int ret, other_chan = ~channel & 0x1;
|
||||
u8 __val = val;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
if (st->in0_1_cache[channel].en == !!val)
|
||||
return 0;
|
||||
|
||||
|
|
@ -933,8 +918,6 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st)
|
|||
{
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
|
||||
ret = __ltc4282_in_write_history(st, LTC4282_VSENSE_LOWEST,
|
||||
st->vsense_max, 0, 40 * MILLI);
|
||||
if (ret)
|
||||
|
|
@ -969,7 +952,6 @@ static int ltc4282_energy_enable_set(struct ltc4282_state *st, long val)
|
|||
{
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
/* setting the bit halts the meter */
|
||||
ret = regmap_update_bits(st->map, LTC4282_ADC_CTRL,
|
||||
LTC4282_METER_HALT_MASK,
|
||||
|
|
@ -1078,6 +1060,9 @@ static umode_t ltc4282_is_visible(const void *data,
|
|||
case hwmon_energy:
|
||||
/* hwmon_energy_enable */
|
||||
return 0644;
|
||||
case hwmon_energy64:
|
||||
/* hwmon_energy_input */
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1106,24 +1091,6 @@ static int ltc4282_read_labels(struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t ltc4282_energy_show(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct ltc4282_state *st = dev_get_drvdata(dev);
|
||||
u64 energy;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&st->lock);
|
||||
if (!st->energy_en)
|
||||
return -ENODATA;
|
||||
|
||||
ret = ltc4282_read_energy(st, &energy);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%llu\n", energy);
|
||||
}
|
||||
|
||||
static const struct clk_ops ltc4282_ops = {
|
||||
.recalc_rate = ltc4282_recalc_rate,
|
||||
.determine_rate = ltc4282_determine_rate,
|
||||
|
|
@ -1588,6 +1555,8 @@ static const struct hwmon_channel_info * const ltc4282_info[] = {
|
|||
HWMON_P_RESET_HISTORY | HWMON_P_LABEL),
|
||||
HWMON_CHANNEL_INFO(energy,
|
||||
HWMON_E_ENABLE),
|
||||
HWMON_CHANNEL_INFO(energy64,
|
||||
HWMON_E_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -1603,15 +1572,6 @@ static const struct hwmon_chip_info ltc4282_chip_info = {
|
|||
.info = ltc4282_info,
|
||||
};
|
||||
|
||||
/* energy attributes are 6bytes wide so we need u64 */
|
||||
static SENSOR_DEVICE_ATTR_RO(energy1_input, ltc4282_energy, 0);
|
||||
|
||||
static struct attribute *ltc4282_attrs[] = {
|
||||
&sensor_dev_attr_energy1_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ltc4282);
|
||||
|
||||
static int ltc4282_show_fault_log(void *arg, u64 *val, u32 mask)
|
||||
{
|
||||
struct ltc4282_state *st = arg;
|
||||
|
|
@ -1716,10 +1676,8 @@ static int ltc4282_probe(struct i2c_client *i2c)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_init(&st->lock);
|
||||
hwmon = devm_hwmon_device_register_with_info(dev, "ltc4282", st,
|
||||
<c4282_chip_info,
|
||||
ltc4282_groups);
|
||||
<c4282_chip_info, NULL);
|
||||
if (IS_ERR(hwmon))
|
||||
return PTR_ERR(hwmon);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,851 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||
/*
|
||||
* Apple SMC hwmon driver for Apple Silicon platforms
|
||||
*
|
||||
* The System Management Controller on Apple Silicon devices is responsible for
|
||||
* measuring data from sensors across the SoC and machine. These include power,
|
||||
* temperature, voltage and current sensors. Some "sensors" actually expose
|
||||
* derived values. An example of this is the key PHPC, which is an estimate
|
||||
* of the heat energy being dissipated by the SoC.
|
||||
*
|
||||
* While each SoC only has one SMC variant, each platform exposes a different
|
||||
* set of sensors. For example, M1 MacBooks expose battery telemetry sensors
|
||||
* which are not present on the M1 Mac mini. For this reason, the available
|
||||
* sensors for a given platform are described in the device tree in a child
|
||||
* node of the SMC device. We must walk this list of available sensors and
|
||||
* populate the required hwmon data structures at runtime.
|
||||
*
|
||||
* Originally based on a concept by Jean-Francois Bortolotti <jeff@borto.fr>
|
||||
*
|
||||
* Copyright The Asahi Linux Contributors
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/mfd/macsmc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define MAX_LABEL_LENGTH 32
|
||||
|
||||
/* Temperature, voltage, current, power, fan(s) */
|
||||
#define NUM_SENSOR_TYPES 5
|
||||
|
||||
#define FLT_EXP_BIAS 127
|
||||
#define FLT_EXP_MASK GENMASK(30, 23)
|
||||
#define FLT_MANT_BIAS 23
|
||||
#define FLT_MANT_MASK GENMASK(22, 0)
|
||||
#define FLT_SIGN_MASK BIT(31)
|
||||
|
||||
static bool fan_control;
|
||||
module_param_unsafe(fan_control, bool, 0644);
|
||||
MODULE_PARM_DESC(fan_control,
|
||||
"Override the SMC to set your own fan speeds on supported machines");
|
||||
|
||||
struct macsmc_hwmon_sensor {
|
||||
struct apple_smc_key_info info;
|
||||
smc_key macsmc_key;
|
||||
char label[MAX_LABEL_LENGTH];
|
||||
u32 attrs;
|
||||
};
|
||||
|
||||
struct macsmc_hwmon_fan {
|
||||
struct macsmc_hwmon_sensor now;
|
||||
struct macsmc_hwmon_sensor min;
|
||||
struct macsmc_hwmon_sensor max;
|
||||
struct macsmc_hwmon_sensor set;
|
||||
struct macsmc_hwmon_sensor mode;
|
||||
char label[MAX_LABEL_LENGTH];
|
||||
u32 attrs;
|
||||
bool manual;
|
||||
};
|
||||
|
||||
struct macsmc_hwmon_sensors {
|
||||
struct hwmon_channel_info channel_info;
|
||||
struct macsmc_hwmon_sensor *sensors;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
struct macsmc_hwmon_fans {
|
||||
struct hwmon_channel_info channel_info;
|
||||
struct macsmc_hwmon_fan *fans;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
struct macsmc_hwmon {
|
||||
struct device *dev;
|
||||
struct apple_smc *smc;
|
||||
struct device *hwmon_dev;
|
||||
struct hwmon_chip_info chip_info;
|
||||
/* Chip + sensor types + NULL */
|
||||
const struct hwmon_channel_info *channel_infos[1 + NUM_SENSOR_TYPES + 1];
|
||||
struct macsmc_hwmon_sensors temp;
|
||||
struct macsmc_hwmon_sensors volt;
|
||||
struct macsmc_hwmon_sensors curr;
|
||||
struct macsmc_hwmon_sensors power;
|
||||
struct macsmc_hwmon_fans fan;
|
||||
};
|
||||
|
||||
static int macsmc_hwmon_read_label(struct device *dev,
|
||||
enum hwmon_sensor_types type, u32 attr,
|
||||
int channel, const char **str)
|
||||
{
|
||||
struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
*str = hwmon->temp.sensors[channel].label;
|
||||
break;
|
||||
case hwmon_in:
|
||||
*str = hwmon->volt.sensors[channel].label;
|
||||
break;
|
||||
case hwmon_curr:
|
||||
*str = hwmon->curr.sensors[channel].label;
|
||||
break;
|
||||
case hwmon_power:
|
||||
*str = hwmon->power.sensors[channel].label;
|
||||
break;
|
||||
case hwmon_fan:
|
||||
*str = hwmon->fan.fans[channel].label;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A number of sensors report data in a 48.16 fixed-point decimal format that is
|
||||
* not used by any other function of the SMC.
|
||||
*/
|
||||
static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
|
||||
u64 *p, int scale)
|
||||
{
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
ret = apple_smc_read_u64(smc, key, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*p = mult_frac(val, scale, 65536);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Many sensors report their data as IEEE-754 floats. No other SMC function uses
|
||||
* them.
|
||||
*/
|
||||
static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
|
||||
int *p, int scale)
|
||||
{
|
||||
u32 fval;
|
||||
u64 val;
|
||||
int ret, exp;
|
||||
|
||||
ret = apple_smc_read_u32(smc, key, &fval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val = ((u64)((fval & FLT_MANT_MASK) | BIT(23)));
|
||||
exp = ((fval >> 23) & 0xff) - FLT_EXP_BIAS - FLT_MANT_BIAS;
|
||||
|
||||
/* We never have negatively scaled SMC floats */
|
||||
val *= scale;
|
||||
|
||||
if (exp > 63)
|
||||
val = U64_MAX;
|
||||
else if (exp < -63)
|
||||
val = 0;
|
||||
else if (exp < 0)
|
||||
val >>= -exp;
|
||||
else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */
|
||||
val = U64_MAX;
|
||||
else
|
||||
val <<= exp;
|
||||
|
||||
if (fval & FLT_SIGN_MASK) {
|
||||
if (val > (-(s64)INT_MIN))
|
||||
*p = INT_MIN;
|
||||
else
|
||||
*p = -val;
|
||||
} else {
|
||||
if (val > INT_MAX)
|
||||
*p = INT_MAX;
|
||||
else
|
||||
*p = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The SMC has keys of multiple types, denoted by a FourCC of the same format
|
||||
* as the key ID. We don't know what data type a key encodes until we poke at it.
|
||||
*/
|
||||
static int macsmc_hwmon_read_key(struct apple_smc *smc,
|
||||
struct macsmc_hwmon_sensor *sensor, int scale,
|
||||
long *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (sensor->info.type_code) {
|
||||
/* 32-bit IEEE 754 float */
|
||||
case __SMC_KEY('f', 'l', 't', ' '): {
|
||||
u32 flt_ = 0;
|
||||
|
||||
ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key,
|
||||
&flt_, scale);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = flt_;
|
||||
break;
|
||||
}
|
||||
/* 48.16 fixed point decimal */
|
||||
case __SMC_KEY('i', 'o', 'f', 't'): {
|
||||
u64 ioft = 0;
|
||||
|
||||
ret = macsmc_hwmon_read_ioft_scaled(smc, sensor->macsmc_key,
|
||||
&ioft, scale);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = (long)ioft;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value)
|
||||
{
|
||||
u64 val;
|
||||
u32 fval = 0;
|
||||
int exp = 0, neg;
|
||||
|
||||
val = abs(value);
|
||||
neg = val != value;
|
||||
|
||||
if (val) {
|
||||
int msb = __fls(val) - exp;
|
||||
|
||||
if (msb > 23) {
|
||||
val >>= msb - FLT_MANT_BIAS;
|
||||
exp -= msb - FLT_MANT_BIAS;
|
||||
} else if (msb < 23) {
|
||||
val <<= FLT_MANT_BIAS - msb;
|
||||
exp += msb;
|
||||
}
|
||||
|
||||
fval = FIELD_PREP(FLT_SIGN_MASK, neg) |
|
||||
FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) |
|
||||
FIELD_PREP(FLT_MANT_MASK, val);
|
||||
}
|
||||
|
||||
return apple_smc_write_u32(smc, key, fval);
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_write_key(struct apple_smc *smc,
|
||||
struct macsmc_hwmon_sensor *sensor, long val)
|
||||
{
|
||||
switch (sensor->info.type_code) {
|
||||
/* 32-bit IEEE 754 float */
|
||||
case __SMC_KEY('f', 'l', 't', ' '):
|
||||
return macsmc_hwmon_write_f32(smc, sensor->macsmc_key, val);
|
||||
/* unsigned 8-bit integer */
|
||||
case __SMC_KEY('u', 'i', '8', ' '):
|
||||
return apple_smc_write_u8(smc, sensor->macsmc_key, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_read_fan(struct macsmc_hwmon *hwmon, u32 attr, int chan,
|
||||
long *val)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
return macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->fan.fans[chan].now, 1, val);
|
||||
case hwmon_fan_min:
|
||||
return macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->fan.fans[chan].min, 1, val);
|
||||
case hwmon_fan_max:
|
||||
return macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->fan.fans[chan].max, 1, val);
|
||||
case hwmon_fan_target:
|
||||
return macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->fan.fans[chan].set, 1, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_write_fan(struct device *dev, u32 attr, int channel,
|
||||
long val)
|
||||
{
|
||||
struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
long min, max;
|
||||
int ret;
|
||||
|
||||
if (!fan_control || hwmon->fan.fans[channel].mode.macsmc_key == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* The SMC does no sanity checks on requested fan speeds, so we need to.
|
||||
*/
|
||||
ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].min,
|
||||
1, &min);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = macsmc_hwmon_read_key(hwmon->smc, &hwmon->fan.fans[channel].max,
|
||||
1, &max);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (val >= min && val <= max) {
|
||||
if (!hwmon->fan.fans[channel].manual) {
|
||||
/* Write 1 to mode key for manual control */
|
||||
ret = macsmc_hwmon_write_key(hwmon->smc,
|
||||
&hwmon->fan.fans[channel].mode, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hwmon->fan.fans[channel].manual = true;
|
||||
}
|
||||
return macsmc_hwmon_write_key(hwmon->smc,
|
||||
&hwmon->fan.fans[channel].set, val);
|
||||
} else if (!val) {
|
||||
if (hwmon->fan.fans[channel].manual) {
|
||||
ret = macsmc_hwmon_write_key(hwmon->smc,
|
||||
&hwmon->fan.fans[channel].mode, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hwmon->fan.fans[channel].manual = false;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct macsmc_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
ret = macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->temp.sensors[channel], 1000, val);
|
||||
break;
|
||||
case hwmon_in:
|
||||
ret = macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->volt.sensors[channel], 1000, val);
|
||||
break;
|
||||
case hwmon_curr:
|
||||
ret = macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->curr.sensors[channel], 1000, val);
|
||||
break;
|
||||
case hwmon_power:
|
||||
/* SMC returns power in Watts with acceptable precision to scale to uW */
|
||||
ret = macsmc_hwmon_read_key(hwmon->smc,
|
||||
&hwmon->power.sensors[channel],
|
||||
1000000, val);
|
||||
break;
|
||||
case hwmon_fan:
|
||||
ret = macsmc_hwmon_read_fan(hwmon, attr, channel, val);
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
return macsmc_hwmon_write_fan(dev, attr, channel, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t macsmc_hwmon_fan_is_visible(const struct macsmc_hwmon_fan *fan,
|
||||
u32 attr)
|
||||
{
|
||||
if (fan->attrs & BIT(attr)) {
|
||||
if (attr == hwmon_fan_target && fan_control && fan->mode.macsmc_key)
|
||||
return 0644;
|
||||
|
||||
return 0444;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t macsmc_hwmon_is_visible(const void *data,
|
||||
enum hwmon_sensor_types type, u32 attr,
|
||||
int channel)
|
||||
{
|
||||
const struct macsmc_hwmon *hwmon = data;
|
||||
struct macsmc_hwmon_sensor *sensor;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_in:
|
||||
sensor = &hwmon->volt.sensors[channel];
|
||||
break;
|
||||
case hwmon_curr:
|
||||
sensor = &hwmon->curr.sensors[channel];
|
||||
break;
|
||||
case hwmon_power:
|
||||
sensor = &hwmon->power.sensors[channel];
|
||||
break;
|
||||
case hwmon_temp:
|
||||
sensor = &hwmon->temp.sensors[channel];
|
||||
break;
|
||||
case hwmon_fan:
|
||||
return macsmc_hwmon_fan_is_visible(&hwmon->fan.fans[channel], attr);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Sensors only register ro attributes */
|
||||
if (sensor->attrs & BIT(attr))
|
||||
return 0444;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_ops macsmc_hwmon_ops = {
|
||||
.is_visible = macsmc_hwmon_is_visible,
|
||||
.read = macsmc_hwmon_read,
|
||||
.read_string = macsmc_hwmon_read_label,
|
||||
.write = macsmc_hwmon_write,
|
||||
};
|
||||
|
||||
/*
|
||||
* Get the key metadata, including key data type, from the SMC.
|
||||
*/
|
||||
static int macsmc_hwmon_parse_key(struct device *dev, struct apple_smc *smc,
|
||||
struct macsmc_hwmon_sensor *sensor,
|
||||
const char *key)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = apple_smc_get_key_info(smc, _SMC_KEY(key), &sensor->info);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "Failed to retrieve key info for %s\n", key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
sensor->macsmc_key = _SMC_KEY(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A sensor is a single key-value pair as made available by the SMC.
|
||||
* The devicetree gives us the SMC key ID and a friendly name where the
|
||||
* purpose of the sensor is known.
|
||||
*/
|
||||
static int macsmc_hwmon_create_sensor(struct device *dev, struct apple_smc *smc,
|
||||
struct device_node *sensor_node,
|
||||
struct macsmc_hwmon_sensor *sensor)
|
||||
{
|
||||
const char *key, *label;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_string(sensor_node, "apple,key-id", &key);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "Could not find apple,key-id in sensor node\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = macsmc_hwmon_parse_key(dev, smc, sensor, key);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = of_property_read_string(sensor_node, "label", &label);
|
||||
if (ret)
|
||||
dev_dbg(dev, "No label found for sensor %s\n", key);
|
||||
else
|
||||
strscpy_pad(sensor->label, label, sizeof(sensor->label));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fan data is exposed by the SMC as multiple sensors.
|
||||
*
|
||||
* The devicetree schema reuses apple,key-id for the actual fan speed sensor.
|
||||
* Min, max and target keys do not need labels, so we can reuse label
|
||||
* for naming the entire fan.
|
||||
*/
|
||||
static int macsmc_hwmon_create_fan(struct device *dev, struct apple_smc *smc,
|
||||
struct device_node *fan_node,
|
||||
struct macsmc_hwmon_fan *fan)
|
||||
{
|
||||
const char *label, *now, *min, *max, *set, *mode;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_string(fan_node, "apple,key-id", &now);
|
||||
if (ret) {
|
||||
dev_err(dev, "apple,key-id not found in fan node!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = macsmc_hwmon_parse_key(dev, smc, &fan->now, now);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fan->attrs = HWMON_F_INPUT;
|
||||
|
||||
ret = of_property_read_string(fan_node, "label", &label);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "No label found for fan %s\n", now);
|
||||
} else {
|
||||
strscpy_pad(fan->label, label, sizeof(fan->label));
|
||||
fan->attrs |= HWMON_F_LABEL;
|
||||
}
|
||||
|
||||
/* The following keys are not required to simply monitor fan speed */
|
||||
if (!of_property_read_string(fan_node, "apple,fan-minimum", &min)) {
|
||||
ret = macsmc_hwmon_parse_key(dev, smc, &fan->min, min);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fan->attrs |= HWMON_F_MIN;
|
||||
}
|
||||
|
||||
if (!of_property_read_string(fan_node, "apple,fan-maximum", &max)) {
|
||||
ret = macsmc_hwmon_parse_key(dev, smc, &fan->max, max);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fan->attrs |= HWMON_F_MAX;
|
||||
}
|
||||
|
||||
if (!of_property_read_string(fan_node, "apple,fan-target", &set)) {
|
||||
ret = macsmc_hwmon_parse_key(dev, smc, &fan->set, set);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fan->attrs |= HWMON_F_TARGET;
|
||||
}
|
||||
|
||||
if (!of_property_read_string(fan_node, "apple,fan-mode", &mode)) {
|
||||
ret = macsmc_hwmon_parse_key(dev, smc, &fan->mode, mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialise fan control mode to automatic */
|
||||
fan->manual = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon,
|
||||
struct device_node *hwmon_node)
|
||||
{
|
||||
struct device_node *key_node __maybe_unused;
|
||||
struct macsmc_hwmon_sensor *sensor;
|
||||
u32 n_current = 0, n_fan = 0, n_power = 0, n_temperature = 0, n_voltage = 0;
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
|
||||
n_current++;
|
||||
}
|
||||
|
||||
if (n_current) {
|
||||
hwmon->curr.sensors = devm_kcalloc(hwmon->dev, n_current,
|
||||
sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
|
||||
if (!hwmon->curr.sensors)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "current-") {
|
||||
sensor = &hwmon->curr.sensors[hwmon->curr.count];
|
||||
if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
|
||||
sensor->attrs = HWMON_C_INPUT;
|
||||
|
||||
if (*sensor->label)
|
||||
sensor->attrs |= HWMON_C_LABEL;
|
||||
|
||||
hwmon->curr.count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
|
||||
n_fan++;
|
||||
}
|
||||
|
||||
if (n_fan) {
|
||||
hwmon->fan.fans = devm_kcalloc(hwmon->dev, n_fan,
|
||||
sizeof(struct macsmc_hwmon_fan), GFP_KERNEL);
|
||||
if (!hwmon->fan.fans)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "fan-") {
|
||||
if (!macsmc_hwmon_create_fan(hwmon->dev, hwmon->smc, key_node,
|
||||
&hwmon->fan.fans[hwmon->fan.count]))
|
||||
hwmon->fan.count++;
|
||||
}
|
||||
}
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
|
||||
n_power++;
|
||||
}
|
||||
|
||||
if (n_power) {
|
||||
hwmon->power.sensors = devm_kcalloc(hwmon->dev, n_power,
|
||||
sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
|
||||
if (!hwmon->power.sensors)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "power-") {
|
||||
sensor = &hwmon->power.sensors[hwmon->power.count];
|
||||
if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
|
||||
sensor->attrs = HWMON_P_INPUT;
|
||||
|
||||
if (*sensor->label)
|
||||
sensor->attrs |= HWMON_P_LABEL;
|
||||
|
||||
hwmon->power.count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
|
||||
n_temperature++;
|
||||
}
|
||||
|
||||
if (n_temperature) {
|
||||
hwmon->temp.sensors = devm_kcalloc(hwmon->dev, n_temperature,
|
||||
sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
|
||||
if (!hwmon->temp.sensors)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "temperature-") {
|
||||
sensor = &hwmon->temp.sensors[hwmon->temp.count];
|
||||
if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
|
||||
sensor->attrs = HWMON_T_INPUT;
|
||||
|
||||
if (*sensor->label)
|
||||
sensor->attrs |= HWMON_T_LABEL;
|
||||
|
||||
hwmon->temp.count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
|
||||
n_voltage++;
|
||||
}
|
||||
|
||||
if (n_voltage) {
|
||||
hwmon->volt.sensors = devm_kcalloc(hwmon->dev, n_voltage,
|
||||
sizeof(struct macsmc_hwmon_sensor), GFP_KERNEL);
|
||||
if (!hwmon->volt.sensors)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-") {
|
||||
sensor = &hwmon->temp.sensors[hwmon->temp.count];
|
||||
if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
|
||||
sensor->attrs = HWMON_I_INPUT;
|
||||
|
||||
if (*sensor->label)
|
||||
sensor->attrs |= HWMON_I_LABEL;
|
||||
|
||||
hwmon->volt.count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create NULL-terminated config arrays */
|
||||
static void macsmc_hwmon_populate_configs(u32 *configs, const struct macsmc_hwmon_sensors *sensors)
|
||||
{
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < sensors->count; idx++)
|
||||
configs[idx] = sensors->sensors[idx].attrs;
|
||||
}
|
||||
|
||||
static void macsmc_hwmon_populate_fan_configs(u32 *configs, const struct macsmc_hwmon_fans *fans)
|
||||
{
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < fans->count; idx++)
|
||||
configs[idx] = fans->fans[idx].attrs;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *const macsmc_chip_channel_info =
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ);
|
||||
|
||||
static int macsmc_hwmon_create_infos(struct macsmc_hwmon *hwmon)
|
||||
{
|
||||
struct hwmon_channel_info *channel_info;
|
||||
int i = 0;
|
||||
|
||||
/* chip */
|
||||
hwmon->channel_infos[i++] = macsmc_chip_channel_info;
|
||||
|
||||
if (hwmon->curr.count) {
|
||||
channel_info = &hwmon->curr.channel_info;
|
||||
channel_info->type = hwmon_curr;
|
||||
channel_info->config = devm_kcalloc(hwmon->dev, hwmon->curr.count + 1,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!channel_info->config)
|
||||
return -ENOMEM;
|
||||
|
||||
macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->curr);
|
||||
hwmon->channel_infos[i++] = channel_info;
|
||||
}
|
||||
|
||||
if (hwmon->fan.count) {
|
||||
channel_info = &hwmon->fan.channel_info;
|
||||
channel_info->type = hwmon_fan;
|
||||
channel_info->config = devm_kcalloc(hwmon->dev, hwmon->fan.count + 1,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!channel_info->config)
|
||||
return -ENOMEM;
|
||||
|
||||
macsmc_hwmon_populate_fan_configs((u32 *)channel_info->config, &hwmon->fan);
|
||||
hwmon->channel_infos[i++] = channel_info;
|
||||
}
|
||||
|
||||
if (hwmon->power.count) {
|
||||
channel_info = &hwmon->power.channel_info;
|
||||
channel_info->type = hwmon_power;
|
||||
channel_info->config = devm_kcalloc(hwmon->dev, hwmon->power.count + 1,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!channel_info->config)
|
||||
return -ENOMEM;
|
||||
|
||||
macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->power);
|
||||
hwmon->channel_infos[i++] = channel_info;
|
||||
}
|
||||
|
||||
if (hwmon->temp.count) {
|
||||
channel_info = &hwmon->temp.channel_info;
|
||||
channel_info->type = hwmon_temp;
|
||||
channel_info->config = devm_kcalloc(hwmon->dev, hwmon->temp.count + 1,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!channel_info->config)
|
||||
return -ENOMEM;
|
||||
|
||||
macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->temp);
|
||||
hwmon->channel_infos[i++] = channel_info;
|
||||
}
|
||||
|
||||
if (hwmon->volt.count) {
|
||||
channel_info = &hwmon->volt.channel_info;
|
||||
channel_info->type = hwmon_in;
|
||||
channel_info->config = devm_kcalloc(hwmon->dev, hwmon->volt.count + 1,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!channel_info->config)
|
||||
return -ENOMEM;
|
||||
|
||||
macsmc_hwmon_populate_configs((u32 *)channel_info->config, &hwmon->volt);
|
||||
hwmon->channel_infos[i++] = channel_info;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int macsmc_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
|
||||
struct macsmc_hwmon *hwmon;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The MFD driver will try to probe us unconditionally. Some devices
|
||||
* with the SMC do not have hwmon capabilities. Only probe if we have
|
||||
* a hwmon node.
|
||||
*/
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon),
|
||||
GFP_KERNEL);
|
||||
if (!hwmon)
|
||||
return -ENOMEM;
|
||||
|
||||
hwmon->dev = &pdev->dev;
|
||||
hwmon->smc = smc;
|
||||
|
||||
ret = macsmc_hwmon_populate_sensors(hwmon, hwmon->dev->of_node);
|
||||
if (ret) {
|
||||
dev_err(hwmon->dev, "Could not parse sensors\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!hwmon->curr.count && !hwmon->fan.count &&
|
||||
!hwmon->power.count && !hwmon->temp.count &&
|
||||
!hwmon->volt.count) {
|
||||
dev_err(hwmon->dev,
|
||||
"No valid sensors found of any supported type\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = macsmc_hwmon_create_infos(hwmon);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hwmon->chip_info.ops = &macsmc_hwmon_ops;
|
||||
hwmon->chip_info.info =
|
||||
(const struct hwmon_channel_info *const *)&hwmon->channel_infos;
|
||||
|
||||
hwmon->hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
|
||||
"macsmc_hwmon", hwmon,
|
||||
&hwmon->chip_info, NULL);
|
||||
if (IS_ERR(hwmon->hwmon_dev))
|
||||
return dev_err_probe(hwmon->dev, PTR_ERR(hwmon->hwmon_dev),
|
||||
"Probing SMC hwmon device failed\n");
|
||||
|
||||
dev_dbg(hwmon->dev, "Registered SMC hwmon device. Sensors:\n");
|
||||
dev_dbg(hwmon->dev,
|
||||
"Current: %d, Fans: %d, Power: %d, Temperature: %d, Voltage: %d",
|
||||
hwmon->curr.count, hwmon->fan.count,
|
||||
hwmon->power.count, hwmon->temp.count,
|
||||
hwmon->volt.count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id macsmc_hwmon_of_table[] = {
|
||||
{ .compatible = "apple,smc-hwmon" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, macsmc_hwmon_of_table);
|
||||
|
||||
static struct platform_driver macsmc_hwmon_driver = {
|
||||
.probe = macsmc_hwmon_probe,
|
||||
.driver = {
|
||||
.name = "macsmc-hwmon",
|
||||
.of_match_table = macsmc_hwmon_of_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(macsmc_hwmon_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Apple Silicon SMC hwmon driver");
|
||||
MODULE_AUTHOR("James Calligeros <jcalligeros99@gmail.com>");
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
|
|
@ -45,7 +45,6 @@
|
|||
#define MAX127_SIGN_BIT BIT(11)
|
||||
|
||||
struct max127_data {
|
||||
struct mutex lock;
|
||||
struct i2c_client *client;
|
||||
u8 ctrl_byte[MAX127_NUM_CHANNELS];
|
||||
};
|
||||
|
|
@ -121,21 +120,16 @@ static int max127_read_input(struct max127_data *data, int channel, long *val)
|
|||
struct i2c_client *client = data->client;
|
||||
u8 ctrl_byte = data->ctrl_byte[channel];
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
status = max127_select_channel(client, ctrl_byte);
|
||||
if (status)
|
||||
goto exit;
|
||||
return status;
|
||||
|
||||
status = max127_read_channel(client, &raw);
|
||||
if (status)
|
||||
goto exit;
|
||||
return status;
|
||||
|
||||
*val = max127_process_raw(ctrl_byte, raw);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->lock);
|
||||
return status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max127_read_min(struct max127_data *data, int channel, long *val)
|
||||
|
|
@ -170,8 +164,6 @@ static int max127_write_min(struct max127_data *data, int channel, long val)
|
|||
{
|
||||
u8 ctrl;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
ctrl = data->ctrl_byte[channel];
|
||||
if (val <= -MAX127_FULL_RANGE) {
|
||||
ctrl |= (MAX127_CTRL_RNG | MAX127_CTRL_BIP);
|
||||
|
|
@ -182,23 +174,15 @@ static int max127_write_min(struct max127_data *data, int channel, long val)
|
|||
ctrl &= ~MAX127_CTRL_BIP;
|
||||
}
|
||||
data->ctrl_byte[channel] = ctrl;
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max127_write_max(struct max127_data *data, int channel, long val)
|
||||
{
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
if (val >= MAX127_FULL_RANGE)
|
||||
data->ctrl_byte[channel] |= MAX127_CTRL_RNG;
|
||||
else
|
||||
data->ctrl_byte[channel] &= ~MAX127_CTRL_RNG;
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +299,6 @@ static int max127_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->lock);
|
||||
for (i = 0; i < ARRAY_SIZE(data->ctrl_byte); i++)
|
||||
data->ctrl_byte[i] = (MAX127_CTRL_START |
|
||||
MAX127_SET_CHANNEL(i));
|
||||
|
|
|
|||
|
|
@ -216,12 +216,13 @@ static ssize_t max16065_current_show(struct device *dev,
|
|||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct max16065_data *data = max16065_update_device(dev);
|
||||
int curr_sense = data->curr_sense;
|
||||
|
||||
if (unlikely(data->curr_sense < 0))
|
||||
return data->curr_sense;
|
||||
if (unlikely(curr_sense < 0))
|
||||
return curr_sense;
|
||||
|
||||
return sysfs_emit(buf, "%d\n",
|
||||
ADC_TO_CURR(data->curr_sense, data->curr_gain));
|
||||
ADC_TO_CURR(curr_sense, data->curr_gain));
|
||||
}
|
||||
|
||||
static ssize_t max16065_limit_store(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@
|
|||
*/
|
||||
struct max31790_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
bool valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
|
|
@ -74,30 +73,27 @@ static struct max31790_data *max31790_update_device(struct device *dev)
|
|||
{
|
||||
struct max31790_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct max31790_data *ret = data;
|
||||
int i;
|
||||
int rv;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
int i, rv;
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
data->valid = false;
|
||||
rv = i2c_smbus_read_byte_data(client,
|
||||
MAX31790_REG_FAN_FAULT_STATUS1);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
return ERR_PTR(rv);
|
||||
data->fault_status |= rv & 0x3F;
|
||||
|
||||
rv = i2c_smbus_read_byte_data(client,
|
||||
MAX31790_REG_FAN_FAULT_STATUS2);
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
return ERR_PTR(rv);
|
||||
data->fault_status |= (rv & 0x3F) << 6;
|
||||
|
||||
for (i = 0; i < NR_CHANNEL; i++) {
|
||||
rv = i2c_smbus_read_word_swapped(client,
|
||||
MAX31790_REG_TACH_COUNT(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
return ERR_PTR(rv);
|
||||
data->tach[i] = rv;
|
||||
|
||||
if (data->fan_config[i]
|
||||
|
|
@ -106,19 +102,19 @@ static struct max31790_data *max31790_update_device(struct device *dev)
|
|||
MAX31790_REG_TACH_COUNT(NR_CHANNEL
|
||||
+ i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
return ERR_PTR(rv);
|
||||
data->tach[NR_CHANNEL + i] = rv;
|
||||
} else {
|
||||
rv = i2c_smbus_read_word_swapped(client,
|
||||
MAX31790_REG_PWM_DUTY_CYCLE(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
return ERR_PTR(rv);
|
||||
data->pwm[i] = rv;
|
||||
|
||||
rv = i2c_smbus_read_word_swapped(client,
|
||||
MAX31790_REG_TARGET_COUNT(i));
|
||||
if (rv < 0)
|
||||
goto abort;
|
||||
return ERR_PTR(rv);
|
||||
data->target_count[i] = rv;
|
||||
}
|
||||
}
|
||||
|
|
@ -126,16 +122,7 @@ static struct max31790_data *max31790_update_device(struct device *dev)
|
|||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
goto done;
|
||||
|
||||
abort:
|
||||
data->valid = false;
|
||||
ret = ERR_PTR(rv);
|
||||
|
||||
done:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return ret;
|
||||
return data;
|
||||
}
|
||||
|
||||
static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 };
|
||||
|
|
@ -189,7 +176,6 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
|
|||
*val = rpm;
|
||||
return 0;
|
||||
case hwmon_fan_fault:
|
||||
mutex_lock(&data->update_lock);
|
||||
*val = !!(data->fault_status & (1 << channel));
|
||||
data->fault_status &= ~(1 << channel);
|
||||
/*
|
||||
|
|
@ -200,10 +186,9 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
|
|||
if (*val) {
|
||||
int reg = MAX31790_REG_TARGET_COUNT(channel % NR_CHANNEL);
|
||||
|
||||
i2c_smbus_write_byte_data(data->client, reg,
|
||||
data->target_count[channel % NR_CHANNEL] >> 8);
|
||||
return i2c_smbus_write_byte_data(data->client, reg,
|
||||
data->target_count[channel % NR_CHANNEL] >> 8);
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
return 0;
|
||||
case hwmon_fan_enable:
|
||||
*val = !!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN);
|
||||
|
|
@ -223,8 +208,6 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel,
|
|||
u8 bits, fan_config;
|
||||
int sr;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_fan_target:
|
||||
val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX);
|
||||
|
|
@ -270,9 +253,6 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel,
|
|||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -338,8 +318,6 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
|
|||
u8 fan_config;
|
||||
int err = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
if (val < 0 || val > 255) {
|
||||
|
|
@ -389,9 +367,6 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
|
|||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -525,7 +500,6 @@ static int max31790_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/*
|
||||
* Initialize the max31790 chip
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
|
@ -99,7 +98,6 @@ struct max31827_state {
|
|||
/*
|
||||
* Prevent simultaneous access to the i2c client.
|
||||
*/
|
||||
struct mutex lock;
|
||||
struct regmap *regmap;
|
||||
bool enable;
|
||||
unsigned int resolution;
|
||||
|
|
@ -123,30 +121,23 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg,
|
|||
* Before the Temperature Threshold Alarm, Alarm Hysteresis Threshold
|
||||
* and Resolution bits from Configuration register are changed over I2C,
|
||||
* the part must be in shutdown mode.
|
||||
*
|
||||
* Mutex is used to ensure, that some other process doesn't change the
|
||||
* configuration register.
|
||||
*/
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
if (!st->enable) {
|
||||
if (!mask)
|
||||
ret = regmap_write(st->regmap, reg, val);
|
||||
else
|
||||
ret = regmap_update_bits(st->regmap, reg, mask, val);
|
||||
goto unlock;
|
||||
return regmap_write(st->regmap, reg, val);
|
||||
return regmap_update_bits(st->regmap, reg, mask, val);
|
||||
}
|
||||
|
||||
ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg;
|
||||
cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK |
|
||||
MAX31827_CONFIGURATION_CNV_RATE_MASK);
|
||||
ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
if (!mask)
|
||||
ret = regmap_write(st->regmap, reg, val);
|
||||
|
|
@ -154,15 +145,11 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg,
|
|||
ret = regmap_update_bits(st->regmap, reg, mask, val);
|
||||
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
|
||||
MAX31827_CONFIGURATION_CNV_RATE_MASK,
|
||||
cnv_rate);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&st->lock);
|
||||
return ret;
|
||||
return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
|
||||
MAX31827_CONFIGURATION_CNV_RATE_MASK,
|
||||
cnv_rate);
|
||||
}
|
||||
|
||||
static int write_alarm_val(struct max31827_state *st, unsigned int reg,
|
||||
|
|
@ -223,23 +210,13 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
|
||||
break;
|
||||
case hwmon_temp_input:
|
||||
mutex_lock(&st->lock);
|
||||
|
||||
if (!st->enable) {
|
||||
/*
|
||||
* This operation requires mutex protection,
|
||||
* because the chip configuration should not
|
||||
* be changed during the conversion process.
|
||||
*/
|
||||
|
||||
ret = regmap_update_bits(st->regmap,
|
||||
MAX31827_CONFIGURATION_REG,
|
||||
MAX31827_CONFIGURATION_1SHOT_MASK,
|
||||
1);
|
||||
if (ret) {
|
||||
mutex_unlock(&st->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
msleep(max31827_conv_times[st->resolution]);
|
||||
}
|
||||
|
||||
|
|
@ -254,8 +231,6 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
|
||||
ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
|
|
@ -352,7 +327,6 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
if (val >> 1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
/**
|
||||
* The chip should not be enabled while a conversion is
|
||||
* performed. Neither should the chip be enabled when
|
||||
|
|
@ -361,15 +335,11 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
|
||||
st->enable = val;
|
||||
|
||||
ret = regmap_update_bits(st->regmap,
|
||||
MAX31827_CONFIGURATION_REG,
|
||||
MAX31827_CONFIGURATION_1SHOT_MASK |
|
||||
MAX31827_CONFIGURATION_CNV_RATE_MASK,
|
||||
MAX31827_DEVICE_ENABLE(val));
|
||||
|
||||
mutex_unlock(&st->lock);
|
||||
|
||||
return ret;
|
||||
return regmap_update_bits(st->regmap,
|
||||
MAX31827_CONFIGURATION_REG,
|
||||
MAX31827_CONFIGURATION_1SHOT_MASK |
|
||||
MAX31827_CONFIGURATION_CNV_RATE_MASK,
|
||||
MAX31827_DEVICE_ENABLE(val));
|
||||
|
||||
case hwmon_temp_max:
|
||||
return write_alarm_val(st, MAX31827_TH_REG, val);
|
||||
|
|
@ -623,8 +593,6 @@ static int max31827_probe(struct i2c_client *client)
|
|||
if (!st)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
st->regmap = devm_regmap_init_i2c(client, &max31827_regmap);
|
||||
if (IS_ERR(st->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(st->regmap),
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ static const u8 target_reg[] = {
|
|||
|
||||
struct max6620_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
bool valid; /* false until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
|
|
@ -161,39 +160,36 @@ static int max6620_update_device(struct device *dev)
|
|||
{
|
||||
struct max6620_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
int i, ret;
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
ret = i2c_smbus_read_byte_data(client, config_reg[i]);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
data->fancfg[i] = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, dyn_reg[i]);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
data->fandyn[i] = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, tach_reg[i]);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
data->tach[i] = (ret << 3) & 0x7f8;
|
||||
ret = i2c_smbus_read_byte_data(client, tach_reg[i] + 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
data->tach[i] |= (ret >> 5) & 0x7;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, target_reg[i]);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
data->target[i] = (ret << 3) & 0x7f8;
|
||||
ret = i2c_smbus_read_byte_data(client, target_reg[i] + 1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
data->target[i] |= (ret >> 5) & 0x7;
|
||||
}
|
||||
|
||||
|
|
@ -204,16 +200,13 @@ static int max6620_update_device(struct device *dev)
|
|||
*/
|
||||
ret = i2c_smbus_read_byte_data(client, MAX6620_REG_FAULT);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
data->fault |= (ret >> 4) & (ret & 0x0F);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t
|
||||
|
|
@ -261,7 +254,6 @@ max6620_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_alarm:
|
||||
mutex_lock(&data->update_lock);
|
||||
*val = !!(data->fault & BIT(channel));
|
||||
|
||||
/* Setting TACH count to re-enable fan fault detection */
|
||||
|
|
@ -270,21 +262,15 @@ max6620_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
val2 = (data->target[channel] << 5) & 0xe0;
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
target_reg[channel], val1);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
target_reg[channel] + 1, val2);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->fault &= ~BIT(channel);
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
break;
|
||||
case hwmon_fan_div:
|
||||
*val = max6620_fan_div_from_reg(data->fandyn[channel]);
|
||||
|
|
@ -334,7 +320,6 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
return ret;
|
||||
data = dev_get_drvdata(dev);
|
||||
client = data->client;
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
|
|
@ -360,8 +345,7 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
div = 5;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
return -EINVAL;
|
||||
}
|
||||
data->fandyn[channel] &= 0x1F;
|
||||
data->fandyn[channel] |= div << 5;
|
||||
|
|
@ -396,8 +380,6 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
break;
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +460,6 @@ static int max6620_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
err = max6620_init_client(data);
|
||||
if (err)
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
|
|
@ -75,7 +73,6 @@ static const unsigned int freq_table[] = { 20, 33, 50, 100, 5000, 8333, 12500,
|
|||
*/
|
||||
struct max6639_data {
|
||||
struct regmap *regmap;
|
||||
struct mutex update_lock;
|
||||
|
||||
/* Register values initialized only once */
|
||||
u8 ppr[MAX6639_NUM_CHANNELS]; /* Pulses per rotation 0..3 for 1..4 ppr */
|
||||
|
|
@ -249,16 +246,11 @@ static int max6639_write_fan(struct device *dev, u32 attr, int channel,
|
|||
if (val <= 0 || val > 4)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
/* Set Fan pulse per revolution */
|
||||
err = max6639_set_ppr(data, channel, val);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
data->ppr[channel] = val;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -320,21 +312,17 @@ static int max6639_write_pwm(struct device *dev, u32 attr, int channel,
|
|||
case hwmon_pwm_input:
|
||||
if (val < 0 || val > 255)
|
||||
return -EINVAL;
|
||||
err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel),
|
||||
val * 120 / 255);
|
||||
return err;
|
||||
return regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel),
|
||||
val * 120 / 255);
|
||||
case hwmon_pwm_freq:
|
||||
val = clamp_val(val, 0, 25000);
|
||||
|
||||
i = find_closest(val, freq_table, ARRAY_SIZE(freq_table));
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = regmap_update_bits(data->regmap, MAX6639_REG_FAN_CONFIG3(channel),
|
||||
MAX6639_FAN_CONFIG3_FREQ_MASK, i);
|
||||
if (err < 0) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (i >> 2)
|
||||
err = regmap_set_bits(data->regmap, MAX6639_REG_GCONFIG,
|
||||
|
|
@ -343,7 +331,6 @@ static int max6639_write_pwm(struct device *dev, u32 attr, int channel,
|
|||
err = regmap_clear_bits(data->regmap, MAX6639_REG_GCONFIG,
|
||||
MAX6639_GCONFIG_PWM_FREQ_HI);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return err;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -753,8 +740,6 @@ static int max6639_probe(struct i2c_client *client)
|
|||
}
|
||||
}
|
||||
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Initialize the max6639 chip */
|
||||
err = max6639_init_client(client, data);
|
||||
if (err < 0)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -91,8 +90,6 @@ struct max6697_data {
|
|||
|
||||
int temp_offset; /* in degrees C */
|
||||
|
||||
struct mutex update_lock;
|
||||
|
||||
#define MAX6697_TEMP_INPUT 0
|
||||
#define MAX6697_TEMP_EXT 1
|
||||
#define MAX6697_TEMP_MAX 2
|
||||
|
|
@ -302,7 +299,6 @@ static int max6697_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
val = clamp_val(val, 0, 255);
|
||||
return regmap_write(regmap, MAX6697_REG_MIN, val);
|
||||
case hwmon_temp_offset:
|
||||
mutex_lock(&data->update_lock);
|
||||
val = clamp_val(val, MAX6581_OFFSET_MIN, MAX6581_OFFSET_MAX);
|
||||
val = DIV_ROUND_CLOSEST(val, 250);
|
||||
if (!val) { /* disable this (and only this) channel */
|
||||
|
|
@ -313,11 +309,9 @@ static int max6697_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
ret = regmap_set_bits(regmap, MAX6581_REG_OFFSET_SELECT,
|
||||
BIT(channel - 1));
|
||||
if (ret)
|
||||
goto unlock;
|
||||
return ret;
|
||||
ret = regmap_write(regmap, MAX6581_REG_OFFSET, val);
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -548,7 +542,7 @@ static int max6697_probe(struct i2c_client *client)
|
|||
struct regmap *regmap;
|
||||
int err;
|
||||
|
||||
regmap = regmap_init_i2c(client, &max6697_regmap_config);
|
||||
regmap = devm_regmap_init_i2c(client, &max6697_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
|
|
@ -559,7 +553,6 @@ static int max6697_probe(struct i2c_client *client)
|
|||
data->regmap = regmap;
|
||||
data->type = (uintptr_t)i2c_get_match_data(client);
|
||||
data->chip = &max6697_chip_data[data->type];
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
err = max6697_init_chip(client->dev.of_node, data);
|
||||
if (err)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/kstrtox.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
|
|
|||
|
|
@ -1403,6 +1403,7 @@ static const char * const asus_msi_boards[] = {
|
|||
"ROG STRIX X670E-E GAMING WIFI",
|
||||
"ROG STRIX X670E-F GAMING WIFI",
|
||||
"ROG STRIX X670E-I GAMING WIFI",
|
||||
"ROG STRIX X870E-H GAMING WIFI7",
|
||||
"ROG STRIX Z590-A GAMING WIFI",
|
||||
"ROG STRIX Z590-A GAMING WIFI II",
|
||||
"ROG STRIX Z590-E GAMING WIFI",
|
||||
|
|
|
|||
|
|
@ -7,10 +7,8 @@
|
|||
#include <linux/bits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
|
|
@ -128,7 +127,6 @@ static const unsigned short normal_i2c[] = {
|
|||
struct nct7904_data {
|
||||
struct i2c_client *client;
|
||||
struct watchdog_device wdt;
|
||||
struct mutex bank_lock;
|
||||
int bank_sel;
|
||||
u32 fanin_mask;
|
||||
u32 vsen_mask;
|
||||
|
|
@ -142,24 +140,19 @@ struct nct7904_data {
|
|||
};
|
||||
|
||||
/* Access functions */
|
||||
static int nct7904_bank_lock(struct nct7904_data *data, unsigned int bank)
|
||||
static int nct7904_bank_select(struct nct7904_data *data, unsigned int bank)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->bank_lock);
|
||||
if (data->bank_sel == bank)
|
||||
return 0;
|
||||
ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank);
|
||||
if (ret == 0)
|
||||
data->bank_sel = bank;
|
||||
else
|
||||
if (ret < 0) {
|
||||
data->bank_sel = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void nct7904_bank_release(struct nct7904_data *data)
|
||||
{
|
||||
mutex_unlock(&data->bank_lock);
|
||||
return ret;
|
||||
}
|
||||
data->bank_sel = bank;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */
|
||||
|
|
@ -169,12 +162,10 @@ static int nct7904_read_reg(struct nct7904_data *data,
|
|||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
ret = nct7904_bank_lock(data, bank);
|
||||
if (ret == 0)
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
|
||||
nct7904_bank_release(data);
|
||||
return ret;
|
||||
ret = nct7904_bank_select(data, bank);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -187,19 +178,16 @@ static int nct7904_read_reg16(struct nct7904_data *data,
|
|||
struct i2c_client *client = data->client;
|
||||
int ret, hi;
|
||||
|
||||
ret = nct7904_bank_lock(data, bank);
|
||||
if (ret == 0) {
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
if (ret >= 0) {
|
||||
hi = ret;
|
||||
ret = i2c_smbus_read_byte_data(client, reg + 1);
|
||||
if (ret >= 0)
|
||||
ret |= hi << 8;
|
||||
}
|
||||
}
|
||||
|
||||
nct7904_bank_release(data);
|
||||
return ret;
|
||||
ret = nct7904_bank_select(data, bank);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
hi = i2c_smbus_read_byte_data(client, reg);
|
||||
if (hi < 0)
|
||||
return hi;
|
||||
ret = i2c_smbus_read_byte_data(client, reg + 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ret | (hi << 8);
|
||||
}
|
||||
|
||||
/* Write 1-byte register. Returns 0 or -ERRNO on error. */
|
||||
|
|
@ -209,12 +197,10 @@ static int nct7904_write_reg(struct nct7904_data *data,
|
|||
struct i2c_client *client = data->client;
|
||||
int ret;
|
||||
|
||||
ret = nct7904_bank_lock(data, bank);
|
||||
if (ret == 0)
|
||||
ret = i2c_smbus_write_byte_data(client, reg, val);
|
||||
|
||||
nct7904_bank_release(data);
|
||||
return ret;
|
||||
ret = nct7904_bank_select(data, bank);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return i2c_smbus_write_byte_data(client, reg, val);
|
||||
}
|
||||
|
||||
static int nct7904_read_fan(struct device *dev, u32 attr, int channel,
|
||||
|
|
@ -1023,7 +1009,6 @@ static int nct7904_probe(struct i2c_client *client)
|
|||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->bank_lock);
|
||||
data->bank_sel = -1;
|
||||
|
||||
/* Setup sensor groups. */
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -198,7 +197,6 @@ struct npcm7xx_pwm_fan_data {
|
|||
int pwm_modules;
|
||||
struct clk *pwm_clk;
|
||||
struct clk *fan_clk;
|
||||
struct mutex pwm_lock[NPCM7XX_PWM_MAX_MODULES];
|
||||
spinlock_t fan_lock[NPCM7XX_FAN_MAX_MODULE];
|
||||
int fan_irq[NPCM7XX_FAN_MAX_MODULE];
|
||||
bool pwm_present[NPCM7XX_PWM_MAX_CHN_NUM];
|
||||
|
|
@ -221,7 +219,6 @@ static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_fan_data *data,
|
|||
/*
|
||||
* Config PWM Comparator register for setting duty cycle
|
||||
*/
|
||||
mutex_lock(&data->pwm_lock[module]);
|
||||
|
||||
/* write new CMR value */
|
||||
iowrite32(val, NPCM7XX_PWM_REG_CMRx(data->pwm_base, module, pwm_ch));
|
||||
|
|
@ -245,7 +242,6 @@ static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_fan_data *data,
|
|||
env_bit = NPCM7XX_PWM_CTRL_CH3_INV_BIT;
|
||||
break;
|
||||
default:
|
||||
mutex_unlock(&data->pwm_lock[module]);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
@ -260,8 +256,6 @@ static int npcm7xx_pwm_config_set(struct npcm7xx_pwm_fan_data *data,
|
|||
}
|
||||
|
||||
iowrite32(tmp_buf, NPCM7XX_PWM_REG_CR(data->pwm_base, module));
|
||||
mutex_unlock(&data->pwm_lock[module]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -932,8 +926,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct device *hwmon;
|
||||
char name[20];
|
||||
int ret, cnt;
|
||||
u32 output_freq;
|
||||
int ret;
|
||||
u32 i;
|
||||
|
||||
np = dev->of_node;
|
||||
|
|
@ -985,9 +979,6 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
|
|||
output_freq = npcm7xx_pwm_init(data);
|
||||
npcm7xx_fan_init(data);
|
||||
|
||||
for (cnt = 0; cnt < data->pwm_modules; cnt++)
|
||||
mutex_init(&data->pwm_lock[cnt]);
|
||||
|
||||
for (i = 0; i < NPCM7XX_FAN_MAX_MODULE; i++) {
|
||||
spin_lock_init(&data->fan_lock[i]);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ enum ntc_thermistor_type {
|
|||
TYPE_NCPXXWF104,
|
||||
TYPE_NCPXXWL333,
|
||||
TYPE_NCPXXXH103,
|
||||
TYPE_NCPXXWM474,
|
||||
};
|
||||
|
||||
struct ntc_compensation {
|
||||
|
|
@ -46,6 +47,7 @@ enum {
|
|||
NTC_NCP18WB473,
|
||||
NTC_NCP21WB473,
|
||||
NTC_SSG1404001221,
|
||||
NTC_NCP18WM474,
|
||||
NTC_LAST,
|
||||
};
|
||||
|
||||
|
|
@ -60,6 +62,7 @@ static const struct platform_device_id ntc_thermistor_id[] = {
|
|||
[NTC_NCP18WB473] = { "ncp18wb473", TYPE_NCPXXWB473 },
|
||||
[NTC_NCP21WB473] = { "ncp21wb473", TYPE_NCPXXWB473 },
|
||||
[NTC_SSG1404001221] = { "ssg1404_001221", TYPE_NCPXXWB473 },
|
||||
[NTC_NCP18WM474] = { "ncp18wm474", TYPE_NCPXXWM474 },
|
||||
[NTC_LAST] = { },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, ntc_thermistor_id);
|
||||
|
|
@ -217,6 +220,43 @@ static const struct ntc_compensation ncpXXxh103[] = {
|
|||
{ .temp_c = 125, .ohm = 531 },
|
||||
};
|
||||
|
||||
static const struct ntc_compensation ncpXXwm474[] = {
|
||||
{ .temp_c = -40, .ohm = 10900000 },
|
||||
{ .temp_c = -35, .ohm = 9600000 },
|
||||
{ .temp_c = -30, .ohm = 8300000 },
|
||||
{ .temp_c = -25, .ohm = 7000000 },
|
||||
{ .temp_c = -20, .ohm = 5980000 },
|
||||
{ .temp_c = -15, .ohm = 4960000 },
|
||||
{ .temp_c = -10, .ohm = 3940000 },
|
||||
{ .temp_c = -5, .ohm = 2920000 },
|
||||
{ .temp_c = 0, .ohm = 1900000 },
|
||||
{ .temp_c = 5, .ohm = 1614000 },
|
||||
{ .temp_c = 10, .ohm = 1328000 },
|
||||
{ .temp_c = 15, .ohm = 1042000 },
|
||||
{ .temp_c = 20, .ohm = 756000 },
|
||||
{ .temp_c = 25, .ohm = 470000 },
|
||||
{ .temp_c = 30, .ohm = 404000 },
|
||||
{ .temp_c = 35, .ohm = 338000 },
|
||||
{ .temp_c = 40, .ohm = 272000 },
|
||||
{ .temp_c = 45, .ohm = 206000 },
|
||||
{ .temp_c = 50, .ohm = 140000 },
|
||||
{ .temp_c = 55, .ohm = 122000 },
|
||||
{ .temp_c = 60, .ohm = 104000 },
|
||||
{ .temp_c = 65, .ohm = 86000 },
|
||||
{ .temp_c = 70, .ohm = 68000 },
|
||||
{ .temp_c = 75, .ohm = 50000 },
|
||||
{ .temp_c = 80, .ohm = 44200 },
|
||||
{ .temp_c = 85, .ohm = 38400 },
|
||||
{ .temp_c = 90, .ohm = 32600 },
|
||||
{ .temp_c = 95, .ohm = 26800 },
|
||||
{ .temp_c = 100, .ohm = 21000 },
|
||||
{ .temp_c = 105, .ohm = 18600 },
|
||||
{ .temp_c = 110, .ohm = 16200 },
|
||||
{ .temp_c = 115, .ohm = 13800 },
|
||||
{ .temp_c = 120, .ohm = 11400 },
|
||||
{ .temp_c = 125, .ohm = 9000 },
|
||||
};
|
||||
|
||||
/*
|
||||
* The following compensation tables are from the specifications in EPCOS NTC
|
||||
* Thermistors Datasheets
|
||||
|
|
@ -319,6 +359,7 @@ static const struct ntc_type ntc_type[] = {
|
|||
NTC_TYPE(TYPE_NCPXXWF104, ncpXXwf104),
|
||||
NTC_TYPE(TYPE_NCPXXWL333, ncpXXwl333),
|
||||
NTC_TYPE(TYPE_NCPXXXH103, ncpXXxh103),
|
||||
NTC_TYPE(TYPE_NCPXXWM474, ncpXXwm474),
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -675,6 +716,8 @@ static const struct of_device_id ntc_match[] = {
|
|||
.data = &ntc_thermistor_id[NTC_NCP21WB473] },
|
||||
{ .compatible = "samsung,1404-001221",
|
||||
.data = &ntc_thermistor_id[NTC_SSG1404001221] },
|
||||
{ .compatible = "murata,ncp18wm474",
|
||||
.data = &ntc_thermistor_id[NTC_NCP18WM474] },
|
||||
|
||||
/* Usage of vendor name "ntc" is deprecated */
|
||||
{ .compatible = "ntc,ncp03wb473",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue