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:
Linus Torvalds 2025-12-04 12:19:49 -08:00
commit 02892f90a9
129 changed files with 3852 additions and 1284 deletions

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -18,8 +18,11 @@ description: |
properties: properties:
compatible: compatible:
enum: oneOf:
- aspeed,ast2600-pwm-tach - items:
- const: aspeed,ast2700-pwm-tach
- const: aspeed,ast2600-pwm-tach
- const: aspeed,ast2600-pwm-tach
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -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>;
};

View File

@ -20,7 +20,11 @@ description: >
properties: properties:
compatible: compatible:
const: maxim,max31790 enum:
- maxim,max31785
- maxim,max31785a
- maxim,max31785b
- maxim,max31790
reg: reg:
maxItems: 1 maxItems: 1
@ -31,11 +35,17 @@ properties:
resets: resets:
maxItems: 1 maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
"#pwm-cells": "#pwm-cells":
const: 1 const: 1
patternProperties: patternProperties:
"^fan-[0-9]+$": "^fan@[0-9]+$":
$ref: fan-common.yaml# $ref: fan-common.yaml#
unevaluatedProperties: false unevaluatedProperties: false
@ -56,13 +66,17 @@ examples:
reg = <0x20>; reg = <0x20>;
clocks = <&sys_clk>; clocks = <&sys_clk>;
resets = <&reset 0>; resets = <&reset 0>;
#address-cells = <1>;
#pwm-cells = <1>; #pwm-cells = <1>;
#size-cells = <0>;
fan-0 { fan@0 {
reg = <0x0>;
pwms = <&pwm_provider 1>; pwms = <&pwm_provider 1>;
}; };
fan-1 { fan@1 {
reg = <0x1>;
pwms = <&pwm_provider 2>; pwms = <&pwm_provider 2>;
}; };
}; };

View File

@ -75,6 +75,7 @@ properties:
- const: murata,ncp15wl333 - const: murata,ncp15wl333
- const: murata,ncp03wf104 - const: murata,ncp03wf104
- const: murata,ncp15xh103 - const: murata,ncp15xh103
- const: murata,ncp18wm474
- const: samsung,1404-001221 - const: samsung,1404-001221
# Deprecated "ntc," compatible strings # Deprecated "ntc," compatible strings
- const: ntc,ncp15wb473 - const: ntc,ncp15wb473

View File

@ -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>;
};
};
...

View File

@ -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;
};
};

View File

@ -43,8 +43,14 @@ properties:
- adi,ad5110 - adi,ad5110
# Temperature sensor with integrated fan control # Temperature sensor with integrated fan control
- adi,adm1027 - adi,adm1027
# Analog Devices ADT7410 High Accuracy Digital Temperature Sensor
- adi,adt7410
# Analog Devices ADT7411 Temperature Sensor and 8-channel ADC # Analog Devices ADT7411 Temperature Sensor and 8-channel ADC
- adi,adt7411 - 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 # Temperature sensor with integrated fan control
- adi,adt7463 - adi,adt7463
# Temperature sensor with integrated fan control # Temperature sensor with integrated fan control
@ -299,6 +305,10 @@ properties:
- mps,mp2888 - mps,mp2888
# Monolithic Power Systems Inc. multi-phase controller mp2891 # Monolithic Power Systems Inc. multi-phase controller mp2891
- mps,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 # Monolithic Power Systems Inc. multi-phase controller mp29502
- mps,mp29502 - mps,mp29502
# Monolithic Power Systems Inc. multi-phase controller mp29608 # Monolithic Power Systems Inc. multi-phase controller mp29608
@ -319,6 +329,8 @@ properties:
- mps,mp5998 - mps,mp5998
# Monolithic Power Systems Inc. digital step-down converter mp9941 # Monolithic Power Systems Inc. digital step-down converter mp9941
- mps,mp9941 - mps,mp9941
# Monolithic Power Systems Inc. digital step-down converter mp9945
- mps,mp9945
# Temperature sensor with integrated fan control # Temperature sensor with integrated fan control
- national,lm63 - national,lm63
# Temperature sensor with integrated fan control # Temperature sensor with integrated fan control

View File

@ -20,6 +20,14 @@ Supported chips:
English: http://www.aosong.com/userfiles/files/media/Data%20Sheet%20AHT20.pdf 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> Author: Johannes Cornelis Draaijer <jcdra1@gmail.com>
@ -33,7 +41,7 @@ The address of this i2c device may only be 0x38
Special Features 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. values.
Usage Notes Usage Notes

View File

@ -9,6 +9,7 @@ Supported boards:
* PRIME X570-PRO * PRIME X570-PRO
* PRIME X670E-PRO WIFI * PRIME X670E-PRO WIFI
* PRIME Z270-A * PRIME Z270-A
* Pro WS TRX50-SAGE WIFI
* Pro WS X570-ACE * Pro WS X570-ACE
* Pro WS WRX90E-SAGE SE * Pro WS WRX90E-SAGE SE
* ProArt X570-CREATOR WIFI * ProArt X570-CREATOR WIFI
@ -29,14 +30,17 @@ Supported boards:
* ROG STRIX B550-I GAMING * ROG STRIX B550-I GAMING
* ROG STRIX B650E-I GAMING WIFI * ROG STRIX B650E-I GAMING WIFI
* ROG STRIX B850-I GAMING WIFI * ROG STRIX B850-I GAMING WIFI
* ROG STRIX X470-I GAMING
* ROG STRIX X570-E GAMING * ROG STRIX X570-E GAMING
* ROG STRIX X570-E GAMING WIFI II * ROG STRIX X570-E GAMING WIFI II
* ROG STRIX X570-F GAMING * ROG STRIX X570-F GAMING
* ROG STRIX X570-I GAMING * ROG STRIX X570-I GAMING
* ROG STRIX X670E-E GAMING WIFI * ROG STRIX X670E-E GAMING WIFI
* ROG STRIX X670E-I GAMING WIFI * ROG STRIX X670E-I GAMING WIFI
* ROG STRIX X870-F GAMING WIFI
* ROG STRIX X870-I GAMING WIFI * ROG STRIX X870-I GAMING WIFI
* ROG STRIX X870E-E GAMING WIFI * ROG STRIX X870E-E GAMING WIFI
* ROG STRIX X870E-H GAMING WIFI7
* ROG STRIX Z390-F GAMING * ROG STRIX Z390-F GAMING
* ROG STRIX Z490-F GAMING * ROG STRIX Z490-F GAMING
* ROG STRIX Z690-A GAMING WIFI D4 * ROG STRIX Z690-A GAMING WIFI D4

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: none 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 * Dallas Semiconductor DS1625
@ -17,7 +17,7 @@ Supported chips:
Addresses scanned: none 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 * Maxim Integrated DS1631
@ -25,7 +25,7 @@ Supported chips:
Addresses scanned: none 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 * Maxim Integrated DS1721
@ -33,7 +33,7 @@ Supported chips:
Addresses scanned: none 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 * Maxim Integrated DS1731
@ -41,7 +41,7 @@ Supported chips:
Addresses scanned: none 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: Authors:
- Christian W. Zuckschwerdt <zany@triq.net> - Christian W. Zuckschwerdt <zany@triq.net>

View File

@ -144,6 +144,7 @@ Hardware Monitoring Kernel Drivers
ltc4261 ltc4261
ltc4282 ltc4282
ltc4286 ltc4286
macsmc-hwmon
max127 max127
max15301 max15301
max16064 max16064
@ -151,6 +152,7 @@ Hardware Monitoring Kernel Drivers
max1619 max1619
max16601 max16601
max1668 max1668
max17616
max197 max197
max20730 max20730
max20751 max20751
@ -177,6 +179,7 @@ Hardware Monitoring Kernel Drivers
mp2869 mp2869
mp2888 mp2888
mp2891 mp2891
mp2925
mp29502 mp29502
mp2975 mp2975
mp2993 mp2993
@ -184,6 +187,7 @@ Hardware Monitoring Kernel Drivers
mp5920 mp5920
mp5990 mp5990
mp9941 mp9941
mp9945
mpq8785 mpq8785
nct6683 nct6683
nct6775 nct6775
@ -253,6 +257,7 @@ Hardware Monitoring Kernel Drivers
tps40422 tps40422
tps53679 tps53679
tps546d24 tps546d24
tsc1641
twl4030-madc-hwmon twl4030-madc-hwmon
ucd9000 ucd9000
ucd9200 ucd9200

View File

@ -414,6 +414,16 @@ Supported chips:
Publicly available (after August 2020 launch) at the Renesas website 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: Authors:
- Maxim Sloyko <maxims@google.com> - Maxim Sloyko <maxims@google.com>
- Robert Lippert <rlippert@google.com> - Robert Lippert <rlippert@google.com>

View File

@ -33,7 +33,7 @@ Supported chips:
Datasheets: 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 * Microchip MCP9804, MCP9805, MCP9808, MCP98242, MCP98243, MCP98244, MCP9843

View File

@ -23,15 +23,17 @@ Supported chips:
http://www.national.com/ http://www.national.com/
* Dallas Semiconductor (now Maxim) DS75, DS1775, DS7505 * Dallas Semiconductor (now Analog Devices) DS75, DS1775, DS7505
Prefixes: 'ds75', 'ds1775', 'ds7505' Prefixes: 'ds75', 'ds1775', 'ds7505'
Addresses scanned: none 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 * Maxim MAX6625, MAX6626, MAX31725, MAX31726
@ -39,9 +41,10 @@ Supported chips:
Addresses scanned: none 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 * Microchip (TelCom) TCN75

View File

@ -9,7 +9,9 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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 * National Semiconductor LM90
@ -17,9 +19,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * National Semiconductor LM89
@ -27,9 +29,9 @@ Supported chips:
Addresses scanned: I2C 0x4c and 0x4d 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 * National Semiconductor LM99
@ -37,9 +39,9 @@ Supported chips:
Addresses scanned: I2C 0x4c and 0x4d 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 * National Semiconductor LM86
@ -47,9 +49,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * Analog Devices ADM1020
@ -57,7 +59,9 @@ Supported chips:
Addresses scanned: I2C 0x4c - 0x4e 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 * Analog Devices ADM1021
@ -65,7 +69,9 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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 * Analog Devices ADM1021A/ADM1023
@ -75,15 +81,18 @@ Supported chips:
Datasheet: Publicly available at the Analog Devices website 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 * Analog Devices ADM1032
Prefix: 'adm1032' Prefix: 'adm1032'
Addresses scanned: I2C 0x4c and 0x4d 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 * Analog Devices ADT7461
@ -111,9 +120,9 @@ Supported chips:
Addresses scanned: I2C 0x4b and 0x4c 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 * Analog Devices ADT7482
@ -191,7 +200,9 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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 * Maxim MAX1617A
@ -199,7 +210,9 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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 * Maxim MAX6642
@ -207,9 +220,9 @@ Supported chips:
Addresses scanned: I2C 0x48-0x4f 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 * Maxim MAX6646
@ -217,9 +230,9 @@ Supported chips:
Addresses scanned: I2C 0x4d 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 * Maxim MAX6647
@ -227,9 +240,9 @@ Supported chips:
Addresses scanned: I2C 0x4e 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 * Maxim MAX6648
@ -237,9 +250,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * Maxim MAX6649
@ -247,9 +260,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * Maxim MAX6654
@ -259,9 +272,9 @@ Supported chips:
0x4c, 0x4d and 0x4e 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 * Maxim MAX6657
@ -269,9 +282,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * Maxim MAX6658
@ -279,9 +292,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * Maxim MAX6659
@ -289,9 +302,9 @@ Supported chips:
Addresses scanned: I2C 0x4c, 0x4d, 0x4e 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 * Maxim MAX6680
@ -301,9 +314,9 @@ Supported chips:
0x4c, 0x4d and 0x4e 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 * Maxim MAX6681
@ -313,9 +326,9 @@ Supported chips:
0x4c, 0x4d and 0x4e 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 * Maxim MAX6692
@ -323,9 +336,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * Maxim MAX6695
@ -333,9 +346,9 @@ Supported chips:
Addresses scanned: I2C 0x18 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 * Maxim MAX6696
@ -345,9 +358,9 @@ Supported chips:
0x4c, 0x4d and 0x4e 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 * Winbond/Nuvoton W83L771W/G
@ -355,7 +368,9 @@ Supported chips:
Addresses scanned: I2C 0x4c 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 * Winbond/Nuvoton W83L771AWG/ASG
@ -401,7 +416,7 @@ Supported chips:
Datasheet: Publicly available at NXP website 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 * GMT G781
@ -437,7 +452,9 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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 * Philips NE1618
@ -445,7 +462,9 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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 * Genesys Logic GL523SM
@ -453,7 +472,7 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Datasheet: No longer available at Genesys Logic website
* TI THMC10 * TI THMC10
@ -461,7 +480,7 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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 * Onsemi MC1066
@ -469,7 +488,7 @@ Supported chips:
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e 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> Author: Jean Delvare <jdelvare@suse.de>

View File

@ -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

View File

@ -13,7 +13,7 @@ Supported chips:
Prefix: 'max127' 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 Description
----------- -----------

View File

@ -11,7 +11,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX15303

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: - 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> Author: Guenter Roeck <linux@roeck-us.net>

View File

@ -12,7 +12,7 @@ Supported chips:
Datasheet: 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 * Maxim MAX16067
@ -22,7 +22,7 @@ Supported chips:
Datasheet: Datasheet:
http://datasheets.maxim-ic.com/en/ds/MAX16067.pdf https://www.analog.com/media/en/technical-documentation/data-sheets/max16067.pdf
* Maxim MAX16068 * Maxim MAX16068
@ -32,7 +32,7 @@ Supported chips:
Datasheet: 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 * Maxim MAX16070/MAX16071
@ -42,7 +42,7 @@ Supported chips:
Datasheet: 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> Author: Guenter Roeck <linux@roeck-us.net>

View File

@ -9,9 +9,9 @@ Supported chips:
Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e 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: Authors:
- Oleksij Rempel <bug-track@fisher-privat.net>, - Oleksij Rempel <bug-track@fisher-privat.net>,

View File

@ -35,7 +35,7 @@ Supported chips:
Addresses scanned: - 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> Author: Guenter Roeck <linux@roeck-us.net>

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e 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: Author:

View File

@ -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
================= ========================================

View File

@ -11,13 +11,13 @@ Supported chips:
Prefix: 'max197' 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 * Maxim MAX199
Prefix: '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 Description
----------- -----------

View File

@ -11,7 +11,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX20730
@ -19,7 +19,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX20734
@ -27,7 +27,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX20743
@ -35,7 +35,7 @@ Supported chips:
Addresses scanned: - 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> Author: Guenter Roeck <linux@roeck-us.net>

View File

@ -11,7 +11,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim Integrated MAX31723
@ -21,7 +21,7 @@ Supported chips:
Addresses scanned: - 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> Author: Tiberiu Breana <tiberiu.a.breana@intel.com>

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: 0x1c, 0x1d, 0x1e, 0x1f, 0x4c, 0x4d, 0x4e, 0x4f 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> Author: Guenter Roeck <linux@roeck-us.net>

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: - 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> Author: Andrew Jeffery <andrew@aj.id.au>

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: - 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> Author: Il Han <corone.il.han@gmail.com>

View File

@ -11,7 +11,7 @@ Supported chips:
Addresses scanned: I2C 0x40 - 0x5f 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 * Maxim MAX31828
@ -19,7 +19,7 @@ Supported chips:
Addresses scanned: I2C 0x40 - 0x5f 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 * Maxim MAX31829
@ -27,7 +27,7 @@ Supported chips:
Addresses scanned: I2C 0x40 - 0x5f 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: Authors:

View File

@ -11,13 +11,21 @@ Supported chips:
Datasheet: - Datasheet: -
* ADI ADPM12200
Prefixes: 'adpm12200'
Addresses scanned: -
Datasheet: -
* Maxim MAX34440 * Maxim MAX34440
Prefixes: 'max34440' Prefixes: 'max34440'
Addresses scanned: - 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 * Maxim MAX34441
@ -27,7 +35,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX34446
@ -37,7 +45,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX34451
@ -47,7 +55,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX34460
@ -57,7 +65,7 @@ Supported chips:
Addresses scanned: - 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 * Maxim MAX34461
@ -67,7 +75,7 @@ Supported chips:
Addresses scanned: - 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> 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 PMBus 6-Channel Power-Supply Manager, MAX34441 PMBus 5-Channel Power-Supply
Manager and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data Manager and Intelligent Fan Controller, and MAX34446 PMBus Power-Supply Data
Logger; PMBus Voltage Monitor and Sequencers for MAX34451, MAX34460, and Logger; PMBus Voltage Monitor and Sequencers for MAX34451, MAX34460, and
MAX34461; PMBus DC/DC Power Module ADPM12160. The MAX34451 supports monitoring MAX34461; PMBus DC/DC Power Module ADPM12160, and ADPM12200. The MAX34451
voltage or current of 12 channels based on GIN pins. The MAX34460 supports 12 supports monitoring voltage or current of 12 channels based on GIN pins. The
voltage channels, and the MAX34461 supports 16 voltage channels. The ADPM1260 MAX34460 supports 12 voltage channels, and the MAX34461 supports 16 voltage
also monitors both input and output of voltage and current. 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 The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus.rst for details on PMBus client drivers. 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:: .. note::
- MAX34446 only supports in[1-4]. - 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 Curr
~~~~ ~~~~
@ -162,7 +172,8 @@ curr[1-6]_reset_history Write any value to reset history.
- in6 and curr6 attributes only exist for MAX34440. - in6 and curr6 attributes only exist for MAX34440.
- MAX34446 only supports curr[1-4]. - 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 Power
~~~~~ ~~~~~
@ -198,7 +209,7 @@ temp[1-8]_reset_history Write any value to reset history.
.. note:: .. note::
- temp7 and temp8 attributes only exist for MAX34440. - temp7 and temp8 attributes only exist for MAX34440.
- MAX34446 only supports temp[1-3]. - MAX34446 only supports temp[1-3].
- ADPM12160 only supports temp[1]. - ADPM12160, and ADPM12200 only supports temp[1].
.. note:: .. note::

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: I2C 0x2c, 0x2e, 0x2f 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: Authors:
- He Changqing <hechangqing@semptian.com> - He Changqing <hechangqing@semptian.com>

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: none 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 * Maxim MAX6651
@ -17,7 +17,7 @@ Supported chips:
Addresses scanned: none 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: Authors:
- Hans J. Koch <hjk@hansjkoch.de> - Hans J. Koch <hjk@hansjkoch.de>

