mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 19:43:40 +02:00
hwmon updates for v6.3
- New drivers
* Infineon TDA38640 Voltage Regulator
* NXP MC34VR500 PMIC
* GXP fan controller
* MPQ7932 Power Management IC
- New chip or board support added to existing drivers
* it87: IT87952E; also other cleanup/improvements
* intel-m10-bmc-hwmon: N6000
* pmbus/max16601: MAX16600
* aquacomputer_d5next: Aquacomputer Aquastream Ultimate, Aquacomputer Poweradjust 3,
Aquacomputer Aquaero
* nct6775: Support for B650/B660/X670 ASUS boards
* oxp-sensors: AYANEO AIR and AIR Pro
- Other notable changes
* Various kernel documentation fixes
* Various devicetree bindings fixes
* Explicitly deprecated [devm_]hwmon_device_register_with_groups
* ftsteutates: Support for fanX_fault and other cleanup
* ltc2945: Support for setting shunt resistor and other cleanup/fixes
* coretemp: Avoid RDMSR interrupts to isolated CPUs,
and simplify platform device handling
- Vaious other minoc cleanups and fixes
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmP09dcACgkQyx8mb86f
mYGXqxAArB9RNWemn18582Fg49ME9wkRDT+ZFPMKDSupjOgW+EXZZi86FPfIzl/c
PO9g4E/I3PZBgJddc16F2JPmg10JZlExQ+iOwCWQrviAEoBdxjBGoXWC5JhcnU6O
VCsn2nCsBwBcbBk2wqVuksvsRQIvRX/BeiTE0xw6yIQgGqEava7au2Av3W0NEX0+
ItPNQ9vqzp4ikufeY6Y2FoGM0PfVWSIulqDZoDhhqTdSDI4VnAcOdiies9Z4oaG2
pN+AwO+iNqQcbUiZyhUJz39j6+ywkhSxZJOsprsG6KA0shFwaR0N/3vCqZAxo8so
KaKJCGM6mkUqOBfmAeX6/kj1DuSvkR6+WixABbmk15AJIIoFHCeG9kTEHwTj7Ovk
vZ3rpZFCpTtCtlTCbMFFe/EW7ssbkucOJVtpaqWBtC7X/+rZO2LGMXQSA9tJW9N1
qGKbbxlwsxnVc1rIb7FM5QdoxMhbv+h4N7fJ/M6WDHg35xiEfugI9R9KvMv0P5+A
Z4CvIjeeUm8XjET1+3pKhpScXdVGdueuRO2SZ/NSAb7x4zdB/GPX4NELASWHvxXl
rFrfe7tvEtkIDAONeqYrA9wBCaH0YfqJHyTBz9UqQegp+3nA7mA+4PxVpAA6ntUq
0CuzS4NGxFVX7bPy3ONCQ+kViCQ76nXG2F4/TLL8lmwRZqkaTOM=
=yXoY
-----END PGP SIGNATURE-----
Merge tag 'hwmon-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
"New drivers:
- Infineon TDA38640 Voltage Regulator
- NXP MC34VR500 PMIC
- GXP fan controller
- MPQ7932 Power Management IC
New chip or board support added to existing drivers:
- it87: IT87952E; also other cleanup/improvements
- intel-m10-bmc-hwmon: N6000
- pmbus/max16601: MAX16600
- aquacomputer_d5next: Aquacomputer Aquastream Ultimate, Aquacomputer
Poweradjust 3, Aquacomputer Aquaero
- nct6775: Support for B650/B660/X670 ASUS boards
- oxp-sensors: AYANEO AIR and AIR Pro
Other notable changes:
- Various kernel documentation fixes
- Various devicetree bindings fixes
- Explicitly deprecated [devm_]hwmon_device_register_with_groups
- ftsteutates: Support for fanX_fault and other cleanup
- ltc2945: Support for setting shunt resistor and other cleanup/fixes
- coretemp: Avoid RDMSR interrupts to isolated CPUs, and simplify
platform device handling
... and various other minor cleanups and fixes"
* tag 'hwmon-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (66 commits)
hwmon: Deprecate [devm_]hwmon_device_register_with_groups
hwmon: (mlxreg-fan) Return zero speed for broken fan
hwmon: (gxp-fan-ctrl) use devm_platform_get_and_ioremap_resource()
hwmon: (aquacomputer_d5next) Add support for Aquacomputer Aquastream Ultimate
hwmon: (aquacomputer_d5next) Add support for Aquacomputer Poweradjust 3
hwmon: (iio_hwmon) use dev_err_probe
hwmon: intel-m10-bmc-hwmon: Add N6000 sensors
Docs/hwmon/index: Add missing SPDX License Identifier
hwmon: (it87) Updated documentation for recent updates to it87
hwmon: (it87) Add new chipset IT87952E
hwmon: (it87) Allow multiple chip IDs for force_id
hwmon: (it87) Add chip_id in some info message
hwmon: (it87) List full chip model name
hwmon: (it87) Disable configuration exit for certain chips
hwmon: (it87) Allow disabling exiting of configuration mode
Documentation: hwmon: correct spelling
hwmon: (pmbus/max16601) Add support for MAX16600
hwmon: (ltc2945) Allow setting shunt resistor
hwmon: (ltc2945) Handle error case in ltc2945_value_store
hwmon: (ltc2945) Add devicetree match table
...
This commit is contained in:
commit
241ed6ab74
|
|
@ -276,6 +276,15 @@ Description:
|
|||
|
||||
RW
|
||||
|
||||
What: /sys/class/hwmon/hwmonX/fanY_fault
|
||||
Description:
|
||||
Reports if a fan has reported failure.
|
||||
|
||||
- 1: Failed
|
||||
- 0: Ok
|
||||
|
||||
RO
|
||||
|
||||
What: /sys/class/hwmon/hwmonX/pwmY
|
||||
Description:
|
||||
Pulse width modulation fan control.
|
||||
|
|
|
|||
|
|
@ -52,16 +52,16 @@ examples:
|
|||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c0 {
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pwmon@5a {
|
||||
compatible = "adi,adm1177";
|
||||
reg = <0x5a>;
|
||||
shunt-resistor-micro-ohms = <50000>; /* 50 mOhm */
|
||||
adi,shutdown-threshold-microamp = <1059000>; /* 1.059 A */
|
||||
adi,vrange-high-enable;
|
||||
compatible = "adi,adm1177";
|
||||
reg = <0x5a>;
|
||||
shunt-resistor-micro-ohms = <50000>; /* 50 mOhm */
|
||||
adi,shutdown-threshold-microamp = <1059000>; /* 1.059 A */
|
||||
adi,vrange-high-enable;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
adm1266@40 {
|
||||
compatible = "adi,adm1266";
|
||||
reg = <0x40>;
|
||||
compatible = "adi,adm1266";
|
||||
reg = <0x40>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -49,15 +49,15 @@ additionalProperties: false
|
|||
examples:
|
||||
- |
|
||||
fpga_axi: fpga-axi {
|
||||
#address-cells = <0x2>;
|
||||
#size-cells = <0x1>;
|
||||
#address-cells = <0x2>;
|
||||
#size-cells = <0x1>;
|
||||
|
||||
axi_fan_control: axi-fan-control@80000000 {
|
||||
compatible = "adi,axi-fan-control-1.00.a";
|
||||
reg = <0x0 0x80000000 0x10000>;
|
||||
clocks = <&clk 71>;
|
||||
interrupts = <0 110 0>;
|
||||
pulses-per-revolution = <2>;
|
||||
};
|
||||
axi_fan_control: axi-fan-control@80000000 {
|
||||
compatible = "adi,axi-fan-control-1.00.a";
|
||||
reg = <0x0 0x80000000 0x10000>;
|
||||
clocks = <&clk 71>;
|
||||
interrupts = <0 110 0>;
|
||||
pulses-per-revolution = <2>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
49
Documentation/devicetree/bindings/hwmon/adi,ltc2945.yaml
Normal file
49
Documentation/devicetree/bindings/hwmon/adi,ltc2945.yaml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/adi,ltc2945.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices LTC2945 wide range i2c power monitor
|
||||
|
||||
maintainers:
|
||||
- Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
description: |
|
||||
Analog Devices LTC2945 wide range i2c power monitor over I2C.
|
||||
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/LTC2945.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- adi,ltc2945
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
description:
|
||||
Shunt resistor value in micro-Ohms
|
||||
default: 1000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
power-monitor@6e {
|
||||
compatible = "adi,ltc2945";
|
||||
reg = <0x6e>;
|
||||
/* 10 milli-Ohm shunt resistor */
|
||||
shunt-resistor-micro-ohms = <10000>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -87,15 +87,15 @@ additionalProperties: false
|
|||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ltc2947_spi: ltc2947@0 {
|
||||
compatible = "adi,ltc2947";
|
||||
reg = <0>;
|
||||
/* accumulation takes place always for energ1/charge1. */
|
||||
/* accumulation only on positive current for energy2/charge2. */
|
||||
adi,accumulator-ctl-pol = <0 1>;
|
||||
};
|
||||
ltc2947_spi: ltc2947@0 {
|
||||
compatible = "adi,ltc2947";
|
||||
reg = <0>;
|
||||
/* accumulation takes place always for energ1/charge1. */
|
||||
/* accumulation only on positive current for energy2/charge2. */
|
||||
adi,accumulator-ctl-pol = <0 1>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -55,26 +55,26 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
i2c1 {
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ltc2992@6F {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
ltc2992@6f {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
compatible = "adi,ltc2992";
|
||||
reg = <0x6F>;
|
||||
compatible = "adi,ltc2992";
|
||||
reg = <0x6f>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0x0>;
|
||||
shunt-resistor-micro-ohms = <10000>;
|
||||
};
|
||||
channel@0 {
|
||||
reg = <0x0>;
|
||||
shunt-resistor-micro-ohms = <10000>;
|
||||
};
|
||||
|
||||
channel@1 {
|
||||
reg = <0x1>;
|
||||
shunt-resistor-micro-ohms = <10000>;
|
||||
};
|
||||
channel@1 {
|
||||
reg = <0x1>;
|
||||
shunt-resistor-micro-ohms = <10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -41,13 +41,13 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sbrmi@3c {
|
||||
compatible = "amd,sbrmi";
|
||||
reg = <0x3c>;
|
||||
compatible = "amd,sbrmi";
|
||||
reg = <0x3c>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
i2c0 {
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sbtsi@4c {
|
||||
compatible = "amd,sbtsi";
|
||||
reg = <0x4c>;
|
||||
compatible = "amd,sbtsi";
|
||||
reg = <0x4c>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/hpe,gxp-fan-ctrl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: HPE GXP Fan Controller
|
||||
|
||||
maintainers:
|
||||
- Nick Hawkins <nick.hawkins@hpe.com>
|
||||
|
||||
description: |
|
||||
The HPE GXP fan controller controls the fans through an external CPLD
|
||||
device that connects to the fans.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: hpe,gxp-fan-ctrl
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Fan controller PWM
|
||||
- description: Programmable logic
|
||||
- description: Function 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: base
|
||||
- const: pl
|
||||
- const: fn2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
fan-controller@1000c00 {
|
||||
compatible = "hpe,gxp-fan-ctrl";
|
||||
reg = <0x1000c00 0x200>, <0xd1000000 0xff>, <0x80200000 0x100000>;
|
||||
reg-names = "base", "pl", "fn2";
|
||||
};
|
||||
|
|
@ -31,7 +31,7 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
iio-hwmon {
|
||||
compatible = "iio-hwmon";
|
||||
io-channels = <&adc 1>, <&adc 2>;
|
||||
};
|
||||
iio-hwmon {
|
||||
compatible = "iio-hwmon";
|
||||
io-channels = <&adc 1>, <&adc 2>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -198,30 +198,30 @@ examples:
|
|||
};
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
sensor@4c {
|
||||
compatible = "adi,adt7481";
|
||||
reg = <0x4c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0x0>;
|
||||
label = "local";
|
||||
};
|
||||
sensor@4c {
|
||||
compatible = "adi,adt7481";
|
||||
reg = <0x4c>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@1 {
|
||||
reg = <0x1>;
|
||||
label = "front";
|
||||
temperature-offset-millicelsius = <4000>;
|
||||
};
|
||||
channel@0 {
|
||||
reg = <0x0>;
|
||||
label = "local";
|
||||
};
|
||||
|
||||
channel@2 {
|
||||
reg = <0x2>;
|
||||
label = "back";
|
||||
temperature-offset-millicelsius = <750>;
|
||||
channel@1 {
|
||||
reg = <0x1>;
|
||||
label = "front";
|
||||
temperature-offset-millicelsius = <4000>;
|
||||
};
|
||||
|
||||
channel@2 {
|
||||
reg = <0x2>;
|
||||
label = "back";
|
||||
temperature-offset-millicelsius = <750>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ additionalProperties: false
|
|||
|
||||
examples:
|
||||
- |
|
||||
thermistor0 {
|
||||
thermistor {
|
||||
compatible = "murata,ncp18wb473";
|
||||
io-channels = <&gpadc 0x06>;
|
||||
pullup-uv = <1800000>;
|
||||
|
|
|
|||
|
|
@ -123,23 +123,23 @@ examples:
|
|||
#size-cells = <0>;
|
||||
|
||||
channel@0 { /* LTD */
|
||||
reg = <0>;
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
channel@1 { /* RTD1 */
|
||||
reg = <1>;
|
||||
sensor-type = "voltage";
|
||||
reg = <1>;
|
||||
sensor-type = "voltage";
|
||||
};
|
||||
|
||||
channel@2 { /* RTD2 */
|
||||
reg = <2>;
|
||||
sensor-type = "temperature";
|
||||
temperature-mode = "thermal-diode";
|
||||
reg = <2>;
|
||||
sensor-type = "temperature";
|
||||
temperature-mode = "thermal-diode";
|
||||
};
|
||||
|
||||
channel@3 { /* RTD3 */
|
||||
reg = <3>;
|
||||
sensor-type = "temperature";
|
||||
reg = <3>;
|
||||
sensor-type = "temperature";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
36
Documentation/devicetree/bindings/hwmon/nxp,mc34vr500.yaml
Normal file
36
Documentation/devicetree/bindings/hwmon/nxp,mc34vr500.yaml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/nxp,mc34vr500.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP MC34VR500 hwmon sensor
|
||||
|
||||
maintainers:
|
||||
- Mario Kicherer <dev@kicherer.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- nxp,mc34vr500
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pmic@8 {
|
||||
compatible = "nxp,mc34vr500";
|
||||
reg = <0x08>;
|
||||
};
|
||||
};
|
||||
|
|
@ -77,15 +77,15 @@ additionalProperties: false
|
|||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tmp513@5c {
|
||||
compatible = "ti,tmp513";
|
||||
reg = <0x5C>;
|
||||
shunt-resistor-micro-ohms = <330000>;
|
||||
ti,bus-range-microvolt = <32000000>;
|
||||
ti,pga-gain = <8>;
|
||||
ti,nfactor = <0x1 0xF3 0x00>;
|
||||
};
|
||||
tmp513@5c {
|
||||
compatible = "ti,tmp513";
|
||||
reg = <0x5c>;
|
||||
shunt-resistor-micro-ohms = <330000>;
|
||||
ti,bus-range-microvolt = <32000000>;
|
||||
ti,pga-gain = <8>;
|
||||
ti,nfactor = <0x1 0xf3 0x00>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ additionalProperties: false
|
|||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tps23861@30 {
|
||||
compatible = "ti,tps23861";
|
||||
reg = <0x30>;
|
||||
shunt-resistor-micro-ohms = <255000>;
|
||||
};
|
||||
tps23861@30 {
|
||||
compatible = "ti,tps23861";
|
||||
reg = <0x30>;
|
||||
shunt-resistor-micro-ohms = <255000>;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ properties:
|
|||
- infineon,slb9645tt
|
||||
# Infineon SLB9673 I2C TPM 2.0
|
||||
- infineon,slb9673
|
||||
# Infineon TDA38640 Voltage Regulator
|
||||
- infineon,tda38640
|
||||
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
|
||||
- infineon,tlv493d-a1b6
|
||||
# Infineon Multi-phase Digital VR Controller xdpe11280
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ Sysfs entries
|
|||
-------------
|
||||
|
||||
=============== ============================================
|
||||
temp1_input Measured temperature in millidegrees Celcius
|
||||
temp1_input Measured temperature in millidegrees Celsius
|
||||
humidity1_input Measured humidity in %H
|
||||
update_interval The minimum interval for polling the sensor,
|
||||
in milliseconds. Writable. Must be at
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ Kernel driver aquacomputer-d5next
|
|||
|
||||
Supported devices:
|
||||
|
||||
* Aquacomputer Aquaero 5/6 fan controllers
|
||||
* Aquacomputer D5 Next watercooling pump
|
||||
* Aquacomputer Farbwerk RGB controller
|
||||
* Aquacomputer Farbwerk 360 RGB controller
|
||||
* Aquacomputer Octo fan controller
|
||||
* Aquacomputer Quadro fan controller
|
||||
* Aquacomputer High Flow Next sensor
|
||||
* Aquacomputer Aquastream Ultimate watercooling pump
|
||||
* Aquacomputer Poweradjust 3 fan controller
|
||||
|
||||
Author: Aleksa Savic
|
||||
|
||||
|
|
@ -20,6 +23,10 @@ Description
|
|||
This driver exposes hardware sensors of listed Aquacomputer devices, which
|
||||
communicate through proprietary USB HID protocols.
|
||||
|
||||
The Aquaero devices expose eight physical, eight virtual and four calculated
|
||||
virtual temperature sensors, as well as two flow sensors. The fans expose their
|
||||
speed (in RPM), power, voltage and current.
|
||||
|
||||
For the D5 Next pump, available sensors are pump and fan speed, power, voltage
|
||||
and current, as well as coolant temperature and eight virtual temp sensors. Also
|
||||
available through debugfs are the serial number, firmware version and power-on
|
||||
|
|
@ -48,6 +55,12 @@ The High Flow Next exposes +5V voltages, water quality, conductivity and flow re
|
|||
A temperature sensor can be connected to it, in which case it provides its reading
|
||||
and an estimation of the dissipated/absorbed power in the liquid cooling loop.
|
||||
|
||||
The Aquastream Ultimate pump exposes coolant temp and an external temp sensor, along
|
||||
with speed, power, voltage and current of both the pump and optionally connected fan.
|
||||
It also exposes pressure and flow speed readings.
|
||||
|
||||
The Poweradjust 3 controller exposes a single external temperature sensor.
|
||||
|
||||
Depending on the device, not all sysfs and debugfs entries will be available.
|
||||
Writing to virtual temperature sensors is not currently supported.
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Authors:
|
|||
Description:
|
||||
------------
|
||||
This driver implements support for ASPEED AST2400/2500 PWM and Fan Tacho
|
||||
controller. The PWM controller supports upto 8 PWM outputs. The Fan tacho
|
||||
controller. The PWM controller supports up to 8 PWM outputs. The Fan tacho
|
||||
controller supports up to 16 tachometer inputs.
|
||||
|
||||
The driver provides the following sensor accesses in sysfs:
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ Supported boards:
|
|||
* ROG STRIX X570-I GAMING
|
||||
* ROG STRIX Z690-A GAMING WIFI D4
|
||||
* ROG ZENITH II EXTREME
|
||||
* ROG ZENITH II EXTREME ALPHA
|
||||
|
||||
Authors:
|
||||
- Eugene Shalygin <eugene.shalygin@gmail.com>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ This driver implements the sysfs interface for the Corsair PSUs with a HID proto
|
|||
interface of the HXi and RMi series.
|
||||
These power supplies provide access to a micro-controller with 2 attached
|
||||
temperature sensors, 1 fan rpm sensor, 4 sensors for volt levels, 4 sensors for
|
||||
power usage and 4 sensors for current levels and addtional non-sensor information
|
||||
power usage and 4 sensors for current levels and additional non-sensor information
|
||||
like uptimes.
|
||||
|
||||
Sysfs entries
|
||||
|
|
|
|||
|
|
@ -22,6 +22,15 @@ enhancements. It can monitor up to 4 voltages, 16 temperatures and
|
|||
8 fans. It also contains an integrated watchdog which is currently
|
||||
implemented in this driver.
|
||||
|
||||
The ``pwmX_auto_channels_temp`` attributes show which temperature sensor
|
||||
is currently driving which fan channel. This value might dynamically change
|
||||
during runtime depending on the temperature sensor selected by
|
||||
the fan control circuit.
|
||||
|
||||
The 4 voltages require a board-specific multiplier, since the BMC can
|
||||
only measure voltages up to 3.3V and thus relies on voltage dividers.
|
||||
Consult your motherboard manual for details.
|
||||
|
||||
To clear a temperature or fan alarm, execute the following command with the
|
||||
correct path to the alarm file::
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Temperature Monitoring
|
|||
|
||||
Temperatures are measured with 12-bit or 10-bit resolution and are scaled
|
||||
either internally or by the driver depending on the GSC version and firmware.
|
||||
The values returned by the driver reflect millidegree Celcius:
|
||||
The values returned by the driver reflect millidegree Celsius:
|
||||
|
||||
tempX_input Measured temperature.
|
||||
tempX_label Name of temperature input.
|
||||
|
|
@ -41,8 +41,8 @@ PWM Output Control
|
|||
------------------
|
||||
|
||||
The GSC features 1 PWM output that operates in automatic mode where the
|
||||
PWM value will be scalled depending on 6 temperature boundaries.
|
||||
The tempeature boundaries are read-write and in millidegree Celcius and the
|
||||
PWM value will be scaled depending on 6 temperature boundaries.
|
||||
The tempeature boundaries are read-write and in millidegree Celsius and the
|
||||
read-only PWM values range from 0 (off) to 255 (full speed).
|
||||
Fan speed will be set to minimum (off) when the temperature sensor reads
|
||||
less than pwm1_auto_point1_temp and maximum when the temperature sensor
|
||||
|
|
|
|||
28
Documentation/hwmon/gxp-fan-ctrl.rst
Normal file
28
Documentation/hwmon/gxp-fan-ctrl.rst
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
Kernel driver gxp-fan-ctrl
|
||||
==========================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* HPE GXP SOC
|
||||
|
||||
Author: Nick Hawkins <nick.hawkins@hpe.com>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
gxp-fan-ctrl is a driver which provides fan control for the hpe gxp soc.
|
||||
The driver allows the gathering of fan status and the use of fan
|
||||
PWM control.
|
||||
|
||||
|
||||
Sysfs attributes
|
||||
----------------
|
||||
|
||||
======================= ===========================================================
|
||||
pwm[0-7] Fan 0 to 7 respective PWM value (0-255)
|
||||
fan[0-7]_fault Fan 0 to 7 respective fault status: 1 fail, 0 ok
|
||||
fan[0-7]_enable Fan 0 to 7 respective enabled status: 1 enabled, 0 disabled
|
||||
======================= ===========================================================
|
||||
|
|
@ -57,7 +57,7 @@ register/unregister functions::
|
|||
hwmon_device_register_with_groups registers a hardware monitoring device.
|
||||
The first parameter of this function is a pointer to the parent device.
|
||||
The name parameter is a pointer to the hwmon device name. The registration
|
||||
function wil create a name sysfs attribute pointing to this name.
|
||||
function will create a name sysfs attribute pointing to this name.
|
||||
The drvdata parameter is the pointer to the local driver data.
|
||||
hwmon_device_register_with_groups will attach this pointer to the newly
|
||||
allocated hwmon device. The pointer can be retrieved by the driver using
|
||||
|
|
@ -299,7 +299,7 @@ Parameters:
|
|||
|
||||
Return value:
|
||||
The file mode for this attribute. Typically, this will be 0 (the
|
||||
attribute will not be created), S_IRUGO, or 'S_IRUGO | S_IWUSR'.
|
||||
attribute will not be created), 0444, or 0644.
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -360,7 +360,7 @@ functions is used.
|
|||
The header file linux/hwmon-sysfs.h provides a number of useful macros to
|
||||
declare and use hardware monitoring sysfs attributes.
|
||||
|
||||
In many cases, you can use the exsting define DEVICE_ATTR or its variants
|
||||
In many cases, you can use the existing define DEVICE_ATTR or its variants
|
||||
DEVICE_ATTR_{RW,RO,WO} to declare such attributes. This is feasible if an
|
||||
attribute has no additional context. However, in many cases there will be
|
||||
additional information such as a sensor index which will need to be passed
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================
|
||||
Linux Hardware Monitoring
|
||||
=========================
|
||||
|
|
@ -73,6 +75,7 @@ Hardware Monitoring Kernel Drivers
|
|||
g762
|
||||
gsc-hwmon
|
||||
gl518sm
|
||||
gxp-fan-ctrl
|
||||
hih6130
|
||||
ibmaem
|
||||
ibm-cffps
|
||||
|
|
@ -144,6 +147,7 @@ Hardware Monitoring Kernel Drivers
|
|||
max6697
|
||||
max8688
|
||||
mc13783-adc
|
||||
mc34vr500
|
||||
mcp3021
|
||||
menf21bmc
|
||||
mlxreg-fan
|
||||
|
|
|
|||
|
|
@ -145,6 +145,22 @@ Supported chips:
|
|||
|
||||
Datasheet: Not publicly available
|
||||
|
||||
* IT8792E/IT8795E
|
||||
|
||||
Prefix: 'it8792'
|
||||
|
||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||
|
||||
Datasheet: Not publicly available
|
||||
|
||||
* IT87952E
|
||||
|
||||
Prefix: 'it87952'
|
||||
|
||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||
|
||||
Datasheet: Not publicly available
|
||||
|
||||
* SiS950 [clone of IT8705F]
|
||||
|
||||
Prefix: 'it87'
|
||||
|
|
@ -162,7 +178,7 @@ Authors:
|
|||
Module Parameters
|
||||
-----------------
|
||||
|
||||
* update_vbat: int
|
||||
* update_vbat bool
|
||||
0 if vbat should report power on value, 1 if vbat should be updated after
|
||||
each read. Default is 0. On some boards the battery voltage is provided
|
||||
by either the battery or the onboard power supply. Only the first reading
|
||||
|
|
@ -171,11 +187,31 @@ Module Parameters
|
|||
the chip so can be read at any time. Excessive reading may decrease
|
||||
battery life but no information is given in the datasheet.
|
||||
|
||||
* fix_pwm_polarity int
|
||||
* fix_pwm_polarity bool
|
||||
Force PWM polarity to active high (DANGEROUS). Some chips are
|
||||
misconfigured by BIOS - PWM values would be inverted. This option tries
|
||||
to fix this. Please contact your BIOS manufacturer and ask him for fix.
|
||||
|
||||
* force_id short, short
|
||||
|
||||
Force multiple chip ID to specified value, separated by ','.
|
||||
For example "force_id=0x8689,0x8633". A value of 0 is ignored
|
||||
for that chip.
|
||||
Note: A single force_id value (e.g. "force_id=0x8689") is used for
|
||||
all chips, to only set the first chip use "force_id=0x8689,0".
|
||||
Should only be used for testing.
|
||||
|
||||
* ignore_resource_conflict bool
|
||||
|
||||
Similar to acpi_enforce_resources=lax, but only affects this driver.
|
||||
ACPI resource conflicts are ignored if this parameter is provided and
|
||||
set to 1.
|
||||
Provided since there are reports that system-wide acpi_enfore_resources=lax
|
||||
can result in boot failures on some systems.
|
||||
Note: This is inherently risky since it means that both ACPI and this driver
|
||||
may access the chip at the same time. This can result in race conditions and,
|
||||
worst case, result in unexpected system reboots.
|
||||
|
||||
|
||||
Hardware Interfaces
|
||||
-------------------
|
||||
|
|
@ -193,8 +229,8 @@ Description
|
|||
|
||||
This driver implements support for the IT8603E, IT8620E, IT8623E, IT8628E,
|
||||
IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F,
|
||||
IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and
|
||||
SiS950 chips.
|
||||
IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E,
|
||||
IT8792E/IT8795E, IT87952E and SiS950 chips.
|
||||
|
||||
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
|
||||
joysticks and other miscellaneous stuff. For hardware monitoring, they
|
||||
|
|
@ -238,7 +274,8 @@ of the fan is not supported (value 0 of pwmX_enable).
|
|||
The IT8620E and IT8628E are custom designs, hardware monitoring part is similar
|
||||
to IT8728F. It only supports 16-bit fan mode. Both chips support up to 6 fans.
|
||||
|
||||
The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled.
|
||||
The IT8790E, IT8792E/IT8795E and IT87952E support up to 3 fans. 16-bit fan
|
||||
mode is always enabled.
|
||||
|
||||
The IT8732F supports a closed-loop mode for fan control, but this is not
|
||||
currently implemented by the driver.
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ temp[N]_input Measured temperature.
|
|||
- On LTC3883, temp1 reports an external temperature,
|
||||
and temp2 reports the chip temperature.
|
||||
|
||||
temp[N]_min Mimimum temperature.
|
||||
temp[N]_min Minimum temperature.
|
||||
|
||||
LTC2972, LTC2974, LCT2977, LTM2980, LTC2978,
|
||||
LTC2979, and LTM2987 only.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,14 @@ Supported chips:
|
|||
|
||||
Datasheet: Not published
|
||||
|
||||
* Maxim MAX16600
|
||||
|
||||
Prefix: 'max16600'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: Not published
|
||||
|
||||
* Maxim MAX16601
|
||||
|
||||
Prefix: 'max16601'
|
||||
|
|
@ -36,7 +44,8 @@ Description
|
|||
-----------
|
||||
|
||||
This driver supports the MAX16508 VR13 Dual-Output Voltage Regulator
|
||||
as well as the MAX16601 VR13.HC Dual-Output Voltage Regulator chipsets.
|
||||
as well as the MAX16600, MAX16601, and MAX16602 VR13.HC Dual-Output
|
||||
Voltage Regulator chipsets.
|
||||
|
||||
The driver is a client driver to the core PMBus driver.
|
||||
Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ Description
|
|||
This driver implements support for several MAX6697 compatible temperature sensor
|
||||
chips. The chips support one local temperature sensor plus four, six, or seven
|
||||
remote temperature sensors. Remote temperature sensors are diode-connected
|
||||
thermal transitors, except for MAX6698 which supports three diode-connected
|
||||
thermal transistors, except for MAX6698 which supports three diode-connected
|
||||
thermal transistors plus three thermistors in addition to the local temperature
|
||||
sensor.
|
||||
|
||||
|
|
|
|||
32
Documentation/hwmon/mc34vr500.rst
Normal file
32
Documentation/hwmon/mc34vr500.rst
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
Kernel driver mc34vr500
|
||||
=======================
|
||||
|
||||
Supported Chips:
|
||||
|
||||
* NXP MC34VR500
|
||||
|
||||
Prefix: 'mc34vr500'
|
||||
|
||||
Datasheet: https://www.nxp.com/docs/en/data-sheet/MC34VR500.pdf
|
||||
|
||||
Author: Mario Kicherer <dev@kicherer.org>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements initial support for the NXP MC34VR500 PMIC. The MC34VR500
|
||||
monitors the temperature, input voltage and output currents and provides
|
||||
corresponding alarms. For the temperature, the chip can send interrupts if
|
||||
the temperature rises above one of the following values: 110°, 120°, 125° and
|
||||
130° Celsius. For the input voltage, an interrupt is sent when the voltage
|
||||
drops below 2.8V.
|
||||
|
||||
Currently, this driver only implements the input voltage and temperature
|
||||
alarms. The interrupts are mapped as follows:
|
||||
|
||||
<= 2.8V -> in0_min_alarm
|
||||
>110°c -> temp1_max_alarm
|
||||
>120°c -> temp1_crit_alarm
|
||||
>130°c -> temp1_emergency_alarm
|
||||
|
|
@ -7,7 +7,7 @@ Supported chips:
|
|||
|
||||
Prefix: 'menf21bmc_hwmon'
|
||||
|
||||
Adresses scanned: -
|
||||
Addresses scanned: -
|
||||
|
||||
Author: Andreas Werner <andreas.werner@men.de>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,18 +3,21 @@
|
|||
Kernel driver oxp-sensors
|
||||
=========================
|
||||
|
||||
Author:
|
||||
Authors:
|
||||
- Derek John Clark <derekjohn.clark@gmail.com>
|
||||
- Joaquín Ignacio Aramendía <samsagax@gmail.com>
|
||||
|
||||
Description:
|
||||
------------
|
||||
|
||||
One X Player devices from One Netbook provide fan readings and fan control
|
||||
through its Embedded Controller.
|
||||
Handheld devices from One Netbook and Aya Neo provide fan readings and fan
|
||||
control through their embedded controllers.
|
||||
|
||||
Currently only supports AMD boards from the One X Player and AOK ZOE lineup.
|
||||
Intel boards could be supported if we could figure out the EC registers and
|
||||
values to write to since the EC layout and model is different.
|
||||
Currently only supports AMD boards from One X Player, AOK ZOE, and some Aya
|
||||
Neo devices. One X Player Intel boards could be supported if we could figure
|
||||
out the EC registers and values to write to since the EC layout and model is
|
||||
different. Aya Neo devices preceding the AIR may not be supportable as the EC
|
||||
model is different and do not appear to have manual control capabilities.
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
|
|
@ -22,6 +25,8 @@ Supported devices
|
|||
Currently the driver supports the following handhelds:
|
||||
|
||||
- AOK ZOE A1
|
||||
- Aya Neo AIR
|
||||
- Aya Neo AIR Pro
|
||||
- OneXPlayer AMD
|
||||
- OneXPlayer mini AMD
|
||||
- OneXPlayer mini AMD PRO
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ Read byte from page <page>, register <reg>.
|
|||
int (*read_word_data)(struct i2c_client *client, int page, int phase,
|
||||
int reg);
|
||||
|
||||
Read word from page <page>, phase <pase>, register <reg>. If the chip does not
|
||||
Read word from page <page>, phase <phase>, register <reg>. If the chip does not
|
||||
support multiple phases, the phase parameter can be ignored. If the chip
|
||||
supports multiple phases, a phase value of 0xff indicates all phases.
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ Sysfs entries
|
|||
-------------
|
||||
|
||||
=============== ============================================
|
||||
temp1_input Measured temperature in millidegrees Celcius
|
||||
temp1_input Measured temperature in millidegrees Celsius
|
||||
humidity1_input Measured humidity in %H
|
||||
update_interval The minimum interval for polling the sensor,
|
||||
in milliseconds. Writable. Must be at least
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ in9_crit_alarm AIN1 critical alarm
|
|||
in10_crit_alarm AIN2 critical alarm
|
||||
|
||||
temp1_input Chip temperature
|
||||
temp1_min Mimimum chip temperature
|
||||
temp1_min Minimum chip temperature
|
||||
temp1_max Maximum chip temperature
|
||||
temp1_crit Critical chip temperature
|
||||
temp1_crit_alarm Temperature critical alarm
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ output voltage as a positive or negative offset in the interval 50mV to 400mV
|
|||
in 50mV steps. This means that the absolute values of the limits will change
|
||||
when the commanded output voltage changes. Also, care should be taken when
|
||||
writing to those limits since in the worst case the commanded output voltage
|
||||
could change at the same time as the limit is written to, wich will lead to
|
||||
could change at the same time as the limit is written to, which will lead to
|
||||
unpredictable results.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ increase the chances of your change being accepted.
|
|||
* Use devm_hwmon_device_register_with_info() or, if your driver needs a remove
|
||||
function, hwmon_device_register_with_info() to register your driver with the
|
||||
hwmon subsystem. Try using devm_add_action() instead of a remove function if
|
||||
possible. Do not use hwmon_device_register().
|
||||
possible. Do not use any of the deprecated registration functions.
|
||||
|
||||
* Your driver should be buildable as module. If not, please be prepared to
|
||||
explain why it has to be built into the kernel.
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ Versatile Express platform (http://www.arm.com/versatileexpress/) is a
|
|||
reference & prototyping system for ARM Ltd. processors. It can be set up
|
||||
from a wide range of boards, each of them containing (apart of the main
|
||||
chip/FPGA) a number of microcontrollers responsible for platform
|
||||
configuration and control. Theses microcontrollers can also monitor the
|
||||
configuration and control. These microcontrollers can also monitor the
|
||||
board and its environment by a number of internal and external sensors,
|
||||
providing information about power lines voltages and currents, board
|
||||
temperature and power usage. Some of them also calculate consumed energy
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ representable value is around 2600 RPM.
|
|||
|
||||
Voltage sensors (also known as IN sensors) report their values in volts.
|
||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||
or maximum limit. Voltages are internally scalled, so each voltage channel
|
||||
or maximum limit. Voltages are internally scaled, so each voltage channel
|
||||
has a different resolution and range.
|
||||
|
||||
If an alarm triggers, it will remain triggered until the hardware register
|
||||
|
|
|
|||
|
|
@ -2234,13 +2234,16 @@ ARM/HPE GXP ARCHITECTURE
|
|||
M: Jean-Marie Verdun <verdun@hpe.com>
|
||||
M: Nick Hawkins <nick.hawkins@hpe.com>
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/gxp-fan-ctrl.rst
|
||||
F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml
|
||||
F: Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml
|
||||
F: Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml
|
||||
F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
|
||||
F: arch/arm/boot/dts/hpe-bmc*
|
||||
F: arch/arm/boot/dts/hpe-gxp*
|
||||
F: arch/arm/mach-hpe/
|
||||
F: drivers/clocksource/timer-gxp.c
|
||||
F: drivers/hwmon/gxp-fan-ctrl.c
|
||||
F: drivers/spi/spi-gxp.c
|
||||
F: drivers/watchdog/gxp-wdt.c
|
||||
|
||||
|
|
@ -14046,6 +14049,7 @@ M: Saravanan Sekar <sravanhome@gmail.com>
|
|||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mfd/mps,mp2629.yaml
|
||||
F: Documentation/devicetree/bindings/regulator/mps,mp*.yaml
|
||||
F: drivers/hwmon/pmbus/mpq7932.c
|
||||
F: drivers/iio/adc/mp2629_adc.c
|
||||
F: drivers/mfd/mp2629.c
|
||||
F: drivers/power/supply/mp2629_charger.c
|
||||
|
|
@ -15481,6 +15485,7 @@ F: drivers/mtd/nand/onenand/
|
|||
F: include/linux/mtd/onenand*.h
|
||||
|
||||
ONEXPLAYER FAN DRIVER
|
||||
M: Derek John Clark <derekjohn.clark@gmail.com>
|
||||
M: Joaquín Ignacio Aramendía <samsagax@gmail.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
|
|
|
|||
|
|
@ -714,6 +714,15 @@ config SENSORS_GPIO_FAN
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called gpio-fan.
|
||||
|
||||
config SENSORS_GXP_FAN_CTRL
|
||||
tristate "HPE GXP fan controller"
|
||||
depends on ARCH_HPE_GXP || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for GXP fan control functionality.
|
||||
|
||||
The GXP controls fan function via the CPLD through the use of PWM
|
||||
registers. This driver reports status and pwm setting of the fans.
|
||||
|
||||
config SENSORS_HIH6130
|
||||
tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor"
|
||||
depends on I2C
|
||||
|
|
@ -1166,6 +1175,13 @@ config SENSORS_MAX31790
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called max31790.
|
||||
|
||||
config SENSORS_MC34VR500
|
||||
tristate "NXP MC34VR500 hardware monitoring driver"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the temperature and input
|
||||
voltage sensors of the NXP MC34VR500.
|
||||
|
||||
config SENSORS_MCP3021
|
||||
tristate "Microchip MCP3021 and compatibles"
|
||||
depends on I2C
|
||||
|
|
@ -1516,7 +1532,7 @@ config SENSORS_NCT6775_CORE
|
|||
config SENSORS_NCT6775
|
||||
tristate "Platform driver for Nuvoton NCT6775F and compatibles"
|
||||
depends on !PPC
|
||||
depends on ACPI_WMI || ACPI_WMI=n
|
||||
depends on ACPI || ACPI=n
|
||||
select HWMON_VID
|
||||
select SENSORS_NCT6775_CORE
|
||||
help
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
|
|||
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
|
||||
obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
|
||||
obj-$(CONFIG_SENSORS_GXP_FAN_CTRL) += gxp-fan-ctrl.o
|
||||
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
|
||||
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
|
||||
obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o
|
||||
|
|
@ -149,6 +150,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
|||
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
|
||||
obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
|
||||
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
|
||||
obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o
|
||||
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
|
||||
obj-$(CONFIG_SENSORS_TC654) += tc654.o
|
||||
obj-$(CONFIG_SENSORS_TPS23861) += tps23861.o
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ struct aht10_data {
|
|||
|
||||
/**
|
||||
* aht10_init() - Initialize an AHT10 chip
|
||||
* @client: the i2c client associated with the AHT10
|
||||
* @data: the data associated with this AHT10 chip
|
||||
* Return: 0 if succesfull, 1 if not
|
||||
*/
|
||||
|
|
@ -124,7 +123,7 @@ static int aht10_polltime_expired(struct aht10_data *data)
|
|||
|
||||
/**
|
||||
* aht10_read_values() - read and parse the raw data from the AHT10
|
||||
* @aht10_data: the struct aht10_data to use for the lock
|
||||
* @data: the struct aht10_data to use for the lock
|
||||
* Return: 0 if succesfull, 1 if not
|
||||
*/
|
||||
static int aht10_read_values(struct aht10_data *data)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
|
||||
* Quadro, High Flow Next)
|
||||
* Quadro, High Flow Next, Aquaero, Aquastream Ultimate)
|
||||
*
|
||||
* Aquacomputer devices send HID reports (with ID 0x01) every second to report
|
||||
* sensor values.
|
||||
* sensor values, except for devices that communicate through the
|
||||
* legacy way (currently, Poweradjust 3).
|
||||
*
|
||||
* Copyright 2021 Aleksa Savic <savicaleksa83@gmail.com>
|
||||
* Copyright 2022 Jack Doan <me@jackdoan.com>
|
||||
|
|
@ -21,14 +22,20 @@
|
|||
#include <asm/unaligned.h>
|
||||
|
||||
#define USB_VENDOR_ID_AQUACOMPUTER 0x0c70
|
||||
#define USB_PRODUCT_ID_AQUAERO 0xf001
|
||||
#define USB_PRODUCT_ID_FARBWERK 0xf00a
|
||||
#define USB_PRODUCT_ID_QUADRO 0xf00d
|
||||
#define USB_PRODUCT_ID_D5NEXT 0xf00e
|
||||
#define USB_PRODUCT_ID_FARBWERK360 0xf010
|
||||
#define USB_PRODUCT_ID_OCTO 0xf011
|
||||
#define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012
|
||||
#define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b
|
||||
#define USB_PRODUCT_ID_POWERADJUST3 0xf0bd
|
||||
|
||||
enum kinds { d5next, farbwerk, farbwerk360, octo, quadro, highflownext };
|
||||
enum kinds {
|
||||
d5next, farbwerk, farbwerk360, octo, quadro,
|
||||
highflownext, aquaero, poweradjust3, aquastreamult
|
||||
};
|
||||
|
||||
static const char *const aqc_device_names[] = {
|
||||
[d5next] = "d5next",
|
||||
|
|
@ -36,16 +43,17 @@ static const char *const aqc_device_names[] = {
|
|||
[farbwerk360] = "farbwerk360",
|
||||
[octo] = "octo",
|
||||
[quadro] = "quadro",
|
||||
[highflownext] = "highflownext"
|
||||
[highflownext] = "highflownext",
|
||||
[aquaero] = "aquaero",
|
||||
[aquastreamult] = "aquastreamultimate",
|
||||
[poweradjust3] = "poweradjust3"
|
||||
};
|
||||
|
||||
#define DRIVER_NAME "aquacomputer_d5next"
|
||||
|
||||
#define STATUS_REPORT_ID 0x01
|
||||
#define STATUS_UPDATE_INTERVAL (2 * HZ) /* In seconds */
|
||||
#define SERIAL_FIRST_PART 3
|
||||
#define SERIAL_SECOND_PART 5
|
||||
#define FIRMWARE_VERSION 13
|
||||
#define SERIAL_PART_OFFSET 2
|
||||
|
||||
#define CTRL_REPORT_ID 0x03
|
||||
|
||||
|
|
@ -59,8 +67,14 @@ static u8 secondary_ctrl_report[] = {
|
|||
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
|
||||
};
|
||||
|
||||
/* Sensor sizes and offsets for all Aquacomputer devices */
|
||||
#define AQC_TEMP_SENSOR_SIZE 0x02
|
||||
/* Report IDs for legacy devices */
|
||||
#define POWERADJUST3_STATUS_REPORT_ID 0x03
|
||||
|
||||
/* Info, sensor sizes and offsets for most Aquacomputer devices */
|
||||
#define AQC_SERIAL_START 0x3
|
||||
#define AQC_FIRMWARE_VERSION 0xD
|
||||
|
||||
#define AQC_SENSOR_SIZE 0x02
|
||||
#define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF
|
||||
#define AQC_FAN_PERCENT_OFFSET 0x00
|
||||
#define AQC_FAN_VOLTAGE_OFFSET 0x02
|
||||
|
|
@ -68,6 +82,26 @@ static u8 secondary_ctrl_report[] = {
|
|||
#define AQC_FAN_POWER_OFFSET 0x06
|
||||
#define AQC_FAN_SPEED_OFFSET 0x08
|
||||
|
||||
/* Specs of the Aquaero fan controllers */
|
||||
#define AQUAERO_SERIAL_START 0x07
|
||||
#define AQUAERO_FIRMWARE_VERSION 0x0B
|
||||
#define AQUAERO_NUM_FANS 4
|
||||
#define AQUAERO_NUM_SENSORS 8
|
||||
#define AQUAERO_NUM_VIRTUAL_SENSORS 8
|
||||
#define AQUAERO_NUM_CALC_VIRTUAL_SENSORS 4
|
||||
#define AQUAERO_NUM_FLOW_SENSORS 2
|
||||
|
||||
/* Sensor report offsets for Aquaero fan controllers */
|
||||
#define AQUAERO_SENSOR_START 0x65
|
||||
#define AQUAERO_VIRTUAL_SENSOR_START 0x85
|
||||
#define AQUAERO_CALC_VIRTUAL_SENSOR_START 0x95
|
||||
#define AQUAERO_FLOW_SENSORS_START 0xF9
|
||||
#define AQUAERO_FAN_VOLTAGE_OFFSET 0x04
|
||||
#define AQUAERO_FAN_CURRENT_OFFSET 0x06
|
||||
#define AQUAERO_FAN_POWER_OFFSET 0x08
|
||||
#define AQUAERO_FAN_SPEED_OFFSET 0x00
|
||||
static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
|
||||
|
||||
/* Specs of the D5 Next pump */
|
||||
#define D5NEXT_NUM_FANS 2
|
||||
#define D5NEXT_NUM_SENSORS 1
|
||||
|
|
@ -82,12 +116,32 @@ static u8 secondary_ctrl_report[] = {
|
|||
#define D5NEXT_5V_VOLTAGE 0x39
|
||||
#define D5NEXT_12V_VOLTAGE 0x37
|
||||
#define D5NEXT_VIRTUAL_SENSORS_START 0x3f
|
||||
static u8 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
|
||||
static u16 d5next_sensor_fan_offsets[] = { D5NEXT_PUMP_OFFSET, D5NEXT_FAN_OFFSET };
|
||||
|
||||
/* Control report offsets for the D5 Next pump */
|
||||
#define D5NEXT_TEMP_CTRL_OFFSET 0x2D /* Temperature sensor offsets location */
|
||||
static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (from 0-100%) */
|
||||
|
||||
/* Specs of the Aquastream Ultimate pump */
|
||||
/* Pump does not follow the standard structure, so only consider the fan */
|
||||
#define AQUASTREAMULT_NUM_FANS 1
|
||||
#define AQUASTREAMULT_NUM_SENSORS 2
|
||||
|
||||
/* Sensor report offsets for the Aquastream Ultimate pump */
|
||||
#define AQUASTREAMULT_SENSOR_START 0x2D
|
||||
#define AQUASTREAMULT_PUMP_OFFSET 0x51
|
||||
#define AQUASTREAMULT_PUMP_VOLTAGE 0x3D
|
||||
#define AQUASTREAMULT_PUMP_CURRENT 0x53
|
||||
#define AQUASTREAMULT_PUMP_POWER 0x55
|
||||
#define AQUASTREAMULT_FAN_OFFSET 0x41
|
||||
#define AQUASTREAMULT_PRESSURE_OFFSET 0x57
|
||||
#define AQUASTREAMULT_FLOW_SENSOR_OFFSET 0x37
|
||||
#define AQUASTREAMULT_FAN_VOLTAGE_OFFSET 0x02
|
||||
#define AQUASTREAMULT_FAN_CURRENT_OFFSET 0x00
|
||||
#define AQUASTREAMULT_FAN_POWER_OFFSET 0x04
|
||||
#define AQUASTREAMULT_FAN_SPEED_OFFSET 0x06
|
||||
static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
|
||||
|
||||
/* Spec and sensor report offset for the Farbwerk RGB controller */
|
||||
#define FARBWERK_NUM_SENSORS 4
|
||||
#define FARBWERK_SENSOR_START 0x2f
|
||||
|
|
@ -114,7 +168,7 @@ static u16 d5next_ctrl_fan_offsets[] = { 0x97, 0x42 }; /* Pump and fan speed (fr
|
|||
#define OCTO_POWER_CYCLES 0x18
|
||||
#define OCTO_SENSOR_START 0x3D
|
||||
#define OCTO_VIRTUAL_SENSORS_START 0x45
|
||||
static u8 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
|
||||
static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
|
||||
|
||||
/* Control report offsets for the Octo */
|
||||
#define OCTO_TEMP_CTRL_OFFSET 0xA
|
||||
|
|
@ -125,6 +179,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
|
|||
#define QUADRO_NUM_FANS 4
|
||||
#define QUADRO_NUM_SENSORS 4
|
||||
#define QUADRO_NUM_VIRTUAL_SENSORS 16
|
||||
#define QUADRO_NUM_FLOW_SENSORS 1
|
||||
#define QUADRO_CTRL_REPORT_SIZE 0x3c1
|
||||
|
||||
/* Sensor report offsets for the Quadro */
|
||||
|
|
@ -132,7 +187,7 @@ static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0
|
|||
#define QUADRO_SENSOR_START 0x34
|
||||
#define QUADRO_VIRTUAL_SENSORS_START 0x3c
|
||||
#define QUADRO_FLOW_SENSOR_OFFSET 0x6e
|
||||
static u8 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
|
||||
static u16 quadro_sensor_fan_offsets[] = { 0x70, 0x7D, 0x8A, 0x97 };
|
||||
|
||||
/* Control report offsets for the Quadro */
|
||||
#define QUADRO_TEMP_CTRL_OFFSET 0xA
|
||||
|
|
@ -141,6 +196,7 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
|
|||
|
||||
/* Specs of High Flow Next flow sensor */
|
||||
#define HIGHFLOWNEXT_NUM_SENSORS 2
|
||||
#define HIGHFLOWNEXT_NUM_FLOW_SENSORS 1
|
||||
|
||||
/* Sensor report offsets for the High Flow Next */
|
||||
#define HIGHFLOWNEXT_SENSOR_START 85
|
||||
|
|
@ -151,6 +207,13 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
|
|||
#define HIGHFLOWNEXT_5V_VOLTAGE 97
|
||||
#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99
|
||||
|
||||
/* Specs of the Poweradjust 3 */
|
||||
#define POWERADJUST3_NUM_SENSORS 1
|
||||
#define POWERADJUST3_SENSOR_REPORT_SIZE 0x32
|
||||
|
||||
/* Sensor report offsets for the Poweradjust 3 */
|
||||
#define POWERADJUST3_SENSOR_START 0x03
|
||||
|
||||
/* Labels for D5 Next */
|
||||
static const char *const label_d5next_temp[] = {
|
||||
"Coolant temp"
|
||||
|
|
@ -178,12 +241,16 @@ static const char *const label_d5next_current[] = {
|
|||
"Fan current"
|
||||
};
|
||||
|
||||
/* Labels for Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
|
||||
/* Labels for Aquaero, Farbwerk, Farbwerk 360 and Octo and Quadro temperature sensors */
|
||||
static const char *const label_temp_sensors[] = {
|
||||
"Sensor 1",
|
||||
"Sensor 2",
|
||||
"Sensor 3",
|
||||
"Sensor 4"
|
||||
"Sensor 4",
|
||||
"Sensor 5",
|
||||
"Sensor 6",
|
||||
"Sensor 7",
|
||||
"Sensor 8"
|
||||
};
|
||||
|
||||
static const char *const label_virtual_temp_sensors[] = {
|
||||
|
|
@ -205,6 +272,13 @@ static const char *const label_virtual_temp_sensors[] = {
|
|||
"Virtual sensor 16",
|
||||
};
|
||||
|
||||
static const char *const label_aquaero_calc_temp_sensors[] = {
|
||||
"Calc. virtual sensor 1",
|
||||
"Calc. virtual sensor 2",
|
||||
"Calc. virtual sensor 3",
|
||||
"Calc. virtual sensor 4"
|
||||
};
|
||||
|
||||
/* Labels for Octo and Quadro (except speed) */
|
||||
static const char *const label_fan_speed[] = {
|
||||
"Fan 1 speed",
|
||||
|
|
@ -259,6 +333,16 @@ static const char *const label_quadro_speeds[] = {
|
|||
"Flow speed [dL/h]"
|
||||
};
|
||||
|
||||
/* Labels for Aquaero fan speeds */
|
||||
static const char *const label_aquaero_speeds[] = {
|
||||
"Fan 1 speed",
|
||||
"Fan 2 speed",
|
||||
"Fan 3 speed",
|
||||
"Fan 4 speed",
|
||||
"Flow sensor 1 [dL/h]",
|
||||
"Flow sensor 2 [dL/h]"
|
||||
};
|
||||
|
||||
/* Labels for High Flow Next */
|
||||
static const char *const label_highflownext_temp_sensors[] = {
|
||||
"Coolant temp",
|
||||
|
|
@ -280,6 +364,70 @@ static const char *const label_highflownext_voltage[] = {
|
|||
"+5V USB voltage"
|
||||
};
|
||||
|
||||
/* Labels for Aquastream Ultimate */
|
||||
static const char *const label_aquastreamult_temp[] = {
|
||||
"Coolant temp",
|
||||
"External temp"
|
||||
};
|
||||
|
||||
static const char *const label_aquastreamult_speeds[] = {
|
||||
"Fan speed",
|
||||
"Pump speed",
|
||||
"Pressure [mbar]",
|
||||
"Flow speed [dL/h]"
|
||||
};
|
||||
|
||||
static const char *const label_aquastreamult_power[] = {
|
||||
"Fan power",
|
||||
"Pump power"
|
||||
};
|
||||
|
||||
static const char *const label_aquastreamult_voltages[] = {
|
||||
"Fan voltage",
|
||||
"Pump voltage"
|
||||
};
|
||||
|
||||
static const char *const label_aquastreamult_current[] = {
|
||||
"Fan current",
|
||||
"Pump current"
|
||||
};
|
||||
|
||||
/* Labels for Poweradjust 3 */
|
||||
static const char *const label_poweradjust3_temp_sensors[] = {
|
||||
"External sensor"
|
||||
};
|
||||
|
||||
struct aqc_fan_structure_offsets {
|
||||
u8 voltage;
|
||||
u8 curr;
|
||||
u8 power;
|
||||
u8 speed;
|
||||
};
|
||||
|
||||
/* Fan structure offsets for Aquaero */
|
||||
static struct aqc_fan_structure_offsets aqc_aquaero_fan_structure = {
|
||||
.voltage = AQUAERO_FAN_VOLTAGE_OFFSET,
|
||||
.curr = AQUAERO_FAN_CURRENT_OFFSET,
|
||||
.power = AQUAERO_FAN_POWER_OFFSET,
|
||||
.speed = AQUAERO_FAN_SPEED_OFFSET
|
||||
};
|
||||
|
||||
/* Fan structure offsets for Aquastream Ultimate */
|
||||
static struct aqc_fan_structure_offsets aqc_aquastreamult_fan_structure = {
|
||||
.voltage = AQUASTREAMULT_FAN_VOLTAGE_OFFSET,
|
||||
.curr = AQUASTREAMULT_FAN_CURRENT_OFFSET,
|
||||
.power = AQUASTREAMULT_FAN_POWER_OFFSET,
|
||||
.speed = AQUASTREAMULT_FAN_SPEED_OFFSET
|
||||
};
|
||||
|
||||
/* Fan structure offsets for all devices except those above */
|
||||
static struct aqc_fan_structure_offsets aqc_general_fan_structure = {
|
||||
.voltage = AQC_FAN_VOLTAGE_OFFSET,
|
||||
.curr = AQC_FAN_CURRENT_OFFSET,
|
||||
.power = AQC_FAN_POWER_OFFSET,
|
||||
.speed = AQC_FAN_SPEED_OFFSET
|
||||
};
|
||||
|
||||
struct aqc_data {
|
||||
struct hid_device *hdev;
|
||||
struct device *hwmon_dev;
|
||||
|
|
@ -288,6 +436,8 @@ struct aqc_data {
|
|||
enum kinds kind;
|
||||
const char *name;
|
||||
|
||||
int status_report_id; /* Used for legacy devices, report is stored in buffer */
|
||||
|
||||
int buffer_size;
|
||||
u8 *buffer;
|
||||
int checksum_start;
|
||||
|
|
@ -295,26 +445,32 @@ struct aqc_data {
|
|||
int checksum_offset;
|
||||
|
||||
int num_fans;
|
||||
u8 *fan_sensor_offsets;
|
||||
u16 *fan_sensor_offsets;
|
||||
u16 *fan_ctrl_offsets;
|
||||
int num_temp_sensors;
|
||||
int temp_sensor_start_offset;
|
||||
int num_virtual_temp_sensors;
|
||||
int virtual_temp_sensor_start_offset;
|
||||
int num_calc_virt_temp_sensors;
|
||||
int calc_virt_temp_sensor_start_offset;
|
||||
u16 temp_ctrl_offset;
|
||||
u16 power_cycle_count_offset;
|
||||
u8 flow_sensor_offset;
|
||||
int num_flow_sensors;
|
||||
u8 flow_sensors_start_offset;
|
||||
u8 flow_pulses_ctrl_offset;
|
||||
struct aqc_fan_structure_offsets *fan_structure;
|
||||
|
||||
/* General info, same across all devices */
|
||||
u8 serial_number_start_offset;
|
||||
u32 serial_number[2];
|
||||
u8 firmware_version_offset;
|
||||
u16 firmware_version;
|
||||
|
||||
/* How many times the device was powered on, if available */
|
||||
u32 power_cycles;
|
||||
|
||||
/* Sensor values */
|
||||
s32 temp_input[20]; /* Max 4 physical and 16 virtual */
|
||||
s32 temp_input[20]; /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */
|
||||
u16 speed_input[8];
|
||||
u32 power_input[8];
|
||||
u16 voltage_input[8];
|
||||
|
|
@ -323,6 +479,7 @@ struct aqc_data {
|
|||
/* Label values */
|
||||
const char *const *temp_label;
|
||||
const char *const *virtual_temp_label;
|
||||
const char *const *calc_virt_temp_label; /* For Aquaero */
|
||||
const char *const *speed_label;
|
||||
const char *const *power_label;
|
||||
const char *const *voltage_label;
|
||||
|
|
@ -443,7 +600,9 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
|||
}
|
||||
}
|
||||
|
||||
if (channel < priv->num_temp_sensors + priv->num_virtual_temp_sensors)
|
||||
if (channel <
|
||||
priv->num_temp_sensors + priv->num_virtual_temp_sensors +
|
||||
priv->num_calc_virt_temp_sensors)
|
||||
switch (attr) {
|
||||
case hwmon_temp_label:
|
||||
case hwmon_temp_input:
|
||||
|
|
@ -467,6 +626,14 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
|||
case hwmon_fan_input:
|
||||
case hwmon_fan_label:
|
||||
switch (priv->kind) {
|
||||
case aquastreamult:
|
||||
/*
|
||||
* Special case to support pump RPM, fan RPM,
|
||||
* pressure and flow sensor
|
||||
*/
|
||||
if (channel < 4)
|
||||
return 0444;
|
||||
break;
|
||||
case highflownext:
|
||||
/* Special case to support flow sensor, water quality
|
||||
* and conductivity
|
||||
|
|
@ -474,9 +641,10 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
|||
if (channel < 3)
|
||||
return 0444;
|
||||
break;
|
||||
case aquaero:
|
||||
case quadro:
|
||||
/* Special case to support flow sensor */
|
||||
if (channel < priv->num_fans + 1)
|
||||
/* Special case to support flow sensors */
|
||||
if (channel < priv->num_fans + priv->num_flow_sensors)
|
||||
return 0444;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -496,6 +664,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
|||
break;
|
||||
case hwmon_power:
|
||||
switch (priv->kind) {
|
||||
case aquastreamult:
|
||||
/* Special case to support pump and fan power */
|
||||
if (channel < 2)
|
||||
return 0444;
|
||||
break;
|
||||
case highflownext:
|
||||
/* Special case to support one power sensor */
|
||||
if (channel == 0)
|
||||
|
|
@ -508,8 +681,17 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
|||
}
|
||||
break;
|
||||
case hwmon_curr:
|
||||
if (channel < priv->num_fans)
|
||||
return 0444;
|
||||
switch (priv->kind) {
|
||||
case aquastreamult:
|
||||
/* Special case to support pump and fan current */
|
||||
if (channel < 2)
|
||||
return 0444;
|
||||
break;
|
||||
default:
|
||||
if (channel < priv->num_fans)
|
||||
return 0444;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_in:
|
||||
switch (priv->kind) {
|
||||
|
|
@ -518,6 +700,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
|||
if (channel < priv->num_fans + 2)
|
||||
return 0444;
|
||||
break;
|
||||
case aquastreamult:
|
||||
case highflownext:
|
||||
/* Special case to support two voltage sensors */
|
||||
if (channel < 2)
|
||||
|
|
@ -536,14 +719,49 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Read device sensors by manually requesting the sensor report (legacy way) */
|
||||
static int aqc_legacy_read(struct aqc_data *priv)
|
||||
{
|
||||
int ret, i, sensor_value;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
memset(priv->buffer, 0x00, priv->buffer_size);
|
||||
ret = hid_hw_raw_request(priv->hdev, priv->status_report_id, priv->buffer,
|
||||
priv->buffer_size, HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
|
||||
/* Temperature sensor readings */
|
||||
for (i = 0; i < priv->num_temp_sensors; i++) {
|
||||
sensor_value = get_unaligned_le16(priv->buffer + priv->temp_sensor_start_offset +
|
||||
i * AQC_SENSOR_SIZE);
|
||||
priv->temp_input[i] = sensor_value * 10;
|
||||
}
|
||||
|
||||
priv->updated = jiffies;
|
||||
|
||||
unlock_and_return:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
int channel, long *val)
|
||||
{
|
||||
int ret;
|
||||
struct aqc_data *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL))
|
||||
return -ENODATA;
|
||||
if (time_after(jiffies, priv->updated + STATUS_UPDATE_INTERVAL)) {
|
||||
if (priv->status_report_id != 0) {
|
||||
/* Legacy devices require manual reads */
|
||||
ret = aqc_legacy_read(priv);
|
||||
if (ret < 0)
|
||||
return -ENODATA;
|
||||
} else {
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
|
|
@ -557,7 +775,7 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
case hwmon_temp_offset:
|
||||
ret =
|
||||
aqc_get_ctrl_val(priv, priv->temp_ctrl_offset +
|
||||
channel * AQC_TEMP_SENSOR_SIZE, val);
|
||||
channel * AQC_SENSOR_SIZE, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -611,12 +829,20 @@ static int aqc_read_string(struct device *dev, enum hwmon_sensor_types type, u32
|
|||
{
|
||||
struct aqc_data *priv = dev_get_drvdata(dev);
|
||||
|
||||
/* Number of sensors that are not calculated */
|
||||
int num_non_calc_sensors = priv->num_temp_sensors + priv->num_virtual_temp_sensors;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
if (channel < priv->num_temp_sensors)
|
||||
if (channel < priv->num_temp_sensors) {
|
||||
*str = priv->temp_label[channel];
|
||||
else
|
||||
*str = priv->virtual_temp_label[channel - priv->num_temp_sensors];
|
||||
} else {
|
||||
if (priv->kind == aquaero && channel >= num_non_calc_sensors)
|
||||
*str =
|
||||
priv->calc_virt_temp_label[channel - num_non_calc_sensors];
|
||||
else
|
||||
*str = priv->virtual_temp_label[channel - priv->num_temp_sensors];
|
||||
}
|
||||
break;
|
||||
case hwmon_fan:
|
||||
*str = priv->speed_label[channel];
|
||||
|
|
@ -651,7 +877,7 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
val = clamp_val(val, -15000, 15000) / 10;
|
||||
ret =
|
||||
aqc_set_ctrl_val(priv, priv->temp_ctrl_offset +
|
||||
channel * AQC_TEMP_SENSOR_SIZE, val);
|
||||
channel * AQC_SENSOR_SIZE, val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
|
|
@ -789,15 +1015,16 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
|||
priv = hid_get_drvdata(hdev);
|
||||
|
||||
/* Info provided with every report */
|
||||
priv->serial_number[0] = get_unaligned_be16(data + SERIAL_FIRST_PART);
|
||||
priv->serial_number[1] = get_unaligned_be16(data + SERIAL_SECOND_PART);
|
||||
priv->firmware_version = get_unaligned_be16(data + FIRMWARE_VERSION);
|
||||
priv->serial_number[0] = get_unaligned_be16(data + priv->serial_number_start_offset);
|
||||
priv->serial_number[1] = get_unaligned_be16(data + priv->serial_number_start_offset +
|
||||
SERIAL_PART_OFFSET);
|
||||
priv->firmware_version = get_unaligned_be16(data + priv->firmware_version_offset);
|
||||
|
||||
/* Physical temperature sensor readings */
|
||||
for (i = 0; i < priv->num_temp_sensors; i++) {
|
||||
sensor_value = get_unaligned_be16(data +
|
||||
priv->temp_sensor_start_offset +
|
||||
i * AQC_TEMP_SENSOR_SIZE);
|
||||
i * AQC_SENSOR_SIZE);
|
||||
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
|
||||
priv->temp_input[i] = -ENODATA;
|
||||
else
|
||||
|
|
@ -808,7 +1035,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
|||
for (j = 0; j < priv->num_virtual_temp_sensors; j++) {
|
||||
sensor_value = get_unaligned_be16(data +
|
||||
priv->virtual_temp_sensor_start_offset +
|
||||
j * AQC_TEMP_SENSOR_SIZE);
|
||||
j * AQC_SENSOR_SIZE);
|
||||
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
|
||||
priv->temp_input[i] = -ENODATA;
|
||||
else
|
||||
|
|
@ -819,15 +1046,24 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
|||
/* Fan speed and related readings */
|
||||
for (i = 0; i < priv->num_fans; i++) {
|
||||
priv->speed_input[i] =
|
||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_SPEED_OFFSET);
|
||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
||||
priv->fan_structure->speed);
|
||||
priv->power_input[i] =
|
||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
||||
AQC_FAN_POWER_OFFSET) * 10000;
|
||||
priv->fan_structure->power) * 10000;
|
||||
priv->voltage_input[i] =
|
||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
||||
AQC_FAN_VOLTAGE_OFFSET) * 10;
|
||||
priv->fan_structure->voltage) * 10;
|
||||
priv->current_input[i] =
|
||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] + AQC_FAN_CURRENT_OFFSET);
|
||||
get_unaligned_be16(data + priv->fan_sensor_offsets[i] +
|
||||
priv->fan_structure->curr);
|
||||
}
|
||||
|
||||
/* Flow sensor readings */
|
||||
for (j = 0; j < priv->num_flow_sensors; j++) {
|
||||
priv->speed_input[i] = get_unaligned_be16(data + priv->flow_sensors_start_offset +
|
||||
j * AQC_SENSOR_SIZE);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (priv->power_cycle_count_offset != 0)
|
||||
|
|
@ -835,13 +1071,35 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
|||
|
||||
/* Special-case sensor readings */
|
||||
switch (priv->kind) {
|
||||
case aquaero:
|
||||
/* Read calculated virtual temp sensors */
|
||||
i = priv->num_temp_sensors + priv->num_virtual_temp_sensors;
|
||||
for (j = 0; j < priv->num_calc_virt_temp_sensors; j++) {
|
||||
sensor_value = get_unaligned_be16(data +
|
||||
priv->calc_virt_temp_sensor_start_offset +
|
||||
j * AQC_SENSOR_SIZE);
|
||||
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
|
||||
priv->temp_input[i] = -ENODATA;
|
||||
else
|
||||
priv->temp_input[i] = sensor_value * 10;
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case aquastreamult:
|
||||
priv->speed_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_OFFSET);
|
||||
priv->speed_input[2] = get_unaligned_be16(data + AQUASTREAMULT_PRESSURE_OFFSET);
|
||||
priv->speed_input[3] = get_unaligned_be16(data + AQUASTREAMULT_FLOW_SENSOR_OFFSET);
|
||||
|
||||
priv->power_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_POWER) * 10000;
|
||||
|
||||
priv->voltage_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_VOLTAGE) * 10;
|
||||
|
||||
priv->current_input[1] = get_unaligned_be16(data + AQUASTREAMULT_PUMP_CURRENT);
|
||||
break;
|
||||
case d5next:
|
||||
priv->voltage_input[2] = get_unaligned_be16(data + D5NEXT_5V_VOLTAGE) * 10;
|
||||
priv->voltage_input[3] = get_unaligned_be16(data + D5NEXT_12V_VOLTAGE) * 10;
|
||||
break;
|
||||
case quadro:
|
||||
priv->speed_input[4] = get_unaligned_be16(data + priv->flow_sensor_offset);
|
||||
break;
|
||||
case highflownext:
|
||||
/* If external temp sensor is not connected, its power reading is also N/A */
|
||||
if (priv->temp_input[1] == -ENODATA)
|
||||
|
|
@ -854,7 +1112,6 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
|
|||
priv->voltage_input[1] =
|
||||
get_unaligned_be16(data + HIGHFLOWNEXT_5V_VOLTAGE_USB) * 10;
|
||||
|
||||
priv->speed_input[0] = get_unaligned_be16(data + HIGHFLOWNEXT_FLOW);
|
||||
priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY);
|
||||
priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY);
|
||||
break;
|
||||
|
|
@ -907,9 +1164,13 @@ static void aqc_debugfs_init(struct aqc_data *priv)
|
|||
dev_name(&priv->hdev->dev));
|
||||
|
||||
priv->debugfs = debugfs_create_dir(name, NULL);
|
||||
debugfs_create_file("serial_number", 0444, priv->debugfs, priv, &serial_number_fops);
|
||||
debugfs_create_file("firmware_version", 0444, priv->debugfs, priv, &firmware_version_fops);
|
||||
|
||||
if (priv->serial_number_start_offset != 0)
|
||||
debugfs_create_file("serial_number", 0444, priv->debugfs, priv,
|
||||
&serial_number_fops);
|
||||
if (priv->firmware_version_offset != 0)
|
||||
debugfs_create_file("firmware_version", 0444, priv->debugfs, priv,
|
||||
&firmware_version_fops);
|
||||
if (priv->power_cycle_count_offset != 0)
|
||||
debugfs_create_file("power_cycles", 0444, priv->debugfs, priv, &power_cycles_fops);
|
||||
}
|
||||
|
|
@ -949,6 +1210,45 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
goto fail_and_stop;
|
||||
|
||||
switch (hdev->product) {
|
||||
case USB_PRODUCT_ID_AQUAERO:
|
||||
/*
|
||||
* Aquaero presents itself as three HID devices under the same product ID:
|
||||
* "aquaero keyboard/mouse", "aquaero System Control" and "aquaero Device",
|
||||
* which is the one we want to communicate with. Unlike most other Aquacomputer
|
||||
* devices, Aquaero does not return meaningful data when explicitly requested
|
||||
* using GET_FEATURE_REPORT.
|
||||
*
|
||||
* The difference between "aquaero Device" and the other two is in the collections
|
||||
* they present. The two other devices have the type of the second element in
|
||||
* their respective collections set to 1, while the real device has it set to 0.
|
||||
*/
|
||||
if (hdev->collection[1].type != 0) {
|
||||
ret = -ENODEV;
|
||||
goto fail_and_close;
|
||||
}
|
||||
|
||||
priv->kind = aquaero;
|
||||
|
||||
priv->num_fans = AQUAERO_NUM_FANS;
|
||||
priv->fan_sensor_offsets = aquaero_sensor_fan_offsets;
|
||||
|
||||
priv->num_temp_sensors = AQUAERO_NUM_SENSORS;
|
||||
priv->temp_sensor_start_offset = AQUAERO_SENSOR_START;
|
||||
priv->num_virtual_temp_sensors = AQUAERO_NUM_VIRTUAL_SENSORS;
|
||||
priv->virtual_temp_sensor_start_offset = AQUAERO_VIRTUAL_SENSOR_START;
|
||||
priv->num_calc_virt_temp_sensors = AQUAERO_NUM_CALC_VIRTUAL_SENSORS;
|
||||
priv->calc_virt_temp_sensor_start_offset = AQUAERO_CALC_VIRTUAL_SENSOR_START;
|
||||
priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS;
|
||||
priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START;
|
||||
|
||||
priv->temp_label = label_temp_sensors;
|
||||
priv->virtual_temp_label = label_virtual_temp_sensors;
|
||||
priv->calc_virt_temp_label = label_aquaero_calc_temp_sensors;
|
||||
priv->speed_label = label_aquaero_speeds;
|
||||
priv->power_label = label_fan_power;
|
||||
priv->voltage_label = label_fan_voltage;
|
||||
priv->current_label = label_fan_current;
|
||||
break;
|
||||
case USB_PRODUCT_ID_D5NEXT:
|
||||
priv->kind = d5next;
|
||||
|
||||
|
|
@ -1034,11 +1334,13 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
priv->temp_sensor_start_offset = QUADRO_SENSOR_START;
|
||||
priv->num_virtual_temp_sensors = QUADRO_NUM_VIRTUAL_SENSORS;
|
||||
priv->virtual_temp_sensor_start_offset = QUADRO_VIRTUAL_SENSORS_START;
|
||||
priv->num_flow_sensors = QUADRO_NUM_FLOW_SENSORS;
|
||||
priv->flow_sensors_start_offset = QUADRO_FLOW_SENSOR_OFFSET;
|
||||
|
||||
priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET;
|
||||
|
||||
priv->buffer_size = QUADRO_CTRL_REPORT_SIZE;
|
||||
|
||||
priv->flow_sensor_offset = QUADRO_FLOW_SENSOR_OFFSET;
|
||||
priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET;
|
||||
priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
|
||||
|
||||
|
|
@ -1056,6 +1358,8 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
|
||||
priv->num_temp_sensors = HIGHFLOWNEXT_NUM_SENSORS;
|
||||
priv->temp_sensor_start_offset = HIGHFLOWNEXT_SENSOR_START;
|
||||
priv->num_flow_sensors = HIGHFLOWNEXT_NUM_FLOW_SENSORS;
|
||||
priv->flow_sensors_start_offset = HIGHFLOWNEXT_FLOW;
|
||||
|
||||
priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
|
||||
|
||||
|
|
@ -1064,10 +1368,57 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
priv->power_label = label_highflownext_power;
|
||||
priv->voltage_label = label_highflownext_voltage;
|
||||
break;
|
||||
case USB_PRODUCT_ID_AQUASTREAMULT:
|
||||
priv->kind = aquastreamult;
|
||||
|
||||
priv->num_fans = AQUASTREAMULT_NUM_FANS;
|
||||
priv->fan_sensor_offsets = aquastreamult_sensor_fan_offsets;
|
||||
|
||||
priv->num_temp_sensors = AQUASTREAMULT_NUM_SENSORS;
|
||||
priv->temp_sensor_start_offset = AQUASTREAMULT_SENSOR_START;
|
||||
|
||||
priv->temp_label = label_aquastreamult_temp;
|
||||
priv->speed_label = label_aquastreamult_speeds;
|
||||
priv->power_label = label_aquastreamult_power;
|
||||
priv->voltage_label = label_aquastreamult_voltages;
|
||||
priv->current_label = label_aquastreamult_current;
|
||||
break;
|
||||
case USB_PRODUCT_ID_POWERADJUST3:
|
||||
priv->kind = poweradjust3;
|
||||
|
||||
priv->num_fans = 0;
|
||||
|
||||
priv->num_temp_sensors = POWERADJUST3_NUM_SENSORS;
|
||||
priv->temp_sensor_start_offset = POWERADJUST3_SENSOR_START;
|
||||
priv->buffer_size = POWERADJUST3_SENSOR_REPORT_SIZE;
|
||||
|
||||
priv->temp_label = label_poweradjust3_temp_sensors;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (priv->kind) {
|
||||
case aquaero:
|
||||
priv->serial_number_start_offset = AQUAERO_SERIAL_START;
|
||||
priv->firmware_version_offset = AQUAERO_FIRMWARE_VERSION;
|
||||
|
||||
priv->fan_structure = &aqc_aquaero_fan_structure;
|
||||
break;
|
||||
case poweradjust3:
|
||||
priv->status_report_id = POWERADJUST3_STATUS_REPORT_ID;
|
||||
break;
|
||||
default:
|
||||
priv->serial_number_start_offset = AQC_SERIAL_START;
|
||||
priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
|
||||
|
||||
if (priv->kind == aquastreamult)
|
||||
priv->fan_structure = &aqc_aquastreamult_fan_structure;
|
||||
else
|
||||
priv->fan_structure = &aqc_general_fan_structure;
|
||||
break;
|
||||
}
|
||||
|
||||
if (priv->buffer_size != 0) {
|
||||
priv->checksum_start = 0x01;
|
||||
priv->checksum_length = priv->buffer_size - 3;
|
||||
|
|
@ -1115,12 +1466,15 @@ static void aqc_remove(struct hid_device *hdev)
|
|||
}
|
||||
|
||||
static const struct hid_device_id aqc_table[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUAERO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_D5NEXT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_FARBWERK360) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ static const struct ec_board_info board_info_pro_art_x570_creator_wifi = {
|
|||
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
|
||||
SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |
|
||||
SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
|
||||
.family = family_amd_500_series,
|
||||
};
|
||||
|
||||
|
|
@ -466,6 +467,8 @@ static const struct dmi_system_id dmi_table[] = {
|
|||
&board_info_strix_z690_a_gaming_wifi_d4),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",
|
||||
&board_info_zenith_ii_extreme),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA",
|
||||
&board_info_zenith_ii_extreme),
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <asm/msr.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <linux/sched/isolation.h>
|
||||
|
||||
#define DRVNAME "coretemp"
|
||||
|
||||
|
|
@ -502,6 +503,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
|
|||
u32 eax, edx;
|
||||
int err, index, attr_no;
|
||||
|
||||
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Find attr number for sysfs:
|
||||
* We map the attr number to core id of the CPU
|
||||
|
|
@ -588,66 +592,49 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx)
|
|||
ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO);
|
||||
}
|
||||
|
||||
static int coretemp_probe(struct platform_device *pdev)
|
||||
static int coretemp_device_add(int zoneid)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct platform_device *pdev;
|
||||
struct platform_data *pdata;
|
||||
int err;
|
||||
|
||||
/* Initialize the per-zone data structures */
|
||||
pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
|
||||
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata->pkg_id = pdev->id;
|
||||
pdata->pkg_id = zoneid;
|
||||
ida_init(&pdata->ida);
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
|
||||
pdata, NULL);
|
||||
return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
|
||||
}
|
||||
|
||||
static int coretemp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct platform_data *pdata = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = MAX_CORE_DATA - 1; i >= 0; --i)
|
||||
if (pdata->core_data[i])
|
||||
coretemp_remove_core(pdata, i);
|
||||
|
||||
ida_destroy(&pdata->ida);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver coretemp_driver = {
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
},
|
||||
.probe = coretemp_probe,
|
||||
.remove = coretemp_remove,
|
||||
};
|
||||
|
||||
static struct platform_device *coretemp_device_add(unsigned int cpu)
|
||||
{
|
||||
int err, zoneid = topology_logical_die_id(cpu);
|
||||
struct platform_device *pdev;
|
||||
|
||||
if (zoneid < 0)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pdev = platform_device_alloc(DRVNAME, zoneid);
|
||||
if (!pdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err) {
|
||||
platform_device_put(pdev);
|
||||
return ERR_PTR(err);
|
||||
if (!pdev) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_pdata;
|
||||
}
|
||||
|
||||
err = platform_device_add(pdev);
|
||||
if (err)
|
||||
goto err_put_dev;
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
zone_devices[zoneid] = pdev;
|
||||
return pdev;
|
||||
return 0;
|
||||
|
||||
err_put_dev:
|
||||
platform_device_put(pdev);
|
||||
err_free_pdata:
|
||||
kfree(pdata);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void coretemp_device_remove(int zoneid)
|
||||
{
|
||||
struct platform_device *pdev = zone_devices[zoneid];
|
||||
struct platform_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
ida_destroy(&pdata->ida);
|
||||
kfree(pdata);
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
|
||||
static int coretemp_cpu_online(unsigned int cpu)
|
||||
|
|
@ -671,7 +658,10 @@ static int coretemp_cpu_online(unsigned int cpu)
|
|||
if (!cpu_has(c, X86_FEATURE_DTHERM))
|
||||
return -ENODEV;
|
||||
|
||||
if (!pdev) {
|
||||
pdata = platform_get_drvdata(pdev);
|
||||
if (!pdata->hwmon_dev) {
|
||||
struct device *hwmon;
|
||||
|
||||
/* Check the microcode version of the CPU */
|
||||
if (chk_ucode_version(cpu))
|
||||
return -EINVAL;
|
||||
|
|
@ -682,9 +672,11 @@ static int coretemp_cpu_online(unsigned int cpu)
|
|||
* online. So, initialize per-pkg data structures and
|
||||
* then bring this core online.
|
||||
*/
|
||||
pdev = coretemp_device_add(cpu);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
|
||||
pdata, NULL);
|
||||
if (IS_ERR(hwmon))
|
||||
return PTR_ERR(hwmon);
|
||||
pdata->hwmon_dev = hwmon;
|
||||
|
||||
/*
|
||||
* Check whether pkgtemp support is available.
|
||||
|
|
@ -694,7 +686,6 @@ static int coretemp_cpu_online(unsigned int cpu)
|
|||
coretemp_add_core(pdev, cpu, 1);
|
||||
}
|
||||
|
||||
pdata = platform_get_drvdata(pdev);
|
||||
/*
|
||||
* Check whether a thread sibling is already online. If not add the
|
||||
* interface for this CPU core.
|
||||
|
|
@ -713,18 +704,14 @@ static int coretemp_cpu_offline(unsigned int cpu)
|
|||
struct temp_data *tdata;
|
||||
int i, indx = -1, target;
|
||||
|
||||
/*
|
||||
* Don't execute this on suspend as the device remove locks
|
||||
* up the machine.
|
||||
*/
|
||||
/* No need to tear down any interfaces for suspend */
|
||||
if (cpuhp_tasks_frozen)
|
||||
return 0;
|
||||
|
||||
/* If the physical CPU device does not exist, just return */
|
||||
if (!pdev)
|
||||
return 0;
|
||||
|
||||
pd = platform_get_drvdata(pdev);
|
||||
if (!pd->hwmon_dev)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < NUM_REAL_CORES; i++) {
|
||||
if (pd->cpu_map[i] == topology_core_id(cpu)) {
|
||||
|
|
@ -756,13 +743,14 @@ static int coretemp_cpu_offline(unsigned int cpu)
|
|||
}
|
||||
|
||||
/*
|
||||
* If all cores in this pkg are offline, remove the device. This
|
||||
* will invoke the platform driver remove function, which cleans up
|
||||
* the rest.
|
||||
* If all cores in this pkg are offline, remove the interface.
|
||||
*/
|
||||
tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
|
||||
if (cpumask_empty(&pd->cpumask)) {
|
||||
zone_devices[topology_logical_die_id(cpu)] = NULL;
|
||||
platform_device_unregister(pdev);
|
||||
if (tdata)
|
||||
coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO);
|
||||
hwmon_device_unregister(pd->hwmon_dev);
|
||||
pd->hwmon_dev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -770,7 +758,6 @@ static int coretemp_cpu_offline(unsigned int cpu)
|
|||
* Check whether this core is the target for the package
|
||||
* interface. We need to assign it to some other cpu.
|
||||
*/
|
||||
tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
|
||||
if (tdata && tdata->cpu == cpu) {
|
||||
target = cpumask_first(&pd->cpumask);
|
||||
mutex_lock(&tdata->update_lock);
|
||||
|
|
@ -789,7 +776,7 @@ static enum cpuhp_state coretemp_hp_online;
|
|||
|
||||
static int __init coretemp_init(void)
|
||||
{
|
||||
int err;
|
||||
int i, err;
|
||||
|
||||
/*
|
||||
* CPUID.06H.EAX[0] indicates whether the CPU has thermal
|
||||
|
|
@ -805,20 +792,22 @@ static int __init coretemp_init(void)
|
|||
if (!zone_devices)
|
||||
return -ENOMEM;
|
||||
|
||||
err = platform_driver_register(&coretemp_driver);
|
||||
if (err)
|
||||
goto outzone;
|
||||
for (i = 0; i < max_zones; i++) {
|
||||
err = coretemp_device_add(i);
|
||||
if (err)
|
||||
goto outzone;
|
||||
}
|
||||
|
||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
|
||||
coretemp_cpu_online, coretemp_cpu_offline);
|
||||
if (err < 0)
|
||||
goto outdrv;
|
||||
goto outzone;
|
||||
coretemp_hp_online = err;
|
||||
return 0;
|
||||
|
||||
outdrv:
|
||||
platform_driver_unregister(&coretemp_driver);
|
||||
outzone:
|
||||
while (i--)
|
||||
coretemp_device_remove(i);
|
||||
kfree(zone_devices);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -826,8 +815,11 @@ module_init(coretemp_init)
|
|||
|
||||
static void __exit coretemp_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cpuhp_remove_state(coretemp_hp_online);
|
||||
platform_driver_unregister(&coretemp_driver);
|
||||
for (i = 0; i < max_zones; i++)
|
||||
coretemp_device_remove(i);
|
||||
kfree(zone_devices);
|
||||
}
|
||||
module_exit(coretemp_exit)
|
||||
|
|
|
|||
|
|
@ -59,10 +59,11 @@ static const struct i2c_device_id emc2305_ids[] = {
|
|||
MODULE_DEVICE_TABLE(i2c, emc2305_ids);
|
||||
|
||||
/**
|
||||
* @cdev: cooling device;
|
||||
* @curr_state: cooling current state;
|
||||
* @last_hwmon_state: last cooling state updated by hwmon subsystem;
|
||||
* @last_thermal_state: last cooling state updated by thermal subsystem;
|
||||
* struct emc2305_cdev_data - device-specific cooling device state
|
||||
* @cdev: cooling device
|
||||
* @cur_state: cooling current state
|
||||
* @last_hwmon_state: last cooling state updated by hwmon subsystem
|
||||
* @last_thermal_state: last cooling state updated by thermal subsystem
|
||||
*
|
||||
* The 'last_hwmon_state' and 'last_thermal_state' fields are provided to support fan low limit
|
||||
* speed feature. The purpose of this feature is to provides ability to limit fan speed
|
||||
|
|
@ -86,13 +87,14 @@ struct emc2305_cdev_data {
|
|||
};
|
||||
|
||||
/**
|
||||
* @client: i2c client;
|
||||
* @hwmon_dev: hwmon device;
|
||||
* @max_state: maximum cooling state of the cooling device;
|
||||
* @pwm_num: number of PWM channels;
|
||||
* @pwm_separate: separate PWM settings for every channel;
|
||||
* @pwm_min: array of minimum PWM per channel;
|
||||
* @cdev_data: array of cooling devices data;
|
||||
* struct emc2305_data - device-specific data
|
||||
* @client: i2c client
|
||||
* @hwmon_dev: hwmon device
|
||||
* @max_state: maximum cooling state of the cooling device
|
||||
* @pwm_num: number of PWM channels
|
||||
* @pwm_separate: separate PWM settings for every channel
|
||||
* @pwm_min: array of minimum PWM per channel
|
||||
* @cdev_data: array of cooling devices data
|
||||
*/
|
||||
struct emc2305_data {
|
||||
struct i2c_client *client;
|
||||
|
|
|
|||
|
|
@ -6,17 +6,14 @@
|
|||
* Thilo Cestonaro <thilo.cestonaro@ts.fujitsu.com>
|
||||
*/
|
||||
#include <linux/err.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define FTS_DEVICE_ID_REG 0x0000
|
||||
|
|
@ -48,6 +45,8 @@
|
|||
#define FTS_NO_TEMP_SENSORS 0x10
|
||||
#define FTS_NO_VOLT_SENSORS 0x04
|
||||
|
||||
#define FTS_FAN_SOURCE_INVALID 0xff
|
||||
|
||||
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
|
||||
|
||||
static const struct i2c_device_id fts_id[] = {
|
||||
|
|
@ -187,7 +186,7 @@ static int fts_update_device(struct fts_data *data)
|
|||
data->fan_source[i] = err;
|
||||
} else {
|
||||
data->fan_input[i] = 0;
|
||||
data->fan_source[i] = 0;
|
||||
data->fan_source[i] = FTS_FAN_SOURCE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,373 +335,243 @@ static int fts_watchdog_init(struct fts_data *data)
|
|||
/* max timeout 255 minutes. */
|
||||
data->wdd.max_hw_heartbeat_ms = 0xFF * 60 * MSEC_PER_SEC;
|
||||
|
||||
return watchdog_register_device(&data->wdd);
|
||||
return devm_watchdog_register_device(&data->client->dev, &data->wdd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SysFS handler functions */
|
||||
/*****************************************************************************/
|
||||
static ssize_t in_value_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
static umode_t fts_is_visible(const void *devdata, enum hwmon_sensor_types type, u32 attr,
|
||||
int channel)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int err;
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
case hwmon_temp_fault:
|
||||
return 0444;
|
||||
case hwmon_temp_alarm:
|
||||
return 0644;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
case hwmon_fan_fault:
|
||||
return 0444;
|
||||
case hwmon_fan_alarm:
|
||||
return 0644;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_pwm:
|
||||
case hwmon_in:
|
||||
return 0444;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
err = fts_update_device(data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%u\n", data->volt[index]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t temp_value_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
static int fts_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
|
||||
long *val)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int err;
|
||||
int ret = fts_update_device(data);
|
||||
|
||||
err = fts_update_device(data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%u\n", data->temp_input[index]);
|
||||
}
|
||||
|
||||
static ssize_t temp_fault_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int err;
|
||||
|
||||
err = fts_update_device(data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* 00h Temperature = Sensor Error */
|
||||
return sprintf(buf, "%d\n", data->temp_input[index] == 0);
|
||||
}
|
||||
|
||||
static ssize_t temp_alarm_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int err;
|
||||
|
||||
err = fts_update_device(data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%u\n", !!(data->temp_alarm & BIT(index)));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
temp_alarm_store(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
long ret;
|
||||
|
||||
ret = fts_update_device(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (kstrtoul(buf, 10, &ret) || ret != 0)
|
||||
return -EINVAL;
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
*val = (data->temp_input[channel] - 64) * 1000;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(index));
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return 0;
|
||||
case hwmon_temp_alarm:
|
||||
*val = !!(data->temp_alarm & BIT(channel));
|
||||
|
||||
ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(index),
|
||||
ret | 0x1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return 0;
|
||||
case hwmon_temp_fault:
|
||||
/* 00h Temperature = Sensor Error */;
|
||||
*val = (data->temp_input[channel] == 0);
|
||||
|
||||
data->valid = false;
|
||||
ret = count;
|
||||
error:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
*val = data->fan_input[channel] * 60;
|
||||
|
||||
return 0;
|
||||
case hwmon_fan_alarm:
|
||||
*val = !!(data->fan_alarm & BIT(channel));
|
||||
|
||||
return 0;
|
||||
case hwmon_fan_fault:
|
||||
*val = !(data->fan_present & BIT(channel));
|
||||
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_pwm:
|
||||
switch (attr) {
|
||||
case hwmon_pwm_auto_channels_temp:
|
||||
if (data->fan_source[channel] == FTS_FAN_SOURCE_INVALID)
|
||||
*val = 0;
|
||||
else
|
||||
*val = BIT(data->fan_source[channel]);
|
||||
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_in:
|
||||
switch (attr) {
|
||||
case hwmon_in_input:
|
||||
*val = DIV_ROUND_CLOSEST(data->volt[channel] * 3300, 255);
|
||||
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static ssize_t fan_value_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
static int fts_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
|
||||
long val)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int err;
|
||||
int ret = fts_update_device(data);
|
||||
|
||||
err = fts_update_device(data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%u\n", data->fan_input[index]);
|
||||
}
|
||||
|
||||
static ssize_t fan_source_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int err;
|
||||
|
||||
err = fts_update_device(data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%u\n", data->fan_source[index]);
|
||||
}
|
||||
|
||||
static ssize_t fan_alarm_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
int err;
|
||||
|
||||
err = fts_update_device(data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%d\n", !!(data->fan_alarm & BIT(index)));
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
fan_alarm_store(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(dev);
|
||||
int index = to_sensor_dev_attr(devattr)->index;
|
||||
long ret;
|
||||
|
||||
ret = fts_update_device(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (kstrtoul(buf, 10, &ret) || ret != 0)
|
||||
return -EINVAL;
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_alarm:
|
||||
if (val)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(index));
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = fts_read_byte(data->client, FTS_REG_TEMP_CONTROL(channel));
|
||||
if (ret >= 0)
|
||||
ret = fts_write_byte(data->client, FTS_REG_TEMP_CONTROL(channel),
|
||||
ret | 0x1);
|
||||
if (ret >= 0)
|
||||
data->valid = false;
|
||||
|
||||
ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(index),
|
||||
ret | 0x1);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->valid = false;
|
||||
ret = count;
|
||||
error:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_alarm:
|
||||
if (val)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = fts_read_byte(data->client, FTS_REG_FAN_CONTROL(channel));
|
||||
if (ret >= 0)
|
||||
ret = fts_write_byte(data->client, FTS_REG_FAN_CONTROL(channel),
|
||||
ret | 0x1);
|
||||
if (ret >= 0)
|
||||
data->valid = false;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SysFS structs */
|
||||
/*****************************************************************************/
|
||||
static const struct hwmon_ops fts_ops = {
|
||||
.is_visible = fts_is_visible,
|
||||
.read = fts_read,
|
||||
.write = fts_write,
|
||||
};
|
||||
|
||||
/* Temperature sensors */
|
||||
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_value, 0);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_value, 1);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp3_input, temp_value, 2);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp4_input, temp_value, 3);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp5_input, temp_value, 4);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp6_input, temp_value, 5);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp7_input, temp_value, 6);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp8_input, temp_value, 7);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp9_input, temp_value, 8);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp10_input, temp_value, 9);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp11_input, temp_value, 10);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp12_input, temp_value, 11);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp13_input, temp_value, 12);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp14_input, temp_value, 13);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp15_input, temp_value, 14);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp16_input, temp_value, 15);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_RO(temp1_fault, temp_fault, 0);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp2_fault, temp_fault, 1);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp3_fault, temp_fault, 2);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp4_fault, temp_fault, 3);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp5_fault, temp_fault, 4);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp6_fault, temp_fault, 5);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp7_fault, temp_fault, 6);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp8_fault, temp_fault, 7);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp9_fault, temp_fault, 8);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp10_fault, temp_fault, 9);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp11_fault, temp_fault, 10);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp12_fault, temp_fault, 11);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp13_fault, temp_fault, 12);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp14_fault, temp_fault, 13);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp15_fault, temp_fault, 14);
|
||||
static SENSOR_DEVICE_ATTR_RO(temp16_fault, temp_fault, 15);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_RW(temp1_alarm, temp_alarm, 0);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp2_alarm, temp_alarm, 1);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp3_alarm, temp_alarm, 2);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp4_alarm, temp_alarm, 3);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp5_alarm, temp_alarm, 4);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp6_alarm, temp_alarm, 5);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp7_alarm, temp_alarm, 6);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp8_alarm, temp_alarm, 7);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp9_alarm, temp_alarm, 8);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp10_alarm, temp_alarm, 9);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp11_alarm, temp_alarm, 10);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp12_alarm, temp_alarm, 11);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp13_alarm, temp_alarm, 12);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp14_alarm, temp_alarm, 13);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp15_alarm, temp_alarm, 14);
|
||||
static SENSOR_DEVICE_ATTR_RW(temp16_alarm, temp_alarm, 15);
|
||||
|
||||
static struct attribute *fts_temp_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp9_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp10_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp11_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp12_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp13_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp14_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp15_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp16_input.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp9_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp10_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp11_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp12_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp13_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp14_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp15_fault.dev_attr.attr,
|
||||
&sensor_dev_attr_temp16_fault.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp4_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp5_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp6_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp7_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp8_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp9_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp10_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp11_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp12_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp13_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp14_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp15_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp16_alarm.dev_attr.attr,
|
||||
static const struct hwmon_channel_info *fts_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT
|
||||
),
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_ALARM | HWMON_F_FAULT
|
||||
),
|
||||
HWMON_CHANNEL_INFO(pwm,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||
HWMON_PWM_AUTO_CHANNELS_TEMP
|
||||
),
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT
|
||||
),
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Fans */
|
||||
static SENSOR_DEVICE_ATTR_RO(fan1_input, fan_value, 0);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan2_input, fan_value, 1);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan3_input, fan_value, 2);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan4_input, fan_value, 3);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan5_input, fan_value, 4);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan6_input, fan_value, 5);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan7_input, fan_value, 6);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan8_input, fan_value, 7);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_RO(fan1_source, fan_source, 0);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan2_source, fan_source, 1);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan3_source, fan_source, 2);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan4_source, fan_source, 3);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan5_source, fan_source, 4);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan6_source, fan_source, 5);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan7_source, fan_source, 6);
|
||||
static SENSOR_DEVICE_ATTR_RO(fan8_source, fan_source, 7);
|
||||
|
||||
static SENSOR_DEVICE_ATTR_RW(fan1_alarm, fan_alarm, 0);
|
||||
static SENSOR_DEVICE_ATTR_RW(fan2_alarm, fan_alarm, 1);
|
||||
static SENSOR_DEVICE_ATTR_RW(fan3_alarm, fan_alarm, 2);
|
||||
static SENSOR_DEVICE_ATTR_RW(fan4_alarm, fan_alarm, 3);
|
||||
static SENSOR_DEVICE_ATTR_RW(fan5_alarm, fan_alarm, 4);
|
||||
static SENSOR_DEVICE_ATTR_RW(fan6_alarm, fan_alarm, 5);
|
||||
static SENSOR_DEVICE_ATTR_RW(fan7_alarm, fan_alarm, 6);
|
||||
static SENSOR_DEVICE_ATTR_RW(fan8_alarm, fan_alarm, 7);
|
||||
|
||||
static struct attribute *fts_fan_attrs[] = {
|
||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_fan8_input.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_fan1_source.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_source.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_source.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_source.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_source.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_source.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_source.dev_attr.attr,
|
||||
&sensor_dev_attr_fan8_source.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_fan3_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_fan4_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_fan5_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_fan6_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_fan7_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_fan8_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Voltages */
|
||||
static SENSOR_DEVICE_ATTR_RO(in1_input, in_value, 0);
|
||||
static SENSOR_DEVICE_ATTR_RO(in2_input, in_value, 1);
|
||||
static SENSOR_DEVICE_ATTR_RO(in3_input, in_value, 2);
|
||||
static SENSOR_DEVICE_ATTR_RO(in4_input, in_value, 3);
|
||||
static struct attribute *fts_voltage_attrs[] = {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group fts_voltage_attr_group = {
|
||||
.attrs = fts_voltage_attrs
|
||||
};
|
||||
|
||||
static const struct attribute_group fts_temp_attr_group = {
|
||||
.attrs = fts_temp_attrs
|
||||
};
|
||||
|
||||
static const struct attribute_group fts_fan_attr_group = {
|
||||
.attrs = fts_fan_attrs
|
||||
};
|
||||
|
||||
static const struct attribute_group *fts_attr_groups[] = {
|
||||
&fts_voltage_attr_group,
|
||||
&fts_temp_attr_group,
|
||||
&fts_fan_attr_group,
|
||||
NULL
|
||||
static const struct hwmon_chip_info fts_chip_info = {
|
||||
.ops = &fts_ops,
|
||||
.info = fts_info,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -744,13 +613,6 @@ static int fts_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fts_remove(struct i2c_client *client)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(&client->dev);
|
||||
|
||||
watchdog_unregister_device(&data->wdd);
|
||||
}
|
||||
|
||||
static int fts_probe(struct i2c_client *client)
|
||||
{
|
||||
u8 revision;
|
||||
|
|
@ -793,10 +655,8 @@ static int fts_probe(struct i2c_client *client)
|
|||
return err;
|
||||
revision = err;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
|
||||
"ftsteutates",
|
||||
data,
|
||||
fts_attr_groups);
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, "ftsteutates", data,
|
||||
&fts_chip_info, NULL);
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
|
|
@ -819,7 +679,6 @@ static struct i2c_driver fts_driver = {
|
|||
},
|
||||
.id_table = fts_id,
|
||||
.probe_new = fts_probe,
|
||||
.remove = fts_remove,
|
||||
.detect = fts_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
|
|
|||
253
drivers/hwmon/gxp-fan-ctrl.c
Normal file
253
drivers/hwmon/gxp-fan-ctrl.c
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */
|
||||
#define OFS_FAN_FAIL 2 /* Is 2 bytes after base */
|
||||
#define OFS_SEVSTAT 0 /* Is 0 because fn2 base will be set at SEVSTAT */
|
||||
#define POWER_BIT 24
|
||||
|
||||
struct gxp_fan_ctrl_drvdata {
|
||||
void __iomem *base;
|
||||
void __iomem *plreg;
|
||||
void __iomem *fn2;
|
||||
};
|
||||
|
||||
static bool fan_installed(struct device *dev, int fan)
|
||||
{
|
||||
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
|
||||
u8 val;
|
||||
|
||||
val = readb(drvdata->plreg + OFS_FAN_INST);
|
||||
|
||||
return !!(val & BIT(fan));
|
||||
}
|
||||
|
||||
static long fan_failed(struct device *dev, int fan)
|
||||
{
|
||||
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
|
||||
u8 val;
|
||||
|
||||
val = readb(drvdata->plreg + OFS_FAN_FAIL);
|
||||
|
||||
return !!(val & BIT(fan));
|
||||
}
|
||||
|
||||
static long fan_enabled(struct device *dev, int fan)
|
||||
{
|
||||
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* Check the power status as if the platform is off the value
|
||||
* reported for the PWM will be incorrect. Report fan as
|
||||
* disabled.
|
||||
*/
|
||||
val = readl(drvdata->fn2 + OFS_SEVSTAT);
|
||||
|
||||
return !!((val & BIT(POWER_BIT)) && fan_installed(dev, fan));
|
||||
}
|
||||
|
||||
static int gxp_pwm_write(struct device *dev, u32 attr, int channel, long val)
|
||||
{
|
||||
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
if (val > 255 || val < 0)
|
||||
return -EINVAL;
|
||||
writeb(val, drvdata->base + channel);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int gxp_fan_ctrl_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_pwm:
|
||||
return gxp_pwm_write(dev, attr, channel, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int gxp_fan_read(struct device *dev, u32 attr, int channel, long *val)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_fan_enable:
|
||||
*val = fan_enabled(dev, channel);
|
||||
return 0;
|
||||
case hwmon_fan_fault:
|
||||
*val = fan_failed(dev, channel);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int gxp_pwm_read(struct device *dev, u32 attr, int channel, long *val)
|
||||
{
|
||||
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Check the power status of the platform. If the platform is off
|
||||
* the value reported for the PWM will be incorrect. In this case
|
||||
* report a PWM of zero.
|
||||
*/
|
||||
|
||||
reg = readl(drvdata->fn2 + OFS_SEVSTAT);
|
||||
|
||||
if (reg & BIT(POWER_BIT))
|
||||
*val = fan_installed(dev, channel) ? readb(drvdata->base + channel) : 0;
|
||||
else
|
||||
*val = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gxp_fan_ctrl_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
return gxp_fan_read(dev, attr, channel, val);
|
||||
case hwmon_pwm:
|
||||
return gxp_pwm_read(dev, attr, channel, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t gxp_fan_ctrl_is_visible(const void *_data,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
umode_t mode = 0;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_enable:
|
||||
case hwmon_fan_fault:
|
||||
mode = 0444;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_pwm:
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
mode = 0644;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static const struct hwmon_ops gxp_fan_ctrl_ops = {
|
||||
.is_visible = gxp_fan_ctrl_is_visible,
|
||||
.read = gxp_fan_ctrl_read,
|
||||
.write = gxp_fan_ctrl_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *gxp_fan_ctrl_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE),
|
||||
HWMON_CHANNEL_INFO(pwm,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info gxp_fan_ctrl_chip_info = {
|
||||
.ops = &gxp_fan_ctrl_ops,
|
||||
.info = gxp_fan_ctrl_info,
|
||||
|
||||
};
|
||||
|
||||
static int gxp_fan_ctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gxp_fan_ctrl_drvdata *drvdata;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
drvdata = devm_kzalloc(dev, sizeof(struct gxp_fan_ctrl_drvdata),
|
||||
GFP_KERNEL);
|
||||
if (!drvdata)
|
||||
return -ENOMEM;
|
||||
|
||||
drvdata->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(drvdata->base))
|
||||
return dev_err_probe(dev, PTR_ERR(drvdata->base),
|
||||
"failed to map base\n");
|
||||
|
||||
drvdata->plreg = devm_platform_ioremap_resource_byname(pdev,
|
||||
"pl");
|
||||
if (IS_ERR(drvdata->plreg))
|
||||
return dev_err_probe(dev, PTR_ERR(drvdata->plreg),
|
||||
"failed to map plreg\n");
|
||||
|
||||
drvdata->fn2 = devm_platform_ioremap_resource_byname(pdev,
|
||||
"fn2");
|
||||
if (IS_ERR(drvdata->fn2))
|
||||
return dev_err_probe(dev, PTR_ERR(drvdata->fn2),
|
||||
"failed to map fn2\n");
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
|
||||
"hpe_gxp_fan_ctrl",
|
||||
drvdata,
|
||||
&gxp_fan_ctrl_chip_info,
|
||||
NULL);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id gxp_fan_ctrl_of_match[] = {
|
||||
{ .compatible = "hpe,gxp-fan-ctrl", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gxp_fan_ctrl_of_match);
|
||||
|
||||
static struct platform_driver gxp_fan_ctrl_driver = {
|
||||
.probe = gxp_fan_ctrl_probe,
|
||||
.driver = {
|
||||
.name = "gxp-fan-ctrl",
|
||||
.of_match_table = gxp_fan_ctrl_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(gxp_fan_ctrl_driver);
|
||||
|
||||
MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
|
||||
MODULE_DESCRIPTION("HPE GXP fan controller");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -150,7 +150,7 @@ static int hih6130_update_measurements(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* hih6130_show_temperature() - show temperature measurement value in sysfs
|
||||
* hih6130_temperature_show() - show temperature measurement value in sysfs
|
||||
* @dev: device
|
||||
* @attr: device attribute
|
||||
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
|
||||
|
|
@ -172,7 +172,7 @@ static ssize_t hih6130_temperature_show(struct device *dev,
|
|||
}
|
||||
|
||||
/**
|
||||
* hih6130_show_humidity() - show humidity measurement value in sysfs
|
||||
* hih6130_humidity_show() - show humidity measurement value in sysfs
|
||||
* @dev: device
|
||||
* @attr: device attribute
|
||||
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ static void ibmpex_bmc_gone(int iface)
|
|||
|
||||
static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
|
||||
{
|
||||
struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
|
||||
struct ibmpex_bmc_data *data = user_msg_data;
|
||||
|
||||
if (msg->msgid != data->tx_msgid) {
|
||||
dev_err(data->bmc_device,
|
||||
|
|
|
|||
|
|
@ -77,9 +77,11 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
|||
|
||||
channels = devm_iio_channel_get_all(dev);
|
||||
if (IS_ERR(channels)) {
|
||||
if (PTR_ERR(channels) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
return PTR_ERR(channels);
|
||||
ret = PTR_ERR(channels);
|
||||
if (ret == -ENODEV)
|
||||
ret = -EPROBE_DEFER;
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get channels\n");
|
||||
}
|
||||
|
||||
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
|
||||
|
|
|
|||
|
|
@ -340,6 +340,231 @@ static const struct m10bmc_hwmon_board_data n5010bmc_hwmon_bdata = {
|
|||
.hinfo = n5010bmc_hinfo,
|
||||
};
|
||||
|
||||
static const struct m10bmc_sdata n6000bmc_temp_tbl[] = {
|
||||
{ 0x444, 0x448, 0x44c, 0x0, 0x0, 500, "FPGA E-TILE Temperature #1" },
|
||||
{ 0x450, 0x454, 0x458, 0x0, 0x0, 500, "FPGA E-TILE Temperature #2" },
|
||||
{ 0x45c, 0x460, 0x464, 0x0, 0x0, 500, "FPGA E-TILE Temperature #3" },
|
||||
{ 0x468, 0x46c, 0x470, 0x0, 0x0, 500, "FPGA E-TILE Temperature #4" },
|
||||
{ 0x474, 0x478, 0x47c, 0x0, 0x0, 500, "FPGA P-TILE Temperature" },
|
||||
{ 0x484, 0x488, 0x48c, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #1" },
|
||||
{ 0x490, 0x494, 0x498, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #2" },
|
||||
{ 0x49c, 0x4a0, 0x4a4, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #3" },
|
||||
{ 0x4a8, 0x4ac, 0x4b0, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #4" },
|
||||
{ 0x4b4, 0x4b8, 0x4bc, 0x0, 0x0, 500, "FPGA FABRIC Digital Temperature #5" },
|
||||
{ 0x4c0, 0x4c4, 0x4c8, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #1" },
|
||||
{ 0x4cc, 0x4d0, 0x4d4, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #2" },
|
||||
{ 0x4d8, 0x4dc, 0x4e0, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #3" },
|
||||
{ 0x4e4, 0x4e8, 0x4ec, 0x0, 0x0, 500, "FPGA FABRIC Remote Digital Temperature #4" },
|
||||
{ 0x4f0, 0x4f4, 0x4f8, 0x52c, 0x0, 500, "Board Top Near FPGA Temperature" },
|
||||
{ 0x4fc, 0x500, 0x504, 0x52c, 0x0, 500, "Board Bottom Near CVL Temperature" },
|
||||
{ 0x508, 0x50c, 0x510, 0x52c, 0x0, 500, "Board Top East Near VRs Temperature" },
|
||||
{ 0x514, 0x518, 0x51c, 0x52c, 0x0, 500, "Columbiaville Die Temperature" },
|
||||
{ 0x520, 0x524, 0x528, 0x52c, 0x0, 500, "Board Rear Side Temperature" },
|
||||
{ 0x530, 0x534, 0x538, 0x52c, 0x0, 500, "Board Front Side Temperature" },
|
||||
{ 0x53c, 0x540, 0x544, 0x0, 0x0, 500, "QSFP1 Case Temperature" },
|
||||
{ 0x548, 0x54c, 0x550, 0x0, 0x0, 500, "QSFP2 Case Temperature" },
|
||||
{ 0x554, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 0 VR Temperature" },
|
||||
{ 0x560, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 1 VR Temperature" },
|
||||
{ 0x56c, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage Phase 2 VR Temperature" },
|
||||
{ 0x578, 0x0, 0x0, 0x0, 0x0, 500, "FPGA Core Voltage VR Controller Temperature" },
|
||||
{ 0x584, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCCH VR Temperature" },
|
||||
{ 0x590, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCC_1V2 VR Temperature" },
|
||||
{ 0x59c, 0x0, 0x0, 0x0, 0x0, 500, "FPGA VCCH, VCC_1V2 VR Controller Temperature" },
|
||||
{ 0x5a8, 0x0, 0x0, 0x0, 0x0, 500, "3V3 VR Temperature" },
|
||||
{ 0x5b4, 0x0, 0x0, 0x0, 0x0, 500, "CVL Core Voltage VR Temperature" },
|
||||
{ 0x5c4, 0x5c8, 0x5cc, 0x5c0, 0x0, 500, "FPGA P-Tile Temperature [Remote]" },
|
||||
{ 0x5d0, 0x5d4, 0x5d8, 0x5c0, 0x0, 500, "FPGA E-Tile Temperature [Remote]" },
|
||||
{ 0x5dc, 0x5e0, 0x5e4, 0x5c0, 0x0, 500, "FPGA SDM Temperature [Remote]" },
|
||||
{ 0x5e8, 0x5ec, 0x5f0, 0x5c0, 0x0, 500, "FPGA Corner Temperature [Remote]" },
|
||||
};
|
||||
|
||||
static const struct m10bmc_sdata n6000bmc_in_tbl[] = {
|
||||
{ 0x5f4, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Voltage" },
|
||||
{ 0x60c, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 12V Aux Rail Voltage" },
|
||||
{ 0x624, 0x0, 0x0, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Voltage" },
|
||||
{ 0x63c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage Rail Voltage" },
|
||||
{ 0x644, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH Rail Voltage" },
|
||||
{ 0x64c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_1V2 Rail Voltage" },
|
||||
{ 0x654, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH_GXER_1V1, VCCA_1V8 Voltage" },
|
||||
{ 0x664, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCIO_1V2 Voltage" },
|
||||
{ 0x674, 0x0, 0x0, 0x0, 0x0, 1, "CVL Non Core Rails Inlet Voltage" },
|
||||
{ 0x684, 0x0, 0x0, 0x0, 0x0, 1, "MAX10 & Board CLK PWR 3V3 Inlet Voltage" },
|
||||
{ 0x694, 0x0, 0x0, 0x0, 0x0, 1, "CVL Core Voltage Rail Voltage" },
|
||||
{ 0x6ac, 0x0, 0x0, 0x0, 0x0, 1, "Board 3V3 VR Voltage" },
|
||||
{ 0x6b4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP 3V3 Rail Voltage" },
|
||||
{ 0x6c4, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Primary) Supply Rail Voltage" },
|
||||
{ 0x6c8, 0x0, 0x0, 0x0, 0x0, 1, "QSFP (Secondary) Supply Rail Voltage" },
|
||||
{ 0x6cc, 0x0, 0x0, 0x0, 0x0, 1, "VCCCLK_GXER_2V5 Voltage" },
|
||||
{ 0x6d0, 0x0, 0x0, 0x0, 0x0, 1, "AVDDH_1V1_CVL Voltage" },
|
||||
{ 0x6d4, 0x0, 0x0, 0x0, 0x0, 1, "VDDH_1V8_CVL Voltage" },
|
||||
{ 0x6d8, 0x0, 0x0, 0x0, 0x0, 1, "VCCA_PLL Voltage" },
|
||||
{ 0x6e0, 0x0, 0x0, 0x0, 0x0, 1, "VCCRT_GXER_0V9 Voltage" },
|
||||
{ 0x6e8, 0x0, 0x0, 0x0, 0x0, 1, "VCCRT_GXPL_0V9 Voltage" },
|
||||
{ 0x6f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCH_GXPL_1V8 Voltage" },
|
||||
{ 0x6f4, 0x0, 0x0, 0x0, 0x0, 1, "VCCPT_1V8 Voltage" },
|
||||
{ 0x6fc, 0x0, 0x0, 0x0, 0x0, 1, "VCC_3V3_M10 Voltage" },
|
||||
{ 0x700, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V8_M10 Voltage" },
|
||||
{ 0x704, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V2_EMIF1_2_3 Voltage" },
|
||||
{ 0x70c, 0x0, 0x0, 0x0, 0x0, 1, "VCC_1V2_EMIF4_5 Voltage" },
|
||||
{ 0x714, 0x0, 0x0, 0x0, 0x0, 1, "VCCA_1V8 Voltage" },
|
||||
{ 0x718, 0x0, 0x0, 0x0, 0x0, 1, "VCCH_GXER_1V1 Voltage" },
|
||||
{ 0x71c, 0x0, 0x0, 0x0, 0x0, 1, "AVDD_ETH_0V9_CVL Voltage" },
|
||||
{ 0x720, 0x0, 0x0, 0x0, 0x0, 1, "AVDD_PCIE_0V9_CVL Voltage" },
|
||||
};
|
||||
|
||||
static const struct m10bmc_sdata n6000bmc_curr_tbl[] = {
|
||||
{ 0x600, 0x604, 0x608, 0x0, 0x0, 1, "Inlet 12V PCIe Rail Current" },
|
||||
{ 0x618, 0x61c, 0x620, 0x0, 0x0, 1, "Inlet 12V Aux Rail Current" },
|
||||
{ 0x630, 0x634, 0x638, 0x0, 0x0, 1, "Inlet 3V3 PCIe Rail Current" },
|
||||
{ 0x640, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage Rail Current" },
|
||||
{ 0x648, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCCH Rail Current" },
|
||||
{ 0x650, 0x0, 0x0, 0x0, 0x0, 1, "FPGA VCC_1V2 Rail Current" },
|
||||
{ 0x658, 0x65c, 0x660, 0x0, 0x0, 1, "FPGA VCCH_GXER_1V1, VCCA_1V8 Current" },
|
||||
{ 0x668, 0x66c, 0x670, 0x0, 0x0, 1, "FPGA VCCIO_1V2 Current" },
|
||||
{ 0x678, 0x67c, 0x680, 0x0, 0x0, 1, "CVL Non Core Rails Inlet Current" },
|
||||
{ 0x688, 0x68c, 0x690, 0x0, 0x0, 1, "MAX10 & Board CLK PWR 3V3 Inlet Current" },
|
||||
{ 0x698, 0x0, 0x0, 0x0, 0x0, 1, "CVL Core Voltage Rail Current" },
|
||||
{ 0x6b0, 0x0, 0x0, 0x0, 0x0, 1, "Board 3V3 VR Current" },
|
||||
{ 0x6b8, 0x6bc, 0x6c0, 0x0, 0x0, 1, "QSFP 3V3 Rail Current" },
|
||||
};
|
||||
|
||||
static const struct m10bmc_sdata n6000bmc_power_tbl[] = {
|
||||
{ 0x724, 0x0, 0x0, 0x0, 0x0, 1, "Board Power" },
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *n6000bmc_hinfo[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL),
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL),
|
||||
HWMON_CHANNEL_INFO(curr,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_LABEL,
|
||||
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_CRIT |
|
||||
HWMON_C_LABEL),
|
||||
HWMON_CHANNEL_INFO(power,
|
||||
HWMON_P_INPUT | HWMON_P_LABEL),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct m10bmc_hwmon_board_data n6000bmc_hwmon_bdata = {
|
||||
.tables = {
|
||||
[hwmon_temp] = n6000bmc_temp_tbl,
|
||||
[hwmon_in] = n6000bmc_in_tbl,
|
||||
[hwmon_curr] = n6000bmc_curr_tbl,
|
||||
[hwmon_power] = n6000bmc_power_tbl,
|
||||
},
|
||||
|
||||
.hinfo = n6000bmc_hinfo,
|
||||
};
|
||||
|
||||
static umode_t
|
||||
m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
|
|
@ -549,6 +774,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = {
|
|||
.name = "n5010bmc-hwmon",
|
||||
.driver_data = (unsigned long)&n5010bmc_hwmon_bdata,
|
||||
},
|
||||
{
|
||||
.name = "n6000bmc-hwmon",
|
||||
.driver_data = (unsigned long)&n6000bmc_hwmon_bdata,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
* IT8786E Super I/O chip w/LPC interface
|
||||
* IT8790E Super I/O chip w/LPC interface
|
||||
* IT8792E Super I/O chip w/LPC interface
|
||||
* IT87952E Super I/O chip w/LPC interface
|
||||
* Sis950 A clone of the IT8705F
|
||||
*
|
||||
* Copyright (C) 2001 Chris Gauthron
|
||||
|
|
@ -63,15 +64,7 @@
|
|||
|
||||
enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
|
||||
it8771, it8772, it8781, it8782, it8783, it8786, it8790,
|
||||
it8792, it8603, it8620, it8622, it8628 };
|
||||
|
||||
static unsigned short force_id;
|
||||
module_param(force_id, ushort, 0);
|
||||
MODULE_PARM_DESC(force_id, "Override the detected device ID");
|
||||
|
||||
static bool ignore_resource_conflict;
|
||||
module_param(ignore_resource_conflict, bool, 0);
|
||||
MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
|
||||
it8792, it8603, it8620, it8622, it8628, it87952 };
|
||||
|
||||
static struct platform_device *it87_pdev[2];
|
||||
|
||||
|
|
@ -87,6 +80,14 @@ static struct platform_device *it87_pdev[2];
|
|||
#define DEVID 0x20 /* Register: Device ID */
|
||||
#define DEVREV 0x22 /* Register: Device Revision */
|
||||
|
||||
static inline void __superio_enter(int ioreg)
|
||||
{
|
||||
outb(0x87, ioreg);
|
||||
outb(0x01, ioreg);
|
||||
outb(0x55, ioreg);
|
||||
outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
|
||||
}
|
||||
|
||||
static inline int superio_inb(int ioreg, int reg)
|
||||
{
|
||||
outb(reg, ioreg);
|
||||
|
|
@ -124,17 +125,16 @@ static inline int superio_enter(int ioreg)
|
|||
if (!request_muxed_region(ioreg, 2, DRVNAME))
|
||||
return -EBUSY;
|
||||
|
||||
outb(0x87, ioreg);
|
||||
outb(0x01, ioreg);
|
||||
outb(0x55, ioreg);
|
||||
outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
|
||||
__superio_enter(ioreg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void superio_exit(int ioreg)
|
||||
static inline void superio_exit(int ioreg, bool noexit)
|
||||
{
|
||||
outb(0x02, ioreg);
|
||||
outb(0x02, ioreg + 1);
|
||||
if (!noexit) {
|
||||
outb(0x02, ioreg);
|
||||
outb(0x02, ioreg + 1);
|
||||
}
|
||||
release_region(ioreg, 2);
|
||||
}
|
||||
|
||||
|
|
@ -161,6 +161,7 @@ static inline void superio_exit(int ioreg)
|
|||
#define IT8622E_DEVID 0x8622
|
||||
#define IT8623E_DEVID 0x8623
|
||||
#define IT8628E_DEVID 0x8628
|
||||
#define IT87952E_DEVID 0x8695
|
||||
#define IT87_ACT_REG 0x30
|
||||
#define IT87_BASE_REG 0x60
|
||||
|
||||
|
|
@ -176,6 +177,13 @@ static inline void superio_exit(int ioreg)
|
|||
#define IT87_SIO_VID_REG 0xfc /* VID value */
|
||||
#define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */
|
||||
|
||||
/* Force chip IDs to specified values. Should only be used for testing */
|
||||
static unsigned short force_id[2];
|
||||
static unsigned int force_id_cnt;
|
||||
|
||||
/* ACPI resource conflicts are ignored if this parameter is set to 1 */
|
||||
static bool ignore_resource_conflict;
|
||||
|
||||
/* Update battery voltage after every reading if true */
|
||||
static bool update_vbat;
|
||||
|
||||
|
|
@ -272,7 +280,7 @@ static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
|
|||
|
||||
struct it87_devices {
|
||||
const char *name;
|
||||
const char * const suffix;
|
||||
const char * const model;
|
||||
u32 features;
|
||||
u8 peci_mask;
|
||||
u8 old_peci_mask;
|
||||
|
|
@ -297,28 +305,35 @@ struct it87_devices {
|
|||
#define FEAT_PWM_FREQ2 BIT(16) /* Separate pwm freq 2 */
|
||||
#define FEAT_SIX_TEMP BIT(17) /* Up to 6 temp sensors */
|
||||
#define FEAT_VIN3_5V BIT(18) /* VIN3 connected to +5V */
|
||||
/*
|
||||
* Disabling configuration mode on some chips can result in system
|
||||
* hang-ups and access failures to the Super-IO chip at the
|
||||
* second SIO address. Never exit configuration mode on these
|
||||
* chips to avoid the problem.
|
||||
*/
|
||||
#define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */
|
||||
|
||||
static const struct it87_devices it87_devices[] = {
|
||||
[it87] = {
|
||||
.name = "it87",
|
||||
.suffix = "F",
|
||||
.model = "IT87F",
|
||||
.features = FEAT_OLD_AUTOPWM, /* may need to overwrite */
|
||||
},
|
||||
[it8712] = {
|
||||
.name = "it8712",
|
||||
.suffix = "F",
|
||||
.model = "IT8712F",
|
||||
.features = FEAT_OLD_AUTOPWM | FEAT_VID,
|
||||
/* may need to overwrite */
|
||||
},
|
||||
[it8716] = {
|
||||
.name = "it8716",
|
||||
.suffix = "F",
|
||||
.model = "IT8716F",
|
||||
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
|
||||
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2,
|
||||
},
|
||||
[it8718] = {
|
||||
.name = "it8718",
|
||||
.suffix = "F",
|
||||
.model = "IT8718F",
|
||||
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
|
||||
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
|
||||
| FEAT_PWM_FREQ2,
|
||||
|
|
@ -326,7 +341,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8720] = {
|
||||
.name = "it8720",
|
||||
.suffix = "F",
|
||||
.model = "IT8720F",
|
||||
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
|
||||
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
|
||||
| FEAT_PWM_FREQ2,
|
||||
|
|
@ -334,7 +349,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8721] = {
|
||||
.name = "it8721",
|
||||
.suffix = "F",
|
||||
.model = "IT8721F",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
|
||||
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
|
||||
|
|
@ -344,7 +359,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8728] = {
|
||||
.name = "it8728",
|
||||
.suffix = "F",
|
||||
.model = "IT8728F",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
|
||||
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
|
||||
|
|
@ -352,7 +367,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8732] = {
|
||||
.name = "it8732",
|
||||
.suffix = "F",
|
||||
.model = "IT8732F",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
|
||||
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
|
||||
|
|
@ -361,7 +376,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8771] = {
|
||||
.name = "it8771",
|
||||
.suffix = "E",
|
||||
.model = "IT8771E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
|
||||
| FEAT_PWM_FREQ2,
|
||||
|
|
@ -373,7 +388,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8772] = {
|
||||
.name = "it8772",
|
||||
.suffix = "E",
|
||||
.model = "IT8772E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
|
||||
| FEAT_PWM_FREQ2,
|
||||
|
|
@ -385,28 +400,28 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8781] = {
|
||||
.name = "it8781",
|
||||
.suffix = "F",
|
||||
.model = "IT8781F",
|
||||
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
|
||||
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
|
||||
.old_peci_mask = 0x4,
|
||||
},
|
||||
[it8782] = {
|
||||
.name = "it8782",
|
||||
.suffix = "F",
|
||||
.model = "IT8782F",
|
||||
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
|
||||
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
|
||||
.old_peci_mask = 0x4,
|
||||
},
|
||||
[it8783] = {
|
||||
.name = "it8783",
|
||||
.suffix = "E/F",
|
||||
.model = "IT8783E/F",
|
||||
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
|
||||
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
|
||||
.old_peci_mask = 0x4,
|
||||
},
|
||||
[it8786] = {
|
||||
.name = "it8786",
|
||||
.suffix = "E",
|
||||
.model = "IT8786E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
|
||||
| FEAT_PWM_FREQ2,
|
||||
|
|
@ -414,24 +429,24 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8790] = {
|
||||
.name = "it8790",
|
||||
.suffix = "E",
|
||||
.model = "IT8790E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
|
||||
| FEAT_PWM_FREQ2,
|
||||
| FEAT_PWM_FREQ2 | FEAT_CONF_NOEXIT,
|
||||
.peci_mask = 0x07,
|
||||
},
|
||||
[it8792] = {
|
||||
.name = "it8792",
|
||||
.suffix = "E",
|
||||
.model = "IT8792E/IT8795E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
|
||||
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
|
||||
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
|
||||
.peci_mask = 0x07,
|
||||
.old_peci_mask = 0x02, /* Actually reports PCH */
|
||||
},
|
||||
[it8603] = {
|
||||
.name = "it8603",
|
||||
.suffix = "E",
|
||||
.model = "IT8603E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
|
||||
| FEAT_AVCC3 | FEAT_PWM_FREQ2,
|
||||
|
|
@ -439,7 +454,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8620] = {
|
||||
.name = "it8620",
|
||||
.suffix = "E",
|
||||
.model = "IT8620E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
|
||||
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
|
||||
|
|
@ -448,7 +463,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8622] = {
|
||||
.name = "it8622",
|
||||
.suffix = "E",
|
||||
.model = "IT8622E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
|
||||
| FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
|
||||
|
|
@ -457,13 +472,22 @@ static const struct it87_devices it87_devices[] = {
|
|||
},
|
||||
[it8628] = {
|
||||
.name = "it8628",
|
||||
.suffix = "E",
|
||||
.model = "IT8628E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
|
||||
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
|
||||
| FEAT_SIX_TEMP | FEAT_VIN3_5V,
|
||||
.peci_mask = 0x07,
|
||||
},
|
||||
[it87952] = {
|
||||
.name = "it87952",
|
||||
.model = "IT87952E",
|
||||
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
|
||||
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
|
||||
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
|
||||
.peci_mask = 0x07,
|
||||
.old_peci_mask = 0x02, /* Actually reports PCH */
|
||||
},
|
||||
};
|
||||
|
||||
#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS)
|
||||
|
|
@ -490,6 +514,7 @@ static const struct it87_devices it87_devices[] = {
|
|||
#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)
|
||||
#define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP)
|
||||
#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V)
|
||||
#define has_conf_noexit(data) ((data)->features & FEAT_CONF_NOEXIT)
|
||||
|
||||
struct it87_sio_data {
|
||||
int sioaddr;
|
||||
|
|
@ -2397,11 +2422,11 @@ static const struct attribute_group it87_group_auto_pwm = {
|
|||
|
||||
/* SuperIO detection - will change isa_address if a chip is found */
|
||||
static int __init it87_find(int sioaddr, unsigned short *address,
|
||||
struct it87_sio_data *sio_data)
|
||||
struct it87_sio_data *sio_data, int chip_cnt)
|
||||
{
|
||||
int err;
|
||||
u16 chip_type;
|
||||
const struct it87_devices *config;
|
||||
const struct it87_devices *config = NULL;
|
||||
|
||||
err = superio_enter(sioaddr);
|
||||
if (err)
|
||||
|
|
@ -2413,8 +2438,12 @@ static int __init it87_find(int sioaddr, unsigned short *address,
|
|||
if (chip_type == 0xffff)
|
||||
goto exit;
|
||||
|
||||
if (force_id)
|
||||
chip_type = force_id;
|
||||
if (force_id_cnt == 1) {
|
||||
/* If only one value given use for all chips */
|
||||
if (force_id[0])
|
||||
chip_type = force_id[0];
|
||||
} else if (force_id[chip_cnt])
|
||||
chip_type = force_id[chip_cnt];
|
||||
|
||||
switch (chip_type) {
|
||||
case IT8705F_DEVID:
|
||||
|
|
@ -2479,6 +2508,9 @@ static int __init it87_find(int sioaddr, unsigned short *address,
|
|||
case IT8628E_DEVID:
|
||||
sio_data->type = it8628;
|
||||
break;
|
||||
case IT87952E_DEVID:
|
||||
sio_data->type = it87952;
|
||||
break;
|
||||
case 0xffff: /* No device at all */
|
||||
goto exit;
|
||||
default:
|
||||
|
|
@ -2486,27 +2518,29 @@ static int __init it87_find(int sioaddr, unsigned short *address,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
config = &it87_devices[sio_data->type];
|
||||
|
||||
superio_select(sioaddr, PME);
|
||||
if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
|
||||
pr_info("Device not activated, skipping\n");
|
||||
pr_info("Device (chip %s ioreg 0x%x) not activated, skipping\n",
|
||||
config->model, sioaddr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1);
|
||||
if (*address == 0) {
|
||||
pr_info("Base address not set, skipping\n");
|
||||
pr_info("Base address not set (chip %s ioreg 0x%x), skipping\n",
|
||||
config->model, sioaddr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
sio_data->sioaddr = sioaddr;
|
||||
sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f;
|
||||
pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type,
|
||||
it87_devices[sio_data->type].suffix,
|
||||
pr_info("Found %s chip at 0x%x, revision %d\n",
|
||||
it87_devices[sio_data->type].model,
|
||||
*address, sio_data->revision);
|
||||
|
||||
config = &it87_devices[sio_data->type];
|
||||
|
||||
/* in7 (VSB or VCCH5V) is always internal on some chips */
|
||||
if (has_in7_internal(config))
|
||||
sio_data->internal |= BIT(1);
|
||||
|
|
@ -2824,7 +2858,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
|
|||
sio_data->skip_pwm |= dmi_data->skip_pwm;
|
||||
|
||||
exit:
|
||||
superio_exit(sioaddr);
|
||||
superio_exit(sioaddr, config ? has_conf_noexit(config) : false);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -3210,7 +3244,7 @@ static void it87_resume_sio(struct platform_device *pdev)
|
|||
reg2c);
|
||||
}
|
||||
|
||||
superio_exit(data->sioaddr);
|
||||
superio_exit(data->sioaddr, has_conf_noexit(data));
|
||||
}
|
||||
|
||||
static int it87_resume(struct device *dev)
|
||||
|
|
@ -3310,6 +3344,27 @@ static int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip
|
||||
* (IT8792E) needs to be in configuration mode before accessing the first
|
||||
* due to a bug in IT8792E which otherwise results in LPC bus access errors.
|
||||
* This needs to be done before accessing the first Super-IO chip since
|
||||
* the second chip may have been accessed prior to loading this driver.
|
||||
*
|
||||
* The problem is also reported to affect IT8795E, which is used on X299 boards
|
||||
* and has the same chip ID as IT8792E (0x8733). It also appears to affect
|
||||
* systems with IT8790E, which is used on some Z97X-Gaming boards as well as
|
||||
* Z87X-OC.
|
||||
* DMI entries for those systems will be added as they become available and
|
||||
* as the problem is confirmed to affect those boards.
|
||||
*/
|
||||
static int it87_sio_force(const struct dmi_system_id *dmi_entry)
|
||||
{
|
||||
__superio_enter(REG_4E);
|
||||
|
||||
return it87_dmi_cb(dmi_entry);
|
||||
};
|
||||
|
||||
/*
|
||||
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
|
||||
* connected to a fan, but to something else. One user
|
||||
|
|
@ -3332,7 +3387,34 @@ static struct it87_dmi_data nvidia_fn68pt = {
|
|||
.driver_data = data, \
|
||||
}
|
||||
|
||||
#define IT87_DMI_MATCH_GBT(name, cb, data) \
|
||||
IT87_DMI_MATCH_VND("Gigabyte Technology Co., Ltd.", name, cb, data)
|
||||
|
||||
static const struct dmi_system_id it87_dmi_table[] __initconst = {
|
||||
IT87_DMI_MATCH_GBT("AB350", it87_sio_force, NULL),
|
||||
/* ? + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("AX370", it87_sio_force, NULL),
|
||||
/* ? + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("Z97X-Gaming G1", it87_sio_force, NULL),
|
||||
/* ? + IT8790E */
|
||||
IT87_DMI_MATCH_GBT("TRX40 AORUS XTREME", it87_sio_force, NULL),
|
||||
/* IT8688E + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("Z390 AORUS ULTRA-CF", it87_sio_force, NULL),
|
||||
/* IT8688E + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("B550 AORUS PRO AC", it87_sio_force, NULL),
|
||||
/* IT8688E + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("X570 AORUS MASTER", it87_sio_force, NULL),
|
||||
/* IT8688E + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("X570 AORUS PRO", it87_sio_force, NULL),
|
||||
/* IT8688E + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("X570 AORUS PRO WIFI", it87_sio_force, NULL),
|
||||
/* IT8688E + IT8792E/IT8795E */
|
||||
IT87_DMI_MATCH_GBT("X570S AERO G", it87_sio_force, NULL),
|
||||
/* IT8689E + IT87952E */
|
||||
IT87_DMI_MATCH_GBT("Z690 AORUS PRO DDR4", it87_sio_force, NULL),
|
||||
/* IT8689E + IT87952E */
|
||||
IT87_DMI_MATCH_GBT("Z690 AORUS PRO", it87_sio_force, NULL),
|
||||
/* IT8689E + IT87952E */
|
||||
IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
|
||||
{ }
|
||||
|
||||
|
|
@ -3356,7 +3438,7 @@ static int __init sm_it87_init(void)
|
|||
for (i = 0; i < ARRAY_SIZE(sioaddr); i++) {
|
||||
memset(&sio_data, 0, sizeof(struct it87_sio_data));
|
||||
isa_address[i] = 0;
|
||||
err = it87_find(sioaddr[i], &isa_address[i], &sio_data);
|
||||
err = it87_find(sioaddr[i], &isa_address[i], &sio_data, i);
|
||||
if (err || isa_address[i] == 0)
|
||||
continue;
|
||||
/*
|
||||
|
|
@ -3404,11 +3486,20 @@ static void __exit sm_it87_exit(void)
|
|||
|
||||
MODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>");
|
||||
MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
|
||||
|
||||
module_param_array(force_id, ushort, &force_id_cnt, 0);
|
||||
MODULE_PARM_DESC(force_id, "Override one or more detected device ID(s)");
|
||||
|
||||
module_param(ignore_resource_conflict, bool, 0);
|
||||
MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
|
||||
|
||||
module_param(update_vbat, bool, 0);
|
||||
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
|
||||
|
||||
module_param(fix_pwm_polarity, bool, 0);
|
||||
MODULE_PARM_DESC(fix_pwm_polarity,
|
||||
"Force PWM polarity to active high (DANGEROUS)");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sm_it87_init);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,22 @@
|
|||
#define CONTROL_MULT_SELECT (1 << 0)
|
||||
#define CONTROL_TEST_MODE (1 << 4)
|
||||
|
||||
static const struct of_device_id __maybe_unused ltc2945_of_match[] = {
|
||||
{ .compatible = "adi,ltc2945" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2945_of_match);
|
||||
|
||||
/**
|
||||
* struct ltc2945_data - LTC2945 device data
|
||||
* @regmap: regmap device
|
||||
* @shunt_resistor: shunt resistor value in micro ohms (1000 by default)
|
||||
*/
|
||||
struct ltc2945_data {
|
||||
struct regmap *regmap;
|
||||
u32 shunt_resistor;
|
||||
};
|
||||
|
||||
static inline bool is_power_reg(u8 reg)
|
||||
{
|
||||
return reg < LTC2945_SENSE_H;
|
||||
|
|
@ -66,7 +82,9 @@ static inline bool is_power_reg(u8 reg)
|
|||
/* Return the value from the given register in uW, mV, or mA */
|
||||
static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
struct ltc2945_data *data = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = data->regmap;
|
||||
u32 shunt_resistor = data->shunt_resistor;
|
||||
unsigned int control;
|
||||
u8 buf[3];
|
||||
long long val;
|
||||
|
|
@ -78,10 +96,10 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
|
|||
return ret;
|
||||
|
||||
if (is_power_reg(reg)) {
|
||||
/* power */
|
||||
/* 24-bit power */
|
||||
val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
|
||||
} else {
|
||||
/* current, voltage */
|
||||
/* 12-bit current, voltage */
|
||||
val = (buf[0] << 4) + (buf[1] >> 4);
|
||||
}
|
||||
|
||||
|
|
@ -92,9 +110,7 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
|
|||
case LTC2945_MAX_POWER_THRES_H:
|
||||
case LTC2945_MIN_POWER_THRES_H:
|
||||
/*
|
||||
* Convert to uW by assuming current is measured with
|
||||
* an 1mOhm sense resistor, similar to current
|
||||
* measurements.
|
||||
* Convert to uW
|
||||
* Control register bit 0 selects if voltage at SENSE+/VDD
|
||||
* or voltage at ADIN is used to measure power.
|
||||
*/
|
||||
|
|
@ -108,6 +124,14 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
|
|||
/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
|
||||
val = (val * 25LL) >> 1;
|
||||
}
|
||||
val *= 1000;
|
||||
/* Overflow check: Assuming max 24-bit power, val is at most 53 bits right now. */
|
||||
val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor);
|
||||
/*
|
||||
* Overflow check: After division, depending on shunt resistor,
|
||||
* val can still be > 32 bits so returning long long makes sense
|
||||
*/
|
||||
|
||||
break;
|
||||
case LTC2945_VIN_H:
|
||||
case LTC2945_MAX_VIN_H:
|
||||
|
|
@ -130,14 +154,11 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
|
|||
case LTC2945_MIN_SENSE_H:
|
||||
case LTC2945_MAX_SENSE_THRES_H:
|
||||
case LTC2945_MIN_SENSE_THRES_H:
|
||||
/*
|
||||
* 25 uV resolution. Convert to current as measured with
|
||||
* an 1 mOhm sense resistor, in mA. If a different sense
|
||||
* resistor is installed, calculate the actual current by
|
||||
* dividing the reported current by the sense resistor value
|
||||
* in mOhm.
|
||||
*/
|
||||
val *= 25;
|
||||
/* 25 uV resolution. Convert to mA. */
|
||||
val *= 25 * 1000;
|
||||
/* Overflow check: Assuming max 12-bit sense, val is at most 27 bits right now */
|
||||
val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor);
|
||||
/* Overflow check: After division, <= 27 bits */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -145,13 +166,18 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
|
|||
return val;
|
||||
}
|
||||
|
||||
static int ltc2945_val_to_reg(struct device *dev, u8 reg,
|
||||
unsigned long val)
|
||||
static long long ltc2945_val_to_reg(struct device *dev, u8 reg,
|
||||
unsigned long long val)
|
||||
{
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
struct ltc2945_data *data = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = data->regmap;
|
||||
u32 shunt_resistor = data->shunt_resistor;
|
||||
unsigned int control;
|
||||
int ret;
|
||||
|
||||
/* Ensure we don't overflow */
|
||||
val = clamp_val(val, 0, U32_MAX);
|
||||
|
||||
switch (reg) {
|
||||
case LTC2945_POWER_H:
|
||||
case LTC2945_MAX_POWER_H:
|
||||
|
|
@ -159,9 +185,6 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
|
|||
case LTC2945_MAX_POWER_THRES_H:
|
||||
case LTC2945_MIN_POWER_THRES_H:
|
||||
/*
|
||||
* Convert to register value by assuming current is measured
|
||||
* with an 1mOhm sense resistor, similar to current
|
||||
* measurements.
|
||||
* Control register bit 0 selects if voltage at SENSE+/VDD
|
||||
* or voltage at ADIN is used to measure power, which in turn
|
||||
* determines register calculations.
|
||||
|
|
@ -171,14 +194,16 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
|
|||
return ret;
|
||||
if (control & CONTROL_MULT_SELECT) {
|
||||
/* 25 mV * 25 uV = 0.625 uV resolution. */
|
||||
val = DIV_ROUND_CLOSEST(val, 625);
|
||||
val *= shunt_resistor;
|
||||
/* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */
|
||||
val = DIV_ROUND_CLOSEST_ULL(val, 625 * 1000);
|
||||
/* Overflow check: val is now <= 44 bits */
|
||||
} else {
|
||||
/*
|
||||
* 0.5 mV * 25 uV = 0.0125 uV resolution.
|
||||
* Divide first to avoid overflow;
|
||||
* accept loss of accuracy.
|
||||
*/
|
||||
val = DIV_ROUND_CLOSEST(val, 25) * 2;
|
||||
/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
|
||||
val *= shunt_resistor;
|
||||
/* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */
|
||||
val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000) * 2;
|
||||
/* Overflow check: val is now <= 51 bits */
|
||||
}
|
||||
break;
|
||||
case LTC2945_VIN_H:
|
||||
|
|
@ -187,7 +212,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
|
|||
case LTC2945_MAX_VIN_THRES_H:
|
||||
case LTC2945_MIN_VIN_THRES_H:
|
||||
/* 25 mV resolution. */
|
||||
val /= 25;
|
||||
val = DIV_ROUND_CLOSEST_ULL(val, 25);
|
||||
break;
|
||||
case LTC2945_ADIN_H:
|
||||
case LTC2945_MAX_ADIN_H:
|
||||
|
|
@ -202,14 +227,11 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
|
|||
case LTC2945_MIN_SENSE_H:
|
||||
case LTC2945_MAX_SENSE_THRES_H:
|
||||
case LTC2945_MIN_SENSE_THRES_H:
|
||||
/*
|
||||
* 25 uV resolution. Convert to current as measured with
|
||||
* an 1 mOhm sense resistor, in mA. If a different sense
|
||||
* resistor is installed, calculate the actual current by
|
||||
* dividing the reported current by the sense resistor value
|
||||
* in mOhm.
|
||||
*/
|
||||
val = DIV_ROUND_CLOSEST(val, 25);
|
||||
/* 25 uV resolution. Convert to mA. */
|
||||
val *= shunt_resistor;
|
||||
/* Overflow check: Assuming 32-bit val and 32-bit shunt resistor, val is 64bits */
|
||||
val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000);
|
||||
/* Overflow check: val is now <= 50 bits */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
|
@ -234,20 +256,23 @@ static ssize_t ltc2945_value_store(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
struct ltc2945_data *data = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = data->regmap;
|
||||
u8 reg = attr->index;
|
||||
unsigned long val;
|
||||
unsigned int val;
|
||||
u8 regbuf[3];
|
||||
int num_regs;
|
||||
int regval;
|
||||
long long regval;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
ret = kstrtouint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* convert to register value, then clamp and write result */
|
||||
regval = ltc2945_val_to_reg(dev, reg, val);
|
||||
if (regval < 0)
|
||||
return regval;
|
||||
if (is_power_reg(reg)) {
|
||||
regval = clamp_val(regval, 0, 0xffffff);
|
||||
regbuf[0] = regval >> 16;
|
||||
|
|
@ -269,7 +294,8 @@ static ssize_t ltc2945_history_store(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
struct ltc2945_data *data = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = data->regmap;
|
||||
u8 reg = attr->index;
|
||||
int num_regs = is_power_reg(reg) ? 3 : 2;
|
||||
u8 buf_min[3] = { 0xff, 0xff, 0xff };
|
||||
|
|
@ -321,7 +347,8 @@ static ssize_t ltc2945_bool_show(struct device *dev,
|
|||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct regmap *regmap = dev_get_drvdata(dev);
|
||||
struct ltc2945_data *data = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = data->regmap;
|
||||
unsigned int fault;
|
||||
int ret;
|
||||
|
||||
|
|
@ -450,6 +477,12 @@ static int ltc2945_probe(struct i2c_client *client)
|
|||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct regmap *regmap;
|
||||
struct ltc2945_data *data;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(dev, data);
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, <c2945_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
|
|
@ -457,11 +490,19 @@ static int ltc2945_probe(struct i2c_client *client)
|
|||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
data->regmap = regmap;
|
||||
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
|
||||
&data->shunt_resistor))
|
||||
data->shunt_resistor = 1000;
|
||||
|
||||
if (data->shunt_resistor == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Clear faults */
|
||||
regmap_write(regmap, LTC2945_FAULT, 0x00);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
regmap,
|
||||
data,
|
||||
ltc2945_groups);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
|
@ -475,8 +516,9 @@ MODULE_DEVICE_TABLE(i2c, ltc2945_id);
|
|||
|
||||
static struct i2c_driver ltc2945_driver = {
|
||||
.driver = {
|
||||
.name = "ltc2945",
|
||||
},
|
||||
.name = "ltc2945",
|
||||
.of_match_table = of_match_ptr(ltc2945_of_match),
|
||||
},
|
||||
.probe_new = ltc2945_probe,
|
||||
.id_table = ltc2945_id,
|
||||
};
|
||||
|
|
|
|||
263
drivers/hwmon/mc34vr500.c
Normal file
263
drivers/hwmon/mc34vr500.c
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* An hwmon driver for the NXP MC34VR500 PMIC
|
||||
*
|
||||
* Author: Mario Kicherer <dev@kicherer.org>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MC34VR500_I2C_ADDR 0x08
|
||||
#define MC34VR500_DEVICEID_VALUE 0x14
|
||||
|
||||
/* INTSENSE0 */
|
||||
#define ENS_BIT BIT(0)
|
||||
#define LOWVINS_BIT BIT(1)
|
||||
#define THERM110S_BIT BIT(2)
|
||||
#define THERM120S_BIT BIT(3)
|
||||
#define THERM125S_BIT BIT(4)
|
||||
#define THERM130S_BIT BIT(5)
|
||||
|
||||
#define MC34VR500_DEVICEID 0x00
|
||||
|
||||
#define MC34VR500_SILICONREVID 0x03
|
||||
#define MC34VR500_FABID 0x04
|
||||
#define MC34VR500_INTSTAT0 0x05
|
||||
#define MC34VR500_INTMASK0 0x06
|
||||
#define MC34VR500_INTSENSE0 0x07
|
||||
|
||||
struct mc34vr500_data {
|
||||
struct device *hwmon_dev;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static irqreturn_t mc34vr500_process_interrupt(int irq, void *userdata)
|
||||
{
|
||||
struct mc34vr500_data *data = (struct mc34vr500_data *)userdata;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, MC34VR500_INTSTAT0, ®);
|
||||
if (ret < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (reg) {
|
||||
if (reg & LOWVINS_BIT)
|
||||
hwmon_notify_event(data->hwmon_dev, hwmon_in,
|
||||
hwmon_in_min_alarm, 0);
|
||||
|
||||
if (reg & THERM110S_BIT)
|
||||
hwmon_notify_event(data->hwmon_dev, hwmon_temp,
|
||||
hwmon_temp_max_alarm, 0);
|
||||
|
||||
if (reg & THERM120S_BIT)
|
||||
hwmon_notify_event(data->hwmon_dev, hwmon_temp,
|
||||
hwmon_temp_crit_alarm, 0);
|
||||
|
||||
if (reg & THERM130S_BIT)
|
||||
hwmon_notify_event(data->hwmon_dev, hwmon_temp,
|
||||
hwmon_temp_emergency_alarm, 0);
|
||||
|
||||
/* write 1 to clear */
|
||||
regmap_write(data->regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
|
||||
THERM110S_BIT | THERM120S_BIT | THERM130S_BIT);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static umode_t mc34vr500_is_visible(const void *data,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_in_min_alarm:
|
||||
case hwmon_temp_max_alarm:
|
||||
case hwmon_temp_crit_alarm:
|
||||
case hwmon_temp_emergency_alarm:
|
||||
return 0444;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mc34vr500_alarm_read(struct mc34vr500_data *data, int index,
|
||||
long *val)
|
||||
{
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, MC34VR500_INTSENSE0, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = !!(reg & index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mc34vr500_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct mc34vr500_data *data = dev_get_drvdata(dev);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_in:
|
||||
switch (attr) {
|
||||
case hwmon_in_min_alarm:
|
||||
return mc34vr500_alarm_read(data, LOWVINS_BIT, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_max_alarm:
|
||||
return mc34vr500_alarm_read(data, THERM110S_BIT, val);
|
||||
case hwmon_temp_crit_alarm:
|
||||
return mc34vr500_alarm_read(data, THERM120S_BIT, val);
|
||||
case hwmon_temp_emergency_alarm:
|
||||
return mc34vr500_alarm_read(data, THERM130S_BIT, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *mc34vr500_info[] = {
|
||||
HWMON_CHANNEL_INFO(in, HWMON_I_MIN_ALARM),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM
|
||||
| HWMON_T_EMERGENCY_ALARM),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct hwmon_ops mc34vr500_hwmon_ops = {
|
||||
.is_visible = mc34vr500_is_visible,
|
||||
.read = mc34vr500_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info mc34vr500_chip_info = {
|
||||
.ops = &mc34vr500_hwmon_ops,
|
||||
.info = mc34vr500_info,
|
||||
};
|
||||
|
||||
static const struct regmap_config mc34vr500_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = MC34VR500_INTSENSE0,
|
||||
};
|
||||
|
||||
static int mc34vr500_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct mc34vr500_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int ret;
|
||||
unsigned int reg, revid, fabid;
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &mc34vr500_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct mc34vr500_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->regmap = regmap;
|
||||
|
||||
ret = regmap_read(regmap, MC34VR500_DEVICEID, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (reg != MC34VR500_DEVICEID_VALUE)
|
||||
return -ENODEV;
|
||||
|
||||
ret = regmap_read(regmap, MC34VR500_SILICONREVID, &revid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(regmap, MC34VR500_FABID, &fabid);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(dev, "mc34vr500: revid 0x%x fabid 0x%x\n", revid, fabid);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
|
||||
data,
|
||||
&mc34vr500_chip_info,
|
||||
NULL);
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
data->hwmon_dev = hwmon_dev;
|
||||
|
||||
if (client->irq) {
|
||||
ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
||||
mc34vr500_process_interrupt,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_ONESHOT |
|
||||
IRQF_SHARED,
|
||||
dev_name(dev), data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* write 1 to clear interrupts */
|
||||
ret = regmap_write(regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
|
||||
THERM110S_BIT | THERM120S_BIT |
|
||||
THERM130S_BIT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* unmask interrupts */
|
||||
ret = regmap_write(regmap, MC34VR500_INTMASK0,
|
||||
(unsigned int) ~(LOWVINS_BIT | THERM110S_BIT |
|
||||
THERM120S_BIT | THERM130S_BIT));
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mc34vr500_id[] = {
|
||||
{ "mc34vr500", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mc34vr500_id);
|
||||
|
||||
static const struct of_device_id __maybe_unused mc34vr500_of_match[] = {
|
||||
{ .compatible = "nxp,mc34vr500" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mc34vr500_of_match);
|
||||
|
||||
static struct i2c_driver mc34vr500_driver = {
|
||||
.driver = {
|
||||
.name = "mc34vr500",
|
||||
.of_match_table = of_match_ptr(mc34vr500_of_match),
|
||||
},
|
||||
.probe_new = mc34vr500_probe,
|
||||
.id_table = mc34vr500_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(mc34vr500_driver);
|
||||
|
||||
MODULE_AUTHOR("Mario Kicherer <dev@kicherer.org>");
|
||||
|
||||
MODULE_DESCRIPTION("MC34VR500 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -155,6 +155,12 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) {
|
||||
/* FAN is broken - return zero for FAN speed. */
|
||||
*val = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*val = MLXREG_FAN_GET_RPM(regval, fan->divider,
|
||||
fan->samples);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1150,7 +1150,7 @@ static int nct6775_write_fan_div(struct nct6775_data *data, int nr)
|
|||
if (err)
|
||||
return err;
|
||||
reg &= 0x70 >> oddshift;
|
||||
reg |= data->fan_div[nr] & (0x7 << oddshift);
|
||||
reg |= (data->fan_div[nr] & 0x7) << oddshift;
|
||||
return nct6775_write_value(data, fandiv_reg, reg);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#include "nct6775.h"
|
||||
|
||||
|
|
@ -107,40 +106,51 @@ struct nct6775_sio_data {
|
|||
void (*sio_exit)(struct nct6775_sio_data *sio_data);
|
||||
};
|
||||
|
||||
#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66"
|
||||
#define ASUSWMI_METHOD "WMBD"
|
||||
#define ASUSWMI_METHODID_RSIO 0x5253494F
|
||||
#define ASUSWMI_METHODID_WSIO 0x5753494F
|
||||
#define ASUSWMI_METHODID_RHWM 0x5248574D
|
||||
#define ASUSWMI_METHODID_WHWM 0x5748574D
|
||||
#define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE
|
||||
#define ASUSWMI_DEVICE_HID "PNP0C14"
|
||||
#define ASUSWMI_DEVICE_UID "ASUSWMI"
|
||||
#define ASUSMSI_DEVICE_UID "AsusMbSwInterface"
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
/*
|
||||
* ASUS boards have only one device with WMI "WMBD" method and have provided
|
||||
* access to only one SuperIO chip at 0x0290.
|
||||
*/
|
||||
static struct acpi_device *asus_acpi_dev;
|
||||
#endif
|
||||
|
||||
static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_ACPI_WMI)
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
acpi_handle handle = acpi_device_handle(asus_acpi_dev);
|
||||
u32 args = bank | (reg << 8) | (val << 16);
|
||||
struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_object_list input;
|
||||
union acpi_object params[3];
|
||||
unsigned long long result;
|
||||
acpi_status status;
|
||||
union acpi_object *obj;
|
||||
u32 tmp = ASUSWMI_UNSUPPORTED_METHOD;
|
||||
|
||||
status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0,
|
||||
method_id, &input, &output);
|
||||
params[0].type = ACPI_TYPE_INTEGER;
|
||||
params[0].integer.value = 0;
|
||||
params[1].type = ACPI_TYPE_INTEGER;
|
||||
params[1].integer.value = method_id;
|
||||
params[2].type = ACPI_TYPE_BUFFER;
|
||||
params[2].buffer.length = sizeof(args);
|
||||
params[2].buffer.pointer = (void *)&args;
|
||||
input.count = 3;
|
||||
input.pointer = params;
|
||||
|
||||
status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
|
||||
obj = output.pointer;
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||
tmp = obj->integer.value;
|
||||
|
||||
if (retval)
|
||||
*retval = tmp;
|
||||
*retval = (u32)result & 0xFFFFFFFF;
|
||||
|
||||
kfree(obj);
|
||||
|
||||
if (tmp == ASUSWMI_UNSUPPORTED_METHOD)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -1099,6 +1109,91 @@ static const char * const asus_wmi_boards[] = {
|
|||
"TUF GAMING Z490-PLUS (WI-FI)",
|
||||
};
|
||||
|
||||
static const char * const asus_msi_boards[] = {
|
||||
"EX-B660M-V5 PRO D4",
|
||||
"PRIME B650-PLUS",
|
||||
"PRIME B650M-A",
|
||||
"PRIME B650M-A AX",
|
||||
"PRIME B650M-A II",
|
||||
"PRIME B650M-A WIFI",
|
||||
"PRIME B650M-A WIFI II",
|
||||
"PRIME B660M-A D4",
|
||||
"PRIME B660M-A WIFI D4",
|
||||
"PRIME X670-P",
|
||||
"PRIME X670-P WIFI",
|
||||
"PRIME X670E-PRO WIFI",
|
||||
"Pro B660M-C-D4",
|
||||
"ProArt B660-CREATOR D4",
|
||||
"ProArt X670E-CREATOR WIFI",
|
||||
"ROG CROSSHAIR X670E EXTREME",
|
||||
"ROG CROSSHAIR X670E GENE",
|
||||
"ROG CROSSHAIR X670E HERO",
|
||||
"ROG MAXIMUS XIII EXTREME GLACIAL",
|
||||
"ROG MAXIMUS Z690 EXTREME",
|
||||
"ROG MAXIMUS Z690 EXTREME GLACIAL",
|
||||
"ROG STRIX B650-A GAMING WIFI",
|
||||
"ROG STRIX B650E-E GAMING WIFI",
|
||||
"ROG STRIX B650E-F GAMING WIFI",
|
||||
"ROG STRIX B650E-I GAMING WIFI",
|
||||
"ROG STRIX B660-A GAMING WIFI D4",
|
||||
"ROG STRIX B660-F GAMING WIFI",
|
||||
"ROG STRIX B660-G GAMING WIFI",
|
||||
"ROG STRIX B660-I GAMING WIFI",
|
||||
"ROG STRIX X670E-A GAMING WIFI",
|
||||
"ROG STRIX X670E-E GAMING WIFI",
|
||||
"ROG STRIX X670E-F GAMING WIFI",
|
||||
"ROG STRIX X670E-I GAMING WIFI",
|
||||
"ROG STRIX Z590-A GAMING WIFI II",
|
||||
"ROG STRIX Z690-A GAMING WIFI D4",
|
||||
"TUF GAMING B650-PLUS",
|
||||
"TUF GAMING B650-PLUS WIFI",
|
||||
"TUF GAMING B650M-PLUS",
|
||||
"TUF GAMING B650M-PLUS WIFI",
|
||||
"TUF GAMING B660M-PLUS WIFI",
|
||||
"TUF GAMING X670E-PLUS",
|
||||
"TUF GAMING X670E-PLUS WIFI",
|
||||
"TUF GAMING Z590-PLUS WIFI",
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
/*
|
||||
* Callback for acpi_bus_for_each_dev() to find the right device
|
||||
* by _UID and _HID and return 1 to stop iteration.
|
||||
*/
|
||||
static int nct6775_asuswmi_device_match(struct device *dev, void *data)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device(dev);
|
||||
const char *uid = acpi_device_uid(adev);
|
||||
const char *hid = acpi_device_hid(adev);
|
||||
|
||||
if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) {
|
||||
asus_acpi_dev = adev;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum sensor_access nct6775_determine_access(const char *device_uid)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
u8 tmp;
|
||||
|
||||
acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid);
|
||||
if (!asus_acpi_dev)
|
||||
return access_direct;
|
||||
|
||||
/* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */
|
||||
if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
|
||||
pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp);
|
||||
return access_asuswmi;
|
||||
}
|
||||
#endif
|
||||
|
||||
return access_direct;
|
||||
}
|
||||
|
||||
static int __init sensors_nct6775_platform_init(void)
|
||||
{
|
||||
int i, err;
|
||||
|
|
@ -1109,7 +1204,6 @@ static int __init sensors_nct6775_platform_init(void)
|
|||
int sioaddr[2] = { 0x2e, 0x4e };
|
||||
enum sensor_access access = access_direct;
|
||||
const char *board_vendor, *board_name;
|
||||
u8 tmp;
|
||||
|
||||
err = platform_driver_register(&nct6775_driver);
|
||||
if (err)
|
||||
|
|
@ -1122,15 +1216,13 @@ static int __init sensors_nct6775_platform_init(void)
|
|||
!strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) {
|
||||
err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards),
|
||||
board_name);
|
||||
if (err >= 0) {
|
||||
/* if reading chip id via WMI succeeds, use WMI */
|
||||
if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
|
||||
pr_info("Using Asus WMI to access %#x chip.\n", tmp);
|
||||
access = access_asuswmi;
|
||||
} else {
|
||||
pr_err("Can't read ChipID by Asus WMI.\n");
|
||||
}
|
||||
}
|
||||
if (err >= 0)
|
||||
access = nct6775_determine_access(ASUSWMI_DEVICE_UID);
|
||||
|
||||
err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards),
|
||||
board_name);
|
||||
if (err >= 0)
|
||||
access = nct6775_determine_access(ASUSMSI_DEVICE_UID);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -791,6 +791,7 @@ static const struct hid_device_id nzxt_smart2_hid_id_table[] = {
|
|||
{ HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller */
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Platform driver for OXP Handhelds that expose fan reading and control
|
||||
* via hwmon sysfs.
|
||||
* Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose
|
||||
* fan reading and control via hwmon sysfs.
|
||||
*
|
||||
* Old boards have the same DMI strings and they are told appart by the
|
||||
* boot cpu vendor (Intel/AMD). Currently only AMD boards are supported
|
||||
* but the code is made to be simple to add other handheld boards in the
|
||||
* future.
|
||||
* Old OXP boards have the same DMI strings and they are told apart by
|
||||
* the boot cpu vendor (Intel/AMD). Currently only AMD boards are
|
||||
* supported but the code is made to be simple to add other handheld
|
||||
* boards in the future.
|
||||
* Fan control is provided via pwm interface in the range [0-255].
|
||||
* Old AMD boards use [0-100] as range in the EC, the written value is
|
||||
* scaled to accommodate for that. Newer boards like the mini PRO and
|
||||
|
|
@ -42,6 +42,8 @@ static bool unlock_global_acpi_lock(void)
|
|||
|
||||
enum oxp_board {
|
||||
aok_zoe_a1 = 1,
|
||||
aya_neo_air,
|
||||
aya_neo_air_pro,
|
||||
oxp_mini_amd,
|
||||
oxp_mini_amd_pro,
|
||||
};
|
||||
|
|
@ -60,6 +62,20 @@ static const struct dmi_system_id dmi_table[] = {
|
|||
},
|
||||
.driver_data = (void *) &(enum oxp_board) {aok_zoe_a1},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
|
||||
},
|
||||
.driver_data = (void *) &(enum oxp_board) {aya_neo_air},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
|
||||
},
|
||||
.driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
|
||||
|
|
@ -161,8 +177,17 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (board == oxp_mini_amd)
|
||||
switch (board) {
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_pro:
|
||||
case oxp_mini_amd:
|
||||
*val = (*val * 255) / 100;
|
||||
break;
|
||||
case oxp_mini_amd_pro:
|
||||
case aok_zoe_a1:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
case hwmon_pwm_enable:
|
||||
return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
|
||||
|
|
@ -191,8 +216,17 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
case hwmon_pwm_input:
|
||||
if (val < 0 || val > 255)
|
||||
return -EINVAL;
|
||||
if (board == oxp_mini_amd)
|
||||
switch (board) {
|
||||
case aya_neo_air:
|
||||
case aya_neo_air_pro:
|
||||
case oxp_mini_amd:
|
||||
val = (val * 100) / 255;
|
||||
break;
|
||||
case aok_zoe_a1:
|
||||
case oxp_mini_amd_pro:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
|
||||
default:
|
||||
break;
|
||||
|
|
@ -233,7 +267,7 @@ static int oxp_platform_probe(struct platform_device *pdev)
|
|||
|
||||
/*
|
||||
* Have to check for AMD processor here because DMI strings are the
|
||||
* same between Intel and AMD boards, the only way to tell them appart
|
||||
* same between Intel and AMD boards, the only way to tell them apart
|
||||
* is the CPU.
|
||||
* Intel boards seem to have different EC registers and values to
|
||||
* read/write.
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ static int create_temp_label(struct peci_cputemp *priv)
|
|||
unsigned long core_max = find_last_bit(priv->core_mask, CORE_NUMS_MAX);
|
||||
int i;
|
||||
|
||||
priv->coretemp_label = devm_kzalloc(priv->dev, core_max * sizeof(char *), GFP_KERNEL);
|
||||
priv->coretemp_label = devm_kzalloc(priv->dev, (core_max + 1) * sizeof(char *), GFP_KERNEL);
|
||||
if (!priv->coretemp_label)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -237,10 +237,10 @@ config SENSORS_MAX16064
|
|||
be called max16064.
|
||||
|
||||
config SENSORS_MAX16601
|
||||
tristate "Maxim MAX16508, MAX16601, MAX16602"
|
||||
tristate "Maxim MAX16508, MAX16600, MAX16601, and MAX16602"
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Maxim
|
||||
MAX16508, MAX16601 and MAX16602.
|
||||
MAX16508, MAX16600, MAX16601, and MAX16602.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called max16601.
|
||||
|
|
@ -317,6 +317,22 @@ config SENSORS_MP5023
|
|||
This driver can also be built as a module. If so, the module will
|
||||
be called mp5023.
|
||||
|
||||
config SENSORS_MPQ7932_REGULATOR
|
||||
bool "Regulator support for MPQ7932"
|
||||
depends on SENSORS_MPQ7932 && REGULATOR
|
||||
help
|
||||
If you say yes here you get six integrated buck converter regulator
|
||||
support for power management IC MPS MPQ7932.
|
||||
|
||||
config SENSORS_MPQ7932
|
||||
tristate "MPS MPQ7932"
|
||||
help
|
||||
If you say yes here you get hardware monitoring functionality support
|
||||
for power management IC MPS MPQ7932.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called mpq7932.
|
||||
|
||||
config SENSORS_PIM4328
|
||||
tristate "Flex PIM4328 and compatibles"
|
||||
help
|
||||
|
|
@ -379,6 +395,22 @@ config SENSORS_STPDDC60
|
|||
This driver can also be built as a module. If so, the module will
|
||||
be called stpddc60.
|
||||
|
||||
config SENSORS_TDA38640
|
||||
tristate "Infineon TDA38640"
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Infineon
|
||||
TDA38640.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called tda38640.
|
||||
|
||||
config SENSORS_TDA38640_REGULATOR
|
||||
bool "Regulator support for TDA38640 and compatibles"
|
||||
depends on SENSORS_TDA38640 && REGULATOR
|
||||
help
|
||||
If you say yes here you get regulator support for Infineon
|
||||
TDA38640 as regulator.
|
||||
|
||||
config SENSORS_TPS40422
|
||||
tristate "TI TPS40422"
|
||||
help
|
||||
|
|
|
|||
|
|
@ -34,11 +34,13 @@ obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
|
|||
obj-$(CONFIG_SENSORS_MP2888) += mp2888.o
|
||||
obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
|
||||
obj-$(CONFIG_SENSORS_MP5023) += mp5023.o
|
||||
obj-$(CONFIG_SENSORS_MPQ7932) += mpq7932.o
|
||||
obj-$(CONFIG_SENSORS_PLI1209BC) += pli1209bc.o
|
||||
obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
|
||||
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
|
||||
obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o
|
||||
obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o
|
||||
obj-$(CONFIG_SENSORS_TDA38640) += tda38640.o
|
||||
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
|
||||
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
|
||||
obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o
|
||||
|
|
|
|||
|
|
@ -570,14 +570,14 @@ MODULE_DEVICE_TABLE(i2c, ltc2978_id);
|
|||
#define LTC2978_N_VOLTAGES ((LTC2978_MAX_UV / LTC2978_UV_STEP) + 1)
|
||||
|
||||
static const struct regulator_desc ltc2978_reg_desc[] = {
|
||||
PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
|
||||
PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
|
||||
};
|
||||
|
||||
static const struct regulator_desc ltc2978_reg_desc_default[] = {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Hardware monitoring driver for Maxim MAX16508, MAX16601 and MAX16602.
|
||||
* Hardware monitoring driver for Maxim MAX16508, MAX16600, MAX16601,
|
||||
* and MAX16602.
|
||||
*
|
||||
* Implementation notes:
|
||||
*
|
||||
|
|
@ -31,7 +32,7 @@
|
|||
|
||||
#include "pmbus.h"
|
||||
|
||||
enum chips { max16508, max16601, max16602 };
|
||||
enum chips { max16508, max16600, max16601, max16602 };
|
||||
|
||||
#define REG_DEFAULT_NUM_POP 0xc4
|
||||
#define REG_SETPT_DVID 0xd1
|
||||
|
|
@ -202,7 +203,7 @@ static int max16601_identify(struct i2c_client *client,
|
|||
else
|
||||
info->vrm_version[0] = vr12;
|
||||
|
||||
if (data->id != max16601 && data->id != max16602)
|
||||
if (data->id != max16600 && data->id != max16601 && data->id != max16602)
|
||||
return 0;
|
||||
|
||||
reg = i2c_smbus_read_byte_data(client, REG_DEFAULT_NUM_POP);
|
||||
|
|
@ -263,6 +264,7 @@ static void max16601_remove(void *_data)
|
|||
|
||||
static const struct i2c_device_id max16601_id[] = {
|
||||
{"max16508", max16508},
|
||||
{"max16600", max16600},
|
||||
{"max16601", max16601},
|
||||
{"max16602", max16602},
|
||||
{}
|
||||
|
|
@ -281,11 +283,13 @@ static int max16601_get_id(struct i2c_client *client)
|
|||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* PMBUS_IC_DEVICE_ID is expected to return "MAX16601y.xx" or
|
||||
* MAX16602y.xx or "MAX16500y.xx".cdxxcccccccccc
|
||||
* PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx" or
|
||||
* "MAX16500y.xx".cdxxcccccccccc
|
||||
*/
|
||||
if (!strncmp(buf, "MAX16500", 8)) {
|
||||
id = max16508;
|
||||
} else if (!strncmp(buf, "MAX16600", 8)) {
|
||||
id = max16600;
|
||||
} else if (!strncmp(buf, "MAX16601", 8)) {
|
||||
id = max16601;
|
||||
} else if (!strncmp(buf, "MAX16602", 8)) {
|
||||
|
|
|
|||
156
drivers/hwmon/pmbus/mpq7932.c
Normal file
156
drivers/hwmon/pmbus/mpq7932.c
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* mpq7932.c - hwmon with optional regulator driver for mps mpq7932
|
||||
* Copyright 2022 Monolithic Power Systems, Inc
|
||||
*
|
||||
* Author: Saravanan Sekar <saravanan@linumiz.com>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pmbus.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
#define MPQ7932_BUCK_UV_MIN 206250
|
||||
#define MPQ7932_UV_STEP 6250
|
||||
#define MPQ7932_N_VOLTAGES 256
|
||||
#define MPQ7932_VOUT_MAX 0xFF
|
||||
#define MPQ7932_NUM_PAGES 6
|
||||
|
||||
#define MPQ7932_TON_DELAY 0x60
|
||||
#define MPQ7932_VOUT_STARTUP_SLEW 0xA3
|
||||
#define MPQ7932_VOUT_SHUTDOWN_SLEW 0xA5
|
||||
#define MPQ7932_VOUT_SLEW_MASK GENMASK(1, 0)
|
||||
#define MPQ7932_TON_DELAY_MASK GENMASK(4, 0)
|
||||
|
||||
struct mpq7932_data {
|
||||
struct pmbus_driver_info info;
|
||||
struct pmbus_platform_data pdata;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
|
||||
static struct regulator_desc mpq7932_regulators_desc[] = {
|
||||
PMBUS_REGULATOR_STEP("buck", 0, MPQ7932_N_VOLTAGES,
|
||||
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
|
||||
PMBUS_REGULATOR_STEP("buck", 1, MPQ7932_N_VOLTAGES,
|
||||
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
|
||||
PMBUS_REGULATOR_STEP("buck", 2, MPQ7932_N_VOLTAGES,
|
||||
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
|
||||
PMBUS_REGULATOR_STEP("buck", 3, MPQ7932_N_VOLTAGES,
|
||||
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
|
||||
PMBUS_REGULATOR_STEP("buck", 4, MPQ7932_N_VOLTAGES,
|
||||
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
|
||||
PMBUS_REGULATOR_STEP("buck", 5, MPQ7932_N_VOLTAGES,
|
||||
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
|
||||
};
|
||||
#endif
|
||||
|
||||
static int mpq7932_write_word_data(struct i2c_client *client, int page, int reg,
|
||||
u16 word)
|
||||
{
|
||||
switch (reg) {
|
||||
/*
|
||||
* chip supports only byte access for VOUT_COMMAND otherwise
|
||||
* access results -EREMOTEIO
|
||||
*/
|
||||
case PMBUS_VOUT_COMMAND:
|
||||
return pmbus_write_byte_data(client, page, reg, word & 0xFF);
|
||||
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int mpq7932_read_word_data(struct i2c_client *client, int page,
|
||||
int phase, int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
/*
|
||||
* chip supports neither (PMBUS_VOUT_MARGIN_HIGH, PMBUS_VOUT_MARGIN_LOW)
|
||||
* nor (PMBUS_MFR_VOUT_MIN, PMBUS_MFR_VOUT_MAX). As a result set voltage
|
||||
* fails due to error in pmbus_regulator_get_low_margin, so faked.
|
||||
*/
|
||||
case PMBUS_MFR_VOUT_MIN:
|
||||
return 0;
|
||||
|
||||
case PMBUS_MFR_VOUT_MAX:
|
||||
return MPQ7932_VOUT_MAX;
|
||||
|
||||
/*
|
||||
* chip supports only byte access for VOUT_COMMAND otherwise
|
||||
* access results in -EREMOTEIO
|
||||
*/
|
||||
case PMBUS_READ_VOUT:
|
||||
return pmbus_read_byte_data(client, page, PMBUS_VOUT_COMMAND);
|
||||
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static int mpq7932_probe(struct i2c_client *client)
|
||||
{
|
||||
struct mpq7932_data *data;
|
||||
struct pmbus_driver_info *info;
|
||||
struct device *dev = &client->dev;
|
||||
int i;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(struct mpq7932_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
info = &data->info;
|
||||
info->pages = MPQ7932_NUM_PAGES;
|
||||
info->format[PSC_VOLTAGE_OUT] = direct;
|
||||
info->m[PSC_VOLTAGE_OUT] = 160;
|
||||
info->b[PSC_VOLTAGE_OUT] = -33;
|
||||
for (i = 0; i < info->pages; i++) {
|
||||
info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_STATUS_TEMP;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
|
||||
info->num_regulators = ARRAY_SIZE(mpq7932_regulators_desc);
|
||||
info->reg_desc = mpq7932_regulators_desc;
|
||||
#endif
|
||||
|
||||
info->read_word_data = mpq7932_read_word_data;
|
||||
info->write_word_data = mpq7932_write_word_data;
|
||||
|
||||
data->pdata.flags = PMBUS_NO_CAPABILITY;
|
||||
dev->platform_data = &data->pdata;
|
||||
|
||||
return pmbus_do_probe(client, info);
|
||||
}
|
||||
|
||||
static const struct of_device_id mpq7932_of_match[] = {
|
||||
{ .compatible = "mps,mpq7932"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mpq7932_of_match);
|
||||
|
||||
static const struct i2c_device_id mpq7932_id[] = {
|
||||
{ "mpq7932", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mpq7932_id);
|
||||
|
||||
static struct i2c_driver mpq7932_regulator_driver = {
|
||||
.driver = {
|
||||
.name = "mpq7932",
|
||||
.of_match_table = mpq7932_of_match,
|
||||
},
|
||||
.probe_new = mpq7932_probe,
|
||||
.id_table = mpq7932_id,
|
||||
};
|
||||
module_i2c_driver(mpq7932_regulator_driver);
|
||||
|
||||
MODULE_AUTHOR("Saravanan Sekar <saravanan@linumiz.com>");
|
||||
MODULE_DESCRIPTION("MPQ7932 PMIC regulator driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(PMBUS);
|
||||
|
|
@ -464,7 +464,7 @@ struct pmbus_driver_info {
|
|||
extern const struct regulator_ops pmbus_regulator_ops;
|
||||
|
||||
/* Macros for filling in array of struct regulator_desc */
|
||||
#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step) \
|
||||
#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step, _min_uV) \
|
||||
[_id] = { \
|
||||
.name = (_name # _id), \
|
||||
.id = (_id), \
|
||||
|
|
@ -475,9 +475,10 @@ extern const struct regulator_ops pmbus_regulator_ops;
|
|||
.owner = THIS_MODULE, \
|
||||
.n_voltages = _voltages, \
|
||||
.uV_step = _step, \
|
||||
.min_uV = _min_uV, \
|
||||
}
|
||||
|
||||
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0)
|
||||
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0)
|
||||
|
||||
/* Function declarations */
|
||||
|
||||
|
|
|
|||
74
drivers/hwmon/pmbus/tda38640.c
Normal file
74
drivers/hwmon/pmbus/tda38640.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Hardware monitoring driver for Infineon TDA38640
|
||||
*
|
||||
* Copyright (c) 2023 9elements GmbH
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
static const struct regulator_desc __maybe_unused tda38640_reg_desc[] = {
|
||||
PMBUS_REGULATOR("vout", 0),
|
||||
};
|
||||
|
||||
static struct pmbus_driver_info tda38640_info = {
|
||||
.pages = 1,
|
||||
.format[PSC_VOLTAGE_IN] = linear,
|
||||
.format[PSC_VOLTAGE_OUT] = linear,
|
||||
.format[PSC_CURRENT_OUT] = linear,
|
||||
.format[PSC_CURRENT_IN] = linear,
|
||||
.format[PSC_POWER] = linear,
|
||||
.format[PSC_TEMPERATURE] = linear,
|
||||
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
|
||||
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
|
||||
| PMBUS_HAVE_IIN
|
||||
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
|
||||
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
|
||||
| PMBUS_HAVE_POUT | PMBUS_HAVE_PIN,
|
||||
#if IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR)
|
||||
.num_regulators = 1,
|
||||
.reg_desc = tda38640_reg_desc,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int tda38640_probe(struct i2c_client *client)
|
||||
{
|
||||
return pmbus_do_probe(client, &tda38640_info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tda38640_id[] = {
|
||||
{"tda38640", 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tda38640_id);
|
||||
|
||||
static const struct of_device_id __maybe_unused tda38640_of_match[] = {
|
||||
{ .compatible = "infineon,tda38640"},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tda38640_of_match);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver tda38640_driver = {
|
||||
.driver = {
|
||||
.name = "tda38640",
|
||||
.of_match_table = of_match_ptr(tda38640_of_match),
|
||||
},
|
||||
.probe_new = tda38640_probe,
|
||||
.id_table = tda38640_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(tda38640_driver);
|
||||
|
||||
MODULE_AUTHOR("Patrick Rudolph <patrick.rudolph@9elements.com>");
|
||||
MODULE_DESCRIPTION("PMBus driver for Infineon TDA38640");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(PMBUS);
|
||||
|
|
@ -668,7 +668,7 @@ static inline int sht15_calc_humid(struct sht15_data *data)
|
|||
}
|
||||
|
||||
/**
|
||||
* sht15_show_status() - show status information in sysfs
|
||||
* sht15_status_show() - show status information in sysfs
|
||||
* @dev: device.
|
||||
* @attr: device attribute.
|
||||
* @buf: sysfs buffer where information is written to.
|
||||
|
|
@ -690,7 +690,7 @@ static ssize_t sht15_status_show(struct device *dev,
|
|||
}
|
||||
|
||||
/**
|
||||
* sht15_store_heater() - change heater state via sysfs
|
||||
* sht15_status_store() - change heater state via sysfs
|
||||
* @dev: device.
|
||||
* @attr: device attribute.
|
||||
* @buf: sysfs buffer to read the new heater state from.
|
||||
|
|
@ -725,7 +725,7 @@ static ssize_t sht15_status_store(struct device *dev,
|
|||
}
|
||||
|
||||
/**
|
||||
* sht15_show_temp() - show temperature measurement value in sysfs
|
||||
* sht15_temp_show() - show temperature measurement value in sysfs
|
||||
* @dev: device.
|
||||
* @attr: device attribute.
|
||||
* @buf: sysfs buffer where measurement values are written to.
|
||||
|
|
@ -747,7 +747,7 @@ static ssize_t sht15_temp_show(struct device *dev,
|
|||
}
|
||||
|
||||
/**
|
||||
* sht15_show_humidity() - show humidity measurement value in sysfs
|
||||
* sht15_humidity_show() - show humidity measurement value in sysfs
|
||||
* @dev: device.
|
||||
* @attr: device attribute.
|
||||
* @buf: sysfs buffer where measurement values are written to.
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ static int sht21_update_measurements(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* sht21_show_temperature() - show temperature measurement value in sysfs
|
||||
* sht21_temperature_show() - show temperature measurement value in sysfs
|
||||
* @dev: device
|
||||
* @attr: device attribute
|
||||
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
|
||||
|
|
@ -136,7 +136,7 @@ static ssize_t sht21_temperature_show(struct device *dev,
|
|||
}
|
||||
|
||||
/**
|
||||
* sht21_show_humidity() - show humidity measurement value in sysfs
|
||||
* sht21_humidity_show() - show humidity measurement value in sysfs
|
||||
* @dev: device
|
||||
* @attr: device attribute
|
||||
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
|
||||
|
|
|
|||
|
|
@ -436,6 +436,10 @@ struct hwmon_chip_info {
|
|||
/* hwmon_device_register() is deprecated */
|
||||
struct device *hwmon_device_register(struct device *dev);
|
||||
|
||||
/*
|
||||
* hwmon_device_register_with_groups() and
|
||||
* devm_hwmon_device_register_with_groups() are deprecated.
|
||||
*/
|
||||
struct device *
|
||||
hwmon_device_register_with_groups(struct device *dev, const char *name,
|
||||
void *drvdata,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user