hwmon updates for v6.4
- New drivers - Driver for Acbel FSB032 power supply - Driver for StarFive JH71x0 temperature sensor - Added support to existing drivers - aquacomputer_d5next: Support for Aquacomputer Aquastream XT - nct6775: Added various ASUS boards to list of boards supporting WMI - asus-ec-sensors: ROG STRIX Z390-F GAMING, ProArt B550-Creator, - Notable improvements - Regulator event and sysfs notification support for PMBus drivers - Notable cleanup: - Constified pointers to hwmon_channel_info - Various other minor bug fixes and improvements -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmRF2DQACgkQyx8mb86f mYEGxhAAnm4r7MkxdBPv8UloSxljTGMtPr+xfJ+TqW+bJVFoPJ57OZ+Coqfa8NTs h58inRehmkYVuYU3dIKYLWq4TiCyCq8W8ACZ/oRiUB7vKEG5Yt5AWw8ZSWjYWf/b b3+N/IdEFSrnR2+xjIx2HcCYfpBomaq/5VDH6DDfRGD+HHkhfp065z1TeiOj4Dr3 3sueu+vbVPowIs55VXhmUwSC95n7+qv9qrA0ZYFtGUd1klDC+4fWy2wQZ+ed1gz2 WATJmbhHu+QhrqFC4qlgiow50FrHjx0EWywEBiwBm9A6bfKNRWitz7YXqe7entP3 TFg9rykBMleowNstwqtMARmaLxzDoH/IpsoIOY8NhGgzka0zy1pVyQ3bXRgVTP2X BRUOqKfj6gsysT3KenUmsMi7Mr+NFJ8LwSl9d4z/v+4ojE5N57l12tdoMaY8qlGs 9bk75xtGuuZm8LYYPTVp1DU3XaF816Qj30fmaBruy3HVgKRyaWw1OEVayZMWQucr KJ+1GoEyoCwlaRDX9UrazPtVg2TocAvIZfUdl2+Zd6WF7Mifl3q9HJg+XMmeZlI5 xRmvMj+srJ99Q2HEWS/SyiOr4n2rjRC+WeTs7N0x6X4zDsbbZTK7ONfEf0Yz1aLL rykeG94DO5qLpz8PQ38X8ONT8OwVcpCg0UF/0xbfAO1zYSqzv5E= =i+Fr -----END PGP SIGNATURE----- Merge tag 'hwmon-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon updates from Guenter Roeck: "New drivers - Driver for Acbel FSB032 power supply - Driver for StarFive JH71x0 temperature sensor Added support to existing drivers: - aquacomputer_d5next: Support for Aquacomputer Aquastream XT - nct6775: Added various ASUS boards to list of boards supporting WMI - asus-ec-sensors: ROG STRIX Z390-F GAMING, ProArt B550-Creator, Notable improvements: - Regulator event and sysfs notification support for PMBus drivers Notable cleanup: - Constified pointers to hwmon_channel_info .. and various other minor bug fixes and improvements" * tag 'hwmon-for-v6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (131 commits) hwmon: lochnagar: Remove the unneeded include <linux/i2c.h> hwmon: (pmbus/fsp-3y) Fix functionality bitmask in FSP-3Y YM-2151E hwmon: (adt7475) Use device_property APIs when configuring polarity hwmon: (aquacomputer_d5next) Add support for Aquacomputer Aquastream XT hwmon: (it87) Disable/enable SMBus access for IT8622E chipset hwmon: (it87) Add calls to smbus_enable/smbus_disable as required hwmon: (it87) Test for error in it87_update_device hwmon: (it87) Disable SMBus access for environmental controller registers. docs: hwmon: Add documentaion for acbel-fsg032 PSU hwmon: (pmbus/acbel-fsg032) Add Acbel power supply dt-bindings: trivial-devices: Add acbel,fsg032 dt-bindings: vendor-prefixes: Add prefix for acbel hwmon: (sfctemp) Simplify error message hwmon: (pmbus/ibm-cffps) Use default debugfs attributes and lock function hwmon: (pmbus/core) Add lock and unlock functions hwmon: (pmbus/core) Request threaded interrupt with IRQF_ONESHOT hwmon: (nct6775) update ASUS WMI monitoring list A620/B760/W790 hwmon: ina2xx: add optional regulator support dt-bindings: hwmon: ina2xx: add supply property dt-bindings: hwmon: pwm-fan: Convert to DT schema ...
This commit is contained in:
commit
4173cf6fb6
@ -1,67 +1 @@
|
||||
Bindings for a fan connected to the PWM lines
|
||||
|
||||
Required properties:
|
||||
- compatible : "pwm-fan"
|
||||
- pwms : the PWM that is used to control the PWM fan
|
||||
- cooling-levels : PWM duty cycle values in a range from 0 to 255
|
||||
which correspond to thermal cooling states
|
||||
|
||||
Optional properties:
|
||||
- fan-supply : phandle to the regulator that provides power to the fan
|
||||
- interrupts : This contains an interrupt specifier for each fan
|
||||
tachometer output connected to an interrupt source.
|
||||
The output signal must generate a defined number of
|
||||
interrupts per fan revolution, which require that
|
||||
it must be self resetting edge interrupts. See
|
||||
interrupt-controller/interrupts.txt for the format.
|
||||
- pulses-per-revolution : define the number of pulses per fan revolution for
|
||||
each tachometer input as an integer (default is 2
|
||||
interrupts per revolution). The value must be
|
||||
greater than zero.
|
||||
|
||||
Example:
|
||||
fan0: pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
#cooling-cells = <2>;
|
||||
pwms = <&pwm 0 10000 0>;
|
||||
cooling-levels = <0 102 170 230>;
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
cpu_thermal: cpu-thermal {
|
||||
thermal-sensors = <&tmu 0>;
|
||||
polling-delay-passive = <0>;
|
||||
polling-delay = <0>;
|
||||
trips {
|
||||
cpu_alert1: cpu-alert1 {
|
||||
temperature = <100000>; /* millicelsius */
|
||||
hysteresis = <2000>; /* millicelsius */
|
||||
type = "passive";
|
||||
};
|
||||
};
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&cpu_alert1>;
|
||||
cooling-device = <&fan0 0 1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Example 2:
|
||||
fan0: pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
pwms = <&pwm 0 40000 0>;
|
||||
fan-supply = <®_fan>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
|
||||
pulses-per-revolution = <2>;
|
||||
};
|
||||
|
||||
Example 3:
|
||||
fan0: pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
pwms = <&pwm1 0 25000 0>;
|
||||
interrupts-extended = <&gpio1 1 IRQ_TYPE_EDGE_FALLING>,
|
||||
<&gpio2 5 IRQ_TYPE_EDGE_FALLING>;
|
||||
pulses-per-revolution = <2>, <1>;
|
||||
};
|
||||
This file has moved to pwm-fan.yaml.
|
||||
|
97
Documentation/devicetree/bindings/hwmon/pwm-fan.yaml
Normal file
97
Documentation/devicetree/bindings/hwmon/pwm-fan.yaml
Normal file
@ -0,0 +1,97 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/pwm-fan.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Fan connected to PWM lines
|
||||
|
||||
maintainers:
|
||||
- Jean Delvare <jdelvare@suse.com>
|
||||
- Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: pwm-fan
|
||||
|
||||
cooling-levels:
|
||||
description: PWM duty cycle values corresponding to thermal cooling states.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
items:
|
||||
maximum: 255
|
||||
|
||||
fan-supply:
|
||||
description: Phandle to the regulator that provides power to the fan.
|
||||
|
||||
interrupts:
|
||||
description:
|
||||
This contains an interrupt specifier for each fan tachometer output
|
||||
connected to an interrupt source. The output signal must generate a
|
||||
defined number of interrupts per fan revolution, which require that
|
||||
it must be self resetting edge interrupts.
|
||||
maxItems: 1
|
||||
|
||||
pulses-per-revolution:
|
||||
description:
|
||||
Define the number of pulses per fan revolution for each tachometer
|
||||
input as an integer.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
maximum: 4
|
||||
default: 2
|
||||
|
||||
pwms:
|
||||
description: The PWM that is used to control the fan.
|
||||
maxItems: 1
|
||||
|
||||
"#cooling-cells": true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- pwms
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
cooling-levels = <0 102 170 230>;
|
||||
pwms = <&pwm 0 10000 0>;
|
||||
#cooling-cells = <2>;
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
cpu_thermal: cpu-thermal {
|
||||
thermal-sensors = <&tmu 0>;
|
||||
polling-delay-passive = <0>;
|
||||
polling-delay = <0>;
|
||||
|
||||
trips {
|
||||
cpu_alert1: cpu-alert1 {
|
||||
temperature = <100000>; /* millicelsius */
|
||||
hysteresis = <2000>; /* millicelsius */
|
||||
type = "passive";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&cpu_alert1>;
|
||||
cooling-device = <&fan0 0 1>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
pwms = <&pwm 0 40000 0>;
|
||||
fan-supply = <®_fan>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
|
||||
pulses-per-revolution = <2>;
|
||||
};
|
@ -0,0 +1,70 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/starfive,jh71x0-temp.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: StarFive JH71x0 Temperature Sensor
|
||||
|
||||
maintainers:
|
||||
- Emil Renner Berthing <kernel@esmil.dk>
|
||||
|
||||
description: |
|
||||
StarFive Technology Co. JH71x0 embedded temperature sensor
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- starfive,jh7100-temp
|
||||
- starfive,jh7110-temp
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: "sense"
|
||||
- const: "bus"
|
||||
|
||||
'#thermal-sensor-cells':
|
||||
const: 0
|
||||
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: "sense"
|
||||
- const: "bus"
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/starfive-jh7100.h>
|
||||
#include <dt-bindings/reset/starfive-jh7100.h>
|
||||
|
||||
temperature-sensor@124a0000 {
|
||||
compatible = "starfive,jh7100-temp";
|
||||
reg = <0x124a0000 0x10000>;
|
||||
clocks = <&clkgen JH7100_CLK_TEMP_SENSE>,
|
||||
<&clkgen JH7100_CLK_TEMP_APB>;
|
||||
clock-names = "sense", "bus";
|
||||
#thermal-sensor-cells = <0>;
|
||||
resets = <&rstgen JH7100_RSTN_TEMP_SENSE>,
|
||||
<&rstgen JH7100_RSTN_TEMP_APB>;
|
||||
reset-names = "sense", "bus";
|
||||
};
|
@ -57,6 +57,10 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [1, 2, 4, 8]
|
||||
|
||||
vs-supply:
|
||||
description: phandle to the regulator that provides the VS supply typically
|
||||
in range from 2.7 V to 5.5 V.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -73,5 +77,6 @@ examples:
|
||||
compatible = "ti,ina220";
|
||||
reg = <0x44>;
|
||||
shunt-resistor = <1000>;
|
||||
vs-supply = <&vdd_3v0>;
|
||||
};
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
title: TMP464 and TMP468 temperature sensors
|
||||
|
||||
maintainers:
|
||||
- Agathe Porte <agathe.porte@nokia.com>
|
||||
- Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
description: |
|
||||
±0.0625°C Remote and Local temperature sensor
|
||||
|
@ -29,6 +29,8 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
# Acbel fsg032 power supply
|
||||
- acbel,fsg032
|
||||
# SMBus/I2C Digital Temperature Sensor in 6-Pin SOT with SMBus Alert and Over Temperature Pin
|
||||
- ad,ad7414
|
||||
# ADM9240: Complete System Hardware Monitor for uProcessor-Based Systems
|
||||
|
@ -37,6 +37,8 @@ patternProperties:
|
||||
description: Abracon Corporation
|
||||
"^abt,.*":
|
||||
description: ShenZhen Asia Better Technology Ltd.
|
||||
"^acbel,.*":
|
||||
description: Acbel Polytech Inc.
|
||||
"^acer,.*":
|
||||
description: Acer Inc.
|
||||
"^acme,.*":
|
||||
|
80
Documentation/hwmon/acbel-fsg032.rst
Normal file
80
Documentation/hwmon/acbel-fsg032.rst
Normal file
@ -0,0 +1,80 @@
|
||||
Kernel driver acbel-fsg032
|
||||
==========================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* ACBEL FSG032-00xG power supply.
|
||||
|
||||
Author: Lakshmi Yadlapati <lakshmiy@us.ibm.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver supports ACBEL FSG032-00xG Power Supply. This driver
|
||||
is a client to the core PMBus driver.
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
This driver does not auto-detect devices. You will have to instantiate the
|
||||
devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
|
||||
details.
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
The following attributes are supported:
|
||||
|
||||
======================= ======================================================
|
||||
curr1_crit Critical maximum current.
|
||||
curr1_crit_alarm Input current critical alarm.
|
||||
curr1_input Measured output current.
|
||||
curr1_label "iin"
|
||||
curr1_max Maximum input current.
|
||||
curr1_max_alarm Maximum input current high alarm.
|
||||
curr1_rated_max Maximum rated input current.
|
||||
curr2_crit Critical maximum current.
|
||||
curr2_crit_alarm Output current critical alarm.
|
||||
curr2_input Measured output current.
|
||||
curr2_label "iout1"
|
||||
curr2_max Maximum output current.
|
||||
curr2_max_alarm Output current high alarm.
|
||||
curr2_rated_max Maximum rated output current.
|
||||
|
||||
|
||||
fan1_alarm Fan 1 warning.
|
||||
fan1_fault Fan 1 fault.
|
||||
fan1_input Fan 1 speed in RPM.
|
||||
fan1_target Set fan speed reference.
|
||||
|
||||
in1_alarm Input voltage under-voltage alarm.
|
||||
in1_input Measured input voltage.
|
||||
in1_label "vin"
|
||||
in1_rated_max Maximum rated input voltage.
|
||||
in1_rated_min Minimum rated input voltage.
|
||||
in2_crit Critical maximum output voltage.
|
||||
in2_crit_alarm Output voltage critical high alarm.
|
||||
in2_input Measured output voltage.
|
||||
in2_label "vout1"
|
||||
in2_lcrit Critical minimum output voltage.
|
||||
in2_lcrit_alarm Output voltage critical low alarm.
|
||||
in2_rated_max Maximum rated output voltage.
|
||||
in2_rated_min Minimum rated output voltage.
|
||||
|
||||
power1_alarm Input fault or alarm.
|
||||
power1_input Measured input power.
|
||||
power1_label "pin"
|
||||
power1_max Input power limit.
|
||||
power1_rated_max Maximum rated input power.
|
||||
power2_crit Critical output power limit.
|
||||
power2_crit_alarm Output power crit alarm limit exceeded.
|
||||
power2_input Measured output power.
|
||||
power2_label "pout"
|
||||
power2_max Output power limit.
|
||||
power2_max_alarm Output power high alarm.
|
||||
power2_rated_max Maximum rated output power.
|
||||
|
||||
temp[1-3]_input Measured temperature.
|
||||
temp[1-2]_max Maximum temperature.
|
||||
temp[1-3]_rated_max Temperature high alarm.
|
||||
======================= ======================================================
|
@ -12,6 +12,7 @@ Supported devices:
|
||||
* Aquacomputer Octo fan controller
|
||||
* Aquacomputer Quadro fan controller
|
||||
* Aquacomputer High Flow Next sensor
|
||||
* Aquacomputer Aquastream XT watercooling pump
|
||||
* Aquacomputer Aquastream Ultimate watercooling pump
|
||||
* Aquacomputer Poweradjust 3 fan controller
|
||||
|
||||
@ -25,7 +26,8 @@ communicate through proprietary USB HID protocols.
|
||||
|
||||
The Aquaero devices expose eight physical, eight virtual and four calculated
|
||||
virtual temperature sensors, as well as two flow sensors. The fans expose their
|
||||
speed (in RPM), power, voltage and current.
|
||||
speed (in RPM), power, voltage and current. Temperature offsets and fan speeds
|
||||
can be controlled.
|
||||
|
||||
For the D5 Next pump, available sensors are pump and fan speed, power, voltage
|
||||
and current, as well as coolant temperature and eight virtual temp sensors. Also
|
||||
@ -55,6 +57,10 @@ The High Flow Next exposes +5V voltages, water quality, conductivity and flow re
|
||||
A temperature sensor can be connected to it, in which case it provides its reading
|
||||
and an estimation of the dissipated/absorbed power in the liquid cooling loop.
|
||||
|
||||
The Aquastream XT pump exposes temperature readings for the coolant, external sensor
|
||||
and fan IC. It also exposes pump and fan speeds (in RPM), voltages, as well as pump
|
||||
current.
|
||||
|
||||
The Aquastream Ultimate pump exposes coolant temp and an external temp sensor, along
|
||||
with speed, power, voltage and current of both the pump and optionally connected fan.
|
||||
It also exposes pressure and flow speed readings.
|
||||
@ -75,7 +81,7 @@ Sysfs entries
|
||||
|
||||
================ ==============================================================
|
||||
temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius)
|
||||
temp[1-4]_offset Temperature sensor correction offset (in millidegrees Celsius)
|
||||
temp[1-8]_offset Temperature sensor correction offset (in millidegrees Celsius)
|
||||
fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h)
|
||||
fan5_pulses Quadro flow sensor pulses
|
||||
power[1-8]_input Pump/fan power (in micro Watts)
|
||||
|
@ -8,6 +8,7 @@ Supported boards:
|
||||
* PRIME X570-PRO
|
||||
* Pro WS X570-ACE
|
||||
* ProArt X570-CREATOR WIFI
|
||||
* ProArt B550-CREATOR
|
||||
* ROG CROSSHAIR VIII DARK HERO
|
||||
* ROG CROSSHAIR VIII HERO (WI-FI)
|
||||
* ROG CROSSHAIR VIII FORMULA
|
||||
@ -21,6 +22,7 @@ Supported boards:
|
||||
* ROG STRIX X570-E GAMING WIFI II
|
||||
* ROG STRIX X570-F GAMING
|
||||
* ROG STRIX X570-I GAMING
|
||||
* ROG STRIX Z390-F GAMING
|
||||
* ROG STRIX Z690-A GAMING WIFI D4
|
||||
* ROG ZENITH II EXTREME
|
||||
* ROG ZENITH II EXTREME ALPHA
|
||||
|
@ -36,7 +36,7 @@ correct path to the alarm file::
|
||||
|
||||
echo 0 >XXXX_alarm
|
||||
|
||||
Specification of the chip can be found here:
|
||||
Specifications of the chip can be found at the `Kontron FTP Server <http://ftp.kontron.com/>`_ (username = "anonymous", no password required)
|
||||
under the following path:
|
||||
|
||||
- ftp://ftp.ts.fujitsu.com/pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/BMC-Teutates_Specification_V1.21.pdf
|
||||
- ftp://ftp.ts.fujitsu.com/pub/Mainboard-OEM-Sales/Services/Software&Tools/Linux_SystemMonitoring&Watchdog&GPIO/Fujitsu_mainboards-1-Sensors_HowTo-en-US.pdf
|
||||
/Services/Software_Tools/Linux_SystemMonitoring_Watchdog_GPIO/BMC-Teutates_Specification_V1.21.pdf
|
||||
|
@ -19,20 +19,10 @@ also read Documentation/hwmon/submitting-patches.rst.
|
||||
|
||||
The API
|
||||
-------
|
||||
Each hardware monitoring driver must #include <linux/hwmon.h> and, in most
|
||||
Each hardware monitoring driver must #include <linux/hwmon.h> and, in some
|
||||
cases, <linux/hwmon-sysfs.h>. linux/hwmon.h declares the following
|
||||
register/unregister functions::
|
||||
|
||||
struct device *
|
||||
hwmon_device_register_with_groups(struct device *dev, const char *name,
|
||||
void *drvdata,
|
||||
const struct attribute_group **groups);
|
||||
|
||||
struct device *
|
||||
devm_hwmon_device_register_with_groups(struct device *dev,
|
||||
const char *name, void *drvdata,
|
||||
const struct attribute_group **groups);
|
||||
|
||||
struct device *
|
||||
hwmon_device_register_with_info(struct device *dev,
|
||||
const char *name, void *drvdata,
|
||||
@ -54,46 +44,30 @@ register/unregister functions::
|
||||
|
||||
char *devm_hwmon_sanitize_name(struct device *dev, const char *name);
|
||||
|
||||
hwmon_device_register_with_groups registers a hardware monitoring device.
|
||||
The first parameter of this function is a pointer to the parent device.
|
||||
The name parameter is a pointer to the hwmon device name. The registration
|
||||
function will create a name sysfs attribute pointing to this name.
|
||||
The drvdata parameter is the pointer to the local driver data.
|
||||
hwmon_device_register_with_groups will attach this pointer to the newly
|
||||
allocated hwmon device. The pointer can be retrieved by the driver using
|
||||
dev_get_drvdata() on the hwmon device pointer. The groups parameter is
|
||||
a pointer to a list of sysfs attribute groups. The list must be NULL terminated.
|
||||
hwmon_device_register_with_groups creates the hwmon device with name attribute
|
||||
as well as all sysfs attributes attached to the hwmon device.
|
||||
This function returns a pointer to the newly created hardware monitoring device
|
||||
or PTR_ERR for failure.
|
||||
|
||||
devm_hwmon_device_register_with_groups is similar to
|
||||
hwmon_device_register_with_groups. However, it is device managed, meaning the
|
||||
hwmon device does not have to be removed explicitly by the removal function.
|
||||
|
||||
hwmon_device_register_with_info is the most comprehensive and preferred means
|
||||
to register a hardware monitoring device. It creates the standard sysfs
|
||||
attributes in the hardware monitoring core, letting the driver focus on reading
|
||||
from and writing to the chip instead of having to bother with sysfs attributes.
|
||||
The parent device parameter as well as the chip parameter must not be NULL. Its
|
||||
parameters are described in more detail below.
|
||||
hwmon_device_register_with_info registers a hardware monitoring device.
|
||||
It creates the standard sysfs attributes in the hardware monitoring core,
|
||||
letting the driver focus on reading from and writing to the chip instead
|
||||
of having to bother with sysfs attributes. The parent device parameter
|
||||
as well as the chip parameter must not be NULL. Its parameters are described
|
||||
in more detail below.
|
||||
|
||||
devm_hwmon_device_register_with_info is similar to
|
||||
hwmon_device_register_with_info. However, it is device managed, meaning the
|
||||
hwmon device does not have to be removed explicitly by the removal function.
|
||||
|
||||
All other hardware monitoring device registration functions are deprecated
|
||||
and must not be used in new drivers.
|
||||
|
||||
hwmon_device_unregister deregisters a registered hardware monitoring device.
|
||||
The parameter of this function is the pointer to the registered hardware
|
||||
monitoring device structure. This function must be called from the driver
|
||||
remove function if the hardware monitoring device was registered with
|
||||
hwmon_device_register_with_groups or hwmon_device_register_with_info.
|
||||
hwmon_device_register_with_info.
|
||||
|
||||
devm_hwmon_device_unregister does not normally have to be called. It is only
|
||||
needed for error handling, and only needed if the driver probe fails after
|
||||
the call to devm_hwmon_device_register_with_groups or
|
||||
hwmon_device_register_with_info and if the automatic (device managed)
|
||||
removal would be too late.
|
||||
the call to hwmon_device_register_with_info and if the automatic (device
|
||||
managed) removal would be too late.
|
||||
|
||||
All supported hwmon device registration functions only accept valid device
|
||||
names. Device names including invalid characters (whitespace, '*', or '-')
|
||||
@ -133,7 +107,7 @@ The hwmon_chip_info structure looks as follows::
|
||||
|
||||
struct hwmon_chip_info {
|
||||
const struct hwmon_ops *ops;
|
||||
const struct hwmon_channel_info **info;
|
||||
const struct hwmon_channel_info * const *info;
|
||||
};
|
||||
|
||||
It contains the following fields:
|
||||
@ -229,7 +203,7 @@ register (HWMON_T_MAX) as well as a maximum temperature hysteresis register
|
||||
.config = lm75_temp_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *lm75_info[] = {
|
||||
static const struct hwmon_channel_info * const lm75_info[] = {
|
||||
&lm75_chip,
|
||||
&lm75_temp,
|
||||
NULL
|
||||
@ -238,7 +212,7 @@ register (HWMON_T_MAX) as well as a maximum temperature hysteresis register
|
||||
The HWMON_CHANNEL_INFO() macro can and should be used when possible.
|
||||
With this macro, the above example can be simplified to
|
||||
|
||||
static const struct hwmon_channel_info *lm75_info[] = {
|
||||
static const struct hwmon_channel_info * const lm75_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
@ -351,11 +325,9 @@ Return value:
|
||||
Driver-provided sysfs attributes
|
||||
--------------------------------
|
||||
|
||||
If the hardware monitoring device is registered with
|
||||
hwmon_device_register_with_info or devm_hwmon_device_register_with_info,
|
||||
it is most likely not necessary to provide sysfs attributes. Only additional
|
||||
non-standard sysfs attributes need to be provided when one of those registration
|
||||
functions is used.
|
||||
In most situations it should not be necessary for a driver to provide sysfs
|
||||
attributes since the hardware monitoring core creates those internally.
|
||||
Only additional non-standard sysfs attributes need to be provided.
|
||||
|
||||
The header file linux/hwmon-sysfs.h provides a number of useful macros to
|
||||
declare and use hardware monitoring sysfs attributes.
|
||||
|
@ -22,6 +22,7 @@ Hardware Monitoring Kernel Drivers
|
||||
|
||||
abituguru
|
||||
abituguru3
|
||||
acbel-fsg032
|
||||
acpi_power_meter
|
||||
ad7314
|
||||
adc128d818
|
||||
@ -184,6 +185,7 @@ Hardware Monitoring Kernel Drivers
|
||||
sch5627
|
||||
sch5636
|
||||
scpi-hwmon
|
||||
sfctemp
|
||||
sht15
|
||||
sht21
|
||||
sht3x
|
||||
|
33
Documentation/hwmon/sfctemp.rst
Normal file
33
Documentation/hwmon/sfctemp.rst
Normal file
@ -0,0 +1,33 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver sfctemp
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
- StarFive JH7100
|
||||
- StarFive JH7110
|
||||
|
||||
Authors:
|
||||
- Emil Renner Berthing <kernel@esmil.dk>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver adds support for reading the built-in temperature sensor on the
|
||||
JH7100 and JH7110 RISC-V SoCs by StarFive Technology Co. Ltd.
|
||||
|
||||
``sysfs`` interface
|
||||
-------------------
|
||||
|
||||
The temperature sensor can be enabled, disabled and queried via the standard
|
||||
hwmon interface in sysfs under ``/sys/class/hwmon/hwmonX`` for some value of
|
||||
``X``:
|
||||
|
||||
================ ==== =============================================
|
||||
Name Perm Description
|
||||
================ ==== =============================================
|
||||
temp1_enable RW Enable or disable temperature sensor.
|
||||
Automatically enabled by the driver,
|
||||
but may be disabled to save power.
|
||||
temp1_input RO Temperature reading in milli-degrees Celsius.
|
||||
================ ==== =============================================
|
@ -201,7 +201,7 @@ PWM
|
||||
Pulse width modulation fan control.
|
||||
|
||||
`pwm[1-*]_enable`
|
||||
Fan speed control method:
|
||||
Fan speed control method.
|
||||
|
||||
`pwm[1-*]_mode`
|
||||
direct current or pulse-width modulation.
|
||||
|
@ -18944,6 +18944,14 @@ S: Supported
|
||||
F: Documentation/networking/devlink/sfc.rst
|
||||
F: drivers/net/ethernet/sfc/
|
||||
|
||||
SFCTEMP HWMON DRIVER
|
||||
M: Emil Renner Berthing <kernel@esmil.dk>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml
|
||||
F: Documentation/hwmon/sfctemp.rst
|
||||
F: drivers/hwmon/sfctemp.c
|
||||
|
||||
SFF/SFP/SFP+ MODULE SUPPORT
|
||||
M: Russell King <linux@armlinux.org.uk>
|
||||
L: netdev@vger.kernel.org
|
||||
@ -21105,7 +21113,6 @@ F: Documentation/hwmon/tmp401.rst
|
||||
F: drivers/hwmon/tmp401.c
|
||||
|
||||
TMP464 HARDWARE MONITOR DRIVER
|
||||
M: Agathe Porte <agathe.porte@nokia.com>
|
||||
M: Guenter Roeck <linux@roeck-us.net>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
|
@ -914,7 +914,7 @@ void hl_hwmon_fini(struct hl_device *hdev)
|
||||
|
||||
void hl_hwmon_release_resources(struct hl_device *hdev)
|
||||
{
|
||||
const struct hwmon_channel_info **channel_info_arr;
|
||||
const struct hwmon_channel_info * const *channel_info_arr;
|
||||
int i = 0;
|
||||
|
||||
if (!hdev->hl_chip_info->info)
|
||||
|
@ -1929,6 +1929,16 @@ config SENSORS_STTS751
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called stts751.
|
||||
|
||||
config SENSORS_SFCTEMP
|
||||
tristate "Starfive JH71x0 temperature sensor"
|
||||
depends on ARCH_STARFIVE || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for temperature sensor
|
||||
on the Starfive JH71x0 SoCs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called sfctemp.
|
||||
|
||||
config SENSORS_SMM665
|
||||
tristate "Summit Microelectronics SMM665"
|
||||
depends on I2C
|
||||
|
@ -6,7 +6,7 @@
|
||||
obj-$(CONFIG_HWMON) += hwmon.o
|
||||
obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
|
||||
|
||||
# APCI drivers
|
||||
# ACPI drivers
|
||||
obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o
|
||||
obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o
|
||||
obj-$(CONFIG_SENSORS_ASUS_EC) += asus-ec-sensors.o
|
||||
@ -181,6 +181,7 @@ obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
|
||||
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
|
||||
obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
|
||||
obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o
|
||||
obj-$(CONFIG_SENSORS_SFCTEMP) += sfctemp.o
|
||||
obj-$(CONFIG_SENSORS_SL28CPLD) += sl28cpld-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_SHT15) += sht15.o
|
||||
obj-$(CONFIG_SENSORS_SHT21) += sht21.o
|
||||
|
@ -168,7 +168,7 @@ static umode_t adm1177_is_visible(const void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *adm1177_info[] = {
|
||||
static const struct hwmon_channel_info * const adm1177_info[] = {
|
||||
HWMON_CHANNEL_INFO(curr,
|
||||
HWMON_C_INPUT | HWMON_C_MAX_ALARM),
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
|
@ -731,7 +731,7 @@ static const struct hwmon_ops adm9240_hwmon_ops = {
|
||||
.write = adm9240_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *adm9240_info[] = {
|
||||
static const struct hwmon_channel_info * const adm9240_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_ALARMS),
|
||||
HWMON_CHANNEL_INFO(intrusion, HWMON_INTRUSION_ALARM),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -636,7 +636,7 @@ static int adt7411_init_device(struct adt7411_data *data)
|
||||
return i2c_smbus_write_byte_data(data->client, ADT7411_REG_CFG1, val);
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *adt7411_info[] = {
|
||||
static const struct hwmon_channel_info * const adt7411_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM,
|
||||
|
@ -1187,7 +1187,7 @@ static const struct hwmon_ops adt7470_hwmon_ops = {
|
||||
.write = adt7470_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *adt7470_info[] = {
|
||||
static const struct hwmon_channel_info * const adt7470_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM,
|
||||
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_ALARM,
|
||||
|
@ -1604,7 +1604,7 @@ static int adt7475_set_pwm_polarity(struct i2c_client *client)
|
||||
int ret, i;
|
||||
u8 val;
|
||||
|
||||
ret = of_property_read_u32_array(client->dev.of_node,
|
||||
ret = device_property_read_u32_array(&client->dev,
|
||||
"adi,pwm-active-state", states,
|
||||
ARRAY_SIZE(states));
|
||||
if (ret)
|
||||
|
@ -309,7 +309,7 @@ static int adt7x10_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *adt7x10_info[] = {
|
||||
static const struct hwmon_channel_info * const adt7x10_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
|
||||
HWMON_T_CRIT | HWMON_T_MAX_HYST | HWMON_T_MIN_HYST |
|
||||
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
|
||||
|
@ -270,7 +270,7 @@ static int aht10_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *aht10_info[] = {
|
||||
static const struct hwmon_channel_info * const aht10_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
|
||||
|
@ -29,12 +29,14 @@
|
||||
#define USB_PRODUCT_ID_FARBWERK360 0xf010
|
||||
#define USB_PRODUCT_ID_OCTO 0xf011
|
||||
#define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012
|
||||
#define USB_PRODUCT_ID_AQUASTREAMXT 0xf0b6
|
||||
#define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b
|
||||
#define USB_PRODUCT_ID_POWERADJUST3 0xf0bd
|
||||
|
||||
enum kinds {
|
||||
d5next, farbwerk, farbwerk360, octo, quadro,
|
||||
highflownext, aquaero, poweradjust3, aquastreamult
|
||||
highflownext, aquaero, poweradjust3, aquastreamult,
|
||||
aquastreamxt
|
||||
};
|
||||
|
||||
static const char *const aqc_device_names[] = {
|
||||
@ -44,6 +46,7 @@ static const char *const aqc_device_names[] = {
|
||||
[octo] = "octo",
|
||||
[quadro] = "quadro",
|
||||
[highflownext] = "highflownext",
|
||||
[aquastreamxt] = "aquastreamxt",
|
||||
[aquaero] = "aquaero",
|
||||
[aquastreamult] = "aquastreamultimate",
|
||||
[poweradjust3] = "poweradjust3"
|
||||
@ -56,6 +59,7 @@ static const char *const aqc_device_names[] = {
|
||||
#define SERIAL_PART_OFFSET 2
|
||||
|
||||
#define CTRL_REPORT_ID 0x03
|
||||
#define AQUAERO_CTRL_REPORT_ID 0x0b
|
||||
|
||||
/* The HID report that the official software always sends
|
||||
* after writing values, currently same for all devices
|
||||
@ -67,9 +71,23 @@ static u8 secondary_ctrl_report[] = {
|
||||
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x34, 0xC6
|
||||
};
|
||||
|
||||
/* Secondary HID report values for Aquaero */
|
||||
#define AQUAERO_SECONDARY_CTRL_REPORT_ID 0x06
|
||||
#define AQUAERO_SECONDARY_CTRL_REPORT_SIZE 0x07
|
||||
|
||||
static u8 aquaero_secondary_ctrl_report[] = {
|
||||
0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* Report IDs for legacy devices */
|
||||
#define AQUASTREAMXT_STATUS_REPORT_ID 0x04
|
||||
|
||||
#define POWERADJUST3_STATUS_REPORT_ID 0x03
|
||||
|
||||
/* Data types for reading and writing control reports */
|
||||
#define AQC_8 0
|
||||
#define AQC_BE16 1
|
||||
|
||||
/* Info, sensor sizes and offsets for most Aquacomputer devices */
|
||||
#define AQC_SERIAL_START 0x3
|
||||
#define AQC_FIRMWARE_VERSION 0xD
|
||||
@ -90,6 +108,10 @@ static u8 secondary_ctrl_report[] = {
|
||||
#define AQUAERO_NUM_VIRTUAL_SENSORS 8
|
||||
#define AQUAERO_NUM_CALC_VIRTUAL_SENSORS 4
|
||||
#define AQUAERO_NUM_FLOW_SENSORS 2
|
||||
#define AQUAERO_CTRL_REPORT_SIZE 0xa93
|
||||
#define AQUAERO_CTRL_PRESET_ID 0x5c
|
||||
#define AQUAERO_CTRL_PRESET_SIZE 0x02
|
||||
#define AQUAERO_CTRL_PRESET_START 0x55c
|
||||
|
||||
/* Sensor report offsets for Aquaero fan controllers */
|
||||
#define AQUAERO_SENSOR_START 0x65
|
||||
@ -102,6 +124,13 @@ static u8 secondary_ctrl_report[] = {
|
||||
#define AQUAERO_FAN_SPEED_OFFSET 0x00
|
||||
static u16 aquaero_sensor_fan_offsets[] = { 0x167, 0x173, 0x17f, 0x18B };
|
||||
|
||||
/* Control report offsets for the Aquaero fan controllers */
|
||||
#define AQUAERO_TEMP_CTRL_OFFSET 0xdb
|
||||
#define AQUAERO_FAN_CTRL_MIN_PWR_OFFSET 0x04
|
||||
#define AQUAERO_FAN_CTRL_MAX_PWR_OFFSET 0x06
|
||||
#define AQUAERO_FAN_CTRL_SRC_OFFSET 0x10
|
||||
static u16 aquaero_ctrl_fan_offsets[] = { 0x20c, 0x220, 0x234, 0x248 };
|
||||
|
||||
/* Specs of the D5 Next pump */
|
||||
#define D5NEXT_NUM_FANS 2
|
||||
#define D5NEXT_NUM_SENSORS 1
|
||||
@ -207,6 +236,24 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
|
||||
#define HIGHFLOWNEXT_5V_VOLTAGE 97
|
||||
#define HIGHFLOWNEXT_5V_VOLTAGE_USB 99
|
||||
|
||||
/* Specs of the Aquastream XT pump */
|
||||
#define AQUASTREAMXT_SERIAL_START 0x3a
|
||||
#define AQUASTREAMXT_FIRMWARE_VERSION 0x32
|
||||
#define AQUASTREAMXT_NUM_FANS 2
|
||||
#define AQUASTREAMXT_NUM_SENSORS 3
|
||||
#define AQUASTREAMXT_FAN_STOPPED 0x4
|
||||
#define AQUASTREAMXT_PUMP_CONVERSION_CONST 45000000
|
||||
#define AQUASTREAMXT_FAN_CONVERSION_CONST 5646000
|
||||
#define AQUASTREAMXT_SENSOR_REPORT_SIZE 0x42
|
||||
|
||||
/* Sensor report offsets and info for Aquastream XT */
|
||||
#define AQUASTREAMXT_SENSOR_START 0xd
|
||||
#define AQUASTREAMXT_FAN_VOLTAGE_OFFSET 0x7
|
||||
#define AQUASTREAMXT_FAN_STATUS_OFFSET 0x1d
|
||||
#define AQUASTREAMXT_PUMP_VOLTAGE_OFFSET 0x9
|
||||
#define AQUASTREAMXT_PUMP_CURR_OFFSET 0xb
|
||||
static u16 aquastreamxt_sensor_fan_offsets[] = { 0x13, 0x1b };
|
||||
|
||||
/* Specs of the Poweradjust 3 */
|
||||
#define POWERADJUST3_NUM_SENSORS 1
|
||||
#define POWERADJUST3_SENSOR_REPORT_SIZE 0x32
|
||||
@ -364,6 +411,13 @@ static const char *const label_highflownext_voltage[] = {
|
||||
"+5V USB voltage"
|
||||
};
|
||||
|
||||
/* Labels for Aquastream XT */
|
||||
static const char *const label_aquastreamxt_temp_sensors[] = {
|
||||
"Fan IC temp",
|
||||
"External sensor",
|
||||
"Coolant temp"
|
||||
};
|
||||
|
||||
/* Labels for Aquastream Ultimate */
|
||||
static const char *const label_aquastreamult_temp[] = {
|
||||
"Coolant temp",
|
||||
@ -437,6 +491,10 @@ struct aqc_data {
|
||||
const char *name;
|
||||
|
||||
int status_report_id; /* Used for legacy devices, report is stored in buffer */
|
||||
int ctrl_report_id;
|
||||
int secondary_ctrl_report_id;
|
||||
int secondary_ctrl_report_size;
|
||||
u8 *secondary_ctrl_report;
|
||||
|
||||
int buffer_size;
|
||||
u8 *buffer;
|
||||
@ -503,13 +561,29 @@ static int aqc_pwm_to_percent(long val)
|
||||
return DIV_ROUND_CLOSEST(val * 100 * 100, 255);
|
||||
}
|
||||
|
||||
/* Converts raw value for Aquastream XT pump speed to RPM */
|
||||
static int aqc_aquastreamxt_convert_pump_rpm(u16 val)
|
||||
{
|
||||
if (val > 0)
|
||||
return DIV_ROUND_CLOSEST(AQUASTREAMXT_PUMP_CONVERSION_CONST, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Converts raw value for Aquastream XT fan speed to RPM */
|
||||
static int aqc_aquastreamxt_convert_fan_rpm(u16 val)
|
||||
{
|
||||
if (val > 0)
|
||||
return DIV_ROUND_CLOSEST(AQUASTREAMXT_FAN_CONVERSION_CONST, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Expects the mutex to be locked */
|
||||
static int aqc_get_ctrl_data(struct aqc_data *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
memset(priv->buffer, 0x00, priv->buffer_size);
|
||||
ret = hid_hw_raw_request(priv->hdev, CTRL_REPORT_ID, priv->buffer, priv->buffer_size,
|
||||
ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
|
||||
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
|
||||
if (ret < 0)
|
||||
ret = -ENODATA;
|
||||
@ -523,28 +597,32 @@ static int aqc_send_ctrl_data(struct aqc_data *priv)
|
||||
int ret;
|
||||
u16 checksum;
|
||||
|
||||
/* Checksum is not needed for Aquaero */
|
||||
if (priv->kind != aquaero) {
|
||||
/* Init and xorout value for CRC-16/USB is 0xffff */
|
||||
checksum = crc16(0xffff, priv->buffer + priv->checksum_start, priv->checksum_length);
|
||||
checksum = crc16(0xffff, priv->buffer + priv->checksum_start,
|
||||
priv->checksum_length);
|
||||
checksum ^= 0xffff;
|
||||
|
||||
/* Place the new checksum at the end of the report */
|
||||
put_unaligned_be16(checksum, priv->buffer + priv->checksum_offset);
|
||||
}
|
||||
|
||||
/* Send the patched up report back to the device */
|
||||
ret = hid_hw_raw_request(priv->hdev, CTRL_REPORT_ID, priv->buffer, priv->buffer_size,
|
||||
ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* The official software sends this report after every change, so do it here as well */
|
||||
ret = hid_hw_raw_request(priv->hdev, SECONDARY_CTRL_REPORT_ID, secondary_ctrl_report,
|
||||
SECONDARY_CTRL_REPORT_SIZE, HID_FEATURE_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
ret = hid_hw_raw_request(priv->hdev, priv->secondary_ctrl_report_id,
|
||||
priv->secondary_ctrl_report, priv->secondary_ctrl_report_size,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Refreshes the control buffer and stores value at offset in val */
|
||||
static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val)
|
||||
static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val, int type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -554,16 +632,25 @@ static int aqc_get_ctrl_val(struct aqc_data *priv, int offset, long *val)
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
|
||||
switch (type) {
|
||||
case AQC_BE16:
|
||||
*val = (s16)get_unaligned_be16(priv->buffer + offset);
|
||||
break;
|
||||
case AQC_8:
|
||||
*val = priv->buffer[offset];
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unlock_and_return:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val)
|
||||
static int aqc_set_ctrl_vals(struct aqc_data *priv, int *offsets, long *vals, int *types, int len)
|
||||
{
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
|
||||
@ -571,7 +658,21 @@ static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val)
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
|
||||
put_unaligned_be16((s16)val, priv->buffer + offset);
|
||||
for (i = 0; i < len; i++) {
|
||||
switch (types[i]) {
|
||||
case AQC_BE16:
|
||||
put_unaligned_be16((s16)vals[i], priv->buffer + offsets[i]);
|
||||
break;
|
||||
case AQC_8:
|
||||
priv->buffer[offsets[i]] = (u8)vals[i];
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto unlock_and_return;
|
||||
|
||||
ret = aqc_send_ctrl_data(priv);
|
||||
|
||||
@ -580,6 +681,11 @@ unlock_and_return:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int aqc_set_ctrl_val(struct aqc_data *priv, int offset, long val, int type)
|
||||
{
|
||||
return aqc_set_ctrl_vals(priv, &offset, &val, &type, 1);
|
||||
}
|
||||
|
||||
static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel)
|
||||
{
|
||||
const struct aqc_data *priv = data;
|
||||
@ -674,6 +780,8 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
||||
if (channel == 0)
|
||||
return 0444;
|
||||
break;
|
||||
case aquastreamxt:
|
||||
break;
|
||||
default:
|
||||
if (channel < priv->num_fans)
|
||||
return 0444;
|
||||
@ -687,6 +795,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
|
||||
if (channel < 2)
|
||||
return 0444;
|
||||
break;
|
||||
case aquastreamxt:
|
||||
/* Special case to support pump current */
|
||||
if (channel == 0)
|
||||
return 0444;
|
||||
break;
|
||||
default:
|
||||
if (channel < priv->num_fans)
|
||||
return 0444;
|
||||
@ -739,6 +852,43 @@ static int aqc_legacy_read(struct aqc_data *priv)
|
||||
priv->temp_input[i] = sensor_value * 10;
|
||||
}
|
||||
|
||||
/* Special-case sensor readings */
|
||||
switch (priv->kind) {
|
||||
case aquastreamxt:
|
||||
/* Info provided with every report */
|
||||
priv->serial_number[0] = get_unaligned_le16(priv->buffer +
|
||||
priv->serial_number_start_offset);
|
||||
priv->firmware_version =
|
||||
get_unaligned_le16(priv->buffer + priv->firmware_version_offset);
|
||||
|
||||
/* Read pump speed in RPM */
|
||||
sensor_value = get_unaligned_le16(priv->buffer + priv->fan_sensor_offsets[0]);
|
||||
priv->speed_input[0] = aqc_aquastreamxt_convert_pump_rpm(sensor_value);
|
||||
|
||||
/* Read fan speed in RPM, if available */
|
||||
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_STATUS_OFFSET);
|
||||
if (sensor_value == AQUASTREAMXT_FAN_STOPPED) {
|
||||
priv->speed_input[1] = 0;
|
||||
} else {
|
||||
sensor_value =
|
||||
get_unaligned_le16(priv->buffer + priv->fan_sensor_offsets[1]);
|
||||
priv->speed_input[1] = aqc_aquastreamxt_convert_fan_rpm(sensor_value);
|
||||
}
|
||||
|
||||
/* Calculation derived from linear regression */
|
||||
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_CURR_OFFSET);
|
||||
priv->current_input[0] = DIV_ROUND_CLOSEST(sensor_value * 176, 100) - 52;
|
||||
|
||||
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_PUMP_VOLTAGE_OFFSET);
|
||||
priv->voltage_input[0] = DIV_ROUND_CLOSEST(sensor_value * 1000, 61);
|
||||
|
||||
sensor_value = get_unaligned_le16(priv->buffer + AQUASTREAMXT_FAN_VOLTAGE_OFFSET);
|
||||
priv->voltage_input[1] = DIV_ROUND_CLOSEST(sensor_value * 1000, 63);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
priv->updated = jiffies;
|
||||
|
||||
unlock_and_return:
|
||||
@ -775,7 +925,7 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
case hwmon_temp_offset:
|
||||
ret =
|
||||
aqc_get_ctrl_val(priv, priv->temp_ctrl_offset +
|
||||
channel * AQC_SENSOR_SIZE, val);
|
||||
channel * AQC_SENSOR_SIZE, val, AQC_BE16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -791,7 +941,8 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
*val = priv->speed_input[channel];
|
||||
break;
|
||||
case hwmon_fan_pulses:
|
||||
ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val);
|
||||
ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset,
|
||||
val, AQC_BE16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
@ -803,12 +954,23 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
*val = priv->power_input[channel];
|
||||
break;
|
||||
case hwmon_pwm:
|
||||
if (priv->fan_ctrl_offsets) {
|
||||
ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel], val);
|
||||
switch (priv->kind) {
|
||||
case aquaero:
|
||||
ret = aqc_get_ctrl_val(priv,
|
||||
AQUAERO_CTRL_PRESET_START + channel * AQUAERO_CTRL_PRESET_SIZE,
|
||||
val, AQC_BE16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = aqc_percent_to_pwm(*val);
|
||||
break;
|
||||
default:
|
||||
ret = aqc_get_ctrl_val(priv, priv->fan_ctrl_offsets[channel],
|
||||
val, AQC_BE16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*val = aqc_percent_to_pwm(ret);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case hwmon_in:
|
||||
@ -867,6 +1029,10 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
long val)
|
||||
{
|
||||
int ret, pwm_value;
|
||||
/* Arrays for setting multiple values at once in the control report */
|
||||
int ctrl_values_offsets[4];
|
||||
long ctrl_values[4];
|
||||
int ctrl_values_types[4];
|
||||
struct aqc_data *priv = dev_get_drvdata(dev);
|
||||
|
||||
switch (type) {
|
||||
@ -877,7 +1043,7 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
val = clamp_val(val, -15000, 15000) / 10;
|
||||
ret =
|
||||
aqc_set_ctrl_val(priv, priv->temp_ctrl_offset +
|
||||
channel * AQC_SENSOR_SIZE, val);
|
||||
channel * AQC_SENSOR_SIZE, val, AQC_BE16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
@ -889,7 +1055,8 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
switch (attr) {
|
||||
case hwmon_fan_pulses:
|
||||
val = clamp_val(val, 10, 1000);
|
||||
ret = aqc_set_ctrl_val(priv, priv->flow_pulses_ctrl_offset, val);
|
||||
ret = aqc_set_ctrl_val(priv, priv->flow_pulses_ctrl_offset,
|
||||
val, AQC_BE16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
@ -900,15 +1067,47 @@ static int aqc_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
case hwmon_pwm:
|
||||
switch (attr) {
|
||||
case hwmon_pwm_input:
|
||||
if (priv->fan_ctrl_offsets) {
|
||||
pwm_value = aqc_pwm_to_percent(val);
|
||||
if (pwm_value < 0)
|
||||
return pwm_value;
|
||||
|
||||
ret = aqc_set_ctrl_val(priv, priv->fan_ctrl_offsets[channel],
|
||||
pwm_value);
|
||||
switch (priv->kind) {
|
||||
case aquaero:
|
||||
/* Write pwm value to preset corresponding to the channel */
|
||||
ctrl_values_offsets[0] = AQUAERO_CTRL_PRESET_START +
|
||||
channel * AQUAERO_CTRL_PRESET_SIZE;
|
||||
ctrl_values[0] = pwm_value;
|
||||
ctrl_values_types[0] = AQC_BE16;
|
||||
|
||||
/* Write preset number in fan control source */
|
||||
ctrl_values_offsets[1] = priv->fan_ctrl_offsets[channel] +
|
||||
AQUAERO_FAN_CTRL_SRC_OFFSET;
|
||||
ctrl_values[1] = AQUAERO_CTRL_PRESET_ID + channel;
|
||||
ctrl_values_types[1] = AQC_BE16;
|
||||
|
||||
/* Set minimum power to 0 to allow the fan to turn off */
|
||||
ctrl_values_offsets[2] = priv->fan_ctrl_offsets[channel] +
|
||||
AQUAERO_FAN_CTRL_MIN_PWR_OFFSET;
|
||||
ctrl_values[2] = 0;
|
||||
ctrl_values_types[2] = AQC_BE16;
|
||||
|
||||
/* Set maximum power to 255 to allow the fan to reach max speed */
|
||||
ctrl_values_offsets[3] = priv->fan_ctrl_offsets[channel] +
|
||||
AQUAERO_FAN_CTRL_MAX_PWR_OFFSET;
|
||||
ctrl_values[3] = aqc_pwm_to_percent(255);
|
||||
ctrl_values_types[3] = AQC_BE16;
|
||||
|
||||
ret = aqc_set_ctrl_vals(priv, ctrl_values_offsets, ctrl_values,
|
||||
ctrl_values_types, 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
ret = aqc_set_ctrl_val(priv, priv->fan_ctrl_offsets[channel],
|
||||
pwm_value, AQC_BE16);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -929,16 +1128,16 @@ static const struct hwmon_ops aqc_hwmon_ops = {
|
||||
.write = aqc_write
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *aqc_info[] = {
|
||||
static const struct hwmon_channel_info * const aqc_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
@ -1231,6 +1430,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
|
||||
priv->num_fans = AQUAERO_NUM_FANS;
|
||||
priv->fan_sensor_offsets = aquaero_sensor_fan_offsets;
|
||||
priv->fan_ctrl_offsets = aquaero_ctrl_fan_offsets;
|
||||
|
||||
priv->num_temp_sensors = AQUAERO_NUM_SENSORS;
|
||||
priv->temp_sensor_start_offset = AQUAERO_SENSOR_START;
|
||||
@ -1241,6 +1441,9 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
priv->num_flow_sensors = AQUAERO_NUM_FLOW_SENSORS;
|
||||
priv->flow_sensors_start_offset = AQUAERO_FLOW_SENSORS_START;
|
||||
|
||||
priv->buffer_size = AQUAERO_CTRL_REPORT_SIZE;
|
||||
priv->temp_ctrl_offset = AQUAERO_TEMP_CTRL_OFFSET;
|
||||
|
||||
priv->temp_label = label_temp_sensors;
|
||||
priv->virtual_temp_label = label_virtual_temp_sensors;
|
||||
priv->calc_virt_temp_label = label_aquaero_calc_temp_sensors;
|
||||
@ -1368,6 +1571,21 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
priv->power_label = label_highflownext_power;
|
||||
priv->voltage_label = label_highflownext_voltage;
|
||||
break;
|
||||
case USB_PRODUCT_ID_AQUASTREAMXT:
|
||||
priv->kind = aquastreamxt;
|
||||
|
||||
priv->num_fans = AQUASTREAMXT_NUM_FANS;
|
||||
priv->fan_sensor_offsets = aquastreamxt_sensor_fan_offsets;
|
||||
|
||||
priv->num_temp_sensors = AQUASTREAMXT_NUM_SENSORS;
|
||||
priv->temp_sensor_start_offset = AQUASTREAMXT_SENSOR_START;
|
||||
priv->buffer_size = AQUASTREAMXT_SENSOR_REPORT_SIZE;
|
||||
|
||||
priv->temp_label = label_aquastreamxt_temp_sensors;
|
||||
priv->speed_label = label_d5next_speeds;
|
||||
priv->voltage_label = label_d5next_voltages;
|
||||
priv->current_label = label_d5next_current;
|
||||
break;
|
||||
case USB_PRODUCT_ID_AQUASTREAMULT:
|
||||
priv->kind = aquastreamult;
|
||||
|
||||
@ -1404,14 +1622,30 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
priv->firmware_version_offset = AQUAERO_FIRMWARE_VERSION;
|
||||
|
||||
priv->fan_structure = &aqc_aquaero_fan_structure;
|
||||
|
||||
priv->ctrl_report_id = AQUAERO_CTRL_REPORT_ID;
|
||||
priv->secondary_ctrl_report_id = AQUAERO_SECONDARY_CTRL_REPORT_ID;
|
||||
priv->secondary_ctrl_report_size = AQUAERO_SECONDARY_CTRL_REPORT_SIZE;
|
||||
priv->secondary_ctrl_report = aquaero_secondary_ctrl_report;
|
||||
break;
|
||||
case poweradjust3:
|
||||
priv->status_report_id = POWERADJUST3_STATUS_REPORT_ID;
|
||||
break;
|
||||
case aquastreamxt:
|
||||
priv->serial_number_start_offset = AQUASTREAMXT_SERIAL_START;
|
||||
priv->firmware_version_offset = AQUASTREAMXT_FIRMWARE_VERSION;
|
||||
|
||||
priv->status_report_id = AQUASTREAMXT_STATUS_REPORT_ID;
|
||||
break;
|
||||
default:
|
||||
priv->serial_number_start_offset = AQC_SERIAL_START;
|
||||
priv->firmware_version_offset = AQC_FIRMWARE_VERSION;
|
||||
|
||||
priv->ctrl_report_id = CTRL_REPORT_ID;
|
||||
priv->secondary_ctrl_report_id = SECONDARY_CTRL_REPORT_ID;
|
||||
priv->secondary_ctrl_report_size = SECONDARY_CTRL_REPORT_SIZE;
|
||||
priv->secondary_ctrl_report = secondary_ctrl_report;
|
||||
|
||||
if (priv->kind == aquastreamult)
|
||||
priv->fan_structure = &aqc_aquastreamult_fan_structure;
|
||||
else
|
||||
@ -1473,6 +1707,7 @@ static const struct hid_device_id aqc_table[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) },
|
||||
{ }
|
||||
|
@ -76,7 +76,7 @@ as370_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *as370_hwmon_info[] = {
|
||||
static const struct hwmon_channel_info * const as370_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
@ -303,6 +303,14 @@ static const struct ec_board_info board_info_pro_art_x570_creator_wifi = {
|
||||
.family = family_amd_500_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_pro_art_b550_creator = {
|
||||
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
|
||||
SENSOR_TEMP_T_SENSOR |
|
||||
SENSOR_FAN_CPU_OPT,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
|
||||
.family = family_amd_500_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_pro_ws_x570_ace = {
|
||||
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
|
||||
SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET |
|
||||
@ -400,6 +408,14 @@ static const struct ec_board_info board_info_strix_x570_i_gaming = {
|
||||
.family = family_amd_500_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_z390_f_gaming = {
|
||||
.sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
|
||||
SENSOR_TEMP_T_SENSOR |
|
||||
SENSOR_FAN_CPU_OPT,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
|
||||
.family = family_intel_300_series,
|
||||
};
|
||||
|
||||
static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = {
|
||||
.sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,
|
||||
.mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
|
||||
@ -435,6 +451,8 @@ static const struct dmi_system_id dmi_table[] = {
|
||||
&board_info_prime_x570_pro),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X570-CREATOR WIFI",
|
||||
&board_info_pro_art_x570_creator_wifi),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR",
|
||||
&board_info_pro_art_b550_creator),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE",
|
||||
&board_info_pro_ws_x570_ace),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII DARK HERO",
|
||||
@ -463,6 +481,8 @@ static const struct dmi_system_id dmi_table[] = {
|
||||
&board_info_strix_x570_f_gaming),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-I GAMING",
|
||||
&board_info_strix_x570_i_gaming),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING",
|
||||
&board_info_strix_z390_f_gaming),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4",
|
||||
&board_info_strix_z690_a_gaming_wifi_d4),
|
||||
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",
|
||||
|
@ -394,7 +394,7 @@ static int axi_fan_control_init(struct axi_fan_control_data *ctl,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *axi_fan_control_info[] = {
|
||||
static const struct hwmon_channel_info * const axi_fan_control_info[] = {
|
||||
HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT),
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_LABEL),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL),
|
||||
|
@ -379,7 +379,7 @@ static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *pvt_channel_info[] = {
|
||||
static const struct hwmon_channel_info * const pvt_channel_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
@ -523,7 +523,7 @@ static int pvt_read_alarm(struct pvt_hwmon *pvt, enum pvt_sensor_type type,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *pvt_channel_info[] = {
|
||||
static const struct hwmon_channel_info * const pvt_channel_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -282,15 +282,9 @@ static int get_tjmax(struct temp_data *tdata, struct device *dev)
|
||||
dev_warn(dev, "Unable to read TjMax from CPU %u\n", tdata->cpu);
|
||||
} else {
|
||||
val = (eax >> 16) & 0xff;
|
||||
/*
|
||||
* If the TjMax is not plausible, an assumption
|
||||
* will be used
|
||||
*/
|
||||
if (val) {
|
||||
dev_dbg(dev, "TjMax is %d degrees C\n", val);
|
||||
if (val)
|
||||
return val * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
if (force_tjmax) {
|
||||
dev_notice(dev, "TjMax forced to %d degrees C by user\n",
|
||||
|
@ -385,7 +385,7 @@ static const struct hwmon_ops ccp_hwmon_ops = {
|
||||
.write = ccp_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *ccp_info[] = {
|
||||
static const struct hwmon_channel_info * const ccp_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -571,7 +571,7 @@ static const struct hwmon_ops corsairpsu_hwmon_ops = {
|
||||
.read_string = corsairpsu_hwmon_ops_read_string,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *corsairpsu_info[] = {
|
||||
static const struct hwmon_channel_info * const corsairpsu_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -920,7 +920,7 @@ static const struct hwmon_ops dell_smm_ops = {
|
||||
.write = dell_smm_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *dell_smm_info[] = {
|
||||
static const struct hwmon_channel_info * const dell_smm_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
|
@ -526,7 +526,7 @@ static umode_t drivetemp_is_visible(const void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *drivetemp_info[] = {
|
||||
static const struct hwmon_channel_info * const drivetemp_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT |
|
||||
|
@ -479,7 +479,7 @@ static const struct hwmon_ops emc2305_ops = {
|
||||
.write = emc2305_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *emc2305_info[] = {
|
||||
static const struct hwmon_channel_info * const emc2305_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_INPUT | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_FAULT,
|
||||
|
@ -520,7 +520,7 @@ static const struct hwmon_ops fts_ops = {
|
||||
.write = fts_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *fts_info[] = {
|
||||
static const struct hwmon_channel_info * const fts_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_FAULT,
|
||||
|
@ -620,7 +620,12 @@ static int g762_of_clock_enable(struct i2c_client *client)
|
||||
data = i2c_get_clientdata(client);
|
||||
data->clk = clk;
|
||||
|
||||
devm_add_action(&client->dev, g762_of_clock_disable, data);
|
||||
ret = devm_add_action(&client->dev, g762_of_clock_disable, data);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to add disable clock action\n");
|
||||
goto clk_unprep;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
clk_unprep:
|
||||
|
@ -586,7 +586,7 @@ static struct platform_driver gpio_fan_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-fan",
|
||||
.pm = pm_sleep_ptr(&gpio_fan_pm),
|
||||
.of_match_table = of_match_ptr(of_gpio_fan_match),
|
||||
.of_match_table = of_gpio_fan_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -168,7 +168,7 @@ static const struct hwmon_ops gxp_fan_ctrl_ops = {
|
||||
.write = gxp_fan_ctrl_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *gxp_fan_ctrl_info[] = {
|
||||
static const struct hwmon_channel_info * const gxp_fan_ctrl_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
|
@ -174,7 +174,7 @@ static int hwmon_thermal_set_trips(struct thermal_zone_device *tz, int low, int
|
||||
struct hwmon_thermal_data *tdata = tz->devdata;
|
||||
struct hwmon_device *hwdev = to_hwmon_device(tdata->dev);
|
||||
const struct hwmon_chip_info *chip = hwdev->chip;
|
||||
const struct hwmon_channel_info **info = chip->info;
|
||||
const struct hwmon_channel_info * const *info = chip->info;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
@ -253,7 +253,7 @@ static int hwmon_thermal_register_sensors(struct device *dev)
|
||||
{
|
||||
struct hwmon_device *hwdev = to_hwmon_device(dev);
|
||||
const struct hwmon_chip_info *chip = hwdev->chip;
|
||||
const struct hwmon_channel_info **info = chip->info;
|
||||
const struct hwmon_channel_info * const *info = chip->info;
|
||||
void *drvdata = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
|
@ -88,7 +88,7 @@ static const struct hwmon_ops i5500_ops = {
|
||||
.read = i5500_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *i5500_info[] = {
|
||||
static const struct hwmon_channel_info * const i5500_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_CRIT |
|
||||
|
@ -456,9 +456,9 @@ static int populate_attr_groups(struct platform_device *pdev)
|
||||
*/
|
||||
if (!of_property_read_string(np, "label", &label))
|
||||
sensor_groups[type].attr_count++;
|
||||
if (of_find_property(np, "sensor-data-min", NULL))
|
||||
if (of_property_present(np, "sensor-data-min"))
|
||||
sensor_groups[type].attr_count++;
|
||||
if (of_find_property(np, "sensor-data-max", NULL))
|
||||
if (of_property_present(np, "sensor-data-max"))
|
||||
sensor_groups[type].attr_count++;
|
||||
}
|
||||
|
||||
|
@ -501,7 +501,7 @@ static umode_t ina238_is_visible(const void *drvdata,
|
||||
HWMON_I_MAX | HWMON_I_MAX_ALARM | \
|
||||
HWMON_I_MIN | HWMON_I_MIN_ALARM)
|
||||
|
||||
static const struct hwmon_channel_info *ina238_info[] = {
|
||||
static const struct hwmon_channel_info * const ina238_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
/* 0: shunt voltage */
|
||||
INA238_HWMON_IN_CONFIG,
|
||||
|
@ -656,6 +656,10 @@ static int ina2xx_probe(struct i2c_client *client)
|
||||
return PTR_ERR(data->regmap);
|
||||
}
|
||||
|
||||
ret = devm_regulator_get_enable(dev, "vs");
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to enable vs regulator\n");
|
||||
|
||||
ret = ina2xx_init(data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "error configuring the device: %d\n", ret);
|
||||
|
@ -650,7 +650,7 @@ static umode_t ina3221_is_visible(const void *drvdata,
|
||||
HWMON_C_CRIT | HWMON_C_CRIT_ALARM | \
|
||||
HWMON_C_MAX | HWMON_C_MAX_ALARM)
|
||||
|
||||
static const struct hwmon_channel_info *ina3221_info[] = {
|
||||
static const struct hwmon_channel_info * const ina3221_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_SAMPLES,
|
||||
HWMON_C_UPDATE_INTERVAL),
|
||||
|
@ -24,7 +24,7 @@ struct m10bmc_sdata {
|
||||
|
||||
struct m10bmc_hwmon_board_data {
|
||||
const struct m10bmc_sdata *tables[hwmon_max];
|
||||
const struct hwmon_channel_info **hinfo;
|
||||
const struct hwmon_channel_info * const *hinfo;
|
||||
};
|
||||
|
||||
struct m10bmc_hwmon {
|
||||
@ -67,7 +67,7 @@ static const struct m10bmc_sdata n3000bmc_power_tbl[] = {
|
||||
{ 0x160, 0x0, 0x0, 0x0, 0x0, 1000, "Board Power" },
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *n3000bmc_hinfo[] = {
|
||||
static const struct hwmon_channel_info * const n3000bmc_hinfo[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
@ -154,7 +154,7 @@ static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
|
||||
.hinfo = n3000bmc_hinfo,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *d5005bmc_hinfo[] = {
|
||||
static const struct hwmon_channel_info * const d5005bmc_hinfo[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
|
||||
@ -280,7 +280,7 @@ static const struct m10bmc_sdata n5010bmc_curr_tbl[] = {
|
||||
{ 0x1a0, 0x0, 0x0, 0x0, 0x0, 1, "CVL2 0.8V Current" },
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *n5010bmc_hinfo[] = {
|
||||
static const struct hwmon_channel_info * const n5010bmc_hinfo[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_LABEL,
|
||||
@ -432,7 +432,7 @@ static const struct m10bmc_sdata n6000bmc_power_tbl[] = {
|
||||
{ 0x724, 0x0, 0x0, 0x0, 0x0, 1, "Board Power" },
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *n6000bmc_hinfo[] = {
|
||||
static const struct hwmon_channel_info * const n6000bmc_hinfo[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_LABEL,
|
||||
|
@ -162,8 +162,11 @@ static inline void superio_exit(int ioreg, bool noexit)
|
||||
#define IT8623E_DEVID 0x8623
|
||||
#define IT8628E_DEVID 0x8628
|
||||
#define IT87952E_DEVID 0x8695
|
||||
|
||||
/* Logical device 4 (Environmental Monitor) registers */
|
||||
#define IT87_ACT_REG 0x30
|
||||
#define IT87_BASE_REG 0x60
|
||||
#define IT87_SPECIAL_CFG_REG 0xf3 /* special configuration register */
|
||||
|
||||
/* Logical device 7 registers (IT8712F and later) */
|
||||
#define IT87_SIO_GPIO1_REG 0x25
|
||||
@ -284,6 +287,8 @@ struct it87_devices {
|
||||
u32 features;
|
||||
u8 peci_mask;
|
||||
u8 old_peci_mask;
|
||||
u8 smbus_bitmap; /* SMBus enable bits in extra config register */
|
||||
u8 ec_special_config;
|
||||
};
|
||||
|
||||
#define FEAT_12MV_ADC BIT(0)
|
||||
@ -469,6 +474,7 @@ static const struct it87_devices it87_devices[] = {
|
||||
| FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
|
||||
| FEAT_AVCC3 | FEAT_VIN3_5V,
|
||||
.peci_mask = 0x07,
|
||||
.smbus_bitmap = BIT(1) | BIT(2),
|
||||
},
|
||||
[it8628] = {
|
||||
.name = "it8628",
|
||||
@ -533,6 +539,8 @@ struct it87_sio_data {
|
||||
u8 skip_fan;
|
||||
u8 skip_pwm;
|
||||
u8 skip_temp;
|
||||
u8 smbus_bitmap;
|
||||
u8 ec_special_config;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -547,6 +555,9 @@ struct it87_data {
|
||||
u8 peci_mask;
|
||||
u8 old_peci_mask;
|
||||
|
||||
u8 smbus_bitmap; /* !=0 if SMBus needs to be disabled */
|
||||
u8 ec_special_config; /* EC special config register restore value */
|
||||
|
||||
unsigned short addr;
|
||||
const char *name;
|
||||
struct mutex update_lock;
|
||||
@ -701,8 +712,42 @@ static const unsigned int pwm_freq[8] = {
|
||||
750000,
|
||||
};
|
||||
|
||||
static int smbus_disable(struct it87_data *data)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (data->smbus_bitmap) {
|
||||
err = superio_enter(data->sioaddr);
|
||||
if (err)
|
||||
return err;
|
||||
superio_select(data->sioaddr, PME);
|
||||
superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
|
||||
data->ec_special_config & ~data->smbus_bitmap);
|
||||
superio_exit(data->sioaddr, has_conf_noexit(data));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int smbus_enable(struct it87_data *data)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (data->smbus_bitmap) {
|
||||
err = superio_enter(data->sioaddr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
superio_select(data->sioaddr, PME);
|
||||
superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
|
||||
data->ec_special_config);
|
||||
superio_exit(data->sioaddr, has_conf_noexit(data));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called with data->update_lock held, except during initialization.
|
||||
* Must be called with SMBus accesses disabled.
|
||||
* We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
* would slow down the IT87 access and should not be necessary.
|
||||
*/
|
||||
@ -714,6 +759,7 @@ static int it87_read_value(struct it87_data *data, u8 reg)
|
||||
|
||||
/*
|
||||
* Must be called with data->update_lock held, except during initialization.
|
||||
* Must be called with SMBus accesses disabled.
|
||||
* We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
|
||||
* would slow down the IT87 access and should not be necessary.
|
||||
*/
|
||||
@ -773,15 +819,39 @@ static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
|
||||
}
|
||||
}
|
||||
|
||||
static int it87_lock(struct it87_data *data)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = smbus_disable(data);
|
||||
if (err)
|
||||
mutex_unlock(&data->update_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void it87_unlock(struct it87_data *data)
|
||||
{
|
||||
smbus_enable(data);
|
||||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
|
||||
static struct it87_data *it87_update_device(struct device *dev)
|
||||
{
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
struct it87_data *ret = data;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
|
||||
!data->valid) {
|
||||
err = smbus_disable(data);
|
||||
if (err) {
|
||||
ret = ERR_PTR(err);
|
||||
goto unlock;
|
||||
}
|
||||
if (update_vbat) {
|
||||
/*
|
||||
* Cleared after each update, so reenable. Value
|
||||
@ -884,11 +954,11 @@ static struct it87_data *it87_update_device(struct device *dev)
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
smbus_enable(data);
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
||||
@ -899,6 +969,9 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
||||
int index = sattr->index;
|
||||
int nr = sattr->nr;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
|
||||
}
|
||||
|
||||
@ -910,17 +983,21 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
|
||||
int index = sattr->index;
|
||||
int nr = sattr->nr;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->in[nr][index] = in_to_reg(data, nr, val);
|
||||
it87_write_value(data,
|
||||
index == 1 ? IT87_REG_VIN_MIN(nr)
|
||||
: IT87_REG_VIN_MAX(nr),
|
||||
data->in[nr][index]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -987,6 +1064,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
|
||||
int index = sattr->index;
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
|
||||
}
|
||||
|
||||
@ -999,11 +1079,14 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
u8 reg, regval;
|
||||
int err;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (index) {
|
||||
default:
|
||||
@ -1026,7 +1109,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
data->temp[nr][index] = TEMP_TO_REG(val);
|
||||
it87_write_value(data, reg, data->temp[nr][index]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1061,8 +1144,13 @@ static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
u8 reg = data->sensor; /* In case value is updated while used */
|
||||
u8 extra = data->extra;
|
||||
u8 reg, extra;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
reg = data->sensor; /* In case value is updated while used */
|
||||
extra = data->extra;
|
||||
|
||||
if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) ||
|
||||
(has_temp_old_peci(data, nr) && (extra & 0x80)))
|
||||
@ -1083,10 +1171,15 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
u8 reg, extra;
|
||||
int err;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
|
||||
reg &= ~(1 << nr);
|
||||
reg &= ~(8 << nr);
|
||||
@ -1109,17 +1202,19 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
|
||||
reg |= (nr + 1) << 6;
|
||||
else if (has_temp_old_peci(data, nr) && val == 6)
|
||||
extra |= 0x80;
|
||||
else if (val != 0)
|
||||
return -EINVAL;
|
||||
else if (val != 0) {
|
||||
count = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->sensor = reg;
|
||||
data->extra = extra;
|
||||
it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
|
||||
if (has_temp_old_peci(data, nr))
|
||||
it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
|
||||
data->valid = false; /* Force cache refresh */
|
||||
mutex_unlock(&data->update_lock);
|
||||
unlock:
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1154,6 +1249,9 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
|
||||
int speed;
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
speed = has_16bit_fans(data) ?
|
||||
FAN16_FROM_REG(data->fan[nr][index]) :
|
||||
FAN_FROM_REG(data->fan[nr][index],
|
||||
@ -1168,6 +1266,9 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr]));
|
||||
}
|
||||
|
||||
@ -1178,6 +1279,9 @@ static ssize_t show_pwm_enable(struct device *dev,
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n", pwm_mode(data, nr));
|
||||
}
|
||||
|
||||
@ -1188,6 +1292,9 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
pwm_from_reg(data, data->pwm_duty[nr]));
|
||||
}
|
||||
@ -1201,6 +1308,9 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
|
||||
unsigned int freq;
|
||||
int index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
if (has_pwm_freq2(data) && nr == 1)
|
||||
index = (data->extra >> 4) & 0x07;
|
||||
else
|
||||
@ -1220,12 +1330,15 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
int err;
|
||||
u8 reg;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (has_16bit_fans(data)) {
|
||||
data->fan[nr][index] = FAN16_TO_REG(val);
|
||||
@ -1252,7 +1365,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
|
||||
data->fan[nr][index]);
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1263,13 +1376,16 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
int nr = sensor_attr->index;
|
||||
unsigned long val;
|
||||
int min;
|
||||
int min, err;
|
||||
u8 old;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
old = it87_read_value(data, IT87_REG_FAN_DIV);
|
||||
|
||||
/* Save fan min limit */
|
||||
@ -1297,7 +1413,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
|
||||
data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
|
||||
it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1338,6 +1454,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
int nr = sensor_attr->index;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
|
||||
return -EINVAL;
|
||||
@ -1348,7 +1465,9 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (val == 0) {
|
||||
if (nr < 3 && data->type != it8603) {
|
||||
@ -1399,7 +1518,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1410,11 +1529,15 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
int nr = sensor_attr->index;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
it87_update_pwm_ctrl(data, nr);
|
||||
if (has_newer_autopwm(data)) {
|
||||
/*
|
||||
@ -1422,8 +1545,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
* is read-only so we can't write the value.
|
||||
*/
|
||||
if (data->pwm_ctrl[nr] & 0x80) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
return -EBUSY;
|
||||
count = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
data->pwm_duty[nr] = pwm_to_reg(data, val);
|
||||
it87_write_value(data, IT87_REG_PWM_DUTY[nr],
|
||||
@ -1440,7 +1563,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||
data->pwm_ctrl[nr]);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
unlock:
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1451,6 +1575,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
int nr = sensor_attr->index;
|
||||
unsigned long val;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0)
|
||||
@ -1465,7 +1590,10 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (nr == 0) {
|
||||
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
|
||||
data->fan_ctl |= i << 4;
|
||||
@ -1475,7 +1603,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
|
||||
data->extra |= i << 4;
|
||||
it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -1488,6 +1616,9 @@ static ssize_t show_pwm_temp_map(struct device *dev,
|
||||
int nr = sensor_attr->index;
|
||||
int map;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
map = data->pwm_temp_map[nr];
|
||||
if (map >= 3)
|
||||
map = 0; /* Should never happen */
|
||||
@ -1505,6 +1636,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
int nr = sensor_attr->index;
|
||||
long val;
|
||||
int err;
|
||||
u8 reg;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
@ -1527,7 +1659,10 @@ static ssize_t set_pwm_temp_map(struct device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
it87_update_pwm_ctrl(data, nr);
|
||||
data->pwm_temp_map[nr] = reg;
|
||||
/*
|
||||
@ -1539,7 +1674,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
|
||||
data->pwm_temp_map[nr];
|
||||
it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1552,6 +1687,9 @@ static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
|
||||
int nr = sensor_attr->nr;
|
||||
int point = sensor_attr->index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n",
|
||||
pwm_from_reg(data, data->auto_pwm[nr][point]));
|
||||
}
|
||||
@ -1566,18 +1704,22 @@ static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
|
||||
int point = sensor_attr->index;
|
||||
int regaddr;
|
||||
long val;
|
||||
int err;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->auto_pwm[nr][point] = pwm_to_reg(data, val);
|
||||
if (has_newer_autopwm(data))
|
||||
regaddr = IT87_REG_AUTO_TEMP(nr, 3);
|
||||
else
|
||||
regaddr = IT87_REG_AUTO_PWM(nr, point);
|
||||
it87_write_value(data, regaddr, data->auto_pwm[nr][point]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1588,6 +1730,9 @@ static ssize_t show_auto_pwm_slope(struct device *dev,
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%d\n", data->auto_pwm[nr][1] & 0x7f);
|
||||
}
|
||||
|
||||
@ -1599,15 +1744,19 @@ static ssize_t set_auto_pwm_slope(struct device *dev,
|
||||
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
|
||||
int nr = sensor_attr->index;
|
||||
unsigned long val;
|
||||
int err;
|
||||
|
||||
if (kstrtoul(buf, 10, &val) < 0 || val > 127)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val;
|
||||
it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4),
|
||||
data->auto_pwm[nr][1]);
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1621,6 +1770,9 @@ static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
|
||||
int point = sensor_attr->index;
|
||||
int reg;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
if (has_old_autopwm(data) || point)
|
||||
reg = data->auto_temp[nr][point];
|
||||
else
|
||||
@ -1639,11 +1791,15 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
|
||||
int point = sensor_attr->index;
|
||||
long val;
|
||||
int reg;
|
||||
int err;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (has_newer_autopwm(data) && !point) {
|
||||
reg = data->auto_temp[nr][1] - TEMP_TO_REG(val);
|
||||
reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0);
|
||||
@ -1656,7 +1812,7 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
|
||||
point--;
|
||||
it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg);
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1841,6 +1997,9 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%u\n", data->alarms);
|
||||
}
|
||||
static DEVICE_ATTR_RO(alarms);
|
||||
@ -1851,6 +2010,9 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
|
||||
}
|
||||
|
||||
@ -1859,13 +2021,16 @@ static ssize_t clear_intrusion(struct device *dev,
|
||||
size_t count)
|
||||
{
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
int config;
|
||||
int err, config;
|
||||
long val;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0 || val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
config = it87_read_value(data, IT87_REG_CONFIG);
|
||||
if (config < 0) {
|
||||
count = config;
|
||||
@ -1875,8 +2040,7 @@ static ssize_t clear_intrusion(struct device *dev,
|
||||
/* Invalidate cache to force re-read */
|
||||
data->valid = false;
|
||||
}
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1906,6 +2070,9 @@ static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1);
|
||||
}
|
||||
|
||||
@ -1915,18 +2082,22 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
|
||||
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||
struct it87_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
int err;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
err = it87_lock(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
|
||||
if (val)
|
||||
data->beeps |= BIT(bitnr);
|
||||
else
|
||||
data->beeps &= ~BIT(bitnr);
|
||||
it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1979,6 +2150,9 @@ static ssize_t cpu0_vid_show(struct device *dev,
|
||||
{
|
||||
struct it87_data *data = it87_update_device(dev);
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm));
|
||||
}
|
||||
static DEVICE_ATTR_RO(cpu0_vid);
|
||||
@ -2004,7 +2178,7 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
if (has_vin3_5v(data) && nr == 0)
|
||||
label = labels[0];
|
||||
else if (has_12mv_adc(data) || has_10_9mv_adc(data))
|
||||
else if (has_scaling(data))
|
||||
label = labels_it8721[nr];
|
||||
else
|
||||
label = labels[nr];
|
||||
@ -2859,6 +3033,15 @@ static int __init it87_find(int sioaddr, unsigned short *address,
|
||||
if (dmi_data)
|
||||
sio_data->skip_pwm |= dmi_data->skip_pwm;
|
||||
|
||||
if (config->smbus_bitmap) {
|
||||
u8 reg;
|
||||
|
||||
superio_select(sioaddr, PME);
|
||||
reg = superio_inb(sioaddr, IT87_SPECIAL_CFG_REG);
|
||||
sio_data->ec_special_config = reg;
|
||||
sio_data->smbus_bitmap = reg & config->smbus_bitmap;
|
||||
}
|
||||
|
||||
exit:
|
||||
superio_exit(sioaddr, config ? has_conf_noexit(config) : false);
|
||||
return err;
|
||||
@ -3077,6 +3260,7 @@ static int it87_probe(struct platform_device *pdev)
|
||||
struct it87_sio_data *sio_data = dev_get_platdata(dev);
|
||||
int enable_pwm_interface;
|
||||
struct device *hwmon_dev;
|
||||
int err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
|
||||
@ -3094,6 +3278,8 @@ static int it87_probe(struct platform_device *pdev)
|
||||
data->addr = res->start;
|
||||
data->sioaddr = sio_data->sioaddr;
|
||||
data->type = sio_data->type;
|
||||
data->smbus_bitmap = sio_data->smbus_bitmap;
|
||||
data->ec_special_config = sio_data->ec_special_config;
|
||||
data->features = it87_devices[sio_data->type].features;
|
||||
data->peci_mask = it87_devices[sio_data->type].peci_mask;
|
||||
data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
|
||||
@ -3120,15 +3306,21 @@ static int it87_probe(struct platform_device *pdev)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now, we do the remaining detection. */
|
||||
if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
|
||||
it87_read_value(data, IT87_REG_CHIPID) != 0x90)
|
||||
return -ENODEV;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
err = smbus_disable(data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Now, we do the remaining detection. */
|
||||
if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
|
||||
it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
|
||||
smbus_enable(data);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Check PWM configuration */
|
||||
enable_pwm_interface = it87_check_pwm(dev);
|
||||
if (!enable_pwm_interface)
|
||||
@ -3189,6 +3381,8 @@ static int it87_probe(struct platform_device *pdev)
|
||||
/* Initialize the IT87 chip */
|
||||
it87_init_device(pdev);
|
||||
|
||||
smbus_enable(data);
|
||||
|
||||
if (!sio_data->skip_vid) {
|
||||
data->has_vid = true;
|
||||
data->vrm = vid_which_vrm();
|
||||
@ -3256,7 +3450,7 @@ static int it87_resume(struct device *dev)
|
||||
|
||||
it87_resume_sio(pdev);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
it87_lock(data);
|
||||
|
||||
it87_check_pwm(dev);
|
||||
it87_check_limit_regs(data);
|
||||
@ -3269,7 +3463,7 @@ static int it87_resume(struct device *dev)
|
||||
/* force update */
|
||||
data->valid = false;
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
it87_unlock(data);
|
||||
|
||||
it87_update_device(dev);
|
||||
|
||||
|
@ -450,7 +450,7 @@ static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *jc42_info[] = {
|
||||
static const struct hwmon_channel_info * const jc42_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -75,6 +75,7 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
|
||||
|
||||
#define ZEN_CUR_TEMP_SHIFT 21
|
||||
#define ZEN_CUR_TEMP_RANGE_SEL_MASK BIT(19)
|
||||
#define ZEN_CUR_TEMP_TJ_SEL_MASK GENMASK(17, 16)
|
||||
|
||||
struct k10temp_data {
|
||||
struct pci_dev *pdev;
|
||||
@ -155,7 +156,8 @@ static long get_raw_temp(struct k10temp_data *data)
|
||||
|
||||
data->read_tempreg(data->pdev, ®val);
|
||||
temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125;
|
||||
if (regval & data->temp_adjust_mask)
|
||||
if ((regval & data->temp_adjust_mask) ||
|
||||
(regval & ZEN_CUR_TEMP_TJ_SEL_MASK) == ZEN_CUR_TEMP_TJ_SEL_MASK)
|
||||
temp -= 49000;
|
||||
return temp;
|
||||
}
|
||||
@ -332,7 +334,7 @@ static bool has_erratum_319(struct pci_dev *pdev)
|
||||
(boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2);
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *k10temp_info[] = {
|
||||
static const struct hwmon_channel_info * const k10temp_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX |
|
||||
HWMON_T_CRIT | HWMON_T_CRIT_HYST |
|
||||
|
@ -118,7 +118,7 @@ static const struct hwmon_ops k8temp_ops = {
|
||||
.read = k8temp_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *k8temp_info[] = {
|
||||
static const struct hwmon_channel_info * const k8temp_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT),
|
||||
NULL
|
||||
|
@ -260,7 +260,7 @@ static umode_t lan966x_hwmon_is_visible(const void *data,
|
||||
return mode;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *lan966x_hwmon_info[] = {
|
||||
static const struct hwmon_channel_info * const lan966x_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
|
||||
|
@ -512,7 +512,7 @@ static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *lm75_info[] = {
|
||||
static const struct hwmon_channel_info * const lm75_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -337,7 +337,7 @@ static umode_t lm83_is_visible(const void *_data, enum hwmon_sensor_types type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *lm83_info[] = {
|
||||
static const struct hwmon_channel_info * const lm83_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_ALARMS),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
|
@ -409,7 +409,7 @@ static void lm95241_init_client(struct i2c_client *client,
|
||||
data->model);
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *lm95241_info[] = {
|
||||
static const struct hwmon_channel_info * const lm95241_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -523,7 +523,7 @@ static const struct regmap_config lm95245_regmap_config = {
|
||||
.use_single_write = true,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *lm95245_info[] = {
|
||||
static const struct hwmon_channel_info * const lm95245_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/mfd/lochnagar.h>
|
||||
#include <linux/mfd/lochnagar2_regs.h>
|
||||
@ -321,7 +320,7 @@ static const struct hwmon_ops lochnagar_ops = {
|
||||
.write = lochnagar_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *lochnagar_info[] = {
|
||||
static const struct hwmon_channel_info * const lochnagar_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||
|
@ -901,7 +901,7 @@ static umode_t ltc2947_is_visible(const void *data,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *ltc2947_info[] = {
|
||||
static const struct hwmon_channel_info * const ltc2947_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST |
|
||||
HWMON_I_MAX | HWMON_I_MIN | HWMON_I_RESET_HISTORY |
|
||||
|
@ -812,7 +812,7 @@ static const struct hwmon_ops ltc2992_hwmon_ops = {
|
||||
.write = ltc2992_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *ltc2992_info[] = {
|
||||
static const struct hwmon_channel_info * const ltc2992_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_IN_RESET_HISTORY),
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
|
@ -387,7 +387,7 @@ static umode_t ltc4245_is_visible(const void *_data,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *ltc4245_info[] = {
|
||||
static const struct hwmon_channel_info * const ltc4245_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
@ -434,7 +434,7 @@ static bool ltc4245_use_extra_gpios(struct i2c_client *client)
|
||||
return pdata->use_extra_gpios;
|
||||
|
||||
/* fallback on OF */
|
||||
if (of_find_property(np, "ltc4245,use-extra-gpios", NULL))
|
||||
if (of_property_read_bool(np, "ltc4245,use-extra-gpios"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -65,7 +65,7 @@ static umode_t ltq_is_visible(const void *_data, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *ltq_info[] = {
|
||||
static const struct hwmon_channel_info * const ltq_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -285,7 +285,7 @@ static const struct hwmon_ops max127_hwmon_ops = {
|
||||
.write = max127_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *max127_info[] = {
|
||||
static const struct hwmon_channel_info * const max127_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
|
||||
|
@ -248,7 +248,7 @@ static umode_t max31730_is_visible(const void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *max31730_info[] = {
|
||||
static const struct hwmon_channel_info * const max31730_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -318,7 +318,7 @@ static int max31760_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *max31760_info[] = {
|
||||
static const struct hwmon_channel_info * const max31760_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
|
@ -445,7 +445,7 @@ static umode_t max31790_is_visible(const void *data,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *max31790_info[] = {
|
||||
static const struct hwmon_channel_info * const max31790_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT | HWMON_F_ENABLE,
|
||||
|
@ -401,7 +401,7 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *max6620_info[] = {
|
||||
static const struct hwmon_channel_info * const max6620_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM,
|
||||
|
@ -449,7 +449,7 @@ static const struct regmap_config max6621_regmap_config = {
|
||||
.num_reg_defaults = ARRAY_SIZE(max6621_regmap_default),
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *max6621_info[] = {
|
||||
static const struct hwmon_channel_info * const max6621_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
|
@ -737,7 +737,7 @@ static umode_t max6650_is_visible(const void *_data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *max6650_info[] = {
|
||||
static const struct hwmon_channel_info * const max6650_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |
|
||||
HWMON_F_MIN_ALARM | HWMON_F_MAX_ALARM |
|
||||
HWMON_F_FAULT,
|
||||
|
@ -138,7 +138,7 @@ static int mc34vr500_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *mc34vr500_info[] = {
|
||||
static const struct hwmon_channel_info * const mc34vr500_info[] = {
|
||||
HWMON_CHANNEL_INFO(in, HWMON_I_MIN_ALARM),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM
|
||||
| HWMON_T_EMERGENCY_ALARM),
|
||||
|
@ -102,7 +102,7 @@ static umode_t mcp3021_is_visible(const void *_data,
|
||||
return 0444;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *mcp3021_info[] = {
|
||||
static const struct hwmon_channel_info * const mcp3021_info[] = {
|
||||
HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
@ -285,7 +285,7 @@ static char *mlxreg_fan_name[] = {
|
||||
"mlxreg_fan3",
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = {
|
||||
static const struct hwmon_channel_info * const mlxreg_fan_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_INPUT | HWMON_F_FAULT,
|
||||
HWMON_F_INPUT | HWMON_F_FAULT,
|
||||
|
@ -149,7 +149,7 @@ static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 va
|
||||
return -EIO;
|
||||
|
||||
if (retval)
|
||||
*retval = (u32)result & 0xFFFFFFFF;
|
||||
*retval = result;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
@ -1052,33 +1052,117 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
|
||||
static struct platform_device *pdev[2];
|
||||
|
||||
static const char * const asus_wmi_boards[] = {
|
||||
"B360M-BASALT",
|
||||
"B360M-D3H",
|
||||
"EX-B360M-V",
|
||||
"EX-B360M-V3",
|
||||
"EX-B360M-V5",
|
||||
"EX-B460M-V5",
|
||||
"EX-H410M-V3",
|
||||
"PRIME A520M-A",
|
||||
"PRIME A520M-A II",
|
||||
"PRIME A520M-E",
|
||||
"PRIME A520M-K",
|
||||
"PRIME B360-PLUS",
|
||||
"PRIME B360M-A",
|
||||
"PRIME B360M-C",
|
||||
"PRIME B360M-D",
|
||||
"PRIME B360M-K",
|
||||
"PRIME B460-PLUS",
|
||||
"PRIME B460I-PLUS",
|
||||
"PRIME B460M-A",
|
||||
"PRIME B460M-A R2.0",
|
||||
"PRIME B460M-K",
|
||||
"PRIME B550-PLUS",
|
||||
"PRIME B550-PLUS AC-HES",
|
||||
"PRIME B550M-A",
|
||||
"PRIME B550M-A (WI-FI)",
|
||||
"PRIME B550M-A AC",
|
||||
"PRIME B550M-A WIFI II",
|
||||
"PRIME B550M-K",
|
||||
"PRIME H310-PLUS",
|
||||
"PRIME H310I-PLUS",
|
||||
"PRIME H310M-A",
|
||||
"PRIME H310M-C",
|
||||
"PRIME H310M-D",
|
||||
"PRIME H310M-DASH",
|
||||
"PRIME H310M-E",
|
||||
"PRIME H310M-E/BR",
|
||||
"PRIME H310M-F",
|
||||
"PRIME H310M-K",
|
||||
"PRIME H310T",
|
||||
"PRIME H370-A",
|
||||
"PRIME H370-PLUS",
|
||||
"PRIME H370M-PLUS",
|
||||
"PRIME H410I-PLUS",
|
||||
"PRIME H410M-A",
|
||||
"PRIME H410M-D",
|
||||
"PRIME H410M-E",
|
||||
"PRIME H410M-F",
|
||||
"PRIME H410M-K",
|
||||
"PRIME H410M-K R2.0",
|
||||
"PRIME H410M-R",
|
||||
"PRIME H470-PLUS",
|
||||
"PRIME H470M-PLUS",
|
||||
"PRIME H510M-K R2.0",
|
||||
"PRIME Q370M-C",
|
||||
"PRIME X570-P",
|
||||
"PRIME X570-PRO",
|
||||
"PRIME Z390-A",
|
||||
"PRIME Z390-A/H10",
|
||||
"PRIME Z390-P",
|
||||
"PRIME Z390M-PLUS",
|
||||
"PRIME Z490-A",
|
||||
"PRIME Z490-P",
|
||||
"PRIME Z490-V",
|
||||
"PRIME Z490M-PLUS",
|
||||
"PRO B460M-C",
|
||||
"PRO H410M-C",
|
||||
"PRO H410T",
|
||||
"PRO Q470M-C",
|
||||
"Pro A520M-C",
|
||||
"Pro A520M-C II",
|
||||
"Pro B550M-C",
|
||||
"Pro WS X570-ACE",
|
||||
"ProArt B550-CREATOR",
|
||||
"ProArt X570-CREATOR WIFI",
|
||||
"ProArt Z490-CREATOR 10G",
|
||||
"Pro B550M-C",
|
||||
"Pro WS X570-ACE",
|
||||
"PRIME B360-PLUS",
|
||||
"PRIME B460-PLUS",
|
||||
"PRIME B550-PLUS",
|
||||
"PRIME B550M-A",
|
||||
"PRIME B550M-A (WI-FI)",
|
||||
"PRIME H410M-R",
|
||||
"PRIME X570-P",
|
||||
"PRIME X570-PRO",
|
||||
"ROG CROSSHAIR VIII DARK HERO",
|
||||
"ROG CROSSHAIR VIII EXTREME",
|
||||
"ROG CROSSHAIR VIII FORMULA",
|
||||
"ROG CROSSHAIR VIII HERO",
|
||||
"ROG CROSSHAIR VIII HERO (WI-FI)",
|
||||
"ROG CROSSHAIR VIII IMPACT",
|
||||
"ROG MAXIMUS XI APEX",
|
||||
"ROG MAXIMUS XI CODE",
|
||||
"ROG MAXIMUS XI EXTREME",
|
||||
"ROG MAXIMUS XI FORMULA",
|
||||
"ROG MAXIMUS XI GENE",
|
||||
"ROG MAXIMUS XI HERO",
|
||||
"ROG MAXIMUS XI HERO (WI-FI)",
|
||||
"ROG MAXIMUS XII APEX",
|
||||
"ROG MAXIMUS XII EXTREME",
|
||||
"ROG MAXIMUS XII FORMULA",
|
||||
"ROG MAXIMUS XII HERO (WI-FI)",
|
||||
"ROG STRIX B360-F GAMING",
|
||||
"ROG STRIX B360-G GAMING",
|
||||
"ROG STRIX B360-H GAMING",
|
||||
"ROG STRIX B360-H GAMING/OPTANE",
|
||||
"ROG STRIX B360-I GAMING",
|
||||
"ROG STRIX B460-F GAMING",
|
||||
"ROG STRIX B460-G GAMING",
|
||||
"ROG STRIX B460-H GAMING",
|
||||
"ROG STRIX B460-I GAMING",
|
||||
"ROG STRIX B550-A GAMING",
|
||||
"ROG STRIX B550-E GAMING",
|
||||
"ROG STRIX B550-F GAMING",
|
||||
"ROG STRIX B550-F GAMING (WI-FI)",
|
||||
"ROG STRIX B550-F GAMING WIFI II",
|
||||
"ROG STRIX B550-I GAMING",
|
||||
"ROG STRIX B550-XE GAMING (WI-FI)",
|
||||
"ROG STRIX B550-XE GAMING WIFI",
|
||||
"ROG STRIX H370-F GAMING",
|
||||
"ROG STRIX H370-I GAMING",
|
||||
"ROG STRIX H470-I GAMING",
|
||||
"ROG STRIX X570-E GAMING",
|
||||
"ROG STRIX X570-E GAMING WIFI II",
|
||||
"ROG STRIX X570-F GAMING",
|
||||
@ -1094,65 +1178,248 @@ static const char * const asus_wmi_boards[] = {
|
||||
"ROG STRIX Z490-G GAMING (WI-FI)",
|
||||
"ROG STRIX Z490-H GAMING",
|
||||
"ROG STRIX Z490-I GAMING",
|
||||
"TUF B360-PLUS GAMING",
|
||||
"TUF B360-PRO GAMING",
|
||||
"TUF B360-PRO GAMING (WI-FI)",
|
||||
"TUF B360M-E GAMING",
|
||||
"TUF B360M-PLUS GAMING",
|
||||
"TUF B360M-PLUS GAMING S",
|
||||
"TUF B360M-PLUS GAMING/BR",
|
||||
"TUF GAMING A520M-PLUS",
|
||||
"TUF GAMING A520M-PLUS II",
|
||||
"TUF GAMING A520M-PLUS WIFI",
|
||||
"TUF GAMING B460-PLUS",
|
||||
"TUF GAMING B460-PRO (WI-FI)",
|
||||
"TUF GAMING B460M-PLUS",
|
||||
"TUF GAMING B460M-PLUS (WI-FI)",
|
||||
"TUF GAMING B460M-PRO",
|
||||
"TUF GAMING B550-PLUS",
|
||||
"TUF GAMING B550-PLUS (WI-FI)",
|
||||
"TUF GAMING B550-PLUS WIFI II",
|
||||
"TUF GAMING B550-PRO",
|
||||
"TUF GAMING B550M ZAKU (WI-FI)",
|
||||
"TUF GAMING B550M-E",
|
||||
"TUF GAMING B550M-E (WI-FI)",
|
||||
"TUF GAMING B550M-E WIFI",
|
||||
"TUF GAMING B550M-PLUS",
|
||||
"TUF GAMING B550M-PLUS (WI-FI)",
|
||||
"TUF GAMING B550M-PLUS WIFI II",
|
||||
"TUF GAMING B550-PLUS",
|
||||
"TUF GAMING B550-PLUS WIFI II",
|
||||
"TUF GAMING B550-PRO",
|
||||
"TUF GAMING H470-PRO",
|
||||
"TUF GAMING H470-PRO (WI-FI)",
|
||||
"TUF GAMING X570-PLUS",
|
||||
"TUF GAMING X570-PLUS (WI-FI)",
|
||||
"TUF GAMING X570-PLUS_BR",
|
||||
"TUF GAMING X570-PRO (WI-FI)",
|
||||
"TUF GAMING X570-PRO WIFI II",
|
||||
"TUF GAMING Z490-PLUS",
|
||||
"TUF GAMING Z490-PLUS (WI-FI)",
|
||||
"TUF H310-PLUS GAMING",
|
||||
"TUF H310M-PLUS GAMING",
|
||||
"TUF H310M-PLUS GAMING/BR",
|
||||
"TUF H370-PRO GAMING",
|
||||
"TUF H370-PRO GAMING (WI-FI)",
|
||||
"TUF Z390-PLUS GAMING",
|
||||
"TUF Z390-PLUS GAMING (WI-FI)",
|
||||
"TUF Z390-PRO GAMING",
|
||||
"TUF Z390M-PRO GAMING",
|
||||
"TUF Z390M-PRO GAMING (WI-FI)",
|
||||
"WS Z390 PRO",
|
||||
"Z490-GUNDAM (WI-FI)",
|
||||
};
|
||||
|
||||
static const char * const asus_msi_boards[] = {
|
||||
"B560M-P",
|
||||
"EX-B560M-V5",
|
||||
"EX-B660M-V5 D4",
|
||||
"EX-B660M-V5 PRO D4",
|
||||
"EX-B760M-V5 D4",
|
||||
"EX-H510M-V3",
|
||||
"EX-H610M-V3 D4",
|
||||
"PRIME A620M-A",
|
||||
"PRIME B560-PLUS",
|
||||
"PRIME B560-PLUS AC-HES",
|
||||
"PRIME B560M-A",
|
||||
"PRIME B560M-A AC",
|
||||
"PRIME B560M-K",
|
||||
"PRIME B650-PLUS",
|
||||
"PRIME B650M-A",
|
||||
"PRIME B650M-A AX",
|
||||
"PRIME B650M-A AX II",
|
||||
"PRIME B650M-A II",
|
||||
"PRIME B650M-A WIFI",
|
||||
"PRIME B650M-A WIFI II",
|
||||
"PRIME B660-PLUS D4",
|
||||
"PRIME B660M-A AC D4",
|
||||
"PRIME B660M-A D4",
|
||||
"PRIME B660M-A WIFI D4",
|
||||
"PRIME B760-PLUS",
|
||||
"PRIME B760-PLUS D4",
|
||||
"PRIME B760M-A",
|
||||
"PRIME B760M-A AX D4",
|
||||
"PRIME B760M-A D4",
|
||||
"PRIME B760M-A WIFI",
|
||||
"PRIME B760M-A WIFI D4",
|
||||
"PRIME B760M-AJ D4",
|
||||
"PRIME B760M-K D4",
|
||||
"PRIME H510M-A",
|
||||
"PRIME H510M-A WIFI",
|
||||
"PRIME H510M-D",
|
||||
"PRIME H510M-E",
|
||||
"PRIME H510M-F",
|
||||
"PRIME H510M-K",
|
||||
"PRIME H510M-R",
|
||||
"PRIME H510T2/CSM",
|
||||
"PRIME H570-PLUS",
|
||||
"PRIME H570M-PLUS",
|
||||
"PRIME H610I-PLUS D4",
|
||||
"PRIME H610M-A D4",
|
||||
"PRIME H610M-A WIFI D4",
|
||||
"PRIME H610M-D D4",
|
||||
"PRIME H610M-E D4",
|
||||
"PRIME H610M-F D4",
|
||||
"PRIME H610M-K D4",
|
||||
"PRIME H610M-R D4",
|
||||
"PRIME H670-PLUS D4",
|
||||
"PRIME H770-PLUS D4",
|
||||
"PRIME X670-P",
|
||||
"PRIME X670-P WIFI",
|
||||
"PRIME X670E-PRO WIFI",
|
||||
"Pro B660M-C-D4",
|
||||
"PRIME Z590-A",
|
||||
"PRIME Z590-P",
|
||||
"PRIME Z590-P WIFI",
|
||||
"PRIME Z590-V",
|
||||
"PRIME Z590M-PLUS",
|
||||
"PRIME Z690-A",
|
||||
"PRIME Z690-P",
|
||||
"PRIME Z690-P D4",
|
||||
"PRIME Z690-P WIFI",
|
||||
"PRIME Z690-P WIFI D4",
|
||||
"PRIME Z690M-PLUS D4",
|
||||
"PRIME Z790-A WIFI",
|
||||
"PRIME Z790-P",
|
||||
"PRIME Z790-P D4",
|
||||
"PRIME Z790-P WIFI",
|
||||
"PRIME Z790-P WIFI D4",
|
||||
"PRIME Z790M-PLUS",
|
||||
"PRIME Z790M-PLUS D4",
|
||||
"Pro B560M-C",
|
||||
"Pro B560M-CT",
|
||||
"Pro B660M-C",
|
||||
"Pro B660M-C D4",
|
||||
"Pro B760M-C",
|
||||
"Pro B760M-CT",
|
||||
"Pro H510M-C",
|
||||
"Pro H510M-CT",
|
||||
"Pro H610M-C",
|
||||
"Pro H610M-C D4",
|
||||
"Pro H610M-CT D4",
|
||||
"Pro H610T D4",
|
||||
"Pro Q670M-C",
|
||||
"Pro WS W680-ACE",
|
||||
"Pro WS W680-ACE IPMI",
|
||||
"Pro WS W790-ACE",
|
||||
"Pro WS W790E-SAGE SE",
|
||||
"ProArt B650-CREATOR",
|
||||
"ProArt B660-CREATOR D4",
|
||||
"ProArt B760-CREATOR D4",
|
||||
"ProArt X670E-CREATOR WIFI",
|
||||
"ProArt Z690-CREATOR WIFI",
|
||||
"ProArt Z790-CREATOR WIFI",
|
||||
"ROG CROSSHAIR X670E EXTREME",
|
||||
"ROG CROSSHAIR X670E GENE",
|
||||
"ROG CROSSHAIR X670E HERO",
|
||||
"ROG MAXIMUS XIII APEX",
|
||||
"ROG MAXIMUS XIII EXTREME",
|
||||
"ROG MAXIMUS XIII EXTREME GLACIAL",
|
||||
"ROG MAXIMUS XIII HERO",
|
||||
"ROG MAXIMUS Z690 APEX",
|
||||
"ROG MAXIMUS Z690 EXTREME",
|
||||
"ROG MAXIMUS Z690 EXTREME GLACIAL",
|
||||
"ROG MAXIMUS Z690 FORMULA",
|
||||
"ROG MAXIMUS Z690 HERO",
|
||||
"ROG MAXIMUS Z690 HERO EVA",
|
||||
"ROG MAXIMUS Z790 APEX",
|
||||
"ROG MAXIMUS Z790 EXTREME",
|
||||
"ROG MAXIMUS Z790 HERO",
|
||||
"ROG STRIX B560-A GAMING WIFI",
|
||||
"ROG STRIX B560-E GAMING WIFI",
|
||||
"ROG STRIX B560-F GAMING WIFI",
|
||||
"ROG STRIX B560-G GAMING WIFI",
|
||||
"ROG STRIX B560-I GAMING WIFI",
|
||||
"ROG STRIX B650-A GAMING WIFI",
|
||||
"ROG STRIX B650E-E GAMING WIFI",
|
||||
"ROG STRIX B650E-F GAMING WIFI",
|
||||
"ROG STRIX B650E-I GAMING WIFI",
|
||||
"ROG STRIX B660-A GAMING WIFI",
|
||||
"ROG STRIX B660-A GAMING WIFI D4",
|
||||
"ROG STRIX B660-F GAMING WIFI",
|
||||
"ROG STRIX B660-G GAMING WIFI",
|
||||
"ROG STRIX B660-I GAMING WIFI",
|
||||
"ROG STRIX B760-A GAMING WIFI",
|
||||
"ROG STRIX B760-A GAMING WIFI D4",
|
||||
"ROG STRIX B760-F GAMING WIFI",
|
||||
"ROG STRIX B760-G GAMING WIFI",
|
||||
"ROG STRIX B760-G GAMING WIFI D4",
|
||||
"ROG STRIX B760-I GAMING WIFI",
|
||||
"ROG STRIX X670E-A GAMING WIFI",
|
||||
"ROG STRIX X670E-E GAMING WIFI",
|
||||
"ROG STRIX X670E-F GAMING WIFI",
|
||||
"ROG STRIX X670E-I GAMING WIFI",
|
||||
"ROG STRIX Z590-A GAMING WIFI",
|
||||
"ROG STRIX Z590-A GAMING WIFI II",
|
||||
"ROG STRIX Z590-E GAMING WIFI",
|
||||
"ROG STRIX Z590-F GAMING WIFI",
|
||||
"ROG STRIX Z590-I GAMING WIFI",
|
||||
"ROG STRIX Z690-A GAMING WIFI",
|
||||
"ROG STRIX Z690-A GAMING WIFI D4",
|
||||
"ROG STRIX Z690-E GAMING WIFI",
|
||||
"ROG STRIX Z690-F GAMING WIFI",
|
||||
"ROG STRIX Z690-G GAMING WIFI",
|
||||
"ROG STRIX Z690-I GAMING WIFI",
|
||||
"ROG STRIX Z790-A GAMING WIFI",
|
||||
"ROG STRIX Z790-A GAMING WIFI D4",
|
||||
"ROG STRIX Z790-E GAMING WIFI",
|
||||
"ROG STRIX Z790-F GAMING WIFI",
|
||||
"ROG STRIX Z790-H GAMING WIFI",
|
||||
"ROG STRIX Z790-I GAMING WIFI",
|
||||
"TUF GAMING A620M-PLUS",
|
||||
"TUF GAMING A620M-PLUS WIFI",
|
||||
"TUF GAMING B560-PLUS WIFI",
|
||||
"TUF GAMING B560M-E",
|
||||
"TUF GAMING B560M-PLUS",
|
||||
"TUF GAMING B560M-PLUS WIFI",
|
||||
"TUF GAMING B650-PLUS",
|
||||
"TUF GAMING B650-PLUS WIFI",
|
||||
"TUF GAMING B650M-PLUS",
|
||||
"TUF GAMING B650M-PLUS WIFI",
|
||||
"TUF GAMING B660-PLUS WIFI D4",
|
||||
"TUF GAMING B660M-E D4",
|
||||
"TUF GAMING B660M-PLUS D4",
|
||||
"TUF GAMING B660M-PLUS WIFI",
|
||||
"TUF GAMING B660M-PLUS WIFI D4",
|
||||
"TUF GAMING B760-PLUS WIFI",
|
||||
"TUF GAMING B760-PLUS WIFI D4",
|
||||
"TUF GAMING B760M-BTF WIFI D4",
|
||||
"TUF GAMING B760M-E D4",
|
||||
"TUF GAMING B760M-PLUS",
|
||||
"TUF GAMING B760M-PLUS D4",
|
||||
"TUF GAMING B760M-PLUS WIFI",
|
||||
"TUF GAMING B760M-PLUS WIFI D4",
|
||||
"TUF GAMING H570-PRO",
|
||||
"TUF GAMING H570-PRO WIFI",
|
||||
"TUF GAMING H670-PRO WIFI D4",
|
||||
"TUF GAMING H770-PRO WIFI",
|
||||
"TUF GAMING X670E-PLUS",
|
||||
"TUF GAMING X670E-PLUS WIFI",
|
||||
"TUF GAMING Z590-PLUS",
|
||||
"TUF GAMING Z590-PLUS WIFI",
|
||||
"TUF GAMING Z690-PLUS",
|
||||
"TUF GAMING Z690-PLUS D4",
|
||||
"TUF GAMING Z690-PLUS WIFI",
|
||||
"TUF GAMING Z690-PLUS WIFI D4",
|
||||
"TUF GAMING Z790-PLUS D4",
|
||||
"TUF GAMING Z790-PLUS WIFI",
|
||||
"TUF GAMING Z790-PLUS WIFI D4",
|
||||
"Z590 WIFI GUNDAM EDITION",
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI)
|
||||
|
@ -803,7 +803,7 @@ static int nct7904_detect(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *nct7904_info[] = {
|
||||
static const struct hwmon_channel_info * const nct7904_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
/* dummy, skipped in is_visible */
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
|
@ -629,7 +629,7 @@ static umode_t npcm7xx_is_visible(const void *data,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *npcm7xx_info[] = {
|
||||
static const struct hwmon_channel_info * const npcm7xx_info[] = {
|
||||
HWMON_CHANNEL_INFO(pwm,
|
||||
HWMON_PWM_INPUT,
|
||||
HWMON_PWM_INPUT,
|
||||
|
@ -546,7 +546,7 @@ static umode_t ntc_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *ntc_info[] = {
|
||||
static const struct hwmon_channel_info * const ntc_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_TYPE),
|
||||
NULL
|
||||
|
@ -86,7 +86,7 @@ static const struct hwmon_ops kraken2_hwmon_ops = {
|
||||
.read_string = kraken2_read_string,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *kraken2_info[] = {
|
||||
static const struct hwmon_channel_info * const kraken2_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL),
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
|
@ -663,7 +663,7 @@ static const struct hwmon_ops nzxt_smart2_hwmon_ops = {
|
||||
.write = nzxt_smart2_hwmon_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *nzxt_smart2_channel_info[] = {
|
||||
static const struct hwmon_channel_info * const nzxt_smart2_channel_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL,
|
||||
HWMON_F_INPUT | HWMON_F_LABEL,
|
||||
HWMON_F_INPUT | HWMON_F_LABEL),
|
||||
@ -721,6 +721,11 @@ static int __maybe_unused nzxt_smart2_hid_reset_resume(struct hid_device *hdev)
|
||||
return init_device(drvdata, drvdata->update_interval);
|
||||
}
|
||||
|
||||
static void mutex_fini(void *lock)
|
||||
{
|
||||
mutex_destroy(lock);
|
||||
}
|
||||
|
||||
static int nzxt_smart2_hid_probe(struct hid_device *hdev,
|
||||
const struct hid_device_id *id)
|
||||
{
|
||||
@ -737,8 +742,9 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
|
||||
init_waitqueue_head(&drvdata->wq);
|
||||
|
||||
mutex_init(&drvdata->mutex);
|
||||
devm_add_action(&hdev->dev, (void (*)(void *))mutex_destroy,
|
||||
&drvdata->mutex);
|
||||
ret = devm_add_action_or_reset(&hdev->dev, mutex_fini, &drvdata->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
if (ret)
|
||||
@ -791,7 +797,8 @@ static const struct hid_device_id nzxt_smart2_hid_id_table[] = {
|
||||
{ HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x2011) }, /* NZXT RGB & Fan Controller (6 RGB) */
|
||||
{ HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller (6 RGB) */
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -239,7 +239,7 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
}
|
||||
|
||||
/* Known sensors in the OXP EC controllers */
|
||||
static const struct hwmon_channel_info *oxp_platform_sensors[] = {
|
||||
static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_INPUT),
|
||||
HWMON_CHANNEL_INFO(pwm,
|
||||
|
@ -447,7 +447,7 @@ static const struct hwmon_ops peci_cputemp_ops = {
|
||||
.read = cputemp_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *peci_cputemp_info[] = {
|
||||
static const struct hwmon_channel_info * const peci_cputemp_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
/* Die temperature */
|
||||
HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX |
|
||||
|
@ -300,7 +300,7 @@ static int create_dimm_temp_label(struct peci_dimmtemp *priv, int chan)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *peci_dimmtemp_temp_info[] = {
|
||||
static const struct hwmon_channel_info * const peci_dimmtemp_temp_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
[0 ... DIMM_NUMS_MAX - 1] = HWMON_T_LABEL |
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT),
|
||||
|
@ -27,6 +27,15 @@ config SENSORS_PMBUS
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called pmbus.
|
||||
|
||||
config SENSORS_ACBEL_FSG032
|
||||
tristate "ACBEL FSG032 Power Supply"
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for the ACBEL
|
||||
FSG032 Power Supply.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called acbel-fsg032.
|
||||
|
||||
config SENSORS_ADM1266
|
||||
tristate "Analog Devices ADM1266 Sequencer"
|
||||
select CRC8
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_PMBUS) += pmbus_core.o
|
||||
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
|
||||
obj-$(CONFIG_SENSORS_ACBEL_FSG032) += acbel-fsg032.o
|
||||
obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o
|
||||
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
|
||||
obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
|
||||
|
85
drivers/hwmon/pmbus/acbel-fsg032.c
Normal file
85
drivers/hwmon/pmbus/acbel-fsg032.c
Normal file
@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright 2023 IBM Corp.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pmbus.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
static const struct i2c_device_id acbel_fsg032_id[] = {
|
||||
{ "acbel_fsg032" },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct pmbus_driver_info acbel_fsg032_info = {
|
||||
.pages = 1,
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
|
||||
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
|
||||
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
|
||||
PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_VOUT |
|
||||
PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_TEMP |
|
||||
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_FAN12,
|
||||
};
|
||||
|
||||
static int acbel_fsg032_probe(struct i2c_client *client)
|
||||
{
|
||||
u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
|
||||
struct device *dev = &client->dev;
|
||||
int rc;
|
||||
|
||||
rc = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Failed to read PMBUS_MFR_ID\n");
|
||||
return rc;
|
||||
}
|
||||
if (strncmp(buf, "ACBEL", 5)) {
|
||||
buf[rc] = '\0';
|
||||
dev_err(dev, "Manufacturer '%s' not supported\n", buf);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "Failed to read PMBUS_MFR_MODEL\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (strncmp(buf, "FSG032", 6)) {
|
||||
buf[rc] = '\0';
|
||||
dev_err(dev, "Model '%s' not supported\n", buf);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = pmbus_do_probe(client, &acbel_fsg032_info);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id acbel_fsg032_of_match[] = {
|
||||
{ .compatible = "acbel,fsg032" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, acbel_fsg032_of_match);
|
||||
|
||||
static struct i2c_driver acbel_fsg032_driver = {
|
||||
.driver = {
|
||||
.name = "acbel-fsg032",
|
||||
.of_match_table = acbel_fsg032_of_match,
|
||||
},
|
||||
.probe_new = acbel_fsg032_probe,
|
||||
.id_table = acbel_fsg032_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(acbel_fsg032_driver);
|
||||
|
||||
MODULE_AUTHOR("Lakshmi Yadlapati");
|
||||
MODULE_DESCRIPTION("PMBus driver for AcBel Power System power supplies");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_IMPORT_NS(PMBUS);
|
@ -180,7 +180,6 @@ static struct pmbus_driver_info fsp3y_info[] = {
|
||||
PMBUS_HAVE_FAN12,
|
||||
.func[YM2151_PAGE_5VSB_LOG] =
|
||||
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT,
|
||||
PMBUS_HAVE_IIN,
|
||||
.read_word_data = fsp3y_read_word_data,
|
||||
.read_byte_data = fsp3y_read_byte_data,
|
||||
},
|
||||
|
@ -18,12 +18,6 @@
|
||||
|
||||
#include "pmbus.h"
|
||||
|
||||
#define CFFPS_MFG_ID_CMD 0x99
|
||||
#define CFFPS_FRU_CMD 0x9A
|
||||
#define CFFPS_PN_CMD 0x9B
|
||||
#define CFFPS_HEADER_CMD 0x9C
|
||||
#define CFFPS_SN_CMD 0x9E
|
||||
#define CFFPS_MAX_POWER_OUT_CMD 0xA7
|
||||
#define CFFPS_CCIN_CMD 0xBD
|
||||
#define CFFPS_FW_CMD 0xFA
|
||||
#define CFFPS1_FW_NUM_BYTES 4
|
||||
@ -32,7 +26,7 @@
|
||||
#define CFFPS_12VCS_VOUT_CMD 0xDE
|
||||
|
||||
#define CFFPS_INPUT_HISTORY_CMD 0xD6
|
||||
#define CFFPS_INPUT_HISTORY_SIZE 100
|
||||
#define CFFPS_INPUT_HISTORY_SIZE 101
|
||||
|
||||
#define CFFPS_CCIN_REVISION GENMASK(7, 0)
|
||||
#define CFFPS_CCIN_REVISION_LEGACY 0xde
|
||||
@ -57,13 +51,7 @@
|
||||
#define CFFPS_BLINK_RATE_MS 250
|
||||
|
||||
enum {
|
||||
CFFPS_DEBUGFS_INPUT_HISTORY = 0,
|
||||
CFFPS_DEBUGFS_MFG_ID,
|
||||
CFFPS_DEBUGFS_FRU,
|
||||
CFFPS_DEBUGFS_PN,
|
||||
CFFPS_DEBUGFS_HEADER,
|
||||
CFFPS_DEBUGFS_SN,
|
||||
CFFPS_DEBUGFS_MAX_POWER_OUT,
|
||||
CFFPS_DEBUGFS_MAX_POWER_OUT = 0,
|
||||
CFFPS_DEBUGFS_CCIN,
|
||||
CFFPS_DEBUGFS_FW,
|
||||
CFFPS_DEBUGFS_ON_OFF_CONFIG,
|
||||
@ -72,19 +60,11 @@ enum {
|
||||
|
||||
enum versions { cffps1, cffps2, cffps_unknown };
|
||||
|
||||
struct ibm_cffps_input_history {
|
||||
struct mutex update_lock;
|
||||
unsigned long last_update;
|
||||
|
||||
u8 byte_count;
|
||||
u8 data[CFFPS_INPUT_HISTORY_SIZE];
|
||||
};
|
||||
|
||||
struct ibm_cffps {
|
||||
enum versions version;
|
||||
struct i2c_client *client;
|
||||
|
||||
struct ibm_cffps_input_history input_history;
|
||||
u8 input_history[CFFPS_INPUT_HISTORY_SIZE];
|
||||
|
||||
int debugfs_entries[CFFPS_DEBUGFS_NUM_ENTRIES];
|
||||
|
||||
@ -93,118 +73,98 @@ struct ibm_cffps {
|
||||
struct led_classdev led;
|
||||
};
|
||||
|
||||
static const struct i2c_device_id ibm_cffps_id[];
|
||||
|
||||
#define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)])
|
||||
|
||||
static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu,
|
||||
char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
static ssize_t ibm_cffps_debugfs_read_input_history(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int rc;
|
||||
u8 msgbuf0[1] = { CFFPS_INPUT_HISTORY_CMD };
|
||||
u8 msgbuf1[CFFPS_INPUT_HISTORY_SIZE + 1] = { 0 };
|
||||
u8 cmd = CFFPS_INPUT_HISTORY_CMD;
|
||||
struct ibm_cffps *psu = file->private_data;
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = psu->client->addr,
|
||||
.flags = psu->client->flags,
|
||||
.len = 1,
|
||||
.buf = msgbuf0,
|
||||
.buf = &cmd,
|
||||
}, {
|
||||
.addr = psu->client->addr,
|
||||
.flags = psu->client->flags | I2C_M_RD,
|
||||
.len = CFFPS_INPUT_HISTORY_SIZE + 1,
|
||||
.buf = msgbuf1,
|
||||
.len = CFFPS_INPUT_HISTORY_SIZE,
|
||||
.buf = psu->input_history,
|
||||
},
|
||||
};
|
||||
|
||||
if (!*ppos) {
|
||||
mutex_lock(&psu->input_history.update_lock);
|
||||
if (time_after(jiffies, psu->input_history.last_update + HZ)) {
|
||||
rc = pmbus_lock_interruptible(psu->client);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pmbus_set_page(psu->client, 0, 0xff);
|
||||
if (rc) {
|
||||
pmbus_unlock(psu->client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use a raw i2c transfer, since we need more bytes
|
||||
* than Linux I2C supports through smbus xfr (only 32).
|
||||
*/
|
||||
rc = i2c_transfer(psu->client->adapter, msg, 2);
|
||||
if (rc < 0) {
|
||||
mutex_unlock(&psu->input_history.update_lock);
|
||||
pmbus_unlock(psu->client);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
psu->input_history.byte_count = msgbuf1[0];
|
||||
memcpy(psu->input_history.data, &msgbuf1[1],
|
||||
CFFPS_INPUT_HISTORY_SIZE);
|
||||
psu->input_history.last_update = jiffies;
|
||||
}
|
||||
|
||||
mutex_unlock(&psu->input_history.update_lock);
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(buf, count, ppos,
|
||||
psu->input_history.data,
|
||||
psu->input_history.byte_count);
|
||||
psu->input_history + 1,
|
||||
psu->input_history[0]);
|
||||
}
|
||||
|
||||
static const struct file_operations ibm_cffps_input_history_fops = {
|
||||
.llseek = noop_llseek,
|
||||
.read = ibm_cffps_debugfs_read_input_history,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
u8 cmd;
|
||||
int i, rc;
|
||||
int *idxp = file->private_data;
|
||||
int idx = *idxp;
|
||||
struct ibm_cffps *psu = to_psu(idxp, idx);
|
||||
char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
|
||||
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
rc = pmbus_lock_interruptible(psu->client);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pmbus_set_page(psu->client, 0, 0xff);
|
||||
if (rc)
|
||||
goto unlock;
|
||||
|
||||
switch (idx) {
|
||||
case CFFPS_DEBUGFS_INPUT_HISTORY:
|
||||
return ibm_cffps_read_input_history(psu, buf, count, ppos);
|
||||
case CFFPS_DEBUGFS_MFG_ID:
|
||||
cmd = CFFPS_MFG_ID_CMD;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_FRU:
|
||||
cmd = CFFPS_FRU_CMD;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_PN:
|
||||
cmd = CFFPS_PN_CMD;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_HEADER:
|
||||
cmd = CFFPS_HEADER_CMD;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_SN:
|
||||
cmd = CFFPS_SN_CMD;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_MAX_POWER_OUT:
|
||||
if (psu->version == cffps1) {
|
||||
rc = i2c_smbus_read_word_swapped(psu->client,
|
||||
CFFPS_MAX_POWER_OUT_CMD);
|
||||
} else {
|
||||
rc = i2c_smbus_read_word_data(psu->client,
|
||||
CFFPS_MAX_POWER_OUT_CMD);
|
||||
}
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (psu->version == cffps1)
|
||||
rc = i2c_smbus_read_word_swapped(psu->client, PMBUS_MFR_POUT_MAX);
|
||||
else
|
||||
rc = i2c_smbus_read_word_data(psu->client, PMBUS_MFR_POUT_MAX);
|
||||
if (rc >= 0)
|
||||
rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc);
|
||||
goto done;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_CCIN:
|
||||
rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (rc >= 0)
|
||||
rc = snprintf(data, 5, "%04X", rc);
|
||||
goto done;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_FW:
|
||||
switch (psu->version) {
|
||||
case cffps1:
|
||||
for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) {
|
||||
rc = i2c_smbus_read_byte_data(psu->client,
|
||||
CFFPS_FW_CMD +
|
||||
i);
|
||||
rc = i2c_smbus_read_byte_data(psu->client, CFFPS_FW_CMD + i);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
snprintf(&data[i * 2], 3, "%02X", rc);
|
||||
}
|
||||
@ -213,11 +173,9 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
|
||||
break;
|
||||
case cffps2:
|
||||
for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) {
|
||||
rc = i2c_smbus_read_word_data(psu->client,
|
||||
CFFPS_FW_CMD +
|
||||
i);
|
||||
rc = i2c_smbus_read_word_data(psu->client, CFFPS_FW_CMD + i);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
goto unlock;
|
||||
|
||||
snprintf(&data[i * 4], 5, "%04X", rc);
|
||||
}
|
||||
@ -225,26 +183,25 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
|
||||
rc = i * 4;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
rc = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
goto done;
|
||||
break;
|
||||
case CFFPS_DEBUGFS_ON_OFF_CONFIG:
|
||||
rc = i2c_smbus_read_byte_data(psu->client,
|
||||
PMBUS_ON_OFF_CONFIG);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = i2c_smbus_read_byte_data(psu->client, PMBUS_ON_OFF_CONFIG);
|
||||
if (rc >= 0)
|
||||
rc = snprintf(data, 3, "%02x", rc);
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
rc = i2c_smbus_read_block_data(psu->client, cmd, data);
|
||||
unlock:
|
||||
pmbus_unlock(psu->client);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
done:
|
||||
data[rc] = '\n';
|
||||
rc += 2;
|
||||
|
||||
@ -263,14 +220,22 @@ static ssize_t ibm_cffps_debugfs_write(struct file *file,
|
||||
|
||||
switch (idx) {
|
||||
case CFFPS_DEBUGFS_ON_OFF_CONFIG:
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
|
||||
rc = simple_write_to_buffer(&data, 1, ppos, buf, count);
|
||||
if (rc <= 0)
|
||||
return rc;
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client,
|
||||
PMBUS_ON_OFF_CONFIG, data);
|
||||
rc = pmbus_lock_interruptible(psu->client);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pmbus_set_page(psu->client, 0, 0xff);
|
||||
if (rc) {
|
||||
pmbus_unlock(psu->client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client, PMBUS_ON_OFF_CONFIG, data);
|
||||
pmbus_unlock(psu->client);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -396,10 +361,19 @@ static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
|
||||
dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n",
|
||||
brightness, next_led_state);
|
||||
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
rc = pmbus_lock_interruptible(psu->client);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pmbus_set_page(psu->client, 0, 0xff);
|
||||
if (rc) {
|
||||
pmbus_unlock(psu->client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
|
||||
next_led_state);
|
||||
pmbus_unlock(psu->client);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@ -418,10 +392,19 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
|
||||
|
||||
dev_dbg(&psu->client->dev, "LED blink set.\n");
|
||||
|
||||
pmbus_set_page(psu->client, 0, 0xff);
|
||||
rc = pmbus_lock_interruptible(psu->client);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pmbus_set_page(psu->client, 0, 0xff);
|
||||
if (rc) {
|
||||
pmbus_unlock(psu->client);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
|
||||
CFFPS_LED_BLINK);
|
||||
pmbus_unlock(psu->client);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@ -474,9 +457,11 @@ static struct pmbus_driver_info ibm_cffps_info[] = {
|
||||
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
|
||||
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
|
||||
PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_VMON,
|
||||
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
|
||||
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
|
||||
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT,
|
||||
.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
|
||||
PMBUS_HAVE_PIN | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
|
||||
PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
|
||||
PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
|
||||
PMBUS_HAVE_STATUS_TEMP,
|
||||
.read_byte_data = ibm_cffps_read_byte_data,
|
||||
.read_word_data = ibm_cffps_read_word_data,
|
||||
},
|
||||
@ -486,12 +471,19 @@ static struct pmbus_platform_data ibm_cffps_pdata = {
|
||||
.flags = PMBUS_SKIP_STATUS_CHECK | PMBUS_NO_CAPABILITY,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id ibm_cffps_id[] = {
|
||||
{ "ibm_cffps1", cffps1 },
|
||||
{ "ibm_cffps2", cffps2 },
|
||||
{ "ibm_cffps", cffps_unknown },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
|
||||
|
||||
static int ibm_cffps_probe(struct i2c_client *client)
|
||||
{
|
||||
int i, rc;
|
||||
enum versions vs = cffps_unknown;
|
||||
struct dentry *debugfs;
|
||||
struct dentry *ibm_cffps_dir;
|
||||
struct ibm_cffps *psu;
|
||||
const void *md = of_device_get_match_data(&client->dev);
|
||||
const struct i2c_device_id *id;
|
||||
@ -560,8 +552,6 @@ static int ibm_cffps_probe(struct i2c_client *client)
|
||||
|
||||
psu->version = vs;
|
||||
psu->client = client;
|
||||
mutex_init(&psu->input_history.update_lock);
|
||||
psu->input_history.last_update = jiffies - HZ;
|
||||
|
||||
ibm_cffps_create_led_class(psu);
|
||||
|
||||
@ -570,55 +560,29 @@ static int ibm_cffps_probe(struct i2c_client *client)
|
||||
if (!debugfs)
|
||||
return 0;
|
||||
|
||||
ibm_cffps_dir = debugfs_create_dir(client->name, debugfs);
|
||||
if (!ibm_cffps_dir)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < CFFPS_DEBUGFS_NUM_ENTRIES; ++i)
|
||||
psu->debugfs_entries[i] = i;
|
||||
|
||||
debugfs_create_file("input_history", 0444, ibm_cffps_dir,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_INPUT_HISTORY],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("mfg_id", 0444, ibm_cffps_dir,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_MFG_ID],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("fru", 0444, ibm_cffps_dir,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_FRU],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("part_number", 0444, ibm_cffps_dir,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_PN],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("header", 0444, ibm_cffps_dir,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_HEADER],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("serial_number", 0444, ibm_cffps_dir,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_SN],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("max_power_out", 0444, ibm_cffps_dir,
|
||||
debugfs_create_file("input_history", 0444, debugfs, psu, &ibm_cffps_input_history_fops);
|
||||
debugfs_create_file("max_power_out", 0444, debugfs,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_MAX_POWER_OUT],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("ccin", 0444, ibm_cffps_dir,
|
||||
debugfs_create_file("ccin", 0444, debugfs,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_CCIN],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("fw_version", 0444, ibm_cffps_dir,
|
||||
debugfs_create_file("fw_version", 0444, debugfs,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_FW],
|
||||
&ibm_cffps_fops);
|
||||
debugfs_create_file("on_off_config", 0644, ibm_cffps_dir,
|
||||
debugfs_create_file("on_off_config", 0644, debugfs,
|
||||
&psu->debugfs_entries[CFFPS_DEBUGFS_ON_OFF_CONFIG],
|
||||
&ibm_cffps_fops);
|
||||
|
||||
/* For compatibility with users of the old naming scheme. */
|
||||
debugfs_create_symlink(client->name, debugfs, ".");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ibm_cffps_id[] = {
|
||||
{ "ibm_cffps1", cffps1 },
|
||||
{ "ibm_cffps2", cffps2 },
|
||||
{ "ibm_cffps", cffps_unknown },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
|
||||
|
||||
static const struct of_device_id ibm_cffps_of_match[] = {
|
||||
{
|
||||
.compatible = "ibm,cffps1",
|
||||
|
@ -26,7 +26,7 @@ enum pmbus_regs {
|
||||
|
||||
PMBUS_CAPABILITY = 0x19,
|
||||
PMBUS_QUERY = 0x1A,
|
||||
|
||||
PMBUS_SMBALERT_MASK = 0x1B,
|
||||
PMBUS_VOUT_MODE = 0x20,
|
||||
PMBUS_VOUT_COMMAND = 0x21,
|
||||
PMBUS_VOUT_TRIM = 0x22,
|
||||
@ -505,6 +505,8 @@ int pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id,
|
||||
enum pmbus_fan_mode mode);
|
||||
int pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id,
|
||||
enum pmbus_fan_mode mode);
|
||||
int pmbus_lock_interruptible(struct i2c_client *client);
|
||||
void pmbus_unlock(struct i2c_client *client);
|
||||
int pmbus_update_fan(struct i2c_client *client, int page, int id,
|
||||
u8 config, u8 mask, u16 command);
|
||||
struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client);
|
||||
|
@ -81,6 +81,7 @@ struct pmbus_label {
|
||||
struct pmbus_data {
|
||||
struct device *dev;
|
||||
struct device *hwmon_dev;
|
||||
struct regulator_dev **rdevs;
|
||||
|
||||
u32 flags; /* from platform data */
|
||||
|
||||
@ -2692,18 +2693,64 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_REGULATOR)
|
||||
static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
|
||||
/* A PMBus status flag and the corresponding REGULATOR_ERROR_* and REGULATOR_EVENTS_* flag */
|
||||
struct pmbus_status_assoc {
|
||||
int pflag, rflag, eflag;
|
||||
};
|
||||
|
||||
/* PMBus->regulator bit mappings for a PMBus status register */
|
||||
struct pmbus_status_category {
|
||||
int func;
|
||||
int reg;
|
||||
const struct pmbus_status_assoc *bits; /* zero-terminated */
|
||||
};
|
||||
|
||||
static const struct pmbus_status_category __maybe_unused pmbus_status_flag_map[] = {
|
||||
{
|
||||
.func = PMBUS_HAVE_STATUS_VOUT,
|
||||
.reg = PMBUS_STATUS_VOUT,
|
||||
.bits = (const struct pmbus_status_assoc[]) {
|
||||
{ PB_VOLTAGE_UV_WARNING, REGULATOR_ERROR_UNDER_VOLTAGE_WARN,
|
||||
REGULATOR_EVENT_UNDER_VOLTAGE_WARN },
|
||||
{ PB_VOLTAGE_UV_FAULT, REGULATOR_ERROR_UNDER_VOLTAGE,
|
||||
REGULATOR_EVENT_UNDER_VOLTAGE },
|
||||
{ PB_VOLTAGE_OV_WARNING, REGULATOR_ERROR_OVER_VOLTAGE_WARN,
|
||||
REGULATOR_EVENT_OVER_VOLTAGE_WARN },
|
||||
{ PB_VOLTAGE_OV_FAULT, REGULATOR_ERROR_REGULATION_OUT,
|
||||
REGULATOR_EVENT_OVER_VOLTAGE_WARN },
|
||||
{ },
|
||||
},
|
||||
}, {
|
||||
.func = PMBUS_HAVE_STATUS_IOUT,
|
||||
.reg = PMBUS_STATUS_IOUT,
|
||||
.bits = (const struct pmbus_status_assoc[]) {
|
||||
{ PB_IOUT_OC_WARNING, REGULATOR_ERROR_OVER_CURRENT_WARN,
|
||||
REGULATOR_EVENT_OVER_CURRENT_WARN },
|
||||
{ PB_IOUT_OC_FAULT, REGULATOR_ERROR_OVER_CURRENT,
|
||||
REGULATOR_EVENT_OVER_CURRENT },
|
||||
{ PB_IOUT_OC_LV_FAULT, REGULATOR_ERROR_OVER_CURRENT,
|
||||
REGULATOR_EVENT_OVER_CURRENT },
|
||||
{ },
|
||||
},
|
||||
}, {
|
||||
.func = PMBUS_HAVE_STATUS_TEMP,
|
||||
.reg = PMBUS_STATUS_TEMPERATURE,
|
||||
.bits = (const struct pmbus_status_assoc[]) {
|
||||
{ PB_TEMP_OT_WARNING, REGULATOR_ERROR_OVER_TEMP_WARN,
|
||||
REGULATOR_EVENT_OVER_TEMP_WARN },
|
||||
{ PB_TEMP_OT_FAULT, REGULATOR_ERROR_OVER_TEMP,
|
||||
REGULATOR_EVENT_OVER_TEMP },
|
||||
{ },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static int _pmbus_is_enabled(struct device *dev, u8 page)
|
||||
{
|
||||
struct device *dev = rdev_get_dev(rdev);
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
u8 page = rdev_get_id(rdev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = _pmbus_read_byte_data(client, page, PMBUS_OPERATION);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -2711,6 +2758,149 @@ static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
|
||||
return !!(ret & PB_OPERATION_CONTROL_ON);
|
||||
}
|
||||
|
||||
static int __maybe_unused pmbus_is_enabled(struct device *dev, u8 page)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = _pmbus_is_enabled(dev, page);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return !!(ret & PB_OPERATION_CONTROL_ON);
|
||||
}
|
||||
|
||||
#define to_dev_attr(_dev_attr) \
|
||||
container_of(_dev_attr, struct device_attribute, attr)
|
||||
|
||||
static void pmbus_notify(struct pmbus_data *data, int page, int reg, int flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data->num_attributes; i++) {
|
||||
struct device_attribute *da = to_dev_attr(data->group.attrs[i]);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
int index = attr->index;
|
||||
u16 smask = pb_index_to_mask(index);
|
||||
u8 spage = pb_index_to_page(index);
|
||||
u16 sreg = pb_index_to_reg(index);
|
||||
|
||||
if (reg == sreg && page == spage && (smask & flags)) {
|
||||
dev_dbg(data->dev, "sysfs notify: %s", da->attr.name);
|
||||
sysfs_notify(&data->dev->kobj, NULL, da->attr.name);
|
||||
kobject_uevent(&data->dev->kobj, KOBJ_CHANGE);
|
||||
flags &= ~smask;
|
||||
}
|
||||
|
||||
if (!flags)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int _pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
|
||||
unsigned int *event, bool notify)
|
||||
{
|
||||
int i, status;
|
||||
const struct pmbus_status_category *cat;
|
||||
const struct pmbus_status_assoc *bit;
|
||||
struct device *dev = data->dev;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int func = data->info->func[page];
|
||||
|
||||
*flags = 0;
|
||||
*event = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmbus_status_flag_map); i++) {
|
||||
cat = &pmbus_status_flag_map[i];
|
||||
if (!(func & cat->func))
|
||||
continue;
|
||||
|
||||
status = _pmbus_read_byte_data(client, page, cat->reg);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
for (bit = cat->bits; bit->pflag; bit++)
|
||||
if (status & bit->pflag) {
|
||||
*flags |= bit->rflag;
|
||||
*event |= bit->eflag;
|
||||
}
|
||||
|
||||
if (notify && status)
|
||||
pmbus_notify(data, page, cat->reg, status);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Map what bits of STATUS_{WORD,BYTE} we can to REGULATOR_ERROR_*
|
||||
* bits. Some of the other bits are tempting (especially for cases
|
||||
* where we don't have the relevant PMBUS_HAVE_STATUS_*
|
||||
* functionality), but there's an unfortunate ambiguity in that
|
||||
* they're defined as indicating a fault *or* a warning, so we can't
|
||||
* easily determine whether to report REGULATOR_ERROR_<foo> or
|
||||
* REGULATOR_ERROR_<foo>_WARN.
|
||||
*/
|
||||
status = pmbus_get_status(client, page, PMBUS_STATUS_WORD);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (_pmbus_is_enabled(dev, page)) {
|
||||
if (status & PB_STATUS_OFF) {
|
||||
*flags |= REGULATOR_ERROR_FAIL;
|
||||
*event |= REGULATOR_EVENT_FAIL;
|
||||
}
|
||||
|
||||
if (status & PB_STATUS_POWER_GOOD_N) {
|
||||
*flags |= REGULATOR_ERROR_REGULATION_OUT;
|
||||
*event |= REGULATOR_EVENT_REGULATION_OUT;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Unlike most other status bits, PB_STATUS_{IOUT_OC,VOUT_OV} are
|
||||
* defined strictly as fault indicators (not warnings).
|
||||
*/
|
||||
if (status & PB_STATUS_IOUT_OC) {
|
||||
*flags |= REGULATOR_ERROR_OVER_CURRENT;
|
||||
*event |= REGULATOR_EVENT_OVER_CURRENT;
|
||||
}
|
||||
if (status & PB_STATUS_VOUT_OV) {
|
||||
*flags |= REGULATOR_ERROR_REGULATION_OUT;
|
||||
*event |= REGULATOR_EVENT_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we haven't discovered any thermal faults or warnings via
|
||||
* PMBUS_STATUS_TEMPERATURE, map PB_STATUS_TEMPERATURE to a warning as
|
||||
* a (conservative) best-effort interpretation.
|
||||
*/
|
||||
if (!(*flags & (REGULATOR_ERROR_OVER_TEMP | REGULATOR_ERROR_OVER_TEMP_WARN)) &&
|
||||
(status & PB_STATUS_TEMPERATURE)) {
|
||||
*flags |= REGULATOR_ERROR_OVER_TEMP_WARN;
|
||||
*event |= REGULATOR_EVENT_OVER_TEMP_WARN;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused pmbus_get_flags(struct pmbus_data *data, u8 page, unsigned int *flags,
|
||||
unsigned int *event, bool notify)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
ret = _pmbus_get_flags(data, page, flags, event, notify);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_REGULATOR)
|
||||
static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
return pmbus_is_enabled(rdev_get_dev(rdev), rdev_get_id(rdev));
|
||||
}
|
||||
|
||||
static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
|
||||
{
|
||||
struct device *dev = rdev_get_dev(rdev);
|
||||
@ -2738,121 +2928,14 @@ static int pmbus_regulator_disable(struct regulator_dev *rdev)
|
||||
return _pmbus_regulator_on_off(rdev, 0);
|
||||
}
|
||||
|
||||
/* A PMBus status flag and the corresponding REGULATOR_ERROR_* flag */
|
||||
struct pmbus_regulator_status_assoc {
|
||||
int pflag, rflag;
|
||||
};
|
||||
|
||||
/* PMBus->regulator bit mappings for a PMBus status register */
|
||||
struct pmbus_regulator_status_category {
|
||||
int func;
|
||||
int reg;
|
||||
const struct pmbus_regulator_status_assoc *bits; /* zero-terminated */
|
||||
};
|
||||
|
||||
static const struct pmbus_regulator_status_category pmbus_regulator_flag_map[] = {
|
||||
{
|
||||
.func = PMBUS_HAVE_STATUS_VOUT,
|
||||
.reg = PMBUS_STATUS_VOUT,
|
||||
.bits = (const struct pmbus_regulator_status_assoc[]) {
|
||||
{ PB_VOLTAGE_UV_WARNING, REGULATOR_ERROR_UNDER_VOLTAGE_WARN },
|
||||
{ PB_VOLTAGE_UV_FAULT, REGULATOR_ERROR_UNDER_VOLTAGE },
|
||||
{ PB_VOLTAGE_OV_WARNING, REGULATOR_ERROR_OVER_VOLTAGE_WARN },
|
||||
{ PB_VOLTAGE_OV_FAULT, REGULATOR_ERROR_REGULATION_OUT },
|
||||
{ },
|
||||
},
|
||||
}, {
|
||||
.func = PMBUS_HAVE_STATUS_IOUT,
|
||||
.reg = PMBUS_STATUS_IOUT,
|
||||
.bits = (const struct pmbus_regulator_status_assoc[]) {
|
||||
{ PB_IOUT_OC_WARNING, REGULATOR_ERROR_OVER_CURRENT_WARN },
|
||||
{ PB_IOUT_OC_FAULT, REGULATOR_ERROR_OVER_CURRENT },
|
||||
{ PB_IOUT_OC_LV_FAULT, REGULATOR_ERROR_OVER_CURRENT },
|
||||
{ },
|
||||
},
|
||||
}, {
|
||||
.func = PMBUS_HAVE_STATUS_TEMP,
|
||||
.reg = PMBUS_STATUS_TEMPERATURE,
|
||||
.bits = (const struct pmbus_regulator_status_assoc[]) {
|
||||
{ PB_TEMP_OT_WARNING, REGULATOR_ERROR_OVER_TEMP_WARN },
|
||||
{ PB_TEMP_OT_FAULT, REGULATOR_ERROR_OVER_TEMP },
|
||||
{ },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static int pmbus_regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags)
|
||||
{
|
||||
int i, status;
|
||||
const struct pmbus_regulator_status_category *cat;
|
||||
const struct pmbus_regulator_status_assoc *bit;
|
||||
struct device *dev = rdev_get_dev(rdev);
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
u8 page = rdev_get_id(rdev);
|
||||
int func = data->info->func[page];
|
||||
int event;
|
||||
|
||||
*flags = 0;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pmbus_regulator_flag_map); i++) {
|
||||
cat = &pmbus_regulator_flag_map[i];
|
||||
if (!(func & cat->func))
|
||||
continue;
|
||||
|
||||
status = _pmbus_read_byte_data(client, page, cat->reg);
|
||||
if (status < 0) {
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
for (bit = cat->bits; bit->pflag; bit++) {
|
||||
if (status & bit->pflag)
|
||||
*flags |= bit->rflag;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Map what bits of STATUS_{WORD,BYTE} we can to REGULATOR_ERROR_*
|
||||
* bits. Some of the other bits are tempting (especially for cases
|
||||
* where we don't have the relevant PMBUS_HAVE_STATUS_*
|
||||
* functionality), but there's an unfortunate ambiguity in that
|
||||
* they're defined as indicating a fault *or* a warning, so we can't
|
||||
* easily determine whether to report REGULATOR_ERROR_<foo> or
|
||||
* REGULATOR_ERROR_<foo>_WARN.
|
||||
*/
|
||||
status = pmbus_get_status(client, page, PMBUS_STATUS_WORD);
|
||||
mutex_unlock(&data->update_lock);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (pmbus_regulator_is_enabled(rdev)) {
|
||||
if (status & PB_STATUS_OFF)
|
||||
*flags |= REGULATOR_ERROR_FAIL;
|
||||
|
||||
if (status & PB_STATUS_POWER_GOOD_N)
|
||||
*flags |= REGULATOR_ERROR_REGULATION_OUT;
|
||||
}
|
||||
/*
|
||||
* Unlike most other status bits, PB_STATUS_{IOUT_OC,VOUT_OV} are
|
||||
* defined strictly as fault indicators (not warnings).
|
||||
*/
|
||||
if (status & PB_STATUS_IOUT_OC)
|
||||
*flags |= REGULATOR_ERROR_OVER_CURRENT;
|
||||
if (status & PB_STATUS_VOUT_OV)
|
||||
*flags |= REGULATOR_ERROR_REGULATION_OUT;
|
||||
|
||||
/*
|
||||
* If we haven't discovered any thermal faults or warnings via
|
||||
* PMBUS_STATUS_TEMPERATURE, map PB_STATUS_TEMPERATURE to a warning as
|
||||
* a (conservative) best-effort interpretation.
|
||||
*/
|
||||
if (!(*flags & (REGULATOR_ERROR_OVER_TEMP | REGULATOR_ERROR_OVER_TEMP_WARN)) &&
|
||||
(status & PB_STATUS_TEMPERATURE))
|
||||
*flags |= REGULATOR_ERROR_OVER_TEMP_WARN;
|
||||
|
||||
return 0;
|
||||
return pmbus_get_flags(data, rdev_get_id(rdev), flags, &event, false);
|
||||
}
|
||||
|
||||
static int pmbus_regulator_get_status(struct regulator_dev *rdev)
|
||||
@ -3050,9 +3133,13 @@ static int pmbus_regulator_register(struct pmbus_data *data)
|
||||
struct device *dev = data->dev;
|
||||
const struct pmbus_driver_info *info = data->info;
|
||||
const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
|
||||
struct regulator_dev *rdev;
|
||||
int i;
|
||||
|
||||
data->rdevs = devm_kzalloc(dev, sizeof(struct regulator_dev *) * info->num_regulators,
|
||||
GFP_KERNEL);
|
||||
if (!data->rdevs)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < info->num_regulators; i++) {
|
||||
struct regulator_config config = { };
|
||||
|
||||
@ -3062,23 +3149,113 @@ static int pmbus_regulator_register(struct pmbus_data *data)
|
||||
if (pdata && pdata->reg_init_data)
|
||||
config.init_data = &pdata->reg_init_data[i];
|
||||
|
||||
rdev = devm_regulator_register(dev, &info->reg_desc[i],
|
||||
data->rdevs[i] = devm_regulator_register(dev, &info->reg_desc[i],
|
||||
&config);
|
||||
if (IS_ERR(rdev))
|
||||
return dev_err_probe(dev, PTR_ERR(rdev),
|
||||
if (IS_ERR(data->rdevs[i]))
|
||||
return dev_err_probe(dev, PTR_ERR(data->rdevs[i]),
|
||||
"Failed to register %s regulator\n",
|
||||
info->reg_desc[i].name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < data->info->num_regulators; j++) {
|
||||
if (page == rdev_get_id(data->rdevs[j])) {
|
||||
regulator_notifier_call_chain(data->rdevs[j], event, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int pmbus_regulator_register(struct pmbus_data *data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val)
|
||||
{
|
||||
return pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8));
|
||||
}
|
||||
|
||||
static irqreturn_t pmbus_fault_handler(int irq, void *pdata)
|
||||
{
|
||||
struct pmbus_data *data = pdata;
|
||||
struct i2c_client *client = to_i2c_client(data->dev);
|
||||
|
||||
int i, status, event;
|
||||
mutex_lock(&data->update_lock);
|
||||
for (i = 0; i < data->info->pages; i++) {
|
||||
_pmbus_get_flags(data, i, &status, &event, true);
|
||||
|
||||
if (event)
|
||||
pmbus_regulator_notify(data, i, event);
|
||||
}
|
||||
|
||||
pmbus_clear_faults(client);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pmbus_irq_setup(struct i2c_client *client, struct pmbus_data *data)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
const struct pmbus_status_category *cat;
|
||||
const struct pmbus_status_assoc *bit;
|
||||
int i, j, err, func;
|
||||
u8 mask;
|
||||
|
||||
static const u8 misc_status[] = {PMBUS_STATUS_CML, PMBUS_STATUS_OTHER,
|
||||
PMBUS_STATUS_MFR_SPECIFIC, PMBUS_STATUS_FAN_12,
|
||||
PMBUS_STATUS_FAN_34};
|
||||
|
||||
if (!client->irq)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < data->info->pages; i++) {
|
||||
func = data->info->func[i];
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(pmbus_status_flag_map); j++) {
|
||||
cat = &pmbus_status_flag_map[j];
|
||||
if (!(func & cat->func))
|
||||
continue;
|
||||
mask = 0;
|
||||
for (bit = cat->bits; bit->pflag; bit++)
|
||||
mask |= bit->pflag;
|
||||
|
||||
err = pmbus_write_smbalert_mask(client, i, cat->reg, ~mask);
|
||||
if (err)
|
||||
dev_dbg_once(dev, "Failed to set smbalert for reg 0x%02x\n",
|
||||
cat->reg);
|
||||
}
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(misc_status); j++)
|
||||
pmbus_write_smbalert_mask(client, i, misc_status[j], 0xff);
|
||||
}
|
||||
|
||||
/* Register notifiers */
|
||||
err = devm_request_threaded_irq(dev, client->irq, NULL, pmbus_fault_handler,
|
||||
IRQF_ONESHOT, "pmbus-irq", data);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to request an irq %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *pmbus_debugfs_dir; /* pmbus debugfs directory */
|
||||
|
||||
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
||||
@ -3086,8 +3263,13 @@ static int pmbus_debugfs_get(void *data, u64 *val)
|
||||
{
|
||||
int rc;
|
||||
struct pmbus_debugfs_entry *entry = data;
|
||||
struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
|
||||
|
||||
rc = mutex_lock_interruptible(&pdata->update_lock);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = _pmbus_read_byte_data(entry->client, entry->page, entry->reg);
|
||||
mutex_unlock(&pdata->update_lock);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@ -3104,7 +3286,11 @@ static int pmbus_debugfs_get_status(void *data, u64 *val)
|
||||
struct pmbus_debugfs_entry *entry = data;
|
||||
struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
|
||||
|
||||
rc = mutex_lock_interruptible(&pdata->update_lock);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pdata->read_status(entry->client, entry->page);
|
||||
mutex_unlock(&pdata->update_lock);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@ -3120,10 +3306,15 @@ static ssize_t pmbus_debugfs_mfr_read(struct file *file, char __user *buf,
|
||||
{
|
||||
int rc;
|
||||
struct pmbus_debugfs_entry *entry = file->private_data;
|
||||
struct pmbus_data *pdata = i2c_get_clientdata(entry->client);
|
||||
char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
|
||||
|
||||
rc = mutex_lock_interruptible(&pdata->update_lock);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = pmbus_read_block_data(entry->client, entry->page, entry->reg,
|
||||
data);
|
||||
mutex_unlock(&pdata->update_lock);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
@ -3441,6 +3632,10 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pmbus_irq_setup(client, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pmbus_init_debugfs(client, data);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to register debugfs\n");
|
||||
@ -3457,6 +3652,22 @@ struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client)
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(pmbus_get_debugfs_dir, PMBUS);
|
||||
|
||||
int pmbus_lock_interruptible(struct i2c_client *client)
|
||||
{
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
|
||||
return mutex_lock_interruptible(&data->update_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(pmbus_lock_interruptible, PMBUS);
|
||||
|
||||
void pmbus_unlock(struct i2c_client *client)
|
||||
{
|
||||
struct pmbus_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(pmbus_unlock, PMBUS);
|
||||
|
||||
static int __init pmbus_core_init(void)
|
||||
{
|
||||
pmbus_debugfs_dir = debugfs_create_dir("pmbus", NULL);
|
||||
|
@ -248,7 +248,7 @@ powr1220_read(struct device *dev, enum hwmon_sensor_types type, u32
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *powr1220_info[] = {
|
||||
static const struct hwmon_channel_info * const powr1220_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
|
||||
HWMON_I_INPUT | HWMON_I_HIGHEST | HWMON_I_LABEL,
|
||||
|
@ -427,7 +427,7 @@ static int pwm_fan_of_get_cooling_data(struct device *dev,
|
||||
struct device_node *np = dev->of_node;
|
||||
int num, i, ret;
|
||||
|
||||
if (!of_find_property(np, "cooling-levels", NULL))
|
||||
if (!of_property_present(np, "cooling-levels"))
|
||||
return 0;
|
||||
|
||||
ret = of_property_count_u32_elems(np, "cooling-levels");
|
||||
@ -507,6 +507,14 @@ static int pwm_fan_probe(struct platform_device *pdev)
|
||||
|
||||
pwm_init_state(ctx->pwm, &ctx->pwm_state);
|
||||
|
||||
/*
|
||||
* PWM fans are controlled solely by the duty cycle of the PWM signal,
|
||||
* they do not care about the exact timing. Thus set usage_power to true
|
||||
* to allow less flexible hardware to work as a PWM source for fan
|
||||
* control.
|
||||
*/
|
||||
ctx->pwm_state.usage_power = true;
|
||||
|
||||
/*
|
||||
* set_pwm assumes that MAX_PWM * (period - 1) fits into an unsigned
|
||||
* long. Check this here to prevent the fan running at a too low
|
||||
|
@ -87,7 +87,7 @@ static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type,
|
||||
return 0444;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *rpi_info[] = {
|
||||
static const struct hwmon_channel_info * const rpi_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_LCRIT_ALARM),
|
||||
NULL
|
||||
|
@ -265,7 +265,7 @@ static umode_t sbrmi_is_visible(const void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *sbrmi_info[] = {
|
||||
static const struct hwmon_channel_info * const sbrmi_info[] = {
|
||||
HWMON_CHANNEL_INFO(power,
|
||||
HWMON_P_INPUT | HWMON_P_CAP | HWMON_P_CAP_MAX),
|
||||
NULL
|
||||
|
@ -182,7 +182,7 @@ static umode_t sbtsi_is_visible(const void *data,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *sbtsi_info[] = {
|
||||
static const struct hwmon_channel_info * const sbtsi_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX),
|
||||
NULL
|
||||
|
@ -379,7 +379,7 @@ static const struct hwmon_ops sch5627_ops = {
|
||||
.write = sch5627_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *sch5627_info[] = {
|
||||
static const struct hwmon_channel_info * const sch5627_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,
|
||||
|
331
drivers/hwmon/sfctemp.c
Normal file
331
drivers/hwmon/sfctemp.c
Normal file
@ -0,0 +1,331 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 Emil Renner Berthing <kernel@esmil.dk>
|
||||
* Copyright (C) 2021 Samin Guo <samin.guo@starfivetech.com>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
/*
|
||||
* TempSensor reset. The RSTN can be de-asserted once the analog core has
|
||||
* powered up. Trst(min 100ns)
|
||||
* 0:reset 1:de-assert
|
||||
*/
|
||||
#define SFCTEMP_RSTN BIT(0)
|
||||
|
||||
/*
|
||||
* TempSensor analog core power down. The analog core will be powered up
|
||||
* Tpu(min 50us) after PD is de-asserted. RSTN should be held low until the
|
||||
* analog core is powered up.
|
||||
* 0:power up 1:power down
|
||||
*/
|
||||
#define SFCTEMP_PD BIT(1)
|
||||
|
||||
/*
|
||||
* TempSensor start conversion enable.
|
||||
* 0:disable 1:enable
|
||||
*/
|
||||
#define SFCTEMP_RUN BIT(2)
|
||||
|
||||
/*
|
||||
* TempSensor conversion value output.
|
||||
* Temp(C)=DOUT*Y/4094 - K
|
||||
*/
|
||||
#define SFCTEMP_DOUT_POS 16
|
||||
#define SFCTEMP_DOUT_MSK GENMASK(27, 16)
|
||||
|
||||
/* DOUT to Celcius conversion constants */
|
||||
#define SFCTEMP_Y1000 237500L
|
||||
#define SFCTEMP_Z 4094L
|
||||
#define SFCTEMP_K1000 81100L
|
||||
|
||||
struct sfctemp {
|
||||
/* serialize access to hardware register and enabled below */
|
||||
struct mutex lock;
|
||||
void __iomem *regs;
|
||||
struct clk *clk_sense;
|
||||
struct clk *clk_bus;
|
||||
struct reset_control *rst_sense;
|
||||
struct reset_control *rst_bus;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static void sfctemp_power_up(struct sfctemp *sfctemp)
|
||||
{
|
||||
/* make sure we're powered down first */
|
||||
writel(SFCTEMP_PD, sfctemp->regs);
|
||||
udelay(1);
|
||||
|
||||
writel(0, sfctemp->regs);
|
||||
/* wait t_pu(50us) + t_rst(100ns) */
|
||||
usleep_range(60, 200);
|
||||
|
||||
/* de-assert reset */
|
||||
writel(SFCTEMP_RSTN, sfctemp->regs);
|
||||
udelay(1); /* wait t_su(500ps) */
|
||||
}
|
||||
|
||||
static void sfctemp_power_down(struct sfctemp *sfctemp)
|
||||
{
|
||||
writel(SFCTEMP_PD, sfctemp->regs);
|
||||
}
|
||||
|
||||
static void sfctemp_run(struct sfctemp *sfctemp)
|
||||
{
|
||||
writel(SFCTEMP_RSTN | SFCTEMP_RUN, sfctemp->regs);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static void sfctemp_stop(struct sfctemp *sfctemp)
|
||||
{
|
||||
writel(SFCTEMP_RSTN, sfctemp->regs);
|
||||
}
|
||||
|
||||
static int sfctemp_enable(struct sfctemp *sfctemp)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&sfctemp->lock);
|
||||
if (sfctemp->enabled)
|
||||
goto done;
|
||||
|
||||
ret = clk_prepare_enable(sfctemp->clk_bus);
|
||||
if (ret)
|
||||
goto err;
|
||||
ret = reset_control_deassert(sfctemp->rst_bus);
|
||||
if (ret)
|
||||
goto err_disable_bus;
|
||||
|
||||
ret = clk_prepare_enable(sfctemp->clk_sense);
|
||||
if (ret)
|
||||
goto err_assert_bus;
|
||||
ret = reset_control_deassert(sfctemp->rst_sense);
|
||||
if (ret)
|
||||
goto err_disable_sense;
|
||||
|
||||
sfctemp_power_up(sfctemp);
|
||||
sfctemp_run(sfctemp);
|
||||
sfctemp->enabled = true;
|
||||
done:
|
||||
mutex_unlock(&sfctemp->lock);
|
||||
return ret;
|
||||
|
||||
err_disable_sense:
|
||||
clk_disable_unprepare(sfctemp->clk_sense);
|
||||
err_assert_bus:
|
||||
reset_control_assert(sfctemp->rst_bus);
|
||||
err_disable_bus:
|
||||
clk_disable_unprepare(sfctemp->clk_bus);
|
||||
err:
|
||||
mutex_unlock(&sfctemp->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sfctemp_disable(struct sfctemp *sfctemp)
|
||||
{
|
||||
mutex_lock(&sfctemp->lock);
|
||||
if (!sfctemp->enabled)
|
||||
goto done;
|
||||
|
||||
sfctemp_stop(sfctemp);
|
||||
sfctemp_power_down(sfctemp);
|
||||
reset_control_assert(sfctemp->rst_sense);
|
||||
clk_disable_unprepare(sfctemp->clk_sense);
|
||||
reset_control_assert(sfctemp->rst_bus);
|
||||
clk_disable_unprepare(sfctemp->clk_bus);
|
||||
sfctemp->enabled = false;
|
||||
done:
|
||||
mutex_unlock(&sfctemp->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sfctemp_disable_action(void *data)
|
||||
{
|
||||
sfctemp_disable(data);
|
||||
}
|
||||
|
||||
static int sfctemp_convert(struct sfctemp *sfctemp, long *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&sfctemp->lock);
|
||||
if (!sfctemp->enabled) {
|
||||
ret = -ENODATA;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* calculate temperature in milli Celcius */
|
||||
*val = (long)((readl(sfctemp->regs) & SFCTEMP_DOUT_MSK) >> SFCTEMP_DOUT_POS)
|
||||
* SFCTEMP_Y1000 / SFCTEMP_Z - SFCTEMP_K1000;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
mutex_unlock(&sfctemp->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static umode_t sfctemp_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_enable:
|
||||
return 0644;
|
||||
case hwmon_temp_input:
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int sfctemp_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct sfctemp *sfctemp = dev_get_drvdata(dev);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_enable:
|
||||
*val = sfctemp->enabled;
|
||||
return 0;
|
||||
case hwmon_temp_input:
|
||||
return sfctemp_convert(sfctemp, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int sfctemp_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
struct sfctemp *sfctemp = dev_get_drvdata(dev);
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_enable:
|
||||
if (val == 0)
|
||||
return sfctemp_disable(sfctemp);
|
||||
if (val == 1)
|
||||
return sfctemp_enable(sfctemp);
|
||||
return -EINVAL;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *sfctemp_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops sfctemp_hwmon_ops = {
|
||||
.is_visible = sfctemp_is_visible,
|
||||
.read = sfctemp_read,
|
||||
.write = sfctemp_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info sfctemp_chip_info = {
|
||||
.ops = &sfctemp_hwmon_ops,
|
||||
.info = sfctemp_info,
|
||||
};
|
||||
|
||||
static int sfctemp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct sfctemp *sfctemp;
|
||||
int ret;
|
||||
|
||||
sfctemp = devm_kzalloc(dev, sizeof(*sfctemp), GFP_KERNEL);
|
||||
if (!sfctemp)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, sfctemp);
|
||||
mutex_init(&sfctemp->lock);
|
||||
|
||||
sfctemp->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(sfctemp->regs))
|
||||
return PTR_ERR(sfctemp->regs);
|
||||
|
||||
sfctemp->clk_sense = devm_clk_get(dev, "sense");
|
||||
if (IS_ERR(sfctemp->clk_sense))
|
||||
return dev_err_probe(dev, PTR_ERR(sfctemp->clk_sense),
|
||||
"error getting sense clock\n");
|
||||
|
||||
sfctemp->clk_bus = devm_clk_get(dev, "bus");
|
||||
if (IS_ERR(sfctemp->clk_bus))
|
||||
return dev_err_probe(dev, PTR_ERR(sfctemp->clk_bus),
|
||||
"error getting bus clock\n");
|
||||
|
||||
sfctemp->rst_sense = devm_reset_control_get_exclusive(dev, "sense");
|
||||
if (IS_ERR(sfctemp->rst_sense))
|
||||
return dev_err_probe(dev, PTR_ERR(sfctemp->rst_sense),
|
||||
"error getting sense reset\n");
|
||||
|
||||
sfctemp->rst_bus = devm_reset_control_get_exclusive(dev, "bus");
|
||||
if (IS_ERR(sfctemp->rst_bus))
|
||||
return dev_err_probe(dev, PTR_ERR(sfctemp->rst_bus),
|
||||
"error getting busreset\n");
|
||||
|
||||
ret = reset_control_assert(sfctemp->rst_sense);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "error asserting sense reset\n");
|
||||
|
||||
ret = reset_control_assert(sfctemp->rst_bus);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "error asserting bus reset\n");
|
||||
|
||||
ret = devm_add_action(dev, sfctemp_disable_action, sfctemp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sfctemp_enable(sfctemp);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "error enabling temperature sensor\n");
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev, "sfctemp", sfctemp,
|
||||
&sfctemp_chip_info, NULL);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id sfctemp_of_match[] = {
|
||||
{ .compatible = "starfive,jh7100-temp" },
|
||||
{ .compatible = "starfive,jh7110-temp" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sfctemp_of_match);
|
||||
|
||||
static struct platform_driver sfctemp_driver = {
|
||||
.probe = sfctemp_probe,
|
||||
.driver = {
|
||||
.name = "sfctemp",
|
||||
.of_match_table = sfctemp_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(sfctemp_driver);
|
||||
|
||||
MODULE_AUTHOR("Emil Renner Berthing");
|
||||
MODULE_DESCRIPTION("StarFive JH71x0 temperature sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -214,7 +214,7 @@ static int sht4x_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *sht4x_info[] = {
|
||||
static const struct hwmon_channel_info * const sht4x_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
|
||||
|
@ -67,7 +67,7 @@ static int sl28cpld_hwmon_read(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *sl28cpld_hwmon_info[] = {
|
||||
static const struct hwmon_channel_info * const sl28cpld_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
@ -385,7 +385,7 @@ static umode_t smpro_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
return 0444;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *smpro_info[] = {
|
||||
static const struct hwmon_channel_info * const smpro_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT,
|
||||
|
@ -86,7 +86,7 @@ static umode_t s5_is_visible(const void *_data, enum hwmon_sensor_types type,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info *s5_info[] = {
|
||||
static const struct hwmon_channel_info * const s5_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
NULL
|
||||
|
@ -52,7 +52,7 @@ static const struct hwmon_ops sy7636a_hwmon_ops = {
|
||||
.read = sy7636a_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *sy7636a_info[] = {
|
||||
static const struct hwmon_channel_info * const sy7636a_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
|
||||
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
|
||||
NULL
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user