View File

@ -7,61 +7,61 @@ Supported chips:
Prefix: 'max6581' 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 * Maxim MAX6602
Prefix: '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 * Maxim MAX6622
Prefix: '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 * Maxim MAX6636
Prefix: '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 * Maxim MAX6689
Prefix: '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 * Maxim MAX6693
Prefix: '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 * Maxim MAX6694
Prefix: '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 * Maxim MAX6697
Prefix: '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 * Maxim MAX6698
Prefix: '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 * Maxim MAX6699
Prefix: '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: Author:

View File

@ -11,7 +11,9 @@ Supported chips:
Addresses scanned: none Addresses scanned: none
Datasheet: Not available Datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/max77505.pdf
Authors: Authors:
- Dzmitry Sankouski <dsankouski@gmail.com> - Dzmitry Sankouski <dsankouski@gmail.com>

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: - 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> Author: Guenter Roeck <linux@roeck-us.net>

View File

@ -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**

View File

@ -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**

View File

@ -74,7 +74,7 @@ Supported chips:
Datasheet: Datasheet:
Not published https://www.analog.com/media/en/technical-documentation/data-sheets/MAX20796.pdf
* Generic PMBus devices * Generic PMBus devices

View File

@ -17,10 +17,10 @@ the Silergy SY7636A PMIC.
The following sensors are supported The following sensors are supported
* Temperature * Temperature
- SoC on-die temperature in milli-degree C - Temperature of external NTC in milli-degree C
sysfs-Interface sysfs-Interface
--------------- ---------------
temp0_input temp0_input
- SoC on-die temperature (milli-degree C) - Temperature of external NTC (milli-degree C)

View File

@ -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
==================== ===========================================================

View File

@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL2005
@ -17,7 +17,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL2006
@ -25,7 +25,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL2008
@ -33,7 +33,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL2105
@ -41,7 +41,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL2106
@ -49,7 +49,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL6100
@ -57,7 +57,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL6105
@ -65,7 +65,7 @@ Supported chips:
Addresses scanned: - 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 * Renesas / Intersil / Zilker Labs ZL8802

View File

@ -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/spi/apple,spi.yaml
F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml
F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
F: Documentation/hwmon/macsmc-hwmon.rst
F: arch/arm64/boot/dts/apple/ F: arch/arm64/boot/dts/apple/
F: drivers/bluetooth/hci_bcm4377.c F: drivers/bluetooth/hci_bcm4377.c
F: drivers/clk/clk-apple-nco.c F: drivers/clk/clk-apple-nco.c
F: drivers/cpufreq/apple-soc-cpufreq.c F: drivers/cpufreq/apple-soc-cpufreq.c
F: drivers/dma/apple-admac.c F: drivers/dma/apple-admac.c
F: drivers/gpio/gpio-macsmc.c F: drivers/gpio/gpio-macsmc.c
F: drivers/hwmon/macsmc-hwmon.c
F: drivers/pmdomain/apple/ F: drivers/pmdomain/apple/
F: drivers/i2c/busses/i2c-pasemi-core.c F: drivers/i2c/busses/i2c-pasemi-core.c
F: drivers/i2c/busses/i2c-pasemi-platform.c F: drivers/i2c/busses/i2c-pasemi-platform.c
@ -15228,6 +15230,15 @@ S: Maintained
F: Documentation/hwmon/max15301.rst F: Documentation/hwmon/max15301.rst
F: drivers/hwmon/pmbus/max15301.c 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 MAX2175 SDR TUNER DRIVER
M: Ramesh Shanmugasundaram <rashanmu@gmail.com> M: Ramesh Shanmugasundaram <rashanmu@gmail.com>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
@ -17545,6 +17556,13 @@ S: Maintained
F: Documentation/hwmon/mp2891.rst F: Documentation/hwmon/mp2891.rst
F: drivers/hwmon/pmbus/mp2891.c 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 MPS MP29502 DRIVER
M: Wensheng Wang <wenswang@yeah.net> M: Wensheng Wang <wenswang@yeah.net>
L: linux-hwmon@vger.kernel.org L: linux-hwmon@vger.kernel.org
@ -17566,6 +17584,13 @@ S: Maintained
F: Documentation/hwmon/mp9941.rst F: Documentation/hwmon/mp9941.rst
F: drivers/hwmon/pmbus/mp9941.c 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 MR800 AVERMEDIA USB FM RADIO DRIVER
M: Alexey Klimov <alexey.klimov@linaro.org> M: Alexey Klimov <alexey.klimov@linaro.org>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
@ -24493,6 +24518,14 @@ S: Maintained
F: Documentation/hwmon/stpddc60.rst F: Documentation/hwmon/stpddc60.rst
F: drivers/hwmon/pmbus/stpddc60.c 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 ST VD55G1 DRIVER
M: Benjamin Mugnier <benjamin.mugnier@foss.st.com> M: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
M: Sylvain Petinot <sylvain.petinot@foss.st.com> M: Sylvain Petinot <sylvain.petinot@foss.st.com>

View File

@ -175,7 +175,7 @@ config SENSORS_ADT7X10
select REGMAP select REGMAP
help help
This module contains common code shared by the ADT7310/ADT7320 and 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. If built as a module, the module will be called adt7x10.
@ -191,12 +191,12 @@ config SENSORS_ADT7310
will be called adt7310. will be called adt7310.
config SENSORS_ADT7410 config SENSORS_ADT7410
tristate "Analog Devices ADT7410/ADT7420" tristate "Analog Devices ADT7410/ADT7420/ADT7422"
depends on I2C depends on I2C
select SENSORS_ADT7X10 select SENSORS_ADT7X10
help help
If you say yes here you get support for the Analog Devices 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 This driver can also be built as a module. If so, the module
will be called adt7410. will be called adt7410.
@ -245,12 +245,12 @@ config SENSORS_ADT7475
will be called adt7475. will be called adt7475.
config SENSORS_AHT10 config SENSORS_AHT10
tristate "Aosong AHT10, AHT20" tristate "Aosong AHT10, AHT20, DHT20"
depends on I2C depends on I2C
select CRC8 select CRC8
help help
If you say yes here, you get support for the Aosong AHT10 and AHT20 If you say yes here, you get support for the Aosong AHT10, AHT20 and
temperature and humidity sensors DHT20 temperature and humidity sensors
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called aht10. will be called aht10.
@ -1174,6 +1174,18 @@ config SENSORS_LTQ_CPUTEMP
If you say yes here you get support for the temperature If you say yes here you get support for the temperature
sensor inside your CPU. 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 config SENSORS_MAX1111
tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles" tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles"
depends on SPI_MASTER depends on SPI_MASTER
@ -2434,6 +2446,18 @@ config SENSORS_TMP513
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called tmp513. 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 config SENSORS_VEXPRESS
tristate "Versatile Express" tristate "Versatile Express"
depends on VEXPRESS_CONFIG depends on VEXPRESS_CONFIG

View File

@ -148,6 +148,7 @@ obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_LTC4282) += ltc4282.o obj-$(CONFIG_SENSORS_LTC4282) += ltc4282.o
obj-$(CONFIG_SENSORS_LTQ_CPUTEMP) += ltq-cputemp.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_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX127) += max127.o obj-$(CONFIG_SENSORS_MAX127) += max127.o
obj-$(CONFIG_SENSORS_MAX16065) += max16065.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_TMP421) += tmp421.o
obj-$(CONFIG_SENSORS_TMP464) += tmp464.o obj-$(CONFIG_SENSORS_TMP464) += tmp464.o
obj-$(CONFIG_SENSORS_TMP513) += tmp513.o obj-$(CONFIG_SENSORS_TMP513) += tmp513.o
obj-$(CONFIG_SENSORS_TSC1641) += tsc1641.o
obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o

View File

@ -197,8 +197,16 @@ static int adm1026_scaling[] = { /* .001 Volts */
#define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \ #define FAN_TO_REG(val, div) ((val) <= 0 ? 0xff : \
clamp_val(1350000 / ((val) * (div)), \ clamp_val(1350000 / ((val) * (div)), \
1, 254)) 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_FROM_REG(val) (1 << (val))
#define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0) #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); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index; int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev); 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])); data->fan_div[nr]));
} }
static ssize_t fan_min_show(struct device *dev, struct device_attribute *attr, 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); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index; int nr = sensor_attr->index;
struct adm1026_data *data = adm1026_update_device(dev); 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])); data->fan_div[nr]));
} }
static ssize_t fan_min_store(struct device *dev, static ssize_t fan_min_store(struct device *dev,

View File

@ -171,14 +171,17 @@ fan_show(struct device *dev, struct device_attribute *devattr, char *buf)
struct adm1029_data *data = adm1029_update_device(dev); struct adm1029_data *data = adm1029_update_device(dev);
u16 val; u16 val;
mutex_lock(&data->update_lock);
if (data->fan[attr->index] == 0 || if (data->fan[attr->index] == 0 ||
(data->fan_div[attr->index] & 0xC0) == 0 || (data->fan_div[attr->index] & 0xC0) == 0 ||
data->fan[attr->index] == 255) { data->fan[attr->index] == 255) {
mutex_unlock(&data->update_lock);
return sprintf(buf, "0\n"); return sprintf(buf, "0\n");
} }
val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index]) val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])
/ data->fan[attr->index]; / data->fan[attr->index];
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", val); return sprintf(buf, "%d\n", val);
} }

View File

@ -37,7 +37,6 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-vid.h> #include <linux/hwmon-vid.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
/* Addresses to scan */ /* Addresses to scan */
@ -125,7 +124,6 @@ static inline unsigned int AOUT_FROM_REG(u8 reg)
struct adm9240_data { struct adm9240_data {
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
struct mutex update_lock;
u8 fan_div[2]; /* rw fan1_div, read-only accessor */ u8 fan_div[2]; /* rw fan1_div, read-only accessor */
u8 vrm; /* -- vrm set on startup, no 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; u8 fan_min;
int err; int err;
mutex_lock(&data->update_lock);
if (!val) { if (!val) {
fan_min = 255; fan_min = 255;
new_div = data->fan_div[channel]; 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); err = regmap_write(data->regmap, ADM9240_REG_FAN_MIN(channel), fan_min);
mutex_unlock(&data->update_lock);
return err; return err;
} }
@ -501,23 +495,17 @@ static int adm9240_fan_read(struct device *dev, u32 attr, int channel, long *val
switch (attr) { switch (attr) {
case hwmon_fan_input: case hwmon_fan_input:
mutex_lock(&data->update_lock);
err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), &regval); err = regmap_read(data->regmap, ADM9240_REG_FAN(channel), &regval);
if (err < 0) { if (err < 0)
mutex_unlock(&data->update_lock);
return err; return err;
}
if (regval == 255 && data->fan_div[channel] < 3) { if (regval == 255 && data->fan_div[channel] < 3) {
/* adjust fan clock divider on overflow */ /* adjust fan clock divider on overflow */
err = adm9240_write_fan_div(data, channel, err = adm9240_write_fan_div(data, channel,
++data->fan_div[channel]); ++data->fan_div[channel]);
if (err) { if (err)
mutex_unlock(&data->update_lock);
return err; return err;
} }
}
*val = FAN_FROM_REG(regval, BIT(data->fan_div[channel])); *val = FAN_FROM_REG(regval, BIT(data->fan_div[channel]));
mutex_unlock(&data->update_lock);
break; break;
case hwmon_fan_div: case hwmon_fan_div:
*val = BIT(data->fan_div[channel]); *val = BIT(data->fan_div[channel]);
@ -791,7 +779,6 @@ static int adm9240_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
data->dev = dev; data->dev = dev;
mutex_init(&data->update_lock);
data->regmap = devm_regmap_init_i2c(client, &adm9240_regmap_config); data->regmap = devm_regmap_init_i2c(client, &adm9240_regmap_config);
if (IS_ERR(data->regmap)) if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap); return PTR_ERR(data->regmap);

View File

@ -7,6 +7,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/regmap.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[] = { static const struct i2c_device_id adt7410_ids[] = {
{ "adt7410" }, { "adt7410" },
{ "adt7420" }, { "adt7420" },
{ "adt7422" },
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, adt7410_ids); 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 = { static struct i2c_driver adt7410_driver = {
.driver = { .driver = {
.name = "adt7410", .name = "adt7410",
.pm = pm_sleep_ptr(&adt7x10_dev_pm_ops), .pm = pm_sleep_ptr(&adt7x10_dev_pm_ops),
.of_match_table = adt7410_of_match,
}, },
.probe = adt7410_i2c_probe, .probe = adt7410_i2c_probe,
.id_table = adt7410_ids, .id_table = adt7410_ids,

View File

@ -11,7 +11,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
@ -99,8 +98,6 @@ static const u8 adt7411_in_alarm_bits[] = {
}; };
struct adt7411_data { struct adt7411_data {
struct mutex device_lock; /* for "atomic" device accesses */
struct mutex update_lock;
unsigned long next_update; unsigned long next_update;
long vref_cached; long vref_cached;
struct i2c_client *client; struct i2c_client *client;
@ -110,55 +107,41 @@ struct adt7411_data {
/* /*
* When reading a register containing (up to 4) lsb, all associated * 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, * 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 * _all_ are unlocked.
* is protected here with a mutex, too.
*/ */
static int adt7411_read_10_bit(struct i2c_client *client, u8 lsb_reg, 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; int val, tmp;
mutex_lock(&data->device_lock);
val = i2c_smbus_read_byte_data(client, lsb_reg); val = i2c_smbus_read_byte_data(client, lsb_reg);
if (val < 0) if (val < 0)
goto exit_unlock; return val;
tmp = (val >> lsb_shift) & 3; tmp = (val >> lsb_shift) & 3;
val = i2c_smbus_read_byte_data(client, msb_reg); val = i2c_smbus_read_byte_data(client, msb_reg);
if (val < 0)
return val;
if (val >= 0)
val = (val << 2) | tmp; val = (val << 2) | tmp;
exit_unlock:
mutex_unlock(&data->device_lock);
return val; return val;
} }
static int adt7411_modify_bit(struct i2c_client *client, u8 reg, u8 bit, 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; int ret, val;
mutex_lock(&data->device_lock);
ret = i2c_smbus_read_byte_data(client, reg); ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) if (ret < 0)
goto exit_unlock; return ret;
if (flag) if (flag)
val = ret | bit; val = ret | bit;
else else
val = ret & ~bit; val = ret & ~bit;
ret = i2c_smbus_write_byte_data(client, reg, val); return i2c_smbus_write_byte_data(client, reg, val);
exit_unlock:
mutex_unlock(&data->device_lock);
return ret;
} }
static ssize_t adt7411_show_bit(struct device *dev, 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) if (ret || flag > 1)
return -EINVAL; return -EINVAL;
hwmon_lock(dev);
ret = adt7411_modify_bit(client, s_attr2->index, s_attr2->nr, flag); ret = adt7411_modify_bit(client, s_attr2->index, s_attr2->nr, flag);
/* force update */ /* force update */
mutex_lock(&data->update_lock);
data->next_update = jiffies; data->next_update = jiffies;
mutex_unlock(&data->update_lock); hwmon_unlock(dev);
return ret < 0 ? ret : count; 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 reg, lsb_reg, lsb_shift;
int nr = channel - 1; int nr = channel - 1;
mutex_lock(&data->update_lock);
ret = adt7411_update_vref(dev); ret = adt7411_update_vref(dev);
if (ret < 0) if (ret < 0)
goto exit_unlock; return ret;
switch (attr) { switch (attr) {
case hwmon_in_input: 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, ADT7411_REG_EXT_TEMP_AIN1_MSB + nr,
lsb_shift); lsb_shift);
if (ret < 0) if (ret < 0)
goto exit_unlock; return ret;
*val = ret * data->vref_cached / 1024; *val = ret * data->vref_cached / 1024;
ret = 0; ret = 0;
break; break;
@ -318,7 +299,7 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel,
: ADT7411_REG_IN_HIGH(channel); : ADT7411_REG_IN_HIGH(channel);
ret = i2c_smbus_read_byte_data(client, reg); ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) if (ret < 0)
goto exit_unlock; return ret;
*val = ret * data->vref_cached / 256; *val = ret * data->vref_cached / 256;
ret = 0; ret = 0;
break; break;
@ -329,8 +310,6 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel,
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;
} }
exit_unlock:
mutex_unlock(&data->update_lock);
return ret; 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; struct i2c_client *client = data->client;
int ret, reg; int ret, reg;
mutex_lock(&data->update_lock);
ret = adt7411_update_vref(dev); ret = adt7411_update_vref(dev);
if (ret < 0) if (ret < 0)
goto exit_unlock; return ret;
val = clamp_val(val, 0, 255 * data->vref_cached / 256); val = clamp_val(val, 0, 255 * data->vref_cached / 256);
val = DIV_ROUND_CLOSEST(val * 256, data->vref_cached); 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); reg = ADT7411_REG_IN_HIGH(channel);
break; break;
default: default:
ret = -EOPNOTSUPP; return -EOPNOTSUPP;
goto exit_unlock;
} }
ret = i2c_smbus_write_byte_data(client, reg, val); ret = i2c_smbus_write_byte_data(client, reg, val);
exit_unlock:
mutex_unlock(&data->update_lock);
return ret; return ret;
} }
@ -679,8 +654,6 @@ static int adt7411_probe(struct i2c_client *client)
i2c_set_clientdata(client, data); i2c_set_clientdata(client, data);
data->client = client; data->client = client;
mutex_init(&data->device_lock);
mutex_init(&data->update_lock);
ret = adt7411_init_device(data); ret = adt7411_init_device(data);
if (ret < 0) if (ret < 0)

View File

