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:
Linus Torvalds 2023-04-25 17:43:44 -07:00
commit 4173cf6fb6
110 changed files with 2161 additions and 607 deletions

View File

@ -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 = <&reg_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.

View 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 = <&reg_fan>;
interrupt-parent = <&gpio5>;
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
pulses-per-revolution = <2>;
};

View File

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

View File

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

View File

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

View File

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

View File

@ -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,.*":

View 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.
======================= ======================================================

View File

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

View File

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

View File

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

View File

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

View File

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

View 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.
================ ==== =============================================

View File

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

View File

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

View File

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

View File

@ -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
@ -1976,7 +1986,7 @@ config SENSORS_ADS7871
config SENSORS_AMC6821
tristate "Texas Instruments AMC6821"
depends on I2C
depends on I2C
help
If you say yes here you get support for the Texas Instruments
AMC6821 hardware monitoring chips.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1604,9 +1604,9 @@ 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,
"adi,pwm-active-state", states,
ARRAY_SIZE(states));
ret = device_property_read_u32_array(&client->dev,
"adi,pwm-active-state", states,
ARRAY_SIZE(states));
if (ret)
return ret;

View File

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

View File

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

View File

@ -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;
/* Init and xorout value for CRC-16/USB is 0xffff */
checksum = crc16(0xffff, priv->buffer + priv->checksum_start, priv->checksum_length);
checksum ^= 0xffff;
/* 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 ^= 0xffff;
/* Place the new checksum at the end of the report */
put_unaligned_be16(checksum, priv->buffer + priv->checksum_offset);
/* 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;
*val = (s16)get_unaligned_be16(priv->buffer + offset);
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;
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) },
{ }

View File

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

View File

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

View File

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

View File

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

View File

@ -282,14 +282,8 @@ 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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
/* 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) {
!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);

View File

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

View File

@ -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, &regval);
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 |

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) */
{},
};

View File

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

View File

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

View File

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

View File

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

View File

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

View 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);

View File

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

View File

@ -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)) {
/*
* 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);
return rc;
}
rc = pmbus_lock_interruptible(psu->client);
if (rc)
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;
rc = pmbus_set_page(psu->client, 0, 0xff);
if (rc) {
pmbus_unlock(psu->client);
return rc;
}
mutex_unlock(&psu->input_history.update_lock);
/*
* 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);
pmbus_unlock(psu->client);
if (rc < 0)
return rc;
}
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;
rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc);
goto done;
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);
break;
case CFFPS_DEBUGFS_CCIN:
rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD);
if (rc < 0)
return rc;
rc = snprintf(data, 5, "%04X", rc);
goto done;
if (rc >= 0)
rc = snprintf(data, 5, "%04X", rc);
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 = snprintf(data, 3, "%02x", rc);
goto done;
rc = i2c_smbus_read_byte_data(psu->client, PMBUS_ON_OFF_CONFIG);
if (rc >= 0)
rc = snprintf(data, 3, "%02x", rc);
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",

View File

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

View File

@ -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],
&config);
if (IS_ERR(rdev))
return dev_err_probe(dev, PTR_ERR(rdev),
data->rdevs[i] = devm_regulator_register(dev, &info->reg_desc[i],
&config);
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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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