@ -15,7 +15,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -55,7 +54,6 @@
/* Each client has this additional data */ /* Each client has this additional data */
struct adt7x10_data { struct adt7x10_data {
struct regmap *regmap; struct regmap *regmap;
struct mutex update_lock;
u8 config; u8 config;
u8 oldconfig; u8 oldconfig;
bool valid; /* true if temperature valid */ 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; unsigned int regval;
int ret; int ret;
mutex_lock(&data->update_lock);
if (index == adt7x10_temperature && !data->valid) { if (index == adt7x10_temperature && !data->valid) {
/* wait for valid temperature */ /* wait for valid temperature */
ret = adt7x10_temp_ready(data->regmap); ret = adt7x10_temp_ready(data->regmap);
if (ret) { if (ret)
mutex_unlock(&data->update_lock);
return ret; return ret;
}
data->valid = true; data->valid = true;
} }
mutex_unlock(&data->update_lock);
ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &regval); ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &regval);
if (ret) 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) static int adt7x10_temp_write(struct adt7x10_data *data, int index, long temp)
{ {
int ret; return regmap_write(data->regmap, ADT7X10_REG_TEMP[index],
mutex_lock(&data->update_lock);
ret = regmap_write(data->regmap, ADT7X10_REG_TEMP[index],
ADT7X10_TEMP_TO_REG(temp)); ADT7X10_TEMP_TO_REG(temp));
mutex_unlock(&data->update_lock);
return ret;
} }
static int adt7x10_hyst_read(struct adt7x10_data *data, int index, long *val) 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; unsigned int regval;
int limit, ret; int limit, ret;
mutex_lock(&data->update_lock);
/* convert absolute hysteresis value to a 4 bit delta value */ /* convert absolute hysteresis value to a 4 bit delta value */
ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, &regval); ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, &regval);
if (ret < 0) if (ret < 0)
goto abort; return ret;
limit = ADT7X10_REG_TO_TEMP(data, regval); limit = ADT7X10_REG_TO_TEMP(data, regval);
hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX); hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0, regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
ADT7X10_T_HYST_MASK); ADT7X10_T_HYST_MASK);
ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval); return regmap_write(data->regmap, ADT7X10_T_HYST, regval);
abort:
mutex_unlock(&data->update_lock);
return ret;
} }
static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val) 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; data->regmap = regmap;
dev_set_drvdata(dev, data); dev_set_drvdata(dev, data);
mutex_init(&data->update_lock);
/* configure as specified */ /* configure as specified */
ret = regmap_read(regmap, ADT7X10_CONFIG, &config); ret = regmap_read(regmap, ADT7X10_CONFIG, &config);

View File

@ -37,6 +37,8 @@
#define AHT10_CMD_MEAS 0b10101100 #define AHT10_CMD_MEAS 0b10101100
#define AHT10_CMD_RST 0b10111010 #define AHT10_CMD_RST 0b10111010
#define DHT20_CMD_INIT 0x71
/* /*
* Flags in the answer byte/command * Flags in the answer byte/command
*/ */
@ -48,11 +50,12 @@
#define AHT10_MAX_POLL_INTERVAL_LEN 30 #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[] = { static const struct i2c_device_id aht10_id[] = {
{ "aht10", aht10 }, { "aht10", aht10 },
{ "aht20", aht20 }, { "aht20", aht20 },
{ "dht20", dht20 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(i2c, aht10_id); 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 * struct aht10_data - All the data required to operate an AHT10/AHT20 chip
* @client: the i2c client associated with the AHT10/AHT20 * @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 * @min_poll_interval: the minimum poll interval
* While the poll rate limit is not 100% necessary, * While the poll rate limit is not 100% necessary,
* the datasheet recommends that a measurement * the datasheet recommends that a measurement
@ -77,21 +78,18 @@ MODULE_DEVICE_TABLE(i2c, aht10_id);
* AHT10/AHT20 * AHT10/AHT20
* @crc8: crc8 support flag * @crc8: crc8 support flag
* @meas_size: measurements data size * @meas_size: measurements data size
* @init_cmd: Initialization command
*/ */
struct aht10_data { struct aht10_data {
struct i2c_client *client; 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 min_poll_interval;
ktime_t previous_poll_time; ktime_t previous_poll_time;
int temperature; int temperature;
int humidity; int humidity;
bool crc8; bool crc8;
unsigned int meas_size; unsigned int meas_size;
u8 init_cmd;
}; };
/* /*
@ -101,13 +99,13 @@ struct aht10_data {
*/ */
static int aht10_init(struct aht10_data *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}; 0x00};
int res; int res;
u8 status; u8 status;
struct i2c_client *client = data->client; 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) if (res < 0)
return res; return res;
@ -168,32 +166,24 @@ static int aht10_read_values(struct aht10_data *data)
u8 raw_data[AHT20_MEAS_SIZE]; u8 raw_data[AHT20_MEAS_SIZE];
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
mutex_lock(&data->lock); if (!aht10_polltime_expired(data))
if (!aht10_polltime_expired(data)) {
mutex_unlock(&data->lock);
return 0; return 0;
}
res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas)); res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas));
if (res < 0) { if (res < 0)
mutex_unlock(&data->lock);
return res; return res;
}
usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA); usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA);
res = i2c_master_recv(client, raw_data, data->meas_size); res = i2c_master_recv(client, raw_data, data->meas_size);
if (res != data->meas_size) { if (res != data->meas_size) {
mutex_unlock(&data->lock);
if (res >= 0) if (res >= 0)
return -ENODATA; return -ENODATA;
return res; return res;
} }
if (data->crc8 && crc8_check(raw_data, data->meas_size)) { if (data->crc8 && crc8_check(raw_data, data->meas_size))
mutex_unlock(&data->lock);
return -EIO; return -EIO;
}
hum = ((u32)raw_data[1] << 12u) | hum = ((u32)raw_data[1] << 12u) |
((u32)raw_data[2] << 4u) | ((u32)raw_data[2] << 4u) |
@ -210,7 +200,6 @@ static int aht10_read_values(struct aht10_data *data)
data->humidity = hum; data->humidity = hum;
data->previous_poll_time = ktime_get_boottime(); data->previous_poll_time = ktime_get_boottime();
mutex_unlock(&data->lock);
return 0; return 0;
} }
@ -352,14 +341,20 @@ static int aht10_probe(struct i2c_client *client)
data->meas_size = AHT20_MEAS_SIZE; data->meas_size = AHT20_MEAS_SIZE;
data->crc8 = true; data->crc8 = true;
crc8_populate_msb(crc8_table, AHT20_CRC8_POLY); 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; break;
default: default:
data->meas_size = AHT10_MEAS_SIZE; data->meas_size = AHT10_MEAS_SIZE;
data->init_cmd = AHT10_CMD_INIT;
break; break;
} }
mutex_init(&data->lock);
res = aht10_init(data); res = aht10_init(data);
if (res < 0) if (res < 0)
return res; return res;

View File

@ -20,7 +20,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/unaligned.h> #include <linux/unaligned.h>
@ -551,7 +550,6 @@ struct aqc_data {
struct hid_device *hdev; struct hid_device *hdev;
struct device *hwmon_dev; struct device *hwmon_dev;
struct dentry *debugfs; struct dentry *debugfs;
struct mutex mutex; /* Used for locking access when reading and writing PWM values */
enum kinds kind; enum kinds kind;
const char *name; 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) static int aqc_get_ctrl_data(struct aqc_data *priv)
{ {
int ret; int ret;
@ -680,7 +677,6 @@ static int aqc_get_ctrl_data(struct aqc_data *priv)
return ret; return ret;
} }
/* Expects the mutex to be locked */
static int aqc_send_ctrl_data(struct aqc_data *priv) static int aqc_send_ctrl_data(struct aqc_data *priv)
{ {
int ret; int ret;
@ -721,11 +717,9 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int ty
{ {
int ret; int ret;
mutex_lock(&priv->mutex);
ret = aqc_get_ctrl_data(priv); ret = aqc_get_ctrl_data(priv);
if (ret < 0) if (ret < 0)
goto unlock_and_return; return ret;
switch (type) { switch (type) {
case AQC_BE16: case AQC_BE16:
@ -737,9 +731,6 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int ty
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
unlock_and_return:
mutex_unlock(&priv->mutex);
return ret; return ret;
} }
@ -747,11 +738,9 @@ static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, in
{ {
int ret, i; int ret, i;
mutex_lock(&priv->mutex);
ret = aqc_get_ctrl_data(priv); ret = aqc_get_ctrl_data(priv);
if (ret < 0) if (ret < 0)
goto unlock_and_return; return ret;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
switch (types[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]; priv->buffer[offsets[i]] = (u8)vals[i];
break; break;
default: default:
ret = -EINVAL; return -EINVAL;
} }
} }
if (ret < 0) return aqc_send_ctrl_data(priv);
goto unlock_and_return;
ret = aqc_send_ctrl_data(priv);
unlock_and_return:
mutex_unlock(&priv->mutex);
return ret;
} }
static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val, int type) 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; int ret, i, sensor_value;
mutex_lock(&priv->mutex);
memset(priv->buffer, 0x00, priv->buffer_size); memset(priv->buffer, 0x00, priv->buffer_size);
ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer, ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer,
priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT); priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0) if (ret < 0)
goto unlock_and_return; return ret;
/* Temperature sensor readings */ /* Temperature sensor readings */
for (i = 0; i < priv->num_temp_sensors; i++) { 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; priv->updated = jiffies;
return 0;
unlock_and_return:
mutex_unlock(&priv->mutex);
return ret;
} }
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, 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; goto fail_and_close;
} }
mutex_init(&priv->mutex);
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, priv->name, priv, priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, priv->name, priv,
&aqc_chip_info, NULL); &aqc_chip_info, NULL);

View File

@ -528,6 +528,9 @@ static const struct of_device_id aspeed_pwm_tach_match[] = {
{ {
.compatible = "aspeed,ast2600-pwm-tach", .compatible = "aspeed,ast2600-pwm-tach",
}, },
{
.compatible = "aspeed,ast2700-pwm-tach",
},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match); MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match);

View File

@ -113,15 +113,19 @@ enum ec_sensors {
ec_sensor_temp_t_sensor, ec_sensor_temp_t_sensor,
/* VRM temperature [℃] */ /* VRM temperature [℃] */
ec_sensor_temp_vrm, ec_sensor_temp_vrm,
/* VRM east (right) temperature [℃] */
ec_sensor_temp_vrme,
/* VRM west (left) temperature [℃] */
ec_sensor_temp_vrmw,
/* CPU Core voltage [mV] */ /* CPU Core voltage [mV] */
ec_sensor_in_cpu_core, ec_sensor_in_cpu_core,
/* CPU_Opt fan [RPM] */ /* CPU_Opt fan [RPM] */
ec_sensor_fan_cpu_opt, ec_sensor_fan_cpu_opt,
/* VRM heat sink fan [RPM] */ /* VRM heat sink fan [RPM] */
ec_sensor_fan_vrm_hs, ec_sensor_fan_vrm_hs,
/* VRM east heat sink fan [RPM] */ /* VRM east (right) heat sink fan [RPM] */
ec_sensor_fan_vrme_hs, ec_sensor_fan_vrme_hs,
/* VRM west heat sink fan [RPM] */ /* VRM west (left) heat sink fan [RPM] */
ec_sensor_fan_vrmw_hs, ec_sensor_fan_vrmw_hs,
/* Chipset fan [RPM] */ /* Chipset fan [RPM] */
ec_sensor_fan_chipset, ec_sensor_fan_chipset,
@ -157,6 +161,8 @@ enum ec_sensors {
#define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb) #define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb)
#define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor) #define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor)
#define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm) #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_IN_CPU_CORE BIT(ec_sensor_in_cpu_core)
#define SENSOR_FAN_CPU_OPT BIT(ec_sensor_fan_cpu_opt) #define SENSOR_FAN_CPU_OPT BIT(ec_sensor_fan_cpu_opt)
#define SENSOR_FAN_VRM_HS BIT(ec_sensor_fan_vrm_hs) #define SENSOR_FAN_VRM_HS BIT(ec_sensor_fan_vrm_hs)
@ -182,6 +188,7 @@ enum board_family {
family_amd_500_series, family_amd_500_series,
family_amd_600_series, family_amd_600_series,
family_amd_800_series, family_amd_800_series,
family_amd_trx_50,
family_amd_wrx_90, family_amd_wrx_90,
family_intel_200_series, family_intel_200_series,
family_intel_300_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), 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[] = { static const struct ec_sensor_info sensors_family_amd_wrx_90[] = {
[ec_sensor_temp_cpu_package] = [ec_sensor_temp_cpu_package] =
EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31), 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, .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 = { static const struct ec_board_info board_info_pro_ws_wrx90e_sage_se = {
/* Board also has a nct6798 with 7 more fans and temperatures */ /* Board also has a nct6798 with 7 more fans and temperatures */
.sensors = SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_T_SENSOR | .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, .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 = { static const struct ec_board_info board_info_strix_x570_e_gaming = {
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
SENSOR_TEMP_T_SENSOR | 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, .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 = { static const struct ec_board_info board_info_strix_x870_i_gaming_wifi = {
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
SENSOR_TEMP_MB | SENSOR_TEMP_VRM, 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, .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 = { static const struct ec_board_info board_info_strix_z390_f_gaming = {
.sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM | .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_T_SENSOR |
@ -739,6 +791,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_pro_art_x670E_creator_wifi), &board_info_pro_art_x670E_creator_wifi),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X870E-CREATOR WIFI",
&board_info_pro_art_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", DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS WRX90E-SAGE SE",
&board_info_pro_ws_wrx90e_sage_se), &board_info_pro_ws_wrx90e_sage_se),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE", 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), &board_info_strix_b650e_i_gaming),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B850-I GAMING WIFI", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B850-I GAMING WIFI",
&board_info_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", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING",
&board_info_strix_x570_e_gaming), &board_info_strix_x570_e_gaming),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING WIFI II", 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), &board_info_strix_x670e_e_gaming_wifi),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X670E-I GAMING WIFI", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X670E-I GAMING WIFI",
&board_info_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", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870-I GAMING WIFI",
&board_info_strix_x870_i_gaming_wifi), &board_info_strix_x870_i_gaming_wifi),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-E GAMING WIFI", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X870E-E GAMING WIFI",
&board_info_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", DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING",
&board_info_strix_z390_f_gaming), &board_info_strix_z390_f_gaming),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z490-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: case family_amd_800_series:
ec_data->sensors_info = sensors_family_amd_800; ec_data->sensors_info = sensors_family_amd_800;
break; break;
case family_amd_trx_50:
ec_data->sensors_info = sensors_family_amd_trx_50;
break;
case family_amd_wrx_90: case family_amd_wrx_90:
ec_data->sensors_info = sensors_family_amd_wrx_90; ec_data->sensors_info = sensors_family_amd_wrx_90;
break; break;

View File

@ -81,10 +81,6 @@ static const char *const rog_ryujin_speed_label[] = {
struct rog_ryujin_data { struct rog_ryujin_data {
struct hid_device *hdev; struct hid_device *hdev;
struct device *hwmon_dev; 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 */ /* For reinitializing the completions below */
spinlock_t status_report_request_lock; spinlock_t status_report_request_lock;
struct completion cooler_status_received; 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 */ /* 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) 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); memcpy_and_pad(priv->buffer, MAX_REPORT_LENGTH, cmd, cmd_length, 0x00);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH); return hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
mutex_unlock(&priv->buffer_lock);
return ret;
} }
/* 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, static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length,
struct completion *status_completion) 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) static int rog_ryujin_get_status(struct rog_ryujin_data *priv)
{ {
int ret = mutex_lock_interruptible(&priv->status_report_request_mutex); int ret;
if (ret < 0)
return ret;
if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) { if (!time_after(jiffies, priv->updated + msecs_to_jiffies(STATUS_VALIDITY))) {
/* Data is up to date */ /* Data is up to date */
goto unlock_and_return; return 0;
} }
/* Retrieve cooler status */ /* 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, rog_ryujin_execute_cmd(priv, get_cooler_status_cmd, GET_CMD_LENGTH,
&priv->cooler_status_received); &priv->cooler_status_received);
if (ret < 0) if (ret < 0)
goto unlock_and_return; return ret;
/* Retrieve controller status (speeds) */ /* Retrieve controller status (speeds) */
ret = ret =
rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH, rog_ryujin_execute_cmd(priv, get_controller_speed_cmd, GET_CMD_LENGTH,
&priv->controller_status_received); &priv->controller_status_received);
if (ret < 0) if (ret < 0)
goto unlock_and_return; return ret;
/* Retrieve cooler duty */ /* Retrieve cooler duty */
ret = ret =
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH, rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
&priv->cooler_duty_received); &priv->cooler_duty_received);
if (ret < 0) if (ret < 0)
goto unlock_and_return; return ret;
/* Retrieve controller duty */ /* Retrieve controller duty */
ret = ret =
rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH, rog_ryujin_execute_cmd(priv, get_controller_duty_cmd, GET_CMD_LENGTH,
&priv->controller_duty_received); &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) if (ret < 0)
return ret; return ret;
priv->updated = jiffies;
return 0; 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 * Retrieve cooler duty since both pump and internal fan are set
* together, then write back with one of them modified. * together, then write back with one of them modified.
*/ */
ret = mutex_lock_interruptible(&priv->status_report_request_mutex);
if (ret < 0)
return ret;
ret = ret =
rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH, rog_ryujin_execute_cmd(priv, get_cooler_duty_cmd, GET_CMD_LENGTH,
&priv->cooler_duty_received); &priv->cooler_duty_received);
if (ret < 0) if (ret < 0)
goto unlock_and_return; return ret;
memcpy(set_cmd, set_cooler_duty_cmd, SET_CMD_LENGTH); 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; set_cmd[RYUJIN_SET_COOLER_FAN_DUTY_OFFSET] = val;
} }
ret = rog_ryujin_execute_cmd(priv, set_cmd, SET_CMD_LENGTH, &priv->cooler_duty_set); return 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;
} else { } else {
/* /*
* Controller fan duty (channel == 2). No need to retrieve current * 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; goto fail_and_close;
} }
mutex_init(&priv->status_report_request_mutex);
mutex_init(&priv->buffer_lock);
spin_lock_init(&priv->status_report_request_lock); spin_lock_init(&priv->status_report_request_lock);
init_completion(&priv->cooler_status_received); init_completion(&priv->cooler_status_received);
init_completion(&priv->controller_status_received); init_completion(&priv->controller_status_received);

View File

@ -81,7 +81,6 @@ struct cc2_data {
struct completion complete; struct completion complete;
struct device *hwmon; struct device *hwmon;
struct i2c_client *client; struct i2c_client *client;
struct mutex dev_access_lock; /* device access lock */
struct regulator *regulator; struct regulator *regulator;
const char *name; const char *name;
int irq_ready; 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); struct cc2_data *data = dev_get_drvdata(dev);
guard(mutex)(&data->dev_access_lock);
switch (type) { switch (type) {
case hwmon_temp: case hwmon_temp:
return cc2_measurement(data, type, val); 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) if (val < 0 || val > CC2_RH_MAX)
return -EINVAL; return -EINVAL;
guard(mutex)(&data->dev_access_lock);
switch (attr) { switch (attr) {
case hwmon_humidity_min: case hwmon_humidity_min:
cmd = CC2_W_ALARM_L_ON; cmd = CC2_W_ALARM_L_ON;
@ -708,8 +703,6 @@ static int cc2_probe(struct i2c_client *client)
i2c_set_clientdata(client, data); i2c_set_clientdata(client, data);
mutex_init(&data->dev_access_lock);
data->client = client; data->client = client;
data->regulator = devm_regulator_get_exclusive(dev, "vdd"); data->regulator = devm_regulator_get_exclusive(dev, "vdd");

View File

@ -40,7 +40,7 @@
#define CTL_GET_TMP 0x11 /* #define CTL_GET_TMP 0x11 /*
* send: byte 1 is channel, rest zero * send: byte 1 is channel, rest zero
* rcv: returns temp for channel in centi-degree celsius * 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 * returns 0x11 in byte 0 if no sensor is connected
*/ */
#define CTL_GET_VOLT 0x12 /* #define CTL_GET_VOLT 0x12 /*
@ -90,10 +90,10 @@ struct ccp_device {
u8 *cmd_buffer; u8 *cmd_buffer;
u8 *buffer; u8 *buffer;
int buffer_recv_size; /* number of received bytes in 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(temp_cnct, NUM_TEMP_SENSORS);
DECLARE_BITMAP(fan_cnct, NUM_FANS); DECLARE_BITMAP(fan_cnct, NUM_FANS);
char fan_label[6][LABEL_LENGTH]; char fan_label[NUM_FANS][LABEL_LENGTH];
u8 firmware_ver[3]; u8 firmware_ver[3];
u8 bootloader_ver[2]; 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); ret = get_data(ccp, CTL_GET_TMP, channel, true);
if (ret < 0) if (ret < 0)
return ret; return ret;
*val = ret * 10; *val = (s16)ret * 10;
return 0; return 0;
default: default:
break; break;

View File

@ -9,11 +9,9 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
@ -124,7 +122,6 @@ struct corsairpsu_data {
struct device *hwmon_dev; struct device *hwmon_dev;
struct dentry *debugfs; struct dentry *debugfs;
struct completion wait_completion; struct completion wait_completion;
struct mutex lock; /* for locking access to cmd_buffer */
u8 *cmd_buffer; u8 *cmd_buffer;
char vendor[REPLY_SIZE]; char vendor[REPLY_SIZE];
char product[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; int ret;
mutex_lock(&priv->lock);
switch (cmd) { switch (cmd) {
case PSU_CMD_RAIL_VOLTS_HCRIT: case PSU_CMD_RAIL_VOLTS_HCRIT:
case PSU_CMD_RAIL_VOLTS_LCRIT: 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: case PSU_CMD_RAIL_WATTS:
ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL); ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL);
if (ret < 0) if (ret < 0)
goto cmd_fail; return ret;
break; break;
default: default:
break; break;
} }
ret = corsairpsu_usb_cmd(priv, 3, cmd, 0, data); return corsairpsu_usb_cmd(priv, 3, cmd, 0, data);
cmd_fail:
mutex_unlock(&priv->lock);
return ret;
} }
static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, long *val) 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; priv->hdev = hdev;
hid_set_drvdata(hdev, priv); hid_set_drvdata(hdev, priv);
mutex_init(&priv->lock);
init_completion(&priv->wait_completion); init_completion(&priv->wait_completion);
hid_device_io_start(hdev); hid_device_io_start(hdev);

View File

@ -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 = { 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", .ident = "Dell Latitude 5480",
.matches = { .matches = {

View File

@ -102,7 +102,6 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <scsi/scsi_cmnd.h> #include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h> #include <scsi/scsi_device.h>
#include <scsi/scsi_driver.h> #include <scsi/scsi_driver.h>
@ -110,7 +109,6 @@
struct drivetemp_data { struct drivetemp_data {
struct list_head list; /* list of instantiated devices */ struct list_head list; /* list of instantiated devices */
struct mutex lock; /* protect data buffer accesses */
struct scsi_device *sdev; /* SCSI device */ struct scsi_device *sdev; /* SCSI device */
struct device *dev; /* instantiating device */ struct device *dev; /* instantiating device */
struct device *hwdev; /* hardware monitoring 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_input:
case hwmon_temp_lowest: case hwmon_temp_lowest:
case hwmon_temp_highest: case hwmon_temp_highest:
mutex_lock(&st->lock);
err = st->get_temp(st, attr, val); err = st->get_temp(st, attr, val);
mutex_unlock(&st->lock);
break; break;
case hwmon_temp_lcrit: case hwmon_temp_lcrit:
*val = st->temp_lcrit; *val = st->temp_lcrit;
@ -566,7 +562,6 @@ static int drivetemp_add(struct device *dev)
st->sdev = sdev; st->sdev = sdev;
st->dev = dev; st->dev = dev;
mutex_init(&st->lock);
if (drivetemp_identify(st)) { if (drivetemp_identify(st)) {
err = -ENODEV; err = -ENODEV;

View File

@ -17,7 +17,6 @@
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/util_macros.h> #include <linux/util_macros.h>
@ -30,7 +29,6 @@ enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 };
struct thermal_data { struct thermal_data {
enum emc1403_chip chip; enum emc1403_chip chip;
struct regmap *regmap; struct regmap *regmap;
struct mutex mutex;
}; };
static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf)
@ -268,7 +266,7 @@ static s8 emc1403_temp_regs_low[][4] = {
}, },
}; };
static int __emc1403_get_temp(struct thermal_data *data, int channel, static int emc1403_get_temp(struct thermal_data *data, int channel,
enum emc1403_reg_map map, long *val) enum emc1403_reg_map map, long *val)
{ {
unsigned int regvalh; unsigned int regvalh;
@ -295,38 +293,23 @@ static int __emc1403_get_temp(struct thermal_data *data, int channel,
return 0; 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, static int emc1403_get_hyst(struct thermal_data *data, int channel,
enum emc1403_reg_map map, long *val) enum emc1403_reg_map map, long *val)
{ {
int hyst, ret; int hyst, ret;
long limit; 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) if (ret < 0)
goto unlock; return ret;
ret = regmap_read(data->regmap, 0x21, &hyst); ret = regmap_read(data->regmap, 0x21, &hyst);
if (ret < 0) if (ret < 0)
goto unlock; return ret;
if (map == temp_min) if (map == temp_min)
*val = limit + hyst * 1000; *val = limit + hyst * 1000;
else else
*val = limit - hyst * 1000; *val = limit - hyst * 1000;
unlock: return 0;
mutex_unlock(&data->mutex);
return ret;
} }
static int emc1403_temp_read(struct thermal_data *data, u32 attr, int channel, long *val) 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 else
val = clamp_val(val, 0, 255000); 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) if (ret < 0)
goto unlock; return ret;
hyst = limit - val; hyst = limit - val;
if (data->chip == emc1428) if (data->chip == emc1428)
hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 127); hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 127);
else else
hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255); hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255);
ret = regmap_write(data->regmap, 0x21, hyst); return regmap_write(data->regmap, 0x21, hyst);
unlock:
mutex_unlock(&data->mutex);
return ret;
} }
static int emc1403_set_temp(struct thermal_data *data, int channel, 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]; regh = emc1403_temp_regs[channel][map];
regl = emc1403_temp_regs_low[channel][map]; regl = emc1403_temp_regs_low[channel][map];
mutex_lock(&data->mutex);
if (regl >= 0) { if (regl >= 0) {
if (data->chip == emc1428) if (data->chip == emc1428)
val = clamp_val(val, -128000, 127875); 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); regval = DIV_ROUND_CLOSEST(val, 125);
ret = regmap_write(data->regmap, regh, (regval >> 3) & 0xff); ret = regmap_write(data->regmap, regh, (regval >> 3) & 0xff);
if (ret < 0) if (ret < 0)
goto unlock; return ret;
ret = regmap_write(data->regmap, regl, (regval & 0x07) << 5); ret = regmap_write(data->regmap, regl, (regval & 0x07) << 5);
} else { } else {
if (data->chip == emc1428) 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); regval = DIV_ROUND_CLOSEST(val, 1000);
ret = regmap_write(data->regmap, regh, regval); ret = regmap_write(data->regmap, regh, regval);
} }
unlock:
mutex_unlock(&data->mutex);
return ret; return ret;
} }
@ -695,8 +671,6 @@ static int emc1403_probe(struct i2c_client *client)
if (IS_ERR(data->regmap)) if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap); return PTR_ERR(data->regmap);
mutex_init(&data->mutex);
hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
client->name, data, client->name, data,
&emc1403_chip_info, &emc1403_chip_info,

View File

@ -277,8 +277,10 @@ fan1_input_show(struct device *dev, struct device_attribute *da, char *buf)
{ {
struct emc2103_data *data = emc2103_update_device(dev); struct emc2103_data *data = emc2103_update_device(dev);
int rpm = 0; int rpm = 0;
mutex_lock(&data->update_lock);
if (data->fan_tach != 0) if (data->fan_tach != 0)
rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_tach; rpm = (FAN_RPM_FACTOR * data->fan_multiplier) / data->fan_tach;
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", rpm); 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); struct emc2103_data *data = emc2103_update_device(dev);
int rpm = 0; int rpm = 0;
mutex_lock(&data->update_lock);
/* high byte of 0xff indicates disabled so return 0 */ /* high byte of 0xff indicates disabled so return 0 */
if ((data->fan_target != 0) && ((data->fan_target & 0x1fe0) != 0x1fe0)) if ((data->fan_target != 0) && ((data->fan_target & 0x1fe0) != 0x1fe0))
rpm = (FAN_RPM_FACTOR * data->fan_multiplier) rpm = (FAN_RPM_FACTOR * data->fan_multiplier)
/ data->fan_target; / data->fan_target;
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", rpm); return sprintf(buf, "%d\n", rpm);
} }

View File

@ -12,7 +12,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/math.h> #include <linux/math.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
@ -62,10 +61,6 @@ enum WATCHDOG_RESOLUTION {
struct fts_data { struct fts_data {
struct i2c_client *client; 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 */ unsigned long last_updated; /* in jiffies */
struct watchdog_device wdd; struct watchdog_device wdd;
enum WATCHDOG_RESOLUTION resolution; enum WATCHDOG_RESOLUTION resolution;
@ -98,21 +93,15 @@ static int fts_read_byte(struct i2c_client *client, unsigned short reg)
{ {
int ret; int ret;
unsigned char page = reg >> 8; 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); dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page);
ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page); ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page);
if (ret < 0) if (ret < 0)
goto error; return ret;
reg &= 0xFF; reg &= 0xFF;
ret = i2c_smbus_read_byte_data(client, reg); ret = i2c_smbus_read_byte_data(client, reg);
dev_dbg(&client->dev, "read - reg: 0x%.02x: val: 0x%.02x\n", reg, ret); dev_dbg(&client->dev, "read - reg: 0x%.02x: val: 0x%.02x\n", reg, ret);
error:
mutex_unlock(&data->access_lock);
return ret; return ret;
} }
@ -121,22 +110,16 @@ static int fts_write_byte(struct i2c_client *client, unsigned short reg,
{ {
int ret; int ret;
unsigned char page = reg >> 8; 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); dev_dbg(&client->dev, "page select - page: 0x%.02x\n", page);
ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page); ret = i2c_smbus_write_byte_data(client, FTS_PAGE_SELECT_REG, page);
if (ret < 0) if (ret < 0)
goto error; return ret;
reg &= 0xFF; reg &= 0xFF;
dev_dbg(&client->dev, dev_dbg(&client->dev,
"write - reg: 0x%.02x: val: 0x%.02x\n", reg, value); "write - reg: 0x%.02x: val: 0x%.02x\n", reg, value);
ret = i2c_smbus_write_byte_data(client, reg, value); ret = i2c_smbus_write_byte_data(client, reg, value);
error:
mutex_unlock(&data->access_lock);
return ret; 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) static int fts_update_device(struct fts_data *data)
{ {
int i; int i, err;
int err = 0;
mutex_lock(&data->update_lock);
if (!time_after(jiffies, data->last_updated + 2 * HZ) && data->valid) 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); err = fts_read_byte(data->client, FTS_DEVICE_STATUS_REG);
if (err < 0) if (err < 0)
goto exit; return err;
data->valid = !!(err & 0x02); /* Data not ready yet */ data->valid = !!(err & 0x02); /* Data not ready yet */
if (unlikely(!data->valid)) { if (unlikely(!data->valid))
err = -EAGAIN; return -EAGAIN;
goto exit;
}
err = fts_read_byte(data->client, FTS_FAN_PRESENT_REG); err = fts_read_byte(data->client, FTS_FAN_PRESENT_REG);
if (err < 0) if (err < 0)
goto exit; return err;
data->fan_present = err; data->fan_present = err;
err = fts_read_byte(data->client, FTS_FAN_EVENT_REG); err = fts_read_byte(data->client, FTS_FAN_EVENT_REG);
if (err < 0) if (err < 0)
goto exit; return err;
data->fan_alarm = err; data->fan_alarm = err;
for (i = 0; i < FTS_NO_FAN_SENSORS; i++) { for (i = 0; i < FTS_NO_FAN_SENSORS; i++) {
if (data->fan_present & BIT(i)) { if (data->fan_present & BIT(i)) {
err = fts_read_byte(data->client, FTS_REG_FAN_INPUT(i)); err = fts_read_byte(data->client, FTS_REG_FAN_INPUT(i));
if (err < 0) if (err < 0)
goto exit; return err;
data->fan_input[i] = err; data->fan_input[i] = err;
err = fts_read_byte(data->client, err = fts_read_byte(data->client,
FTS_REG_FAN_SOURCE(i)); FTS_REG_FAN_SOURCE(i));
if (err < 0) if (err < 0)
goto exit; return err;
data->fan_source[i] = err; data->fan_source[i] = err;
} else { } else {
data->fan_input[i] = 0; 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); err = fts_read_byte(data->client, FTS_SENSOR_EVENT_REG);
if (err < 0) if (err < 0)
goto exit; return err;
data->temp_alarm = err; data->temp_alarm = err;
for (i = 0; i < FTS_NO_TEMP_SENSORS; i++) { for (i = 0; i < FTS_NO_TEMP_SENSORS; i++) {
err = fts_read_byte(data->client, FTS_REG_TEMP_INPUT(i)); err = fts_read_byte(data->client, FTS_REG_TEMP_INPUT(i));
if (err < 0) if (err < 0)
goto exit; return err;
data->temp_input[i] = err; data->temp_input[i] = err;
} }
for (i = 0; i < FTS_NO_VOLT_SENSORS; i++) { for (i = 0; i < FTS_NO_VOLT_SENSORS; i++) {
err = fts_read_byte(data->client, FTS_REG_VOLT(i)); err = fts_read_byte(data->client, FTS_REG_VOLT(i));
if (err < 0) if (err < 0)
goto exit; return err;
data->volt[i] = err; data->volt[i] = err;
} }
data->last_updated = jiffies; data->last_updated = jiffies;
err = 0; return 0;
exit:
mutex_unlock(&data->update_lock);
return err;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -470,18 +446,14 @@ static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
if (val) if (val)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock);
ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(channel)); 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) if (ret < 0)
return ret; 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; return 0;
default: default:
break; break;
@ -493,18 +465,14 @@ static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
if (val) if (val)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock);
ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(channel)); 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) if (ret < 0)
return ret; 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; return 0;
default: default:
break; break;
@ -648,8 +616,6 @@ static int fts_probe(struct i2c_client *client)
if (!data) if (!data)
return -ENOMEM; return -ENOMEM;
mutex_init(&data->update_lock);
mutex_init(&data->access_lock);
data->client = client; data->client = client;
dev_set_drvdata(&client->dev, data); dev_set_drvdata(&client->dev, data);

View File

@ -26,9 +26,6 @@
static char *gpd_fan_board = ""; static char *gpd_fan_board = "";
module_param(gpd_fan_board, charp, 0444); 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 { enum gpd_board {
win_mini, win_mini,
win4_6800u, win4_6800u,
@ -481,87 +478,60 @@ static int gpd_fan_hwmon_read(__always_unused struct device *dev,
{ {
int ret; int ret;
ret = mutex_lock_interruptible(&gpd_fan_sequence_lock);
if (ret)
return ret;
if (type == hwmon_fan) { if (type == hwmon_fan) {
if (attr == hwmon_fan_input) { if (attr == hwmon_fan_input) {
ret = gpd_read_rpm(); ret = gpd_read_rpm();
if (ret < 0) if (ret < 0)
goto OUT; return ret;
*val = ret; *val = ret;
ret = 0; return 0;
goto OUT;
} }
} else if (type == hwmon_pwm) { } else if (type == hwmon_pwm) {
switch (attr) { switch (attr) {
case hwmon_pwm_enable: case hwmon_pwm_enable:
*val = gpd_driver_priv.pwm_enable; *val = gpd_driver_priv.pwm_enable;
ret = 0; return 0;
goto OUT;
case hwmon_pwm_input: case hwmon_pwm_input:
ret = gpd_read_pwm(); ret = gpd_read_pwm();
if (ret < 0) if (ret < 0)
goto OUT; return ret;
*val = ret; *val = ret;
ret = 0; return 0;
goto OUT;
} }
} }
ret = -EOPNOTSUPP; return -EOPNOTSUPP;
OUT:
mutex_unlock(&gpd_fan_sequence_lock);
return ret;
} }
static int gpd_fan_hwmon_write(__always_unused struct device *dev, static int gpd_fan_hwmon_write(__always_unused struct device *dev,
enum hwmon_sensor_types type, u32 attr, enum hwmon_sensor_types type, u32 attr,
__always_unused int channel, long val) __always_unused int channel, long val)
{ {
int ret;
ret = mutex_lock_interruptible(&gpd_fan_sequence_lock);
if (ret)
return ret;
if (type == hwmon_pwm) { if (type == hwmon_pwm) {
switch (attr) { switch (attr) {
case hwmon_pwm_enable: case hwmon_pwm_enable:
if (!in_range(val, 0, 3)) { if (!in_range(val, 0, 3))
ret = -EINVAL; return -EINVAL;
goto OUT;
}
gpd_driver_priv.pwm_enable = val; gpd_driver_priv.pwm_enable = val;
gpd_set_pwm_enable(gpd_driver_priv.pwm_enable); gpd_set_pwm_enable(gpd_driver_priv.pwm_enable);
ret = 0; return 0;
goto OUT;
case hwmon_pwm_input: case hwmon_pwm_input:
if (!in_range(val, 0, 256)) { if (!in_range(val, 0, 256))
ret = -ERANGE; return -EINVAL;
goto OUT;
}
gpd_driver_priv.pwm_value = val; gpd_driver_priv.pwm_value = val;
ret = gpd_write_pwm(val); return gpd_write_pwm(val);
goto OUT;
} }
} }
ret = -EOPNOTSUPP; return -EOPNOTSUPP;
OUT:
mutex_unlock(&gpd_fan_sequence_lock);
return ret;
} }
static const struct hwmon_ops gpd_fan_ops = { static const struct hwmon_ops gpd_fan_ops = {

View File

@ -42,7 +42,6 @@
struct hs3001_data { struct hs3001_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex i2c_lock; /* lock for sending i2c commands */
u32 wait_time; /* in us */ u32 wait_time; /* in us */
int temperature; /* in milli degree */ int temperature; /* in milli degree */
u32 humidity; /* in milli % */ 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; struct i2c_client *client = data->client;
int ret; int ret;
mutex_lock(&data->i2c_lock);
ret = i2c_master_send(client, NULL, 0); ret = i2c_master_send(client, NULL, 0);
if (ret < 0) { if (ret < 0)
mutex_unlock(&data->i2c_lock);
return ret; return ret;
}
/* /*
* Sensor needs some time to process measurement depending on * 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); fsleep(data->wait_time);
ret = hs3001_data_fetch_command(client, data); ret = hs3001_data_fetch_command(client, data);
mutex_unlock(&data->i2c_lock);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -211,8 +205,6 @@ static int hs3001_probe(struct i2c_client *client)
data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION + data->wait_time = (HS3001_WAKEUP_TIME + HS3001_14BIT_RESOLUTION +
HS3001_14BIT_RESOLUTION); HS3001_14BIT_RESOLUTION);
mutex_init(&data->i2c_lock);
hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_dev = devm_hwmon_device_register_with_info(dev,
client->name, client->name,
data, data,

View File

@ -8,13 +8,10 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
/* Register definitions from datasheet */ /* Register definitions from datasheet */
#define REG_TSTHRCATA 0xE2 #define REG_TSTHRCATA 0xE2

View File

@ -117,7 +117,6 @@ struct ina238_config {
struct ina238_data { struct ina238_data {
const struct ina238_config *config; const struct ina238_config *config;
struct i2c_client *client; struct i2c_client *client;
struct mutex config_lock;
struct regmap *regmap; struct regmap *regmap;
u32 rshunt; u32 rshunt;
int gain; 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, static int ina238_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val) u32 attr, int channel, long val)
{ {
struct ina238_data *data = dev_get_drvdata(dev);
int err;
mutex_lock(&data->config_lock);
switch (type) { switch (type) {
case hwmon_in: case hwmon_in:
err = ina238_write_in(dev, attr, channel, val); return ina238_write_in(dev, attr, channel, val);
break;
case hwmon_curr: case hwmon_curr:
err = ina238_write_curr(dev, attr, val); return ina238_write_curr(dev, attr, val);
break;
case hwmon_power: case hwmon_power:
err = ina238_write_power_max(dev, val); return ina238_write_power_max(dev, val);
break;
case hwmon_temp: case hwmon_temp:
err = ina238_write_temp_max(dev, val); return ina238_write_temp_max(dev, val);
break;
default: default:
err = -EOPNOTSUPP; return -EOPNOTSUPP;
break;
} }
mutex_unlock(&data->config_lock);
return err;
} }
static umode_t ina238_is_visible(const void *drvdata, 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 */ /* set the device type */
data->config = &ina238_config[chip]; data->config = &ina238_config[chip];
mutex_init(&data->config_lock);
data->regmap = devm_regmap_init_i2c(client, &ina238_regmap_config); data->regmap = devm_regmap_init_i2c(client, &ina238_regmap_config);
if (IS_ERR(data->regmap)) { if (IS_ERR(data->regmap)) {
dev_err(dev, "failed to allocate register map\n"); dev_err(dev, "failed to allocate register map\n");

View File

@ -156,7 +156,6 @@ struct ina2xx_data {
long rshunt; long rshunt;
long current_lsb_uA; long current_lsb_uA;
long power_lsb_uW; long power_lsb_uW;
struct mutex config_lock;
struct regmap *regmap; struct regmap *regmap;
struct i2c_client *client; 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 regval;
int ret; int ret;
mutex_lock(&data->config_lock);
ret = regmap_read(regmap, INA226_MASK_ENABLE, &regval); ret = regmap_read(regmap, INA226_MASK_ENABLE, &regval);
if (ret) if (ret)
goto abort; return ret;
if (regval & mask) { if (regval & mask) {
ret = regmap_read(regmap, INA226_ALERT_LIMIT, &regval); ret = regmap_read(regmap, INA226_ALERT_LIMIT, &regval);
if (ret) if (ret)
goto abort; return ret;
*val = ina2xx_get_value(data, reg, regval); *val = ina2xx_get_value(data, reg, regval);
} else { } else {
*val = 0; *val = 0;
} }
abort: return 0;
mutex_unlock(&data->config_lock);
return ret;
} }
static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, long val) 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 * due to register write sequence. Then, only enable the alert
* if the value is non-zero. * if the value is non-zero.
*/ */
mutex_lock(&data->config_lock);
ret = regmap_update_bits(regmap, INA226_MASK_ENABLE, ret = regmap_update_bits(regmap, INA226_MASK_ENABLE,
INA226_ALERT_CONFIG_MASK, 0); INA226_ALERT_CONFIG_MASK, 0);
if (ret < 0) if (ret < 0)
goto abort; return ret;
ret = regmap_write(regmap, INA226_ALERT_LIMIT, ret = regmap_write(regmap, INA226_ALERT_LIMIT,
ina226_alert_to_reg(data, reg, val)); ina226_alert_to_reg(data, reg, val));
if (ret < 0) if (ret < 0)
goto abort; return ret;
if (val) if (val)
ret = regmap_update_bits(regmap, INA226_MASK_ENABLE, return regmap_update_bits(regmap, INA226_MASK_ENABLE,
INA226_ALERT_CONFIG_MASK, mask); INA226_ALERT_CONFIG_MASK, mask);
abort: return 0;
mutex_unlock(&data->config_lock);
return ret;
} }
static int ina2xx_chip_read(struct device *dev, u32 attr, long *val) 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) if (status < 0)
return status; return status;
mutex_lock(&data->config_lock); hwmon_lock(dev);
status = ina2xx_set_shunt(data, val); status = ina2xx_set_shunt(data, val);
mutex_unlock(&data->config_lock); hwmon_unlock(dev);
if (status < 0) if (status < 0)
return status; return status;
return count; return count;
@ -951,7 +944,6 @@ static int ina2xx_probe(struct i2c_client *client)
data->client = client; data->client = client;
data->config = &ina2xx_config[chip]; data->config = &ina2xx_config[chip];
data->chip = chip; data->chip = chip;
mutex_init(&data->config_lock);
data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config); data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config);
if (IS_ERR(data->regmap)) { if (IS_ERR(data->regmap)) {

View File

@ -11,7 +11,6 @@
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -115,7 +114,6 @@ struct ina3221_input {
* @regmap: Register map of the device * @regmap: Register map of the device
* @fields: Register fields of the device * @fields: Register fields of the device
* @inputs: Array of channel input source specific structures * @inputs: Array of channel input source specific structures
* @lock: mutex lock to serialize sysfs attribute accesses
* @reg_config: Register value of INA3221_CONFIG * @reg_config: Register value of INA3221_CONFIG
* @summation_shunt_resistor: equivalent shunt resistor value for summation * @summation_shunt_resistor: equivalent shunt resistor value for summation
* @summation_channel_control: Value written to SCC field in INA3221_MASK_ENABLE * @summation_channel_control: Value written to SCC field in INA3221_MASK_ENABLE
@ -126,7 +124,6 @@ struct ina3221_data {
struct regmap *regmap; struct regmap *regmap;
struct regmap_field *fields[F_MAX_FIELDS]; struct regmap_field *fields[F_MAX_FIELDS];
struct ina3221_input inputs[INA3221_NUM_CHANNELS]; struct ina3221_input inputs[INA3221_NUM_CHANNELS];
struct mutex lock;
u32 reg_config; u32 reg_config;
int summation_shunt_resistor; int summation_shunt_resistor;
u32 summation_channel_control; 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, static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val) u32 attr, int channel, long *val)
{ {
struct ina3221_data *ina = dev_get_drvdata(dev);
int ret; int ret;
mutex_lock(&ina->lock);
switch (type) { switch (type) {
case hwmon_chip: case hwmon_chip:
ret = ina3221_read_chip(dev, attr, val); 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; ret = -EOPNOTSUPP;
break; break;
} }
mutex_unlock(&ina->lock);
return ret; return ret;
} }
static int ina3221_write(struct device *dev, enum hwmon_sensor_types type, static int ina3221_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val) u32 attr, int channel, long val)
{ {
struct ina3221_data *ina = dev_get_drvdata(dev);
int ret; int ret;
mutex_lock(&ina->lock);
switch (type) { switch (type) {
case hwmon_chip: case hwmon_chip:
ret = ina3221_write_chip(dev, attr, val); 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; ret = -EOPNOTSUPP;
break; break;
} }
mutex_unlock(&ina->lock);
return ret; return ret;
} }
@ -886,7 +871,6 @@ static int ina3221_probe(struct i2c_client *client)
} }
ina->pm_dev = dev; ina->pm_dev = dev;
mutex_init(&ina->lock);
dev_set_drvdata(dev, ina); dev_set_drvdata(dev, ina);
/* Enable PM runtime -- status is suspended by default */ /* 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 */ /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */
for (i = 0; i < INA3221_NUM_CHANNELS; i++) for (i = 0; i < INA3221_NUM_CHANNELS; i++)
pm_runtime_put_noidle(ina->pm_dev); pm_runtime_put_noidle(ina->pm_dev);
mutex_destroy(&ina->lock);
return ret; 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 */ /* pm_runtime_put_noidle() will decrease the PM refcount until 0 */
for (i = 0; i < INA3221_NUM_CHANNELS; i++) for (i = 0; i < INA3221_NUM_CHANNELS; i++)
pm_runtime_put_noidle(ina->pm_dev); pm_runtime_put_noidle(ina->pm_dev);
mutex_destroy(&ina->lock);
} }
static int ina3221_suspend(struct device *dev) static int ina3221_suspend(struct device *dev)

View File

@ -19,7 +19,6 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
/* Addresses to scan */ /* Addresses to scan */
@ -179,7 +178,6 @@ static struct jc42_chips jc42_chips[] = {
/* Each client has this additional data */ /* Each client has this additional data */
struct jc42_data { struct jc42_data {
struct mutex update_lock; /* protect register access */
struct regmap *regmap; struct regmap *regmap;
bool extended; /* true if extended range supported */ bool extended; /* true if extended range supported */
bool valid; bool valid;
@ -216,8 +214,6 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type,
unsigned int regval; unsigned int regval;
int ret, temp, hyst; int ret, temp, hyst;
mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
case hwmon_temp_input: case hwmon_temp_input:
ret = regmap_read(data->regmap, JC42_REG_TEMP, &regval); ret = regmap_read(data->regmap, JC42_REG_TEMP, &regval);
@ -295,8 +291,6 @@ static int jc42_read(struct device *dev, enum hwmon_sensor_types type,
break; break;
} }
mutex_unlock(&data->update_lock);
return ret; return ret;
} }
@ -308,8 +302,6 @@ static int jc42_write(struct device *dev, enum hwmon_sensor_types type,
int diff, hyst; int diff, hyst;
int ret; int ret;
mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
case hwmon_temp_min: case hwmon_temp_min:
ret = regmap_write(data->regmap, JC42_REG_TEMP_LOWER, 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; break;
} }
mutex_unlock(&data->update_lock);
return ret; return ret;
} }
@ -498,7 +488,6 @@ static int jc42_probe(struct i2c_client *client)
return PTR_ERR(data->regmap); return PTR_ERR(data->regmap);
i2c_set_clientdata(client, data); i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
ret = regmap_read(data->regmap, JC42_REG_CAP, &cap); ret = regmap_read(data->regmap, JC42_REG_CAP, &cap);
if (ret) if (ret)

View File

@ -31,9 +31,6 @@ static bool force;
module_param(force, bool, 0444); module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); 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 #ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3
#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3 #define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3
#endif #endif
@ -84,6 +81,12 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
*/ */
#define AMD_I3255_STR "3255" #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. * PCI Device IDs for AMD's Family 1Ah-based SOCs.
* Defining locally as IDs are not shared. * 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, static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
unsigned int base, int offset, u32 *val) unsigned int base, int offset, u32 *val)
{ {
mutex_lock(&nb_smu_ind_mutex);
pci_bus_write_config_dword(pdev->bus, devfn, pci_bus_write_config_dword(pdev->bus, devfn,
base, offset); base, offset);
pci_bus_read_config_dword(pdev->bus, devfn, pci_bus_read_config_dword(pdev->bus, devfn,
base + 4, val); base + 4, val);
mutex_unlock(&nb_smu_ind_mutex);
} }
static void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval) 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_M40H_DF_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_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_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_17H_MA0H_DF_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_19H_M10H_DF_F3) },

View File

@ -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 * We need the timeouts for at least some LM78-like
* chips. But only if we read 'undefined' registers. * 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); val = inb_p(address + 1);
if (inb_p(address + 2) != val if (inb_p(address + 2) != val
|| inb_p(address + 3) != val || inb_p(address + 3) != val
|| inb_p(address + 7) != val) || inb_p(address + 7) != val)
goto release; goto release;
#undef REALLY_SLOW_IO
/* /*
* We should be able to change the 7 LSB of the address port. The * We should be able to change the 7 LSB of the address port. The

View File

@ -116,8 +116,14 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
(((val) < 0 ? (val) - 500 : \ (((val) < 0 ? (val) - 500 : \
(val) + 500) / 1000)) (val) + 500) / 1000))
#define FAN_FROM_REG(reg, div) ((reg) == 255 || (reg) == 0 ? 0 : \ static int fan_from_reg(int reg, int div)
(1350000 + (reg)*(div) / 2) / ((reg) * (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 : \ #define FAN_TO_REG(val, div) ((val) * (div) * 255 <= 1350000 ? 255 : \
(1350000 + (val)*(div) / 2) / ((val) * (div))) (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); struct lm87_data *data = lm87_update_device(dev);
int nr = to_sensor_dev_attr(attr)->index; 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]))); 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); struct lm87_data *data = lm87_update_device(dev);
int nr = to_sensor_dev_attr(attr)->index; 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]))); FAN_DIV_FROM_REG(data->fan_div[nr])));
} }
@ -534,7 +540,7 @@ static ssize_t fan_div_store(struct device *dev,
return err; return err;
mutex_lock(&data->update_lock); 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])); FAN_DIV_FROM_REG(data->fan_div[nr]));
switch (val) { switch (val) {

View File

@ -108,7 +108,6 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/kstrtox.h> #include <linux/kstrtox.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -735,7 +734,6 @@ struct lm90_data {
struct hwmon_channel_info temp_info; struct hwmon_channel_info temp_info;
const struct hwmon_channel_info *info[3]; const struct hwmon_channel_info *info[3];
struct hwmon_chip_info chip; struct hwmon_chip_info chip;
struct mutex update_lock;
struct delayed_work alert_work; struct delayed_work alert_work;
struct work_struct report_work; struct work_struct report_work;
bool valid; /* true if register values are valid */ 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; int err;
mutex_lock(&data->update_lock); hwmon_lock(data->hwmon_dev);
err = lm90_update_alarms_locked(data, force); err = lm90_update_alarms_locked(data, force);
mutex_unlock(&data->update_lock); hwmon_unlock(data->hwmon_dev);
return err; return err;
} }
@ -1519,9 +1517,7 @@ static int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val)
int err; int err;
u16 bit; u16 bit;
mutex_lock(&data->update_lock);
err = lm90_update_device(dev); err = lm90_update_device(dev);
mutex_unlock(&data->update_lock);
if (err) if (err)
return 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); struct lm90_data *data = dev_get_drvdata(dev);
int err; int err;
mutex_lock(&data->update_lock);
err = lm90_update_device(dev); err = lm90_update_device(dev);
if (err) if (err)
goto error; return err;
switch (attr) { switch (attr) {
case hwmon_temp_min: case hwmon_temp_min:
@ -1624,9 +1618,6 @@ static int lm90_temp_write(struct device *dev, u32 attr, int channel, long val)
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
break; break;
} }
error:
mutex_unlock(&data->update_lock);
return err; 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); struct lm90_data *data = dev_get_drvdata(dev);
int err; int err;
mutex_lock(&data->update_lock);
err = lm90_update_device(dev); err = lm90_update_device(dev);
mutex_unlock(&data->update_lock);
if (err) if (err)
return 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; struct i2c_client *client = data->client;
int err; int err;
mutex_lock(&data->update_lock);
err = lm90_update_device(dev); err = lm90_update_device(dev);
if (err) if (err)
goto error; return err;
switch (attr) { switch (attr) {
case hwmon_chip_update_interval: 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; err = -EOPNOTSUPP;
break; break;
} }
error:
mutex_unlock(&data->update_lock);
return err; return err;
} }
@ -2793,7 +2777,6 @@ static int lm90_probe(struct i2c_client *client)
data->client = client; data->client = client;
i2c_set_clientdata(client, data); i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
INIT_DELAYED_WORK(&data->alert_work, lm90_alert_work); INIT_DELAYED_WORK(&data->alert_work, lm90_alert_work);
INIT_WORK(&data->report_work, lm90_report_alarms); INIT_WORK(&data->report_work, lm90_report_alarms);

View File

@ -32,7 +32,6 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -78,7 +77,6 @@ static inline u8 ALARMS_FROM_REG(s16 reg)
/* Client data (each client gets its own) */ /* Client data (each client gets its own) */
struct lm92_data { struct lm92_data {
struct regmap *regmap; struct regmap *regmap;
struct mutex update_lock;
int resolution; int resolution;
}; };
@ -199,15 +197,11 @@ static int lm92_temp_write(struct lm92_data *data, u32 attr, long val)
break; break;
case hwmon_temp_crit_hyst: case hwmon_temp_crit_hyst:
val = clamp_val(val, -120000, 220000); val = clamp_val(val, -120000, 220000);
mutex_lock(&data->update_lock);
err = regmap_read(regmap, LM92_REG_TEMP_CRIT, &temp); err = regmap_read(regmap, LM92_REG_TEMP_CRIT, &temp);
if (err) if (err)
goto unlock;
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 err;
val = TEMP_TO_REG(TEMP_FROM_REG(temp) - val, data->resolution);
return regmap_write(regmap, LM92_REG_TEMP_HYST, val);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -396,7 +390,6 @@ static int lm92_probe(struct i2c_client *client)
data->regmap = regmap; data->regmap = regmap;
data->resolution = (unsigned long)i2c_get_match_data(client); data->resolution = (unsigned long)i2c_get_match_data(client);
mutex_init(&data->update_lock);
/* Initialize the chipset */ /* Initialize the chipset */
err = lm92_init_client(regmap); err = lm92_init_client(regmap);

View File

@ -14,7 +14,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/util_macros.h> #include <linux/util_macros.h>
@ -54,7 +53,6 @@ static const unsigned short normal_i2c[] = {
/* Client data (each client gets its own) */ /* Client data (each client gets its own) */
struct lm95234_data { struct lm95234_data {
struct regmap *regmap; struct regmap *regmap;
struct mutex update_lock;
enum chips type; enum chips type;
}; };
@ -107,19 +105,14 @@ static ssize_t lm95234_hyst_set(struct lm95234_data *data, long val)
u32 tcrit; u32 tcrit;
int ret; int ret;
mutex_lock(&data->update_lock);
ret = regmap_read(data->regmap, LM95234_REG_TCRIT1(0), &tcrit); ret = regmap_read(data->regmap, LM95234_REG_TCRIT1(0), &tcrit);
if (ret) if (ret)
goto unlock; return ret;
val = DIV_ROUND_CLOSEST(clamp_val(val, -255000, 255000), 1000); val = DIV_ROUND_CLOSEST(clamp_val(val, -255000, 255000), 1000);
val = clamp_val((int)tcrit - val, 0, 31); val = clamp_val((int)tcrit - val, 0, 31);
ret = regmap_write(data->regmap, LM95234_REG_TCRIT_HYST, val); return regmap_write(data->regmap, LM95234_REG_TCRIT_HYST, val);
unlock:
mutex_unlock(&data->update_lock);
return ret;
} }
static int lm95234_crit_reg(int channel) static int lm95234_crit_reg(int channel)
@ -526,7 +519,6 @@ static int lm95234_probe(struct i2c_client *client)
return PTR_ERR(regmap); return PTR_ERR(regmap);
data->regmap = regmap; data->regmap = regmap;
mutex_init(&data->update_lock);
/* Initialize the LM95234 chip */ /* Initialize the LM95234 chip */
err = lm95234_init_client(dev, regmap); err = lm95234_init_client(dev, regmap);

View File

@ -15,7 +15,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#define DEVNAME "lm95241" #define DEVNAME "lm95241"
@ -75,7 +74,6 @@ static const u8 lm95241_reg_address[] = {
/* Client data (each client gets its own) */ /* Client data (each client gets its own) */
struct lm95241_data { struct lm95241_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex update_lock;
unsigned long last_updated; /* in jiffies */ unsigned long last_updated; /* in jiffies */
unsigned long interval; /* in milli-seconds */ unsigned long interval; /* in milli-seconds */
bool valid; /* false until following fields are valid */ 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 lm95241_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated if (time_after(jiffies, data->last_updated
+ msecs_to_jiffies(data->interval)) || + msecs_to_jiffies(data->interval)) ||
!data->valid) { !data->valid) {
@ -120,9 +116,6 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
data->last_updated = jiffies; data->last_updated = jiffies;
data->valid = true; data->valid = true;
} }
mutex_unlock(&data->update_lock);
return data; return data;
} }
@ -204,8 +197,6 @@ static int lm95241_write_chip(struct device *dev, u32 attr, int channel,
u8 config; u8 config;
int ret; int ret;
mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
case hwmon_chip_update_interval: case hwmon_chip_update_interval:
config = data->config & ~CFG_CRMASK; config = data->config & ~CFG_CRMASK;
@ -231,7 +222,6 @@ static int lm95241_write_chip(struct device *dev, u32 attr, int channel,
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;
} }
mutex_unlock(&data->update_lock);
return ret; return ret;
} }
@ -242,8 +232,6 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel,
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
int ret; int ret;
mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
case hwmon_temp_min: case hwmon_temp_min:
if (channel == 1) { if (channel == 1) {
@ -313,9 +301,6 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel,
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;
} }
mutex_unlock(&data->update_lock);
return ret; return ret;
} }
@ -443,7 +428,6 @@ static int lm95241_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
data->client = client; data->client = client;
mutex_init(&data->update_lock);
/* Initialize the LM95241 chip */ /* Initialize the LM95241 chip */
lm95241_init_client(client, data); lm95241_init_client(client, data);

View File

@ -13,7 +13,6 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -86,7 +85,6 @@ static const unsigned short normal_i2c[] = {
/* Client data (each client gets its own) */ /* Client data (each client gets its own) */
struct lm95245_data { struct lm95245_data {
struct regmap *regmap; struct regmap *regmap;
struct mutex update_lock;
int interval; /* in msecs */ 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); ret = regmap_write(regmap, reg, val);
return ret; return ret;
case hwmon_temp_crit_hyst: case hwmon_temp_crit_hyst:
mutex_lock(&data->update_lock);
ret = regmap_read(regmap, LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT, ret = regmap_read(regmap, LM95245_REG_RW_LOCAL_OS_TCRIT_LIMIT,
&regval); &regval);
if (ret < 0) { if (ret < 0)
mutex_unlock(&data->update_lock);
return ret; return ret;
}
/* Clamp to reasonable range to prevent overflow */ /* Clamp to reasonable range to prevent overflow */
val = clamp_val(val, -1000000, 1000000); val = clamp_val(val, -1000000, 1000000);
val = regval - val / 1000; val = regval - val / 1000;
val = clamp_val(val, 0, 31); val = clamp_val(val, 0, 31);
ret = regmap_write(regmap, LM95245_REG_RW_COMMON_HYSTERESIS, ret = regmap_write(regmap, LM95245_REG_RW_COMMON_HYSTERESIS,
val); val);
mutex_unlock(&data->update_lock);
return ret; return ret;
case hwmon_temp_offset: case hwmon_temp_offset:
val = clamp_val(val, -128000, 127875); val = clamp_val(val, -128000, 127875);
@ -332,14 +326,10 @@ static int lm95245_write_chip(struct device *dev, u32 attr, int channel,
long val) long val)
{ {
struct lm95245_data *data = dev_get_drvdata(dev); struct lm95245_data *data = dev_get_drvdata(dev);
int ret;
switch (attr) { switch (attr) {
case hwmon_chip_update_interval: case hwmon_chip_update_interval:
mutex_lock(&data->update_lock); return lm95245_set_conversion_rate(data, val);
ret = lm95245_set_conversion_rate(data, val);
mutex_unlock(&data->update_lock);
return ret;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -542,8 +532,6 @@ static int lm95245_probe(struct i2c_client *client)
if (IS_ERR(data->regmap)) if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap); return PTR_ERR(data->regmap);
mutex_init(&data->update_lock);
/* Initialize the LM95245 chip */ /* Initialize the LM95245 chip */
ret = lm95245_init_client(data); ret = lm95245_init_client(data);
if (ret < 0) if (ret < 0)

View File

@ -10,7 +10,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/mfd/lochnagar.h> #include <linux/mfd/lochnagar.h>
#include <linux/mfd/lochnagar2_regs.h> #include <linux/mfd/lochnagar2_regs.h>
@ -42,9 +41,6 @@ struct lochnagar_hwmon {
struct regmap *regmap; struct regmap *regmap;
long power_nsamples[ARRAY_SIZE(lochnagar_chan_names)]; 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 { enum lochnagar_measure_mode {
@ -178,26 +174,20 @@ static int read_sensor(struct device *dev, int chan,
u32 data; u32 data;
int ret; int ret;
mutex_lock(&priv->sensor_lock);
ret = do_measurement(regmap, chan, mode, nsamples); ret = do_measurement(regmap, chan, mode, nsamples);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to perform measurement: %d\n", ret); dev_err(dev, "Failed to perform measurement: %d\n", ret);
goto error; return ret;
} }
ret = request_data(regmap, chan, &data); ret = request_data(regmap, chan, &data);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "Failed to read measurement: %d\n", ret); dev_err(dev, "Failed to read measurement: %d\n", ret);
goto error; return ret;
} }
*val = float_to_long(data, precision); *val = float_to_long(data, precision);
return 0;
error:
mutex_unlock(&priv->sensor_lock);
return ret;
} }
static int read_power(struct device *dev, int chan, long *val) 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) if (!priv)
return -ENOMEM; return -ENOMEM;
mutex_init(&priv->sensor_lock);
priv->regmap = dev_get_regmap(dev->parent, NULL); priv->regmap = dev_get_regmap(dev->parent, NULL);
if (!priv->regmap) { if (!priv->regmap) {
dev_err(dev, "No register map found\n"); dev_err(dev, "No register map found\n");

View File

@ -9,8 +9,8 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/math64.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/regmap.h> #include <linux/regmap.h>
@ -120,12 +120,6 @@
struct ltc2947_data { struct ltc2947_data {
struct regmap *map; struct regmap *map;
struct device *dev; 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; u32 lsb_energy;
bool gpio_out; bool gpio_out;
}; };
@ -181,13 +175,9 @@ static int ltc2947_val_read(struct ltc2947_data *st, const u8 reg,
int ret; int ret;
u64 __val = 0; u64 __val = 0;
mutex_lock(&st->lock);
ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page); ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page);
if (ret) { if (ret)
mutex_unlock(&st->lock);
return ret; return ret;
}
dev_dbg(st->dev, "Read val, reg:%02X, p:%d sz:%zu\n", reg, page, dev_dbg(st->dev, "Read val, reg:%02X, p:%d sz:%zu\n", reg, page,
size); size);
@ -207,8 +197,6 @@ static int ltc2947_val_read(struct ltc2947_data *st, const u8 reg,
break; break;
} }
mutex_unlock(&st->lock);
if (ret) if (ret)
return ret; return ret;
@ -242,13 +230,10 @@ static int ltc2947_val_write(struct ltc2947_data *st, const u8 reg,
{ {
int ret; int ret;
mutex_lock(&st->lock);
/* set device on correct page */ /* set device on correct page */
ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page); ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, page);
if (ret) { if (ret)
mutex_unlock(&st->lock);
return ret; return ret;
}
dev_dbg(st->dev, "Write val, r:%02X, p:%d, sz:%zu, val:%016llX\n", dev_dbg(st->dev, "Write val, r:%02X, p:%d, sz:%zu, val:%016llX\n",
reg, page, size, val); reg, page, size, val);
@ -265,8 +250,6 @@ static int ltc2947_val_write(struct ltc2947_data *st, const u8 reg,
break; break;
} }
mutex_unlock(&st->lock);
return ret; return ret;
} }
@ -295,11 +278,9 @@ static int ltc2947_alarm_read(struct ltc2947_data *st, const u8 reg,
memset(alarms, 0, sizeof(alarms)); memset(alarms, 0, sizeof(alarms));
mutex_lock(&st->lock);
ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, LTC2947_PAGE0); ret = regmap_write(st->map, LTC2947_REG_PAGE_CTRL, LTC2947_PAGE0);
if (ret) if (ret)
goto unlock; return ret;
dev_dbg(st->dev, "Read alarm, reg:%02X, mask:%02X\n", reg, mask); 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, ret = regmap_bulk_read(st->map, LTC2947_REG_STATUS, alarms,
sizeof(alarms)); sizeof(alarms));
if (ret) if (ret)
goto unlock; return ret;
/* get the alarm */ /* get the alarm */
*val = !!(alarms[offset] & mask); *val = !!(alarms[offset] & mask);
unlock: return 0;
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);
} }
static int ltc2947_read_temp(struct device *dev, const u32 attr, long *val, 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; 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, static int ltc2947_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val) 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); return ltc2947_read_power(dev, attr, val);
case hwmon_temp: case hwmon_temp:
return ltc2947_read_temp(dev, attr, val, channel); return ltc2947_read_temp(dev, attr, val, channel);
case hwmon_energy64:
return ltc2947_read_energy(dev, (s64 *)val, channel);
default: default:
return -ENOTSUPP; return -ENOTSUPP;
} }
@ -897,6 +877,8 @@ static umode_t ltc2947_is_visible(const void *data,
return ltc2947_power_is_visible(attr); return ltc2947_power_is_visible(attr);
case hwmon_temp: case hwmon_temp:
return ltc2947_temp_is_visible(attr); return ltc2947_temp_is_visible(attr);
case hwmon_energy64:
return 0444;
default: default:
return 0; return 0;
} }
@ -929,6 +911,9 @@ static const struct hwmon_channel_info * const ltc2947_info[] = {
HWMON_T_LABEL, HWMON_T_LABEL,
HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | HWMON_T_MAX | HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | HWMON_T_MAX |
HWMON_T_MIN | HWMON_T_LABEL), HWMON_T_MIN | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(energy64,
HWMON_E_INPUT,
HWMON_E_INPUT),
NULL NULL
}; };
@ -944,19 +929,6 @@ static const struct hwmon_chip_info ltc2947_chip_info = {
.info = ltc2947_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) static int ltc2947_setup(struct ltc2947_data *st)
{ {
int ret; int ret;
@ -1107,15 +1079,13 @@ int ltc2947_core_probe(struct regmap *map, const char *name)
st->map = map; st->map = map;
st->dev = dev; st->dev = dev;
dev_set_drvdata(dev, st); dev_set_drvdata(dev, st);
mutex_init(&st->lock);
ret = ltc2947_setup(st); ret = ltc2947_setup(st);
if (ret) if (ret)
return ret; return ret;
hwmon = devm_hwmon_device_register_with_info(dev, name, st, hwmon = devm_hwmon_device_register_with_info(dev, name, st,
&ltc2947_chip_info, &ltc2947_chip_info, NULL);
ltc2947_groups);
return PTR_ERR_OR_ZERO(hwmon); return PTR_ERR_OR_ZERO(hwmon);
} }
EXPORT_SYMBOL_GPL(ltc2947_core_probe); EXPORT_SYMBOL_GPL(ltc2947_core_probe);

View File

@ -18,7 +18,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/platform_data/ltc4245.h> #include <linux/platform_data/ltc4245.h>
@ -51,7 +50,6 @@ enum ltc4245_cmd {
struct ltc4245_data { struct ltc4245_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex update_lock;
bool valid; bool valid;
unsigned long last_updated; /* in jiffies */ unsigned long last_updated; /* in jiffies */
@ -132,10 +130,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
s32 val; s32 val;
int i; int i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
/* Read control registers -- 0x00 to 0x07 */ /* Read control registers -- 0x00 to 0x07 */
for (i = 0; i < ARRAY_SIZE(data->cregs); i++) { for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
val = i2c_smbus_read_byte_data(client, 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; data->valid = true;
} }
mutex_unlock(&data->update_lock);
return data; return data;
} }
@ -454,7 +447,6 @@ static int ltc4245_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
data->client = client; data->client = client;
mutex_init(&data->update_lock);
data->use_extra_gpios = ltc4245_use_extra_gpios(client); data->use_extra_gpios = ltc4245_use_extra_gpios(client);
/* Initialize the LTC4245 chip */ /* Initialize the LTC4245 chip */

View File

@ -12,13 +12,11 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/math.h> #include <linux/math.h>
#include <linux/minmax.h> #include <linux/minmax.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/string.h> #include <linux/string.h>
@ -132,8 +130,6 @@ struct ltc4282_cache {
struct ltc4282_state { struct ltc4282_state {
struct regmap *map; struct regmap *map;
/* Protect against multiple accesses to the device registers */
struct mutex lock;
struct clk_hw clk_hw; struct clk_hw clk_hw;
/* /*
* Used to cache values for VDD/VSOURCE depending which will be used * 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, static int ltc4282_read_alarm(struct ltc4282_state *st, u32 reg, u32 mask,
long *val) long *val)
{ {
guard(mutex)(&st->lock);
return __ltc4282_read_alarm(st, reg, mask, val); return __ltc4282_read_alarm(st, reg, mask, val);
} }
static int ltc4282_vdd_source_read_in(struct ltc4282_state *st, u32 channel, static int ltc4282_vdd_source_read_in(struct ltc4282_state *st, u32 channel,
long *val) long *val)
{ {
guard(mutex)(&st->lock);
if (!st->in0_1_cache[channel].en) if (!st->in0_1_cache[channel].en)
return -ENODATA; return -ENODATA;
@ -301,7 +295,6 @@ static int ltc4282_vdd_source_read_hist(struct ltc4282_state *st, u32 reg,
{ {
int ret; int ret;
guard(mutex)(&st->lock);
if (!st->in0_1_cache[channel].en) { if (!st->in0_1_cache[channel].en) {
*val = *cached; *val = *cached;
return 0; 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, static int ltc4282_vdd_source_read_lim(struct ltc4282_state *st, u32 reg,
u32 channel, u32 *cached, long *val) u32 channel, u32 *cached, long *val)
{ {
guard(mutex)(&st->lock);
if (!st->in0_1_cache[channel].en) if (!st->in0_1_cache[channel].en)
return ltc4282_read_voltage_byte_cached(st, reg, st->vfs_out, return ltc4282_read_voltage_byte_cached(st, reg, st->vfs_out,
val, cached); 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, static int ltc4282_vdd_source_read_alm(struct ltc4282_state *st, u32 mask,
u32 channel, long *val) u32 channel, long *val)
{ {
guard(mutex)(&st->lock);
if (!st->in0_1_cache[channel].en) { if (!st->in0_1_cache[channel].en) {
/* /*
* Do this otherwise alarms can get confused because we clear * 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, channel,
&st->in0_1_cache[channel].in_min_raw, val); &st->in0_1_cache[channel].in_min_raw, val);
case hwmon_in_enable: 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; return 0;
case hwmon_in_fault: case hwmon_in_fault:
/* /*
@ -541,7 +530,7 @@ static int ltc4282_read_power_byte(const struct ltc4282_state *st, u32 reg,
return 0; 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; u64 temp, energy;
__be64 raw; __be64 raw;
@ -613,10 +602,12 @@ static int ltc4282_read(struct device *dev, enum hwmon_sensor_types type,
case hwmon_power: case hwmon_power:
return ltc4282_read_power(st, attr, val); return ltc4282_read_power(st, attr, val);
case hwmon_energy: case hwmon_energy:
scoped_guard(mutex, &st->lock) {
*val = st->energy_en; *val = st->energy_en;
}
return 0; return 0;
case hwmon_energy64:
if (st->energy_en)
return ltc4282_read_energy(st, (s64 *)val);
return -ENODATA;
default: default:
return -EOPNOTSUPP; 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, static int ltc4282_in_write_history(struct ltc4282_state *st, u32 reg,
long lowest, long highest, u32 fs) long lowest, long highest, u32 fs)
{ {
guard(mutex)(&st->lock);
return __ltc4282_in_write_history(st, reg, lowest, highest, fs); 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; int ret;
guard(mutex)(&st->lock);
ret = ltc4282_write_power_word(st, LTC4282_POWER_LOWEST, ret = ltc4282_write_power_word(st, LTC4282_POWER_LOWEST,
st->power_max); st->power_max);
if (ret) if (ret)
@ -798,7 +786,6 @@ static int ltc4282_vdd_source_write_lim(struct ltc4282_state *st, u32 reg,
{ {
int ret; int ret;
guard(mutex)(&st->lock);
if (st->in0_1_cache[channel].en) if (st->in0_1_cache[channel].en)
ret = ltc4282_write_voltage_byte(st, reg, st->vfs_out, val); ret = ltc4282_write_voltage_byte(st, reg, st->vfs_out, val);
else else
@ -816,7 +803,6 @@ static int ltc4282_vdd_source_reset_hist(struct ltc4282_state *st, int channel)
if (channel == LTC4282_CHAN_VDD) if (channel == LTC4282_CHAN_VDD)
lowest = st->vdd; lowest = st->vdd;
guard(mutex)(&st->lock);
if (st->in0_1_cache[channel].en) { if (st->in0_1_cache[channel].en) {
ret = __ltc4282_in_write_history(st, LTC4282_VSOURCE_LOWEST, ret = __ltc4282_in_write_history(st, LTC4282_VSOURCE_LOWEST,
lowest, 0, st->vfs_out); 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; int ret, other_chan = ~channel & 0x1;
u8 __val = val; u8 __val = val;
guard(mutex)(&st->lock);
if (st->in0_1_cache[channel].en == !!val) if (st->in0_1_cache[channel].en == !!val)
return 0; return 0;
@ -933,8 +918,6 @@ static int ltc4282_curr_reset_hist(struct ltc4282_state *st)
{ {
int ret; int ret;
guard(mutex)(&st->lock);
ret = __ltc4282_in_write_history(st, LTC4282_VSENSE_LOWEST, ret = __ltc4282_in_write_history(st, LTC4282_VSENSE_LOWEST,
st->vsense_max, 0, 40 * MILLI); st->vsense_max, 0, 40 * MILLI);
if (ret) if (ret)
@ -969,7 +952,6 @@ static int ltc4282_energy_enable_set(struct ltc4282_state *st, long val)
{ {
int ret; int ret;
guard(mutex)(&st->lock);
/* setting the bit halts the meter */ /* setting the bit halts the meter */
ret = regmap_update_bits(st->map, LTC4282_ADC_CTRL, ret = regmap_update_bits(st->map, LTC4282_ADC_CTRL,
LTC4282_METER_HALT_MASK, LTC4282_METER_HALT_MASK,
@ -1078,6 +1060,9 @@ static umode_t ltc4282_is_visible(const void *data,
case hwmon_energy: case hwmon_energy:
/* hwmon_energy_enable */ /* hwmon_energy_enable */
return 0644; return 0644;
case hwmon_energy64:
/* hwmon_energy_input */
return 0444;
default: default:
return 0; 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 = { static const struct clk_ops ltc4282_ops = {
.recalc_rate = ltc4282_recalc_rate, .recalc_rate = ltc4282_recalc_rate,
.determine_rate = ltc4282_determine_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_P_RESET_HISTORY | HWMON_P_LABEL),
HWMON_CHANNEL_INFO(energy, HWMON_CHANNEL_INFO(energy,
HWMON_E_ENABLE), HWMON_E_ENABLE),
HWMON_CHANNEL_INFO(energy64,
HWMON_E_INPUT),
NULL NULL
}; };
@ -1603,15 +1572,6 @@ static const struct hwmon_chip_info ltc4282_chip_info = {
.info = ltc4282_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) static int ltc4282_show_fault_log(void *arg, u64 *val, u32 mask)
{ {
struct ltc4282_state *st = arg; struct ltc4282_state *st = arg;
@ -1716,10 +1676,8 @@ static int ltc4282_probe(struct i2c_client *i2c)
if (ret) if (ret)
return ret; return ret;
mutex_init(&st->lock);
hwmon = devm_hwmon_device_register_with_info(dev, "ltc4282", st, hwmon = devm_hwmon_device_register_with_info(dev, "ltc4282", st,
&ltc4282_chip_info, &ltc4282_chip_info, NULL);
ltc4282_groups);
if (IS_ERR(hwmon)) if (IS_ERR(hwmon))
return PTR_ERR(hwmon); return PTR_ERR(hwmon);

View File

@ -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");

View File

@ -45,7 +45,6 @@
#define MAX127_SIGN_BIT BIT(11) #define MAX127_SIGN_BIT BIT(11)
struct max127_data { struct max127_data {
struct mutex lock;
struct i2c_client *client; struct i2c_client *client;
u8 ctrl_byte[MAX127_NUM_CHANNELS]; 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; struct i2c_client *client = data->client;
u8 ctrl_byte = data->ctrl_byte[channel]; u8 ctrl_byte = data->ctrl_byte[channel];
mutex_lock(&data->lock);
status = max127_select_channel(client, ctrl_byte); status = max127_select_channel(client, ctrl_byte);
if (status) if (status)
goto exit; return status;
status = max127_read_channel(client, &raw); status = max127_read_channel(client, &raw);
if (status) if (status)
goto exit; return status;
*val = max127_process_raw(ctrl_byte, raw); *val = max127_process_raw(ctrl_byte, raw);
return 0;
exit:
mutex_unlock(&data->lock);
return status;
} }
static int max127_read_min(struct max127_data *data, int channel, long *val) 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; u8 ctrl;
mutex_lock(&data->lock);
ctrl = data->ctrl_byte[channel]; ctrl = data->ctrl_byte[channel];
if (val <= -MAX127_FULL_RANGE) { if (val <= -MAX127_FULL_RANGE) {
ctrl |= (MAX127_CTRL_RNG | MAX127_CTRL_BIP); 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; ctrl &= ~MAX127_CTRL_BIP;
} }
data->ctrl_byte[channel] = ctrl; data->ctrl_byte[channel] = ctrl;
mutex_unlock(&data->lock);
return 0; return 0;
} }
static int max127_write_max(struct max127_data *data, int channel, long val) static int max127_write_max(struct max127_data *data, int channel, long val)
{ {
mutex_lock(&data->lock);
if (val >= MAX127_FULL_RANGE) if (val >= MAX127_FULL_RANGE)
data->ctrl_byte[channel] |= MAX127_CTRL_RNG; data->ctrl_byte[channel] |= MAX127_CTRL_RNG;
else else
data->ctrl_byte[channel] &= ~MAX127_CTRL_RNG; data->ctrl_byte[channel] &= ~MAX127_CTRL_RNG;
mutex_unlock(&data->lock);
return 0; return 0;
} }
@ -315,7 +299,6 @@ static int max127_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
data->client = client; data->client = client;
mutex_init(&data->lock);
for (i = 0; i < ARRAY_SIZE(data->ctrl_byte); i++) for (i = 0; i < ARRAY_SIZE(data->ctrl_byte); i++)
data->ctrl_byte[i] = (MAX127_CTRL_START | data->ctrl_byte[i] = (MAX127_CTRL_START |
MAX127_SET_CHANNEL(i)); MAX127_SET_CHANNEL(i));

View File

@ -216,12 +216,13 @@ static ssize_t max16065_current_show(struct device *dev,
struct device_attribute *da, char *buf) struct device_attribute *da, char *buf)
{ {
struct max16065_data *data = max16065_update_device(dev); struct max16065_data *data = max16065_update_device(dev);
int curr_sense = data->curr_sense;
if (unlikely(data->curr_sense < 0)) if (unlikely(curr_sense < 0))
return data->curr_sense; return curr_sense;
return sysfs_emit(buf, "%d\n", 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, static ssize_t max16065_limit_store(struct device *dev,

View File

@ -57,7 +57,6 @@
*/ */
struct max31790_data { struct max31790_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex update_lock;
bool valid; /* zero until following fields are valid */ bool valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */ 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 max31790_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
struct max31790_data *ret = data; int i, rv;
int i;
int rv;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
data->valid = false;
rv = i2c_smbus_read_byte_data(client, rv = i2c_smbus_read_byte_data(client,
MAX31790_REG_FAN_FAULT_STATUS1); MAX31790_REG_FAN_FAULT_STATUS1);
if (rv < 0) if (rv < 0)
goto abort; return ERR_PTR(rv);
data->fault_status |= rv & 0x3F; data->fault_status |= rv & 0x3F;
rv = i2c_smbus_read_byte_data(client, rv = i2c_smbus_read_byte_data(client,
MAX31790_REG_FAN_FAULT_STATUS2); MAX31790_REG_FAN_FAULT_STATUS2);
if (rv < 0) if (rv < 0)
goto abort; return ERR_PTR(rv);
data->fault_status |= (rv & 0x3F) << 6; data->fault_status |= (rv & 0x3F) << 6;
for (i = 0; i < NR_CHANNEL; i++) { for (i = 0; i < NR_CHANNEL; i++) {
rv = i2c_smbus_read_word_swapped(client, rv = i2c_smbus_read_word_swapped(client,
MAX31790_REG_TACH_COUNT(i)); MAX31790_REG_TACH_COUNT(i));
if (rv < 0) if (rv < 0)
goto abort; return ERR_PTR(rv);
data->tach[i] = rv; data->tach[i] = rv;
if (data->fan_config[i] 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 MAX31790_REG_TACH_COUNT(NR_CHANNEL
+ i)); + i));
if (rv < 0) if (rv < 0)
goto abort; return ERR_PTR(rv);
data->tach[NR_CHANNEL + i] = rv; data->tach[NR_CHANNEL + i] = rv;
} else { } else {
rv = i2c_smbus_read_word_swapped(client, rv = i2c_smbus_read_word_swapped(client,
MAX31790_REG_PWM_DUTY_CYCLE(i)); MAX31790_REG_PWM_DUTY_CYCLE(i));
if (rv < 0) if (rv < 0)
goto abort; return ERR_PTR(rv);
data->pwm[i] = rv; data->pwm[i] = rv;
rv = i2c_smbus_read_word_swapped(client, rv = i2c_smbus_read_word_swapped(client,
MAX31790_REG_TARGET_COUNT(i)); MAX31790_REG_TARGET_COUNT(i));
if (rv < 0) if (rv < 0)
goto abort; return ERR_PTR(rv);
data->target_count[i] = 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->last_updated = jiffies;
data->valid = true; data->valid = true;
} }
goto done; return data;
abort:
data->valid = false;
ret = ERR_PTR(rv);
done:
mutex_unlock(&data->update_lock);
return ret;
} }
static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; 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; *val = rpm;
return 0; return 0;
case hwmon_fan_fault: case hwmon_fan_fault:
mutex_lock(&data->update_lock);
*val = !!(data->fault_status & (1 << channel)); *val = !!(data->fault_status & (1 << channel));
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) { if (*val) {
int reg = MAX31790_REG_TARGET_COUNT(channel % NR_CHANNEL); int reg = MAX31790_REG_TARGET_COUNT(channel % NR_CHANNEL);
i2c_smbus_write_byte_data(data->client, reg, return i2c_smbus_write_byte_data(data->client, reg,
data->target_count[channel % NR_CHANNEL] >> 8); data->target_count[channel % NR_CHANNEL] >> 8);
} }
mutex_unlock(&data->update_lock);
return 0; return 0;
case hwmon_fan_enable: case hwmon_fan_enable:
*val = !!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN); *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; u8 bits, fan_config;
int sr; int sr;
mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
case hwmon_fan_target: case hwmon_fan_target:
val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX); 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; err = -EOPNOTSUPP;
break; break;
} }
mutex_unlock(&data->update_lock);
return err; return err;
} }
@ -338,8 +318,6 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
u8 fan_config; u8 fan_config;
int err = 0; int err = 0;
mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
case hwmon_pwm_input: case hwmon_pwm_input:
if (val < 0 || val > 255) { if (val < 0 || val > 255) {
@ -389,9 +367,6 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
break; break;
} }
mutex_unlock(&data->update_lock);
return err; return err;
} }
@ -525,7 +500,6 @@ static int max31790_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
data->client = client; data->client = client;
mutex_init(&data->update_lock);
/* /*
* Initialize the max31790 chip * Initialize the max31790 chip

View File

@ -10,7 +10,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
@ -99,7 +98,6 @@ struct max31827_state {
/* /*
* Prevent simultaneous access to the i2c client. * Prevent simultaneous access to the i2c client.
*/ */
struct mutex lock;
struct regmap *regmap; struct regmap *regmap;
bool enable; bool enable;
unsigned int resolution; 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 * Before the Temperature Threshold Alarm, Alarm Hysteresis Threshold
* and Resolution bits from Configuration register are changed over I2C, * and Resolution bits from Configuration register are changed over I2C,
* the part must be in shutdown mode. * 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 (!st->enable) {
if (!mask) if (!mask)
ret = regmap_write(st->regmap, reg, val); return regmap_write(st->regmap, reg, val);
else return regmap_update_bits(st->regmap, reg, mask, val);
ret = regmap_update_bits(st->regmap, reg, mask, val);
goto unlock;
} }
ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg); ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg);
if (ret) if (ret)
goto unlock; return ret;
cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg; cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg;
cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK | cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK |
MAX31827_CONFIGURATION_CNV_RATE_MASK); MAX31827_CONFIGURATION_CNV_RATE_MASK);
ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg); ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
if (ret) if (ret)
goto unlock; return ret;
if (!mask) if (!mask)
ret = regmap_write(st->regmap, reg, val); 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); ret = regmap_update_bits(st->regmap, reg, mask, val);
if (ret) if (ret)
goto unlock; return ret;
ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG, return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_CNV_RATE_MASK, MAX31827_CONFIGURATION_CNV_RATE_MASK,
cnv_rate); cnv_rate);
unlock:
mutex_unlock(&st->lock);
return ret;
} }
static int write_alarm_val(struct max31827_state *st, unsigned int reg, 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; break;
case hwmon_temp_input: case hwmon_temp_input:
mutex_lock(&st->lock);
if (!st->enable) { 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, ret = regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG, MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_1SHOT_MASK, MAX31827_CONFIGURATION_1SHOT_MASK,
1); 1);
if (ret) { if (ret)
mutex_unlock(&st->lock);
return ret; return ret;
}
msleep(max31827_conv_times[st->resolution]); 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); ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
mutex_unlock(&st->lock);
if (ret) if (ret)
break; break;
@ -352,7 +327,6 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
if (val >> 1) if (val >> 1)
return -EINVAL; return -EINVAL;
mutex_lock(&st->lock);
/** /**
* The chip should not be enabled while a conversion is * The chip should not be enabled while a conversion is
* performed. Neither should the chip be enabled when * performed. Neither should the chip be enabled when
@ -361,16 +335,12 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
st->enable = val; st->enable = val;
ret = regmap_update_bits(st->regmap, return regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG, MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_1SHOT_MASK | MAX31827_CONFIGURATION_1SHOT_MASK |
MAX31827_CONFIGURATION_CNV_RATE_MASK, MAX31827_CONFIGURATION_CNV_RATE_MASK,
MAX31827_DEVICE_ENABLE(val)); MAX31827_DEVICE_ENABLE(val));
mutex_unlock(&st->lock);
return ret;
case hwmon_temp_max: case hwmon_temp_max:
return write_alarm_val(st, MAX31827_TH_REG, val); return write_alarm_val(st, MAX31827_TH_REG, val);
@ -623,8 +593,6 @@ static int max31827_probe(struct i2c_client *client)
if (!st) if (!st)
return -ENOMEM; return -ENOMEM;
mutex_init(&st->lock);
st->regmap = devm_regmap_init_i2c(client, &max31827_regmap); st->regmap = devm_regmap_init_i2c(client, &max31827_regmap);
if (IS_ERR(st->regmap)) if (IS_ERR(st->regmap))
return dev_err_probe(dev, PTR_ERR(st->regmap), return dev_err_probe(dev, PTR_ERR(st->regmap),

View File

@ -130,7 +130,6 @@ static const u8 target_reg[] = {
struct max6620_data { struct max6620_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex update_lock;
bool valid; /* false until following fields are valid */ bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */ 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 max6620_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
int i; int i, ret;
int ret = 0;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
ret = i2c_smbus_read_byte_data(client, config_reg[i]); ret = i2c_smbus_read_byte_data(client, config_reg[i]);
if (ret < 0) if (ret < 0)
goto error; return ret;
data->fancfg[i] = ret; data->fancfg[i] = ret;
ret = i2c_smbus_read_byte_data(client, dyn_reg[i]); ret = i2c_smbus_read_byte_data(client, dyn_reg[i]);
if (ret < 0) if (ret < 0)
goto error; return ret;
data->fandyn[i] = ret; data->fandyn[i] = ret;
ret = i2c_smbus_read_byte_data(client, tach_reg[i]); ret = i2c_smbus_read_byte_data(client, tach_reg[i]);
if (ret < 0) if (ret < 0)
goto error; return ret;
data->tach[i] = (ret << 3) & 0x7f8; data->tach[i] = (ret << 3) & 0x7f8;
ret = i2c_smbus_read_byte_data(client, tach_reg[i] + 1); ret = i2c_smbus_read_byte_data(client, tach_reg[i] + 1);
if (ret < 0) if (ret < 0)
goto error; return ret;
data->tach[i] |= (ret >> 5) & 0x7; data->tach[i] |= (ret >> 5) & 0x7;
ret = i2c_smbus_read_byte_data(client, target_reg[i]); ret = i2c_smbus_read_byte_data(client, target_reg[i]);
if (ret < 0) if (ret < 0)
goto error; return ret;
data->target[i] = (ret << 3) & 0x7f8; data->target[i] = (ret << 3) & 0x7f8;
ret = i2c_smbus_read_byte_data(client, target_reg[i] + 1); ret = i2c_smbus_read_byte_data(client, target_reg[i] + 1);
if (ret < 0) if (ret < 0)
goto error; return ret;
data->target[i] |= (ret >> 5) & 0x7; 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); ret = i2c_smbus_read_byte_data(client, MAX6620_REG_FAULT);
if (ret < 0) if (ret < 0)
goto error; return ret;
data->fault |= (ret >> 4) & (ret & 0x0F); data->fault |= (ret >> 4) & (ret & 0x0F);
data->last_updated = jiffies; data->last_updated = jiffies;
data->valid = true; data->valid = true;
} }
return 0;
error:
mutex_unlock(&data->update_lock);
return ret;
} }
static umode_t static umode_t
@ -261,7 +254,6 @@ max6620_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
case hwmon_fan: case hwmon_fan:
switch (attr) { switch (attr) {
case hwmon_fan_alarm: case hwmon_fan_alarm:
mutex_lock(&data->update_lock);
*val = !!(data->fault & BIT(channel)); *val = !!(data->fault & BIT(channel));
/* Setting TACH count to re-enable fan fault detection */ /* 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; val2 = (data->target[channel] << 5) & 0xe0;
ret = i2c_smbus_write_byte_data(client, ret = i2c_smbus_write_byte_data(client,
target_reg[channel], val1); target_reg[channel], val1);
if (ret < 0) { if (ret < 0)
mutex_unlock(&data->update_lock);
return ret; return ret;
}
ret = i2c_smbus_write_byte_data(client, ret = i2c_smbus_write_byte_data(client,
target_reg[channel] + 1, val2); target_reg[channel] + 1, val2);
if (ret < 0) { if (ret < 0)
mutex_unlock(&data->update_lock);
return ret; return ret;
}
data->fault &= ~BIT(channel); data->fault &= ~BIT(channel);
} }
mutex_unlock(&data->update_lock);
break; break;
case hwmon_fan_div: case hwmon_fan_div:
*val = max6620_fan_div_from_reg(data->fandyn[channel]); *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; return ret;
data = dev_get_drvdata(dev); data = dev_get_drvdata(dev);
client = data->client; client = data->client;
mutex_lock(&data->update_lock);
switch (type) { switch (type) {
case hwmon_fan: case hwmon_fan:
@ -360,8 +345,7 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
div = 5; div = 5;
break; break;
default: default:
ret = -EINVAL; return -EINVAL;
goto error;
} }
data->fandyn[channel] &= 0x1F; data->fandyn[channel] &= 0x1F;
data->fandyn[channel] |= div << 5; data->fandyn[channel] |= div << 5;
@ -396,8 +380,6 @@ max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
break; break;
} }
error:
mutex_unlock(&data->update_lock);
return ret; return ret;
} }
@ -478,7 +460,6 @@ static int max6620_probe(struct i2c_client *client)
return -ENOMEM; return -ENOMEM;
data->client = client; data->client = client;
mutex_init(&data->update_lock);
err = max6620_init_client(data); err = max6620_init_client(data);
if (err) if (err)

View File

@ -16,9 +16,7 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/util_macros.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 max6639_data {
struct regmap *regmap; struct regmap *regmap;
struct mutex update_lock;
/* Register values initialized only once */ /* Register values initialized only once */
u8 ppr[MAX6639_NUM_CHANNELS]; /* Pulses per rotation 0..3 for 1..4 ppr */ 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) if (val <= 0 || val > 4)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock);
/* Set Fan pulse per revolution */ /* Set Fan pulse per revolution */
err = max6639_set_ppr(data, channel, val); err = max6639_set_ppr(data, channel, val);
if (err < 0) { if (err < 0)
mutex_unlock(&data->update_lock);
return err; return err;
}
data->ppr[channel] = val; data->ppr[channel] = val;
mutex_unlock(&data->update_lock);
return 0; return 0;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -320,21 +312,17 @@ static int max6639_write_pwm(struct device *dev, u32 attr, int channel,
case hwmon_pwm_input: case hwmon_pwm_input:
if (val < 0 || val > 255) if (val < 0 || val > 255)
return -EINVAL; return -EINVAL;
err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel), return regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(channel),
val * 120 / 255); val * 120 / 255);
return err;
case hwmon_pwm_freq: case hwmon_pwm_freq:
val = clamp_val(val, 0, 25000); val = clamp_val(val, 0, 25000);
i = find_closest(val, freq_table, ARRAY_SIZE(freq_table)); 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), err = regmap_update_bits(data->regmap, MAX6639_REG_FAN_CONFIG3(channel),
MAX6639_FAN_CONFIG3_FREQ_MASK, i); MAX6639_FAN_CONFIG3_FREQ_MASK, i);
if (err < 0) { if (err < 0)
mutex_unlock(&data->update_lock);
return err; return err;
}
if (i >> 2) if (i >> 2)
err = regmap_set_bits(data->regmap, MAX6639_REG_GCONFIG, 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, err = regmap_clear_bits(data->regmap, MAX6639_REG_GCONFIG,
MAX6639_GCONFIG_PWM_FREQ_HI); MAX6639_GCONFIG_PWM_FREQ_HI);
mutex_unlock(&data->update_lock);
return err; return err;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -753,8 +740,6 @@ static int max6639_probe(struct i2c_client *client)
} }
} }
mutex_init(&data->update_lock);
/* Initialize the max6639 chip */ /* Initialize the max6639 chip */
err = max6639_init_client(client, data); err = max6639_init_client(client, data);
if (err < 0) if (err < 0)

View File

@ -13,7 +13,6 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -91,8 +90,6 @@ struct max6697_data {
int temp_offset; /* in degrees C */ int temp_offset; /* in degrees C */
struct mutex update_lock;
#define MAX6697_TEMP_INPUT 0 #define MAX6697_TEMP_INPUT 0
#define MAX6697_TEMP_EXT 1 #define MAX6697_TEMP_EXT 1
#define MAX6697_TEMP_MAX 2 #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); val = clamp_val(val, 0, 255);
return regmap_write(regmap, MAX6697_REG_MIN, val); return regmap_write(regmap, MAX6697_REG_MIN, val);
case hwmon_temp_offset: case hwmon_temp_offset:
mutex_lock(&data->update_lock);
val = clamp_val(val, MAX6581_OFFSET_MIN, MAX6581_OFFSET_MAX); val = clamp_val(val, MAX6581_OFFSET_MIN, MAX6581_OFFSET_MAX);
val = DIV_ROUND_CLOSEST(val, 250); val = DIV_ROUND_CLOSEST(val, 250);
if (!val) { /* disable this (and only this) channel */ 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, ret = regmap_set_bits(regmap, MAX6581_REG_OFFSET_SELECT,
BIT(channel - 1)); BIT(channel - 1));
if (ret) if (ret)
goto unlock; return ret;
ret = regmap_write(regmap, MAX6581_REG_OFFSET, val); ret = regmap_write(regmap, MAX6581_REG_OFFSET, val);
} }
unlock:
mutex_unlock(&data->update_lock);
return ret; return ret;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -548,7 +542,7 @@ static int max6697_probe(struct i2c_client *client)
struct regmap *regmap; struct regmap *regmap;
int err; int err;
regmap = regmap_init_i2c(client, &max6697_regmap_config); regmap = devm_regmap_init_i2c(client, &max6697_regmap_config);
if (IS_ERR(regmap)) if (IS_ERR(regmap))
return PTR_ERR(regmap); return PTR_ERR(regmap);
@ -559,7 +553,6 @@ static int max6697_probe(struct i2c_client *client)
data->regmap = regmap; data->regmap = regmap;
data->type = (uintptr_t)i2c_get_match_data(client); data->type = (uintptr_t)i2c_get_match_data(client);
data->chip = &max6697_chip_data[data->type]; data->chip = &max6697_chip_data[data->type];
mutex_init(&data->update_lock);
err = max6697_init_chip(client->dev.of_node, data); err = max6697_init_chip(client->dev.of_node, data);
if (err) if (err)

View File

@ -14,7 +14,6 @@
#include <linux/kstrtox.h> #include <linux/kstrtox.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/regmap.h> #include <linux/regmap.h>

View File

@ -1403,6 +1403,7 @@ static const char * const asus_msi_boards[] = {
"ROG STRIX X670E-E GAMING WIFI", "ROG STRIX X670E-E GAMING WIFI",
"ROG STRIX X670E-F GAMING WIFI", "ROG STRIX X670E-F GAMING WIFI",
"ROG STRIX X670E-I 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",
"ROG STRIX Z590-A GAMING WIFI II", "ROG STRIX Z590-A GAMING WIFI II",
"ROG STRIX Z590-E GAMING WIFI", "ROG STRIX Z590-E GAMING WIFI",

View File

@ -7,10 +7,8 @@
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>

View File

@ -21,7 +21,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
@ -128,7 +127,6 @@ static const unsigned short normal_i2c[] = {
struct nct7904_data { struct nct7904_data {
struct i2c_client *client; struct i2c_client *client;
struct watchdog_device wdt; struct watchdog_device wdt;
struct mutex bank_lock;
int bank_sel; int bank_sel;
u32 fanin_mask; u32 fanin_mask;
u32 vsen_mask; u32 vsen_mask;
@ -142,24 +140,19 @@ struct nct7904_data {
}; };
/* Access functions */ /* 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; int ret;
mutex_lock(&data->bank_lock);
if (data->bank_sel == bank) if (data->bank_sel == bank)
return 0; return 0;
ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank); ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank);
if (ret == 0) if (ret < 0) {
data->bank_sel = bank;
else
data->bank_sel = -1; data->bank_sel = -1;
return ret; return ret;
} }
data->bank_sel = bank;
static inline void nct7904_bank_release(struct nct7904_data *data) return 0;
{
mutex_unlock(&data->bank_lock);
} }
/* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */ /* 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; struct i2c_client *client = data->client;
int ret; int ret;
ret = nct7904_bank_lock(data, bank); ret = nct7904_bank_select(data, bank);
if (ret == 0) if (ret < 0)
ret = i2c_smbus_read_byte_data(client, reg);
nct7904_bank_release(data);
return ret; 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; struct i2c_client *client = data->client;
int ret, hi; int ret, hi;
ret = nct7904_bank_lock(data, bank); ret = nct7904_bank_select(data, bank);
if (ret == 0) { 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; 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. */ /* 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; struct i2c_client *client = data->client;
int ret; int ret;
ret = nct7904_bank_lock(data, bank); ret = nct7904_bank_select(data, bank);
if (ret == 0) if (ret < 0)
ret = i2c_smbus_write_byte_data(client, reg, val);
nct7904_bank_release(data);
return ret; return ret;
return i2c_smbus_write_byte_data(client, reg, val);
} }
static int nct7904_read_fan(struct device *dev, u32 attr, int channel, 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; return -ENOMEM;
data->client = client; data->client = client;
mutex_init(&data->bank_lock);
data->bank_sel = -1; data->bank_sel = -1;
/* Setup sensor groups. */ /* Setup sensor groups. */

View File

@ -4,7 +4,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
@ -198,7 +197,6 @@ struct npcm7xx_pwm_fan_data {
int pwm_modules; int pwm_modules;
struct clk *pwm_clk; struct clk *pwm_clk;
struct clk *fan_clk; struct clk *fan_clk;
struct mutex pwm_lock[NPCM7XX_PWM_MAX_MODULES];
spinlock_t fan_lock[NPCM7XX_FAN_MAX_MODULE]; spinlock_t fan_lock[NPCM7XX_FAN_MAX_MODULE];
int fan_irq[NPCM7XX_FAN_MAX_MODULE]; int fan_irq[NPCM7XX_FAN_MAX_MODULE];
bool pwm_present[NPCM7XX_PWM_MAX_CHN_NUM]; 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 * Config PWM Comparator register for setting duty cycle
*/ */
mutex_lock(&data->pwm_lock[module]);
/* write new CMR value */ /* write new CMR value */
iowrite32(val, NPCM7XX_PWM_REG_CMRx(data->pwm_base, module, pwm_ch)); 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; env_bit = NPCM7XX_PWM_CTRL_CH3_INV_BIT;
break; break;
default: default:
mutex_unlock(&data->pwm_lock[module]);
return -ENODEV; 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)); iowrite32(tmp_buf, NPCM7XX_PWM_REG_CR(data->pwm_base, module));
mutex_unlock(&data->pwm_lock[module]);
return 0; return 0;
} }
@ -932,8 +926,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
struct device *hwmon; struct device *hwmon;
char name[20]; char name[20];
int ret, cnt;
u32 output_freq; u32 output_freq;
int ret;
u32 i; u32 i;
np = dev->of_node; np = dev->of_node;
@ -985,9 +979,6 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
output_freq = npcm7xx_pwm_init(data); output_freq = npcm7xx_pwm_init(data);
npcm7xx_fan_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++) { for (i = 0; i < NPCM7XX_FAN_MAX_MODULE; i++) {
spin_lock_init(&data->fan_lock[i]); spin_lock_init(&data->fan_lock[i]);

View File

@ -24,6 +24,7 @@ enum ntc_thermistor_type {
TYPE_NCPXXWF104, TYPE_NCPXXWF104,
TYPE_NCPXXWL333, TYPE_NCPXXWL333,
TYPE_NCPXXXH103, TYPE_NCPXXXH103,
TYPE_NCPXXWM474,
}; };
struct ntc_compensation { struct ntc_compensation {
@ -46,6 +47,7 @@ enum {
NTC_NCP18WB473, NTC_NCP18WB473,
NTC_NCP21WB473, NTC_NCP21WB473,
NTC_SSG1404001221, NTC_SSG1404001221,
NTC_NCP18WM474,
NTC_LAST, NTC_LAST,
}; };
@ -60,6 +62,7 @@ static const struct platform_device_id ntc_thermistor_id[] = {
[NTC_NCP18WB473] = { "ncp18wb473", TYPE_NCPXXWB473 }, [NTC_NCP18WB473] = { "ncp18wb473", TYPE_NCPXXWB473 },
[NTC_NCP21WB473] = { "ncp21wb473", TYPE_NCPXXWB473 }, [NTC_NCP21WB473] = { "ncp21wb473", TYPE_NCPXXWB473 },
[NTC_SSG1404001221] = { "ssg1404_001221", TYPE_NCPXXWB473 }, [NTC_SSG1404001221] = { "ssg1404_001221", TYPE_NCPXXWB473 },
[NTC_NCP18WM474] = { "ncp18wm474", TYPE_NCPXXWM474 },
[NTC_LAST] = { }, [NTC_LAST] = { },
}; };
MODULE_DEVICE_TABLE(platform, ntc_thermistor_id); MODULE_DEVICE_TABLE(platform, ntc_thermistor_id);
@ -217,6 +220,43 @@ static const struct ntc_compensation ncpXXxh103[] = {
{ .temp_c = 125, .ohm = 531 }, { .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 * The following compensation tables are from the specifications in EPCOS NTC
* Thermistors Datasheets * Thermistors Datasheets
@ -319,6 +359,7 @@ static const struct ntc_type ntc_type[] = {
NTC_TYPE(TYPE_NCPXXWF104, ncpXXwf104), NTC_TYPE(TYPE_NCPXXWF104, ncpXXwf104),
NTC_TYPE(TYPE_NCPXXWL333, ncpXXwl333), NTC_TYPE(TYPE_NCPXXWL333, ncpXXwl333),
NTC_TYPE(TYPE_NCPXXXH103, ncpXXxh103), 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] }, .data = &ntc_thermistor_id[NTC_NCP21WB473] },
{ .compatible = "samsung,1404-001221", { .compatible = "samsung,1404-001221",
.data = &ntc_thermistor_id[NTC_SSG1404001221] }, .data = &ntc_thermistor_id[NTC_SSG1404001221] },
{ .compatible = "murata,ncp18wm474",
.data = &ntc_thermistor_id[NTC_NCP18WM474] },
/* Usage of vendor name "ntc" is deprecated */ /* Usage of vendor name "ntc" is deprecated */
{ .compatible = "ntc,ncp03wb473", { .compatible = "ntc,ncp03wb473",

Some files were not shown because too many files have changed in this diff Show More