hwmon updates for v6.5

* New drivers
 
   - Driver for MAX31827
 
   - Driver to support HP WMI Sensors
 
 * Added support to existing drivers
 
   - aht10: Support for AHT20
 
   - aquacomputer_d5next: Support for Aquacomputer Leakshield
 
   - asus-ec-sensors: Support for ROG Crosshair X670E Hero
 
   - corsair-psu: Cleanups and support for series 2022 and 2023
 
   - it87: Various improvements and support for IT8732F
 
   - nct6683: Support customer ID of some MSI boards.
 
   - nct6755: Support for NCT6799D
 
   - oxp-sensors: Various cleanups; support for AYANEO 2, Geek, OXP Mini,
     and AOKZOE A1 PRO
 
   - pmbus/max16601: Support for new revisions of MAX16508
 
   - pmbus/adm1275: Disable ADC while updating PMON_CONFIG, and fix problems
     with temperature monitoring on ADM1272
 
   - sht3x: Various cleanups; support for medium repeatability
 
 * Other notable changes
 
   - Switched regmap drivers to Maple tree support where appropriate
 
 * Various other minor fixes and improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmSaWu0ACgkQyx8mb86f
 mYHJ/Q//SoGbNpCZLUBDYRQD4YatAPq7G520lWBg9nL7YT/iXnJYL0dULlSg+FAg
 LatgAS26L/KR0l3rmffcPo+216CJ89QJa+oeWBdTxOEJXOUtlt9nxHFk/SB9tS6P
 z94QU2IOd1SuxDrubm1OA+gChwTgt2dbubkBoXbbWDc9z4rk7TGtbXejuqn1OpDr
 OEU5hZMB8+m8ZmFAVuxXDXVHNlSTFBwDs/GQrlmBh8R/B9Kpi4EOb8JKAidyiHnr
 Mz1z7KQqh8KP+c8PscE6M4WlWBLoSHGgCmsURyxZhRvddBkeD1y02y+LBUrh2rwd
 UTugnwqsPSOtOyysX1qOPvqAP4RL2k9mzuojLYOcWwS1Dx73iqBcEuUdtUjotsLo
 sYmU8hEZVzzEhBPpsyHwszOyA/xl7lJpZTtJZf6ztKfTPI6bPIznFWzQFmBB4FYQ
 wW+sG096Dat+6bPGQBo55RZaUD+B4ms4gpyeDUxoCj8c2iRK2n6ZhcreASsNr1De
 qEFz35gN7g/4rDpm4MDBk+DLd/tAK02Dd86gzMlECKULmiPMUrBnHFv6Qyvv9/P6
 yfY8g33ZU288zjlgBSqG9MWczouify5O3MshMdmjnAkSisPP5XOjHfnhhbLVp5kK
 Ar+qR4MfQS9nI07DpWXv+ym6HgeJJyFYFxDLZk5I7OS0/w6FxNM=
 =fP+M
 -----END PGP SIGNATURE-----

Merge tag 'hwmon-for-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon updates from Guenter Roeck:
 "New drivers:

   - Driver for MAX31827

   - Driver to support HP WMI Sensors

  Added support to existing drivers:

   - aht10: Support for AHT20

   - aquacomputer_d5next: Support for Aquacomputer Leakshield

   - asus-ec-sensors: Support for ROG Crosshair X670E Hero

   - corsair-psu: Cleanups and support for series 2022 and 2023

   - it87: Various improvements and support for IT8732F

   - nct6683: Support customer ID of some MSI boards.

   - nct6755: Support for NCT6799D

   - oxp-sensors: Various cleanups; support for AYANEO 2, Geek, OXP
     Mini, and AOKZOE A1 PRO

   - pmbus/max16601: Support for new revisions of MAX16508

   - pmbus/adm1275: Disable ADC while updating PMON_CONFIG, and fix
     problems with temperature monitoring on ADM1272

   - sht3x: Various cleanups; support for medium repeatability

  Other notable changes:

   - Switched regmap drivers to Maple tree support where appropriate

  Various other minor fixes and improvements"

* tag 'hwmon-for-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (54 commits)
  hwmon: max31827: Switch back to use struct i2c_driver::probe
  hwmon: (oxp-sensors) Add support for AOKZOE A1 PRO
  hwmon: (corsair-psu) update Series 2022 and 2023 support
  hwmon: (corsair-psu) various cleanups
  hwmon: (corsair-psu) add support for reading PWM values and mode
  hwmon: (pmbus/adm1275) Disable ADC while updating PMON_CONFIG
  hwmon: (pmbus/adm1275) Prepare for protected write to PMON_CONFIG
  hwmon: (oxp-sensors) Simplify logic of error return
  hwmon: (oxp-sensors) Remove unused header
  hwmon: (nct6755) Add support for NCT6799D
  hwmon: (oxp-sensors) Add tt_toggle attribute on supported boards
  hwmon: (sht3x) complement sysfs interface for sts3x
  hwmon: (sht3x) Add new non-stardard sysfs attribute
  hwmon: (sht3x) add medium repeatability support
  hwmon: (sht3x)replace "high-precision" property to "repeatability"
  hwmon: (sht3x) remove blocking_io property
  hwmon: (sht3x) remove sht3x_platform_data
  hwmon: (pmbus/max16601) Add support for new revisions of MAX16508
  Documentation/hwmon: Fix description of devm_hwmon_device_unregister()
  hwmon: (tmp464) Use maple tree register cache
  ...
This commit is contained in:
Linus Torvalds 2023-06-29 10:01:25 -07:00
commit acd1d46b0d
193 changed files with 3910 additions and 443 deletions

View file

@ -0,0 +1,54 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/adi,max31827.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch
maintainers:
- Daniel Matyas <daniel.matyas@analog.com>
description: |
Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch with
I2C Interface
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf
properties:
compatible:
oneOf:
- const: adi,max31827
- items:
- enum:
- adi,max31828
- adi,max31829
- const: adi,max31827
reg:
maxItems: 1
vref-supply:
description:
Must have values in the interval (1.6V; 3.6V) in order for the device to
function correctly.
required:
- compatible
- reg
- vref-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
temperature-sensor@42 {
compatible = "adi,max31827";
reg = <0x42>;
vref-supply = <&reg_vdd>;
};
};
...

View file

@ -5,32 +5,42 @@ Kernel driver aht10
Supported chips:
* Aosong AHT10
* Aosong AHT10/AHT20
Prefix: 'aht10'
Addresses scanned: None
Datasheet:
Datasheet(AHT10):
Chinese: http://www.aosong.com/userfiles/files/media/AHT10%E4%BA%A7%E5%93%81%E6%89%8B%E5%86%8C%20A3%2020201210.pdf
English: https://server4.eca.ir/eshop/AHT10/Aosong_AHT10_en_draft_0c.pdf
Datasheet(AHT20):
English: http://www.aosong.com/userfiles/files/media/Data%20Sheet%20AHT20.pdf
Author: Johannes Cornelis Draaijer <jcdra1@gmail.com>
Description
-----------
The AHT10 is a Temperature and Humidity sensor
The AHT10/AHT20 is a Temperature and Humidity sensor
The address of this i2c device may only be 0x38
Special Features
----------------
AHT20 has additional CRC8 support which is sent as the last byte of the sensor
values.
Usage Notes
-----------
This driver does not probe for AHT10 devices, as there is no reliable
way to determine if an i2c chip is or isn't an AHT10. The device has
This driver does not probe for AHT10/ATH20 devices, as there is no reliable
way to determine if an i2c chip is or isn't an AHT10/AHT20. The device has
to be instantiated explicitly with the address 0x38. See
Documentation/i2c/instantiating-devices.rst for details.

View file

@ -12,6 +12,7 @@ Supported devices:
* Aquacomputer Octo fan controller
* Aquacomputer Quadro fan controller
* Aquacomputer High Flow Next sensor
* Aquacomputer Leakshield leak prevention system
* Aquacomputer Aquastream XT watercooling pump
* Aquacomputer Aquastream Ultimate watercooling pump
* Aquacomputer Poweradjust 3 fan controller
@ -57,6 +58,11 @@ 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 Leakshield exposes two temperature sensors and coolant pressure (current, min, max and
target readings). It also exposes the estimated reservoir volume and how much of it is
filled with coolant. Pump RPM and flow can be set to enhance on-device calculations,
but this is not yet implemented here.
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.
@ -83,6 +89,9 @@ Sysfs entries
temp[1-20]_input Physical/virtual temperature sensors (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)
fan1_min Minimal fan speed (in RPM)
fan1_max Maximal fan speed (in RPM)
fan1_target Target fan speed (in RPM)
fan5_pulses Quadro flow sensor pulses
power[1-8]_input Pump/fan power (in micro Watts)
in[0-7]_input Pump/fan voltage (in milli Volts)

View file

@ -14,6 +14,7 @@ Supported boards:
* ROG CROSSHAIR VIII FORMULA
* ROG CROSSHAIR VIII HERO
* ROG CROSSHAIR VIII IMPACT
* ROG CROSSHAIR X670E HERO
* ROG MAXIMUS XI HERO
* ROG MAXIMUS XI HERO (WI-FI)
* ROG STRIX B550-E GAMING

View file

@ -15,11 +15,11 @@ Supported devices:
Corsair HX850i
Corsair HX1000i (revision 1 and 2)
Corsair HX1000i (Series 2022 and 2023)
Corsair HX1200i
Corsair HX1500i
Corsair HX1500i (Series 2022 and 2023)
Corsair RM550i
@ -69,6 +69,8 @@ power1_input Total power usage
power2_input Power usage of the 12v psu rail
power3_input Power usage of the 5v psu rail
power4_input Power usage of the 3.3v psu rail
pwm1 PWM value, read only
pwm1_enable PWM mode, read only
temp1_input Temperature of the psu vrm component
temp1_crit Temperature max cirtical value of the psu vrm component
temp2_input Temperature of the psu case
@ -78,11 +80,14 @@ temp2_crit Temperature max critical value of psu case
Usage Notes
-----------
It is an USB HID device, so it is auto-detected and supports hot-swapping.
It is an USB HID device, so it is auto-detected, supports hot-swapping and
several devices at once.
Flickering values in the rail voltage levels can be an indicator for a failing
PSU. The driver also provides some additional useful values via debugfs, which
do not fit into the hwmon class.
PSU. Accordingly to the default automatic fan speed plan the fan starts at about
30% of the wattage rating. If this does not happen, a fan failure is likely. The
driver also provides some additional useful values via debugfs, which do not fit
into the hwmon class.
Debugfs entries
---------------

View file

@ -0,0 +1,140 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
.. include:: <isonum.txt>
===========================
Linux HP WMI Sensors Driver
===========================
:Copyright: |copy| 2023 James Seo <james@equiv.tech>
Description
===========
Hewlett-Packard (and some HP Compaq) business-class computers report hardware
monitoring information via Windows Management Instrumentation (WMI).
This driver exposes that information to the Linux hwmon subsystem, allowing
userspace utilities like ``sensors`` to gather numeric sensor readings.
sysfs interface
===============
When the driver is loaded, it discovers the sensors available on the
system and creates the following sysfs attributes as necessary within
``/sys/class/hwmon/hwmon[X]``:
(``[X]`` is some number that depends on other system components.)
======================= ======= ===================================
Name Perm Description
======================= ======= ===================================
``curr[X]_input`` RO Current in milliamperes (mA).
``curr[X]_label`` RO Current sensor label.
``fan[X]_input`` RO Fan speed in RPM.
``fan[X]_label`` RO Fan sensor label.
``fan[X]_fault`` RO Fan sensor fault indicator.
``fan[X]_alarm`` RO Fan sensor alarm indicator.
``in[X]_input`` RO Voltage in millivolts (mV).
``in[X]_label`` RO Voltage sensor label.
``temp[X]_input`` RO Temperature in millidegrees Celsius
(m\ |deg|\ C).
``temp[X]_label`` RO Temperature sensor label.
``temp[X]_fault`` RO Temperature sensor fault indicator.
``temp[X]_alarm`` RO Temperature sensor alarm indicator.
``intrusion[X]_alarm`` RW Chassis intrusion alarm indicator.
======================= ======= ===================================
``fault`` attributes
Reading ``1`` instead of ``0`` as the ``fault`` attribute for a sensor
indicates that it has encountered some issue during operation such that
measurements from it should not be trusted. If a sensor with the fault
condition recovers later, reading this attribute will return ``0`` again.
``alarm`` attributes
Reading ``1`` instead of ``0`` as the ``alarm`` attribute for a sensor
indicates that one of the following has occurred, depending on its type:
- ``fan``: The fan has stalled or has been disconnected while running.
- ``temp``: The sensor reading has reached a critical threshold.
The exact threshold is system-dependent.
- ``intrusion``: The system's chassis has been opened.
After ``1`` is read from an ``alarm`` attribute, the attribute resets itself
and returns ``0`` on subsequent reads. As an exception, an
``intrusion[X]_alarm`` can only be manually reset by writing ``0`` to it.
debugfs interface
=================
.. warning:: The debugfs interface is subject to change without notice
and is only available when the kernel is compiled with
``CONFIG_DEBUG_FS`` defined.
The standard hwmon interface in sysfs exposes sensors of several common types
that are connected as of driver initialization. However, there are usually
other sensors in WMI that do not meet these criteria. In addition, a number of
system-dependent "platform events objects" used for ``alarm`` attributes may
be present. A debugfs interface is therefore provided for read-only access to
all available HP WMI sensors and platform events objects.
``/sys/kernel/debug/hp-wmi-sensors-[X]/sensor``
contains one numbered entry per sensor with the following attributes:
=============================== =======================================
Name Example
=============================== =======================================
``name`` ``CPU0 Fan``
``description`` ``Reports CPU0 fan speed``
``sensor_type`` ``12``
``other_sensor_type`` (an empty string)
``operational_status`` ``2``
``possible_states`` ``Normal,Caution,Critical,Not Present``
``current_state`` ``Normal``
``base_units`` ``19``
``unit_modifier`` ``0``
``current_reading`` ``1008``
``rate_units`` ``0`` (only exists on some systems)
=============================== =======================================
If platform events objects are available,
``/sys/kernel/debug/hp-wmi-sensors-[X]/platform_events``
contains one numbered entry per object with the following attributes:
=============================== ====================
Name Example
=============================== ====================
``name`` ``CPU0 Fan Stall``
``description`` ``CPU0 Fan Speed``
``source_namespace`` ``root\wmi``
``source_class`` ``HPBIOS_BIOSEvent``
``category`` ``3``
``possible_severity`` ``25``
``possible_status`` ``5``
=============================== ====================
These represent the properties of the underlying ``HPBIOS_BIOSNumericSensor``
and ``HPBIOS_PlatformEvents`` WMI objects, which vary between systems.
See [#]_ for more details and Managed Object Format (MOF) definitions.
Known issues and limitations
============================
- If the existing hp-wmi driver for non-business-class HP systems is already
loaded, ``alarm`` attributes will be unavailable even on systems that
support them. This is because the same WMI event GUID used by this driver
for ``alarm`` attributes is used on those systems for e.g. laptop hotkeys.
- Dubious sensor hardware and inconsistent BIOS WMI implementations have been
observed to cause inaccurate readings and peculiar behavior, such as alarms
failing to occur or occurring only once per boot.
- Only temperature, fan speed, and intrusion sensor types have been seen in
the wild so far. Support for voltage and current sensors is therefore
provisional.
- Although HP WMI sensors may claim to be of any type, any oddball sensor
types unknown to hwmon will not be supported.
References
==========
.. [#] Hewlett-Packard Development Company, L.P.,
"HP Client Management Interface Technical White Paper", 2005. [Online].
Available: https://h20331.www2.hp.com/hpsub/downloads/cmi_whitepaper.pdf

View file

@ -66,7 +66,7 @@ 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 hwmon_device_register_with_info and if the automatic (device
the call to devm_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

View file

@ -9,7 +9,6 @@ Hardware Monitoring
hwmon-kernel-api
pmbus-core
inspur-ipsps1
submitting-patches
sysfs-interface
userspace-tools
@ -78,6 +77,7 @@ Hardware Monitoring Kernel Drivers
gl518sm
gxp-fan-ctrl
hih6130
hp-wmi-sensors
ibmaem
ibm-cffps
ibmpowernv
@ -85,6 +85,7 @@ Hardware Monitoring Kernel Drivers
ina2xx
ina238
ina3221
inspur-ipsps1
intel-m10-bmc-hwmon
ir35221
ir38064
@ -140,6 +141,7 @@ Hardware Monitoring Kernel Drivers
max31760
max31785
max31790
max31827
max34440
max6620
max6639

View file

@ -0,0 +1,90 @@
.. SPDX-License-Identifier: GPL-2.0
Kernel driver max31827
======================
Supported chips:
* Maxim MAX31827
Prefix: 'max31827'
Addresses scanned: I2C 0x40 - 0x5f
Datasheet: Publicly available at the Analog Devices website
* Maxim MAX31828
Prefix: 'max31828'
Addresses scanned: I2C 0x40 - 0x5f
Datasheet: Publicly available at the Analog Devices website
* Maxim MAX31829
Prefix: 'max31829'
Addresses scanned: I2C 0x40 - 0x5f
Datasheet: Publicly available at the Analog Devices website
Authors:
- Daniel Matyas <daniel.matyas@analog.com>
Description
-----------
The chips supported by this driver are quite similar. The only difference
between them is found in the default power-on behaviour of the chips. While the
MAX31827's fault queue is set to 1, the other two chip's fault queue is set to
4. Besides this, the MAX31829's alarm active state is high, while the other two
chip's alarms are active on low. It is important to note that the chips can be
configured to operate in the same manner with 1 write operation to the
configuration register. From here on, we will refer to all these chips as
MAX31827.
MAX31827 implements a temperature sensor with a 6 WLP packaging scheme. This
sensor measures the temperature of the chip itself.
MAX31827 has low and over temperature alarms with an effective value and a
hysteresis value: -40 and -30 degrees for under temperature alarm and +100 and
+90 degrees for over temperature alarm.
The alarm can be configured in comparator and interrupt mode. Currently only
comparator mode is implemented. In Comparator mode, the OT/UT status bits have a
value of 1 when the temperature rises above the TH value or falls below TL,
which is also subject to the Fault Queue selection. OT status returns to 0 when
the temperature drops below the TH_HYST value or when shutdown mode is entered.
Similarly, UT status returns to 0 when the temperature rises above TL_HYST value
or when shutdown mode is entered.
Putting the MAX31827 into shutdown mode also resets the OT/UT status bits. Note
that if the mode is changed while OT/UT status bits are set, an OT/UT status
reset may be required before it begins to behave normally. To prevent this,
it is recommended to perform a read of the configuration/status register to
clear the status bits before changing the operating mode.
The conversions can be manual with the one-shot functionality and automatic with
a set frequency. When powered on, the chip measures temperatures with 1 conv/s.
Enabling the device when it is already enabled has the side effect of setting
the conversion frequency to 1 conv/s. The conversion time varies depending on
the resolution. The conversion time doubles with every bit of increased
resolution. For 10 bit resolution 35ms are needed, while for 12 bit resolution
(default) 140ms. When chip is in shutdown mode and a read operation is
requested, one-shot is triggered, the device waits for 140 (conversion time) + 1
(error) ms, and only after that is the temperature value register read.
The LSB of the temperature values is 0.0625 degrees Celsius, but the values of
the temperatures are displayed in milli-degrees. This means, that some data is
lost. The step between 2 consecutive values is 62 or 63. This effect can be seen
in the writing of alarm values too. For positive numbers the user-input value
will always be rounded down to the nearest possible value, for negative numbers
the user-input will always be rounded up to the nearest possible value.
Notes
-----
Currently fault queue, alarm polarity and resolution cannot be modified.
PEC is not implemented either.

View file

@ -19,18 +19,32 @@ out the EC registers and values to write to since the EC layout and model is
different. Aya Neo devices preceding the AIR may not be supportable as the EC
model is different and do not appear to have manual control capabilities.
Some models have a toggle for changing the behaviour of the "Turbo/Silent"
button of the device. It will change the key event that it triggers with
a flip of the `tt_toggle` attribute. See below for boards that support this
function.
Supported devices
-----------------
Currently the driver supports the following handhelds:
- AOK ZOE A1
- AOK ZOE A1 PRO
- Aya Neo 2
- Aya Neo AIR
- Aya Neo AIR Pro
- Aya Neo Geek
- OneXPlayer AMD
- OneXPlayer mini AMD
- OneXPlayer mini AMD PRO
"Turbo/Silent" button behaviour toggle is only supported on:
- AOK ZOE A1
- AOK ZOE A1 PRO
- OneXPlayer mini AMD (only with updated alpha BIOS)
- OneXPlayer mini AMD PRO
Sysfs entries
-------------
@ -47,3 +61,10 @@ pwm1
Read Write. Read this attribute to see current duty cycle in the range [0-255].
When pwm1_enable is set to "1" (manual) write any value in the range [0-255]
to set fan speed.
tt_toggle
Read Write. Read this attribute to check the status of the turbo/silent
button behaviour function. Write "1" to activate the switch and "0" to
deactivate it. The specific keycodes and behaviour is specific to the device
both with this function on and off. This attribute is attached to the platform
driver and not to the hwmon driver (/sys/devices/platform/oxp-platform/tt_toggle)

View file

@ -28,15 +28,8 @@ The device communicates with the I2C protocol. Sensors can have the I2C
addresses 0x44 or 0x45, depending on the wiring. See
Documentation/i2c/instantiating-devices.rst for methods to instantiate the device.
There are two options configurable by means of sht3x_platform_data:
1. blocking (pull the I2C clock line down while performing the measurement) or
non-blocking mode. Blocking mode will guarantee the fastest result but
the I2C bus will be busy during that time. By default, non-blocking mode
is used. Make sure clock-stretching works properly on your device if you
want to use blocking mode.
2. high or low accuracy. High accuracy is used by default and using it is
strongly recommended.
Even if sht3x sensor supports clock-strech(blocking mode) and non-strench
(non-blocking mode) in single-shot mode, this driver only supports the latter.
The sht3x sensor supports a single shot mode as well as 5 periodic measure
modes, which can be controlled with the update_interval sysfs interface.
@ -85,4 +78,11 @@ heater_enable: heater enable, heating element removes excess humidity from
update_interval: update interval, 0 for single shot, interval in msec
for periodic measurement. If the interval is not supported
by the sensor, the next faster interval is chosen
repeatability: write or read repeatability, higher repeatability means
longer measurement duration, lower noise level and
larger energy consumption:
- 0: low repeatability
- 1: medium repeatability
- 2: high repeatability
=================== ============================================================

View file

@ -9473,6 +9473,13 @@ L: platform-driver-x86@vger.kernel.org
S: Orphan
F: drivers/platform/x86/hp/tc1100-wmi.c
HP WMI HARDWARE MONITOR DRIVER
M: James Seo <james@equiv.tech>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/hp-wmi-sensors.rst
F: drivers/hwmon/hp-wmi-sensors.c
HPET: High Precision Event Timers driver
M: Clemens Ladisch <clemens@ladisch.de>
S: Maintained
@ -12671,6 +12678,15 @@ F: Documentation/userspace-api/media/drivers/max2175.rst
F: drivers/media/i2c/max2175*
F: include/uapi/linux/max2175.h
MAX31827 TEMPERATURE SWITCH DRIVER
M: Daniel Matyas <daniel.matyas@analog.com>
L: linux-hwmon@vger.kernel.org
S: Supported
W: http://ez.analog.com/community/linux-device-drivers
F: Documentation/devicetree/bindings/hwmon/adi,max31827.yaml
F: Documentation/hwmon/max31827.rst
F: drivers/hwmon/max31827.c
MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
L: linux-hwmon@vger.kernel.org
S: Orphan

View file

@ -255,10 +255,11 @@ config SENSORS_ADT7475
will be called adt7475.
config SENSORS_AHT10
tristate "Aosong AHT10"
tristate "Aosong AHT10, AHT20"
depends on I2C
select CRC8
help
If you say yes here, you get support for the Aosong AHT10
If you say yes here, you get support for the Aosong AHT10 and AHT20
temperature and humidity sensors
This driver can also be built as a module. If so, the module
@ -1097,6 +1098,17 @@ config SENSORS_MAX31760
This driver can also be built as a module. If so, the module
will be called max31760.
config MAX31827
tristate "MAX31827 low-power temperature switch and similar devices"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for MAX31827, MAX31828 and
MAX31829 low-power temperature switches and sensors connected with I2C.
This driver can also be built as a module. If so, the module
will be called max31827.
config SENSORS_MAX6620
tristate "Maxim MAX6620 fan controller"
depends on I2C
@ -2409,6 +2421,18 @@ config SENSORS_ASUS_EC
This driver can also be built as a module. If so, the module
will be called asus_ec_sensors.
config SENSORS_HP_WMI
tristate "HP WMI Sensors"
depends on ACPI_WMI
help
If you say yes here you get support for the ACPI hardware monitoring
interface found in HP (and some HP Compaq) business-class computers.
Available sensors vary between systems. Temperature and fan speed
sensors are the most common.
This driver can also be built as a module. If so, the module
will be called hp_wmi_sensors.
endif # ACPI
endif # HWMON

View file

@ -11,6 +11,7 @@ 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
obj-$(CONFIG_SENSORS_ASUS_WMI) += asus_wmi_sensors.o
obj-$(CONFIG_SENSORS_HP_WMI) += hp-wmi-sensors.o
# Native drivers
# asb100, then w83781d go first, as they can override other drivers' addresses.
@ -149,6 +150,7 @@ obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
obj-$(CONFIG_MAX31827) += max31827.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
@ -224,4 +226,3 @@ obj-$(CONFIG_SENSORS_PECI) += peci/
obj-$(CONFIG_PMBUS) += pmbus/
ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG

View file

@ -221,7 +221,7 @@ static struct i2c_driver ad7414_driver = {
.name = "ad7414",
.of_match_table = of_match_ptr(ad7414_of_match),
},
.probe_new = ad7414_probe,
.probe = ad7414_probe,
.id_table = ad7414_id,
};

View file

@ -306,7 +306,7 @@ static struct i2c_driver ad7418_driver = {
.name = "ad7418",
.of_match_table = ad7418_dt_ids,
},
.probe_new = ad7418_probe,
.probe = ad7418_probe,
.id_table = ad7418_id,
};

View file

@ -521,7 +521,7 @@ static struct i2c_driver adc128_driver = {
.name = "adc128d818",
.of_match_table = of_match_ptr(adc128_of_match),
},
.probe_new = adc128_probe,
.probe = adc128_probe,
.remove = adc128_remove,
.id_table = adc128_id,
.detect = adc128_detect,

View file

@ -488,7 +488,7 @@ static struct i2c_driver adm1021_driver = {
.driver = {
.name = "adm1021",
},
.probe_new = adm1021_probe,
.probe = adm1021_probe,
.id_table = adm1021_id,
.detect = adm1021_detect,
.address_list = normal_i2c,

View file

@ -559,7 +559,7 @@ static struct i2c_driver adm1025_driver = {
.driver = {
.name = "adm1025",
},
.probe_new = adm1025_probe,
.probe = adm1025_probe,
.id_table = adm1025_id,
.detect = adm1025_detect,
.address_list = normal_i2c,

View file

@ -1859,7 +1859,7 @@ static struct i2c_driver adm1026_driver = {
.driver = {
.name = "adm1026",
},
.probe_new = adm1026_probe,
.probe = adm1026_probe,
.id_table = adm1026_id,
.detect = adm1026_detect,
.address_list = normal_i2c,

View file

@ -389,7 +389,7 @@ static struct i2c_driver adm1029_driver = {
.driver = {
.name = "adm1029",
},
.probe_new = adm1029_probe,
.probe = adm1029_probe,
.id_table = adm1029_id,
.detect = adm1029_detect,
.address_list = normal_i2c,

View file

@ -1068,7 +1068,7 @@ static struct i2c_driver adm1031_driver = {
.driver = {
.name = "adm1031",
},
.probe_new = adm1031_probe,
.probe = adm1031_probe,
.id_table = adm1031_id,
.detect = adm1031_detect,
.address_list = normal_i2c,

View file

@ -255,7 +255,7 @@ static struct i2c_driver adm1177_driver = {
.name = "adm1177",
.of_match_table = adm1177_dt_ids,
},
.probe_new = adm1177_probe,
.probe = adm1177_probe,
.id_table = adm1177_id,
};
module_i2c_driver(adm1177_driver);

View file

@ -819,7 +819,7 @@ static struct i2c_driver adm9240_driver = {
.driver = {
.name = "adm9240",
},
.probe_new = adm9240_probe,
.probe = adm9240_probe,
.id_table = adm9240_id,
.detect = adm9240_detect,
.address_list = normal_i2c,

View file

@ -208,7 +208,7 @@ static struct i2c_driver ads7828_driver = {
},
.id_table = ads7828_device_ids,
.probe_new = ads7828_probe,
.probe = ads7828_probe,
};
module_i2c_driver(ads7828_driver);

View file

@ -100,7 +100,7 @@ static struct i2c_driver adt7410_driver = {
.name = "adt7410",
.pm = pm_sleep_ptr(&adt7x10_dev_pm_ops),
},
.probe_new = adt7410_i2c_probe,
.probe = adt7410_i2c_probe,
.id_table = adt7410_ids,
.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
};

View file

@ -706,7 +706,7 @@ static struct i2c_driver adt7411_driver = {
.driver = {
.name = "adt7411",
},
.probe_new = adt7411_probe,
.probe = adt7411_probe,
.id_table = adt7411_id,
.detect = adt7411_detect,
.address_list = normal_i2c,

View file

@ -1819,7 +1819,7 @@ static struct i2c_driver adt7462_driver = {
.driver = {
.name = "adt7462",
},
.probe_new = adt7462_probe,
.probe = adt7462_probe,
.id_table = adt7462_id,
.detect = adt7462_detect,
.address_list = normal_i2c,

View file

@ -1314,7 +1314,7 @@ static struct i2c_driver adt7470_driver = {
.driver = {
.name = "adt7470",
},
.probe_new = adt7470_probe,
.probe = adt7470_probe,
.remove = adt7470_remove,
.id_table = adt7470_id,
.detect = adt7470_detect,

View file

@ -1468,7 +1468,7 @@ static int load_config3(const struct i2c_client *client, const char *propname)
u8 config3;
int ret;
ret = of_property_read_string(client->dev.of_node, propname, &function);
ret = device_property_read_string(&client->dev, propname, &function);
if (!ret) {
ret = adt7475_read(REG_CONFIG3);
if (ret < 0)
@ -1494,7 +1494,7 @@ static int load_config4(const struct i2c_client *client, const char *propname)
u8 config4;
int ret;
ret = of_property_read_string(client->dev.of_node, propname, &function);
ret = device_property_read_string(&client->dev, propname, &function);
if (!ret) {
ret = adt7475_read(REG_CONFIG4);
if (ret < 0)
@ -1556,8 +1556,8 @@ static int set_property_bit(const struct i2c_client *client, char *property,
u8 *config, u8 bit_index)
{
u32 prop_value = 0;
int ret = of_property_read_u32(client->dev.of_node, property,
&prop_value);
int ret = device_property_read_u32(&client->dev, property,
&prop_value);
if (!ret) {
if (prop_value)
@ -1821,7 +1821,7 @@ static struct i2c_driver adt7475_driver = {
.name = "adt7475",
.of_match_table = of_match_ptr(adt7475_of_match),
},
.probe_new = adt7475_probe,
.probe = adt7475_probe,
.id_table = adt7475_id,
.detect = adt7475_detect,
.address_list = normal_i2c,

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aht10.c - Linux hwmon driver for AHT10 Temperature and Humidity sensor
* aht10.c - Linux hwmon driver for AHT10/AHT20 Temperature and Humidity sensors
* Copyright (C) 2020 Johannes Cornelis Draaijer
*/
@ -10,9 +10,13 @@
#include <linux/i2c.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/crc8.h>
#define AHT10_MEAS_SIZE 6
#define AHT20_MEAS_SIZE 7
#define AHT20_CRC8_POLY 0x31
/*
* Poll intervals (in milliseconds)
*/
@ -44,9 +48,18 @@
#define AHT10_MAX_POLL_INTERVAL_LEN 30
enum aht10_variant { aht10, aht20 };
static const struct i2c_device_id aht10_id[] = {
{ "aht10", aht10 },
{ "aht20", aht20 },
{ },
};
MODULE_DEVICE_TABLE(i2c, aht10_id);
/**
* struct aht10_data - All the data required to operate an AHT10 chip
* @client: the i2c client associated with the AHT10
* struct aht10_data - All the data required to operate an AHT10/AHT20 chip
* @client: the i2c client associated with the AHT10/AHT20
* @lock: a mutex that is used to prevent parallel access to the
* i2c client
* @min_poll_interval: the minimum poll interval
@ -56,12 +69,14 @@
* the chip from warming up due to the heat it generates.
* If it's unwanted, it can be ignored setting it to
* it to 0. Default value is 2000 ms
* @previous_poll_time: the previous time that the AHT10
* @previous_poll_time: the previous time that the AHT10/AHT20
* was polled
* @temperature: the latest temperature value received from
* the AHT10
* the AHT10/AHT20
* @humidity: the latest humidity value received from the
* AHT10
* AHT10/AHT20
* @crc8: crc8 support flag
* @meas_size: measurements data size
*/
struct aht10_data {
@ -75,12 +90,14 @@ struct aht10_data {
ktime_t previous_poll_time;
int temperature;
int humidity;
bool crc8;
unsigned int meas_size;
};
/**
* aht10_init() - Initialize an AHT10 chip
* @data: the data associated with this AHT10 chip
* Return: 0 if succesfull, 1 if not
* aht10_init() - Initialize an AHT10/AHT20 chip
* @data: the data associated with this AHT10/AHT20 chip
* Return: 0 if successful, 1 if not
*/
static int aht10_init(struct aht10_data *data)
{
@ -121,54 +138,78 @@ static int aht10_polltime_expired(struct aht10_data *data)
return ktime_after(difference, data->min_poll_interval);
}
DECLARE_CRC8_TABLE(crc8_table);
/**
* aht10_read_values() - read and parse the raw data from the AHT10
* crc8_check() - check crc of the sensor's measurements
* @raw_data: data frame received from sensor(including crc as the last byte)
* @count: size of the data frame
* Return: 0 if successful, 1 if not
*/
static int crc8_check(u8 *raw_data, int count)
{
/*
* crc calculated on the whole frame(including crc byte) should yield
* zero in case of correctly received bytes
*/
return crc8(crc8_table, raw_data, count, CRC8_INIT_VALUE);
}
/**
* aht10_read_values() - read and parse the raw data from the AHT10/AHT20
* @data: the struct aht10_data to use for the lock
* Return: 0 if succesfull, 1 if not
* Return: 0 if successful, 1 if not
*/
static int aht10_read_values(struct aht10_data *data)
{
const u8 cmd_meas[] = {AHT10_CMD_MEAS, 0x33, 0x00};
u32 temp, hum;
int res;
u8 raw_data[AHT10_MEAS_SIZE];
u8 raw_data[AHT20_MEAS_SIZE];
struct i2c_client *client = data->client;
mutex_lock(&data->lock);
if (aht10_polltime_expired(data)) {
res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas));
if (res < 0) {
mutex_unlock(&data->lock);
return res;
}
usleep_range(AHT10_MEAS_DELAY,
AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA);
res = i2c_master_recv(client, raw_data, AHT10_MEAS_SIZE);
if (res != AHT10_MEAS_SIZE) {
mutex_unlock(&data->lock);
if (res >= 0)
return -ENODATA;
else
return res;
}
hum = ((u32)raw_data[1] << 12u) |
((u32)raw_data[2] << 4u) |
((raw_data[3] & 0xF0u) >> 4u);
temp = ((u32)(raw_data[3] & 0x0Fu) << 16u) |
((u32)raw_data[4] << 8u) |
raw_data[5];
temp = ((temp * 625) >> 15u) * 10;
hum = ((hum * 625) >> 16u) * 10;
data->temperature = (int)temp - 50000;
data->humidity = hum;
data->previous_poll_time = ktime_get_boottime();
if (!aht10_polltime_expired(data)) {
mutex_unlock(&data->lock);
return 0;
}
res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas));
if (res < 0) {
mutex_unlock(&data->lock);
return res;
}
usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA);
res = i2c_master_recv(client, raw_data, data->meas_size);
if (res != data->meas_size) {
mutex_unlock(&data->lock);
if (res >= 0)
return -ENODATA;
return res;
}
if (data->crc8 && crc8_check(raw_data, data->meas_size)) {
mutex_unlock(&data->lock);
return -EIO;
}
hum = ((u32)raw_data[1] << 12u) |
((u32)raw_data[2] << 4u) |
((raw_data[3] & 0xF0u) >> 4u);
temp = ((u32)(raw_data[3] & 0x0Fu) << 16u) |
((u32)raw_data[4] << 8u) |
raw_data[5];
temp = ((temp * 625) >> 15u) * 10;
hum = ((hum * 625) >> 16u) * 10;
data->temperature = (int)temp - 50000;
data->humidity = hum;
data->previous_poll_time = ktime_get_boottime();
mutex_unlock(&data->lock);
return 0;
}
@ -290,6 +331,8 @@ static const struct hwmon_chip_info aht10_chip_info = {
static int aht10_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_match_id(aht10_id, client);
enum aht10_variant variant = id->driver_data;
struct device *device = &client->dev;
struct device *hwmon_dev;
struct aht10_data *data;
@ -305,6 +348,17 @@ static int aht10_probe(struct i2c_client *client)
data->min_poll_interval = ms_to_ktime(AHT10_DEFAULT_MIN_POLL_INTERVAL);
data->client = client;
switch (variant) {
case aht20:
data->meas_size = AHT20_MEAS_SIZE;
data->crc8 = true;
crc8_populate_msb(crc8_table, AHT20_CRC8_POLY);
break;
default:
data->meas_size = AHT10_MEAS_SIZE;
break;
}
mutex_init(&data->lock);
res = aht10_init(data);
@ -324,23 +378,17 @@ static int aht10_probe(struct i2c_client *client)
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id aht10_id[] = {
{ "aht10", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, aht10_id);
static struct i2c_driver aht10_driver = {
.driver = {
.name = "aht10",
},
.probe_new = aht10_probe,
.probe = aht10_probe,
.id_table = aht10_id,
};
module_i2c_driver(aht10_driver);
MODULE_AUTHOR("Johannes Cornelis Draaijer <jcdra1@gmail.com>");
MODULE_DESCRIPTION("AHT10 Temperature and Humidity sensor driver");
MODULE_DESCRIPTION("AHT10/AHT20 Temperature and Humidity sensor driver");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL v2");

View file

@ -939,7 +939,7 @@ static struct i2c_driver amc6821_driver = {
.driver = {
.name = "amc6821",
},
.probe_new = amc6821_probe,
.probe = amc6821_probe,
.id_table = amc6821_id,
.detect = amc6821_detect,
.address_list = normal_i2c,

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
* Quadro, High Flow Next, Aquaero, Aquastream Ultimate)
* Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield)
*
* Aquacomputer devices send HID reports (with ID 0x01) every second to report
* sensor values, except for devices that communicate through the
@ -29,6 +29,7 @@
#define USB_PRODUCT_ID_FARBWERK360 0xf010
#define USB_PRODUCT_ID_OCTO 0xf011
#define USB_PRODUCT_ID_HIGHFLOWNEXT 0xf012
#define USB_PRODUCT_ID_LEAKSHIELD 0xf014
#define USB_PRODUCT_ID_AQUASTREAMXT 0xf0b6
#define USB_PRODUCT_ID_AQUASTREAMULT 0xf00b
#define USB_PRODUCT_ID_POWERADJUST3 0xf0bd
@ -36,7 +37,7 @@
enum kinds {
d5next, farbwerk, farbwerk360, octo, quadro,
highflownext, aquaero, poweradjust3, aquastreamult,
aquastreamxt
aquastreamxt, leakshield
};
static const char *const aqc_device_names[] = {
@ -46,6 +47,7 @@ static const char *const aqc_device_names[] = {
[octo] = "octo",
[quadro] = "quadro",
[highflownext] = "highflownext",
[leakshield] = "leakshield",
[aquastreamxt] = "aquastreamxt",
[aquaero] = "aquaero",
[aquastreamult] = "aquastreamultimate",
@ -93,7 +95,7 @@ static u8 aquaero_secondary_ctrl_report[] = {
#define AQC_FIRMWARE_VERSION 0xD
#define AQC_SENSOR_SIZE 0x02
#define AQC_TEMP_SENSOR_DISCONNECTED 0x7FFF
#define AQC_SENSOR_NA 0x7FFF
#define AQC_FAN_PERCENT_OFFSET 0x00
#define AQC_FAN_VOLTAGE_OFFSET 0x02
#define AQC_FAN_CURRENT_OFFSET 0x04
@ -236,6 +238,21 @@ 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 Leakshield */
#define LEAKSHIELD_NUM_SENSORS 2
/* Sensor report offsets for Leakshield */
#define LEAKSHIELD_PRESSURE_ADJUSTED 285
#define LEAKSHIELD_TEMPERATURE_1 265
#define LEAKSHIELD_TEMPERATURE_2 287
#define LEAKSHIELD_PRESSURE_MIN 291
#define LEAKSHIELD_PRESSURE_TARGET 293
#define LEAKSHIELD_PRESSURE_MAX 295
#define LEAKSHIELD_PUMP_RPM_IN 101
#define LEAKSHIELD_FLOW_IN 111
#define LEAKSHIELD_RESERVOIR_VOLUME 313
#define LEAKSHIELD_RESERVOIR_FILLED 311
/* Specs of the Aquastream XT pump */
#define AQUASTREAMXT_SERIAL_START 0x3a
#define AQUASTREAMXT_FIRMWARE_VERSION 0x32
@ -411,6 +428,20 @@ static const char *const label_highflownext_voltage[] = {
"+5V USB voltage"
};
/* Labels for Leakshield */
static const char *const label_leakshield_temp_sensors[] = {
"Temperature 1",
"Temperature 2"
};
static const char *const label_leakshield_fan_speed[] = {
"Pressure [ubar]",
"User-Provided Pump Speed",
"User-Provided Flow [dL/h]",
"Reservoir Volume [ml]",
"Reservoir Filled [ml]",
};
/* Labels for Aquastream XT */
static const char *const label_aquastreamxt_temp_sensors[] = {
"Fan IC temp",
@ -529,7 +560,10 @@ struct aqc_data {
/* Sensor values */
s32 temp_input[20]; /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */
u16 speed_input[8];
s32 speed_input[8];
u32 speed_input_min[1];
u32 speed_input_target[1];
u32 speed_input_max[1];
u32 power_input[8];
u16 voltage_input[8];
u16 current_input[8];
@ -747,6 +781,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
if (channel < 3)
return 0444;
break;
case leakshield:
/* Special case for Leakshield sensors */
if (channel < 5)
return 0444;
break;
case aquaero:
case quadro:
/* Special case to support flow sensors */
@ -764,6 +803,13 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
if (priv->kind == quadro && channel == priv->num_fans)
return 0644;
break;
case hwmon_fan_min:
case hwmon_fan_max:
case hwmon_fan_target:
/* Special case for Leakshield pressure sensor */
if (priv->kind == leakshield && channel == 0)
return 0444;
break;
default:
break;
}
@ -938,8 +984,20 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
case hwmon_fan:
switch (attr) {
case hwmon_fan_input:
if (priv->speed_input[channel] == -ENODATA)
return -ENODATA;
*val = priv->speed_input[channel];
break;
case hwmon_fan_min:
*val = priv->speed_input_min[channel];
break;
case hwmon_fan_max:
*val = priv->speed_input_max[channel];
break;
case hwmon_fan_target:
*val = priv->speed_input_target[channel];
break;
case hwmon_fan_pulses:
ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset,
val, AQC_BE16);
@ -1151,7 +1209,8 @@ static const struct hwmon_channel_info * const aqc_info[] = {
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
HWMON_F_TARGET,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL,
@ -1224,7 +1283,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
sensor_value = get_unaligned_be16(data +
priv->temp_sensor_start_offset +
i * AQC_SENSOR_SIZE);
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
if (sensor_value == AQC_SENSOR_NA)
priv->temp_input[i] = -ENODATA;
else
priv->temp_input[i] = sensor_value * 10;
@ -1235,7 +1294,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
sensor_value = get_unaligned_be16(data +
priv->virtual_temp_sensor_start_offset +
j * AQC_SENSOR_SIZE);
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
if (sensor_value == AQC_SENSOR_NA)
priv->temp_input[i] = -ENODATA;
else
priv->temp_input[i] = sensor_value * 10;
@ -1277,7 +1336,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
sensor_value = get_unaligned_be16(data +
priv->calc_virt_temp_sensor_start_offset +
j * AQC_SENSOR_SIZE);
if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
if (sensor_value == AQC_SENSOR_NA)
priv->temp_input[i] = -ENODATA;
else
priv->temp_input[i] = sensor_value * 10;
@ -1314,6 +1373,28 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY);
priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY);
break;
case leakshield:
priv->speed_input[0] =
((s16)get_unaligned_be16(data + LEAKSHIELD_PRESSURE_ADJUSTED)) * 100;
priv->speed_input_min[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MIN) * 100;
priv->speed_input_target[0] =
get_unaligned_be16(data + LEAKSHIELD_PRESSURE_TARGET) * 100;
priv->speed_input_max[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MAX) * 100;
priv->speed_input[1] = get_unaligned_be16(data + LEAKSHIELD_PUMP_RPM_IN);
if (priv->speed_input[1] == AQC_SENSOR_NA)
priv->speed_input[1] = -ENODATA;
priv->speed_input[2] = get_unaligned_be16(data + LEAKSHIELD_FLOW_IN);
if (priv->speed_input[2] == AQC_SENSOR_NA)
priv->speed_input[2] = -ENODATA;
priv->speed_input[3] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_VOLUME);
priv->speed_input[4] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_FILLED);
/* Second temp sensor is not positioned after the first one, read it here */
priv->temp_input[1] = get_unaligned_be16(data + LEAKSHIELD_TEMPERATURE_2) * 10;
break;
default:
break;
}
@ -1571,6 +1652,25 @@ 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_LEAKSHIELD:
/*
* Choose the right Leakshield device, because
* the other one acts as a keyboard
*/
if (hdev->type != 2) {
ret = -ENODEV;
goto fail_and_close;
}
priv->kind = leakshield;
priv->num_fans = 0;
priv->num_temp_sensors = LEAKSHIELD_NUM_SENSORS;
priv->temp_sensor_start_offset = LEAKSHIELD_TEMPERATURE_1;
priv->temp_label = label_leakshield_temp_sensors;
priv->speed_label = label_leakshield_fan_speed;
break;
case USB_PRODUCT_ID_AQUASTREAMXT:
priv->kind = aquastreamxt;
@ -1707,6 +1807,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_LEAKSHIELD) },
{ 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

@ -223,7 +223,7 @@ static struct i2c_driver asb100_driver = {
.driver = {
.name = "asb100",
},
.probe_new = asb100_probe,
.probe = asb100_probe,
.remove = asb100_remove,
.id_table = asb100_id,
.detect = asb100_detect,

View file

@ -1191,7 +1191,7 @@ static struct i2c_driver asc7621_driver = {
.driver = {
.name = "asc7621",
},
.probe_new = asc7621_probe,
.probe = asc7621_probe,
.remove = asc7621_remove,
.id_table = asc7621_id,
.detect = asc7621_detect,

View file

@ -101,6 +101,8 @@ enum ec_sensors {
ec_sensor_temp_chipset,
/* CPU temperature [℃] */
ec_sensor_temp_cpu,
/* CPU package temperature [℃] */
ec_sensor_temp_cpu_package,
/* motherboard temperature [℃] */
ec_sensor_temp_mb,
/* "T_Sensor" temperature sensor reading [℃] */
@ -139,6 +141,7 @@ enum ec_sensors {
#define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset)
#define SENSOR_TEMP_CPU BIT(ec_sensor_temp_cpu)
#define SENSOR_TEMP_CPU_PACKAGE BIT(ec_sensor_temp_cpu_package)
#define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb)
#define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor)
#define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm)
@ -161,6 +164,7 @@ enum board_family {
family_unknown,
family_amd_400_series,
family_amd_500_series,
family_amd_600_series,
family_intel_300_series,
family_intel_600_series
};
@ -233,6 +237,19 @@ static const struct ec_sensor_info sensors_family_amd_500[] = {
EC_SENSOR("Extra_3", hwmon_temp, 1, 0x01, 0x0c),
};
static const struct ec_sensor_info sensors_family_amd_600[] = {
[ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x30),
[ec_sensor_temp_cpu_package] = EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31),
[ec_sensor_temp_mb] =
EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x32),
[ec_sensor_temp_vrm] =
EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33),
[ec_sensor_temp_water_in] =
EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
[ec_sensor_temp_water_out] =
EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
};
static const struct ec_sensor_info sensors_family_intel_300[] = {
[ec_sensor_temp_chipset] =
EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
@ -319,6 +336,14 @@ static const struct ec_board_info board_info_pro_ws_x570_ace = {
.family = family_amd_500_series,
};
static const struct ec_board_info board_info_crosshair_x670e_hero = {
.sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
SENSOR_SET_TEMP_WATER,
.mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
.family = family_amd_600_series,
};
static const struct ec_board_info board_info_crosshair_viii_dark_hero = {
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
SENSOR_TEMP_T_SENSOR |
@ -463,6 +488,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_crosshair_viii_hero),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO (WI-FI)",
&board_info_crosshair_viii_hero),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO",
&board_info_crosshair_x670e_hero),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO",
&board_info_maximus_xi_hero),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)",
@ -946,6 +973,9 @@ static int asus_ec_probe(struct platform_device *pdev)
case family_amd_500_series:
ec_data->sensors_info = sensors_family_amd_500;
break;
case family_amd_600_series:
ec_data->sensors_info = sensors_family_amd_600;
break;
case family_intel_300_series:
ec_data->sensors_info = sensors_family_intel_300;
break;

View file

@ -288,7 +288,7 @@ static struct i2c_driver atxp1_driver = {
.driver = {
.name = "atxp1",
},
.probe_new = atxp1_probe,
.probe = atxp1_probe,
.id_table = atxp1_id,
};

View file

@ -32,23 +32,25 @@
* but it is better to not rely on this (it is also hard to parse)
* - the driver uses raw events to be accessible from userspace (though this is not really
* supported, it is just there for convenience, may be removed in the future)
* - a reply always start with the length and command in the same order the request used it
* - a reply always starts with the length and command in the same order the request used it
* - length of the reply data is specific to the command used
* - some of the commands work on a rail and can be switched to a specific rail (0 = 12v,
* 1 = 5v, 2 = 3.3v)
* - the format of the init command 0xFE is swapped length/command bytes
* - parameter bytes amount and values are specific to the command (rail setting is the only
* for now that uses non-zero values)
* - there are much more commands, especially for configuring the device, but they are not
* supported because a wrong command/length can lockup the micro-controller
* one for now that uses non-zero values)
* - the driver supports debugfs for values not fitting into the hwmon class
* - not every device class (HXi, RMi or AXi) supports all commands
* - it is a pure sensors reading driver (will not support configuring)
* - not every device class (HXi or RMi) supports all commands
* - if configured wrong the PSU resets or shuts down, often before actually hitting the
* reported critical temperature
* - new models like HX1500i Series 2023 have changes in the reported vendor and product
* strings, both are slightly longer now, report vendor and product in one string and are
* the same now
*/
#define DRIVER_NAME "corsair-psu"
#define REPLY_SIZE 16 /* max length of a reply to a single command */
#define REPLY_SIZE 24 /* max length of a reply to a single command */
#define CMD_BUFFER_SIZE 64
#define CMD_TIMEOUT_MS 250
#define SECONDS_PER_HOUR (60 * 60)
@ -58,7 +60,8 @@
#define OCP_MULTI_RAIL 0x02
#define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */
#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 /* the rest of the commands expect length 3 */
#define PSU_CMD_FAN_PWM 0x3B /* the rest of the commands expect length 3 */
#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40
#define PSU_CMD_RAIL_VOLTS_LCRIT 0x44
#define PSU_CMD_RAIL_AMPS_HCRIT 0x46
#define PSU_CMD_TEMP_HCRIT 0x4F
@ -76,6 +79,7 @@
#define PSU_CMD_UPTIME 0xD2
#define PSU_CMD_OCPMODE 0xD8
#define PSU_CMD_TOTAL_WATTS 0xEE
#define PSU_CMD_FAN_PWM_ENABLE 0xF0
#define PSU_CMD_INIT 0xFE
#define L_IN_VOLTS "v_in"
@ -145,6 +149,14 @@ static int corsairpsu_linear11_to_int(const u16 val, const int scale)
return (exp >= 0) ? (result << exp) : (result >> -exp);
}
/* the micro-controller uses percentage values to control pwm */
static int corsairpsu_dutycycle_to_pwm(const long dutycycle)
{
const int result = (256 << 16) / 100;
return (result * dutycycle) >> 16;
}
static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data)
{
unsigned long time;
@ -244,8 +256,8 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l
/*
* the biggest value here comes from the uptime command and to exceed MAXINT total uptime
* needs to be about 68 years, the rest are u16 values and the biggest value coming out of
* the LINEAR11 conversion are the watts values which are about 1200 for the strongest psu
* supported (HX1200i)
* the LINEAR11 conversion are the watts values which are about 1500 for the strongest psu
* supported (HX1500i)
*/
tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
switch (cmd) {
@ -264,6 +276,24 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l
case PSU_CMD_FAN:
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
break;
case PSU_CMD_FAN_PWM_ENABLE:
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
/*
* 0 = automatic mode, means the micro-controller controls the fan using a plan
* which can be modified, but changing this plan is not supported by this
* driver, the matching PWM mode is automatic fan speed control = PWM 2
* 1 = fixed mode, fan runs at a fixed speed represented by a percentage
* value 0-100, this matches the PWM manual fan speed control = PWM 1
* technically there is no PWM no fan speed control mode, it would be a combination
* of 1 at 100%
*/
if (*val == 0)
*val = 2;
break;
case PSU_CMD_FAN_PWM:
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1);
*val = corsairpsu_dutycycle_to_pwm(*val);
break;
case PSU_CMD_RAIL_WATTS:
case PSU_CMD_TOTAL_WATTS:
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000);
@ -349,6 +379,18 @@ static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *pri
}
}
static umode_t corsairpsu_hwmon_pwm_is_visible(const struct corsairpsu_data *priv, u32 attr,
int channel)
{
switch (attr) {
case hwmon_pwm_input:
case hwmon_pwm_enable:
return 0444;
default:
return 0;
}
}
static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr,
int channel)
{
@ -416,6 +458,8 @@ static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sens
return corsairpsu_hwmon_temp_is_visible(priv, attr, channel);
case hwmon_fan:
return corsairpsu_hwmon_fan_is_visible(priv, attr, channel);
case hwmon_pwm:
return corsairpsu_hwmon_pwm_is_visible(priv, attr, channel);
case hwmon_power:
return corsairpsu_hwmon_power_is_visible(priv, attr, channel);
case hwmon_in:
@ -447,6 +491,20 @@ static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, in
return err;
}
static int corsairpsu_hwmon_pwm_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val)
{
switch (attr) {
case hwmon_pwm_input:
return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM, 0, val);
case hwmon_pwm_enable:
return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM_ENABLE, 0, val);
default:
break;
}
return -EOPNOTSUPP;
}
static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel,
long *val)
{
@ -531,6 +589,8 @@ static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types
if (attr == hwmon_fan_input)
return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val);
return -EOPNOTSUPP;
case hwmon_pwm:
return corsairpsu_hwmon_pwm_read(priv, attr, channel, val);
case hwmon_power:
return corsairpsu_hwmon_power_read(priv, attr, channel, val);
case hwmon_in:
@ -571,7 +631,7 @@ static const struct hwmon_ops corsairpsu_hwmon_ops = {
.read_string = corsairpsu_hwmon_ops_read_string,
};
static const struct hwmon_channel_info * const corsairpsu_info[] = {
static const struct hwmon_channel_info *const corsairpsu_info[] = {
HWMON_CHANNEL_INFO(chip,
HWMON_C_REGISTER_TZ),
HWMON_CHANNEL_INFO(temp,
@ -579,6 +639,8 @@ static const struct hwmon_channel_info * const corsairpsu_info[] = {
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
HWMON_CHANNEL_INFO(power,
HWMON_P_INPUT | HWMON_P_LABEL,
HWMON_P_INPUT | HWMON_P_LABEL,
@ -813,15 +875,15 @@ static const struct hid_device_id corsairpsu_idtable[] = {
{ HID_USB_DEVICE(0x1b1c, 0x1c04) }, /* Corsair HX650i */
{ HID_USB_DEVICE(0x1b1c, 0x1c05) }, /* Corsair HX750i */
{ HID_USB_DEVICE(0x1b1c, 0x1c06) }, /* Corsair HX850i */
{ HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i revision 1 */
{ HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i Series 2022 */
{ HID_USB_DEVICE(0x1b1c, 0x1c08) }, /* Corsair HX1200i */
{ HID_USB_DEVICE(0x1b1c, 0x1c09) }, /* Corsair RM550i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0a) }, /* Corsair RM650i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0b) }, /* Corsair RM750i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */
{ HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i revision 2 */
{ HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i */
{ HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */
{ HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Series 2022 and 2023 */
{ },
};
MODULE_DEVICE_TABLE(hid, corsairpsu_idtable);

View file

@ -2528,7 +2528,7 @@ static struct i2c_driver dme1737_i2c_driver = {
.driver = {
.name = "dme1737",
},
.probe_new = dme1737_i2c_probe,
.probe = dme1737_i2c_probe,
.remove = dme1737_i2c_remove,
.id_table = dme1737_id,
.detect = dme1737_i2c_detect,

View file

@ -384,7 +384,7 @@ static struct i2c_driver ds1621_driver = {
.driver = {
.name = "ds1621",
},
.probe_new = ds1621_probe,
.probe = ds1621_probe,
.id_table = ds1621_id,
};

View file

@ -245,7 +245,7 @@ static struct i2c_driver ds620_driver = {
.driver = {
.name = "ds620",
},
.probe_new = ds620_probe,
.probe = ds620_probe,
.id_table = ds620_id,
};

View file

@ -454,7 +454,7 @@ static struct i2c_driver sensor_emc1403 = {
.name = "emc1403",
},
.detect = emc1403_detect,
.probe_new = emc1403_probe,
.probe = emc1403_probe,
.id_table = emc1403_idtable,
.address_list = emc1403_address_list,
};

View file

@ -653,7 +653,7 @@ static struct i2c_driver emc2103_driver = {
.driver = {
.name = "emc2103",
},
.probe_new = emc2103_probe,
.probe = emc2103_probe,
.id_table = emc2103_ids,
.detect = emc2103_detect,
.address_list = normal_i2c,

View file

@ -615,7 +615,7 @@ static struct i2c_driver emc2305_driver = {
.driver = {
.name = "emc2305",
},
.probe_new = emc2305_probe,
.probe = emc2305_probe,
.remove = emc2305_remove,
.id_table = emc2305_ids,
.address_list = emc2305_normal_i2c,

View file

@ -474,7 +474,7 @@ static struct i2c_driver emc6w201_driver = {
.driver = {
.name = "emc6w201",
},
.probe_new = emc6w201_probe,
.probe = emc6w201_probe,
.id_table = emc6w201_id,
.detect = emc6w201_detect,
.address_list = normal_i2c,

View file

@ -1096,8 +1096,11 @@ static ssize_t show_pwm(struct device *dev,
val = data->pwm[nr];
else {
/* RPM mode */
val = 255 * fan_from_reg(data->fan_target[nr])
/ fan_from_reg(data->fan_full_speed[nr]);
if (fan_from_reg(data->fan_full_speed[nr]))
val = 255 * fan_from_reg(data->fan_target[nr])
/ fan_from_reg(data->fan_full_speed[nr]);
else
val = 0;
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", val);

View file

@ -129,7 +129,7 @@ static struct i2c_driver f75375_driver = {
.driver = {
.name = "f75375",
},
.probe_new = f75375_probe,
.probe = f75375_probe,
.remove = f75375_remove,
.id_table = f75375_id,
.detect = f75375_detect,

View file

@ -241,7 +241,7 @@ static struct i2c_driver fschmd_driver = {
.driver = {
.name = "fschmd",
},
.probe_new = fschmd_probe,
.probe = fschmd_probe,
.remove = fschmd_remove,
.id_table = fschmd_id,
.detect = fschmd_detect,

View file

@ -678,7 +678,7 @@ static struct i2c_driver fts_driver = {
.name = "ftsteutates",
},
.id_table = fts_id,
.probe_new = fts_probe,
.probe = fts_probe,
.detect = fts_detect,
.address_list = normal_i2c,
};

View file

@ -206,7 +206,7 @@ static struct i2c_driver g760a_driver = {
.driver = {
.name = "g760a",
},
.probe_new = g760a_probe,
.probe = g760a_probe,
.id_table = g760a_id,
};

View file

@ -1084,7 +1084,7 @@ static struct i2c_driver g762_driver = {
.name = DRVNAME,
.of_match_table = of_match_ptr(g762_dt_match),
},
.probe_new = g762_probe,
.probe = g762_probe,
.id_table = g762_id,
};

View file

@ -652,7 +652,7 @@ static struct i2c_driver gl518_driver = {
.driver = {
.name = "gl518sm",
},
.probe_new = gl518_probe,
.probe = gl518_probe,
.id_table = gl518_id,
.detect = gl518_detect,
.address_list = normal_i2c,

View file

@ -895,7 +895,7 @@ static struct i2c_driver gl520_driver = {
.driver = {
.name = "gl520sm",
},
.probe_new = gl520_probe,
.probe = gl520_probe,
.id_table = gl520_id,
.detect = gl520_detect,
.address_list = normal_i2c,

View file

@ -82,8 +82,8 @@ static ssize_t pwm_auto_point_temp_store(struct device *dev,
if (kstrtol(buf, 10, &temp))
return -EINVAL;
temp = clamp_val(temp, 0, 10000);
temp = DIV_ROUND_CLOSEST(temp, 10);
temp = clamp_val(temp, 0, 100000);
temp = DIV_ROUND_CLOSEST(temp, 100);
regs[0] = temp & 0xff;
regs[1] = (temp >> 8) & 0xff;
@ -100,7 +100,7 @@ static ssize_t pwm_auto_point_pwm_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)) / 100);
return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)));
}
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0);

View file

@ -249,7 +249,7 @@ static struct i2c_driver hih6130_driver = {
.name = "hih6130",
.of_match_table = of_match_ptr(hih6130_of_match),
},
.probe_new = hih6130_probe,
.probe = hih6130_probe,
.id_table = hih6130_id,
};

File diff suppressed because it is too large Load diff

View file

@ -456,6 +456,7 @@ static const char * const hwmon_chip_attrs[] = {
[hwmon_chip_in_samples] = "in_samples",
[hwmon_chip_power_samples] = "power_samples",
[hwmon_chip_temp_samples] = "temp_samples",
[hwmon_chip_beep_enable] = "beep_enable",
};
static const char * const hwmon_temp_attr_templates[] = {
@ -486,6 +487,7 @@ static const char * const hwmon_temp_attr_templates[] = {
[hwmon_temp_reset_history] = "temp%d_reset_history",
[hwmon_temp_rated_min] = "temp%d_rated_min",
[hwmon_temp_rated_max] = "temp%d_rated_max",
[hwmon_temp_beep] = "temp%d_beep",
};
static const char * const hwmon_in_attr_templates[] = {
@ -507,6 +509,7 @@ static const char * const hwmon_in_attr_templates[] = {
[hwmon_in_crit_alarm] = "in%d_crit_alarm",
[hwmon_in_rated_min] = "in%d_rated_min",
[hwmon_in_rated_max] = "in%d_rated_max",
[hwmon_in_beep] = "in%d_beep",
};
static const char * const hwmon_curr_attr_templates[] = {
@ -528,6 +531,7 @@ static const char * const hwmon_curr_attr_templates[] = {
[hwmon_curr_crit_alarm] = "curr%d_crit_alarm",
[hwmon_curr_rated_min] = "curr%d_rated_min",
[hwmon_curr_rated_max] = "curr%d_rated_max",
[hwmon_curr_beep] = "curr%d_beep",
};
static const char * const hwmon_power_attr_templates[] = {
@ -597,6 +601,7 @@ static const char * const hwmon_fan_attr_templates[] = {
[hwmon_fan_min_alarm] = "fan%d_min_alarm",
[hwmon_fan_max_alarm] = "fan%d_max_alarm",
[hwmon_fan_fault] = "fan%d_fault",
[hwmon_fan_beep] = "fan%d_beep",
};
static const char * const hwmon_pwm_attr_templates[] = {
@ -1029,7 +1034,7 @@ EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups);
* @name: hwmon name attribute
* @drvdata: driver data to attach to created device
* @chip: pointer to hwmon chip information
* @groups: pointer to list of driver specific attribute groups
* @extra_groups: pointer to list of driver specific attribute groups
*
* Returns the pointer to the new device. The new device is automatically
* unregistered with the parent device.
@ -1038,7 +1043,7 @@ struct device *
devm_hwmon_device_register_with_info(struct device *dev, const char *name,
void *drvdata,
const struct hwmon_chip_info *chip,
const struct attribute_group **groups)
const struct attribute_group **extra_groups)
{
struct device **ptr, *hwdev;
@ -1050,7 +1055,7 @@ devm_hwmon_device_register_with_info(struct device *dev, const char *name,
return ERR_PTR(-ENOMEM);
hwdev = hwmon_device_register_with_info(dev, name, drvdata, chip,
groups);
extra_groups);
if (IS_ERR(hwdev))
goto error;

View file

@ -594,7 +594,7 @@ static struct i2c_driver ina209_driver = {
.name = "ina209",
.of_match_table = of_match_ptr(ina209_of_match),
},
.probe_new = ina209_probe,
.probe = ina209_probe,
.remove = ina209_remove,
.id_table = ina209_id,
};

View file

@ -633,7 +633,7 @@ static struct i2c_driver ina238_driver = {
.name = "ina238",
.of_match_table = of_match_ptr(ina238_of_match),
},
.probe_new = ina238_probe,
.probe = ina238_probe,
.id_table = ina238_id,
};

View file

@ -721,7 +721,7 @@ static struct i2c_driver ina2xx_driver = {
.name = "ina2xx",
.of_match_table = of_match_ptr(ina2xx_of_match),
},
.probe_new = ina2xx_probe,
.probe = ina2xx_probe,
.id_table = ina2xx_id,
};

View file

@ -1010,7 +1010,7 @@ static const struct i2c_device_id ina3221_ids[] = {
MODULE_DEVICE_TABLE(i2c, ina3221_ids);
static struct i2c_driver ina3221_i2c_driver = {
.probe_new = ina3221_probe,
.probe = ina3221_probe,
.remove = ina3221_remove,
.driver = {
.name = INA3221_DRIVER_NAME,

View file

@ -317,31 +317,37 @@ struct it87_devices {
* chips to avoid the problem.
*/
#define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */
#define FEAT_FOUR_FANS BIT(20) /* Supports four fans */
#define FEAT_FOUR_PWM BIT(21) /* Supports four fan controls */
#define FEAT_FOUR_TEMP BIT(22)
#define FEAT_FANCTL_ONOFF BIT(23) /* chip has FAN_CTL ON/OFF */
static const struct it87_devices it87_devices[] = {
[it87] = {
.name = "it87",
.model = "IT87F",
.features = FEAT_OLD_AUTOPWM, /* may need to overwrite */
.features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF,
/* may need to overwrite */
},
[it8712] = {
.name = "it8712",
.model = "IT8712F",
.features = FEAT_OLD_AUTOPWM | FEAT_VID,
/* may need to overwrite */
.features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF,
/* may need to overwrite */
},
[it8716] = {
.name = "it8716",
.model = "IT8716F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2,
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
},
[it8718] = {
.name = "it8718",
.model = "IT8718F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.old_peci_mask = 0x4,
},
[it8720] = {
@ -349,7 +355,7 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8720F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.old_peci_mask = 0x4,
},
[it8721] = {
@ -358,7 +364,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@ -367,7 +373,8 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8728F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
},
[it8732] = {
@ -375,7 +382,8 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8732F",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
| FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@ -384,7 +392,7 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8771E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
/* PECI: guesswork */
/* 12mV ADC (OHM) */
/* 16 bit fans (OHM) */
@ -396,7 +404,7 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8772E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
/* PECI (coreboot) */
/* 12mV ADC (HWSensors4, OHM) */
/* 16 bit fans (HWSensors4, OHM) */
@ -407,21 +415,24 @@ static const struct it87_devices it87_devices[] = {
.name = "it8781",
.model = "IT8781F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
.old_peci_mask = 0x4,
},
[it8782] = {
.name = "it8782",
.model = "IT8782F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
.old_peci_mask = 0x4,
},
[it8783] = {
.name = "it8783",
.model = "IT8783E/F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
.old_peci_mask = 0x4,
},
[it8786] = {
@ -429,7 +440,7 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8786E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
},
[it8790] = {
@ -437,7 +448,7 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8790E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_CONF_NOEXIT,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_CONF_NOEXIT,
.peci_mask = 0x07,
},
[it8792] = {
@ -445,7 +456,8 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8792E/IT8795E",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
| FEAT_CONF_NOEXIT,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@ -463,7 +475,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V,
| FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
},
[it8622] = {
@ -472,7 +484,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
| FEAT_AVCC3 | FEAT_VIN3_5V,
| FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP,
.peci_mask = 0x07,
.smbus_bitmap = BIT(1) | BIT(2),
},
@ -482,7 +494,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V,
| FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
},
[it87952] = {
@ -490,7 +502,8 @@ static const struct it87_devices it87_devices[] = {
.model = "IT87952E",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
| FEAT_CONF_NOEXIT,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@ -508,21 +521,29 @@ static const struct it87_devices it87_devices[] = {
(((data)->features & FEAT_TEMP_OLD_PECI) && \
((data)->old_peci_mask & BIT(nr)))
#define has_fan16_config(data) ((data)->features & FEAT_FAN16_CONFIG)
#define has_four_fans(data) ((data)->features & (FEAT_FOUR_FANS | \
FEAT_FIVE_FANS | \
FEAT_SIX_FANS))
#define has_five_fans(data) ((data)->features & (FEAT_FIVE_FANS | \
FEAT_SIX_FANS))
#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS)
#define has_vid(data) ((data)->features & FEAT_VID)
#define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL)
#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS)
#define has_avcc3(data) ((data)->features & FEAT_AVCC3)
#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM \
| FEAT_SIX_PWM))
#define has_four_pwm(data) ((data)->features & (FEAT_FOUR_PWM | \
FEAT_FIVE_PWM | \
FEAT_SIX_PWM))
#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM | \
FEAT_SIX_PWM))
#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM)
#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)
#define has_four_temp(data) ((data)->features & FEAT_FOUR_TEMP)
#define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP)
#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V)
#define has_conf_noexit(data) ((data)->features & FEAT_CONF_NOEXIT)
#define has_scaling(data) ((data)->features & (FEAT_12MV_ADC | \
FEAT_10_9MV_ADC))
#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF)
struct it87_sio_data {
int sioaddr;
@ -1229,11 +1250,12 @@ static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
static int pwm_mode(const struct it87_data *data, int nr)
{
if (data->type != it8603 && nr < 3 && !(data->fan_main_ctrl & BIT(nr)))
return 0; /* Full speed */
if (has_fanctl_onoff(data) && nr < 3 &&
!(data->fan_main_ctrl & BIT(nr)))
return 0; /* Full speed */
if (data->pwm_ctrl[nr] & 0x80)
return 2; /* Automatic mode */
if ((data->type == it8603 || nr >= 3) &&
return 2; /* Automatic mode */
if ((!has_fanctl_onoff(data) || nr >= 3) &&
data->pwm_duty[nr] == pwm_to_reg(data, 0xff))
return 0; /* Full speed */
@ -1470,7 +1492,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
return err;
if (val == 0) {
if (nr < 3 && data->type != it8603) {
if (nr < 3 && has_fanctl_onoff(data)) {
int tmp;
/* make sure the fan is on when in on/off mode */
tmp = it87_read_value(data, IT87_REG_FAN_CTL);
@ -1510,7 +1532,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
data->pwm_ctrl[nr] = ctrl;
it87_write_value(data, IT87_REG_PWM[nr], ctrl);
if (data->type != it8603 && nr < 3) {
if (has_fanctl_onoff(data) && nr < 3) {
/* set SmartGuardian mode */
data->fan_main_ctrl |= BIT(nr);
it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
@ -2730,8 +2752,10 @@ static int __init it87_find(int sioaddr, unsigned short *address,
else
sio_data->skip_in |= BIT(9);
if (!has_five_pwm(config))
if (!has_four_pwm(config))
sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);
else if (!has_five_pwm(config))
sio_data->skip_pwm |= BIT(4) | BIT(5);
else if (!has_six_pwm(config))
sio_data->skip_pwm |= BIT(5);
@ -2922,6 +2946,34 @@ static int __init it87_find(int sioaddr, unsigned short *address,
if (!(reg & BIT(0)))
sio_data->skip_in |= BIT(9);
sio_data->beep_pin = superio_inb(sioaddr,
IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8732) {
int reg;
superio_select(sioaddr, GPIO);
/* Check for pwm2, fan2 */
reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
if (reg & BIT(1))
sio_data->skip_pwm |= BIT(1);
if (reg & BIT(2))
sio_data->skip_fan |= BIT(1);
/* Check for pwm3, fan3, fan4 */
reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
if (reg & BIT(6))
sio_data->skip_pwm |= BIT(2);
if (reg & BIT(7))
sio_data->skip_fan |= BIT(2);
if (reg & BIT(5))
sio_data->skip_fan |= BIT(3);
/* Check if AVCC is on VIN3 */
reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
if (reg & BIT(0))
sio_data->internal |= BIT(0);
sio_data->beep_pin = superio_inb(sioaddr,
IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else {
@ -3169,16 +3221,14 @@ static void it87_init_device(struct platform_device *pdev)
it87_check_tachometers_16bit_mode(pdev);
/* Check for additional fans */
if (has_five_fans(data)) {
tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
if (tmp & BIT(4))
data->has_fan |= BIT(3); /* fan4 enabled */
if (tmp & BIT(5))
data->has_fan |= BIT(4); /* fan5 enabled */
if (has_six_fans(data) && (tmp & BIT(2)))
data->has_fan |= BIT(5); /* fan6 enabled */
}
if (has_four_fans(data) && (tmp & BIT(4)))
data->has_fan |= BIT(3); /* fan4 enabled */
if (has_five_fans(data) && (tmp & BIT(5)))
data->has_fan |= BIT(4); /* fan5 enabled */
if (has_six_fans(data) && (tmp & BIT(2)))
data->has_fan |= BIT(5); /* fan6 enabled */
/* Fan input pins may be used for alternative functions */
data->has_fan &= ~sio_data->skip_fan;
@ -3356,7 +3406,9 @@ static int it87_probe(struct platform_device *pdev)
data->need_in7_reroute = sio_data->need_in7_reroute;
data->has_in = 0x3ff & ~sio_data->skip_in;
if (has_six_temp(data)) {
if (has_four_temp(data)) {
data->has_temp |= BIT(3);
} else if (has_six_temp(data)) {
u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE);
/* Check for additional temperature sensors */

View file

@ -629,7 +629,7 @@ static struct i2c_driver jc42_driver = {
.pm = JC42_DEV_PM_OPS,
.of_match_table = of_match_ptr(jc42_of_ids),
},
.probe_new = jc42_probe,
.probe = jc42_probe,
.remove = jc42_remove,
.id_table = jc42_id,
.detect = jc42_detect,

View file

@ -511,7 +511,7 @@ static struct i2c_driver pem_driver = {
.driver = {
.name = "lineage_pem",
},
.probe_new = pem_probe,
.probe = pem_probe,
.id_table = pem_id,
};

View file

@ -1164,7 +1164,7 @@ static struct i2c_driver lm63_driver = {
.name = "lm63",
.of_match_table = of_match_ptr(lm63_of_match),
},
.probe_new = lm63_probe,
.probe = lm63_probe,
.id_table = lm63_id,
.detect = lm63_detect,
.address_list = normal_i2c,

View file

@ -277,7 +277,7 @@ static struct i2c_driver lm73_driver = {
.name = "lm73",
.of_match_table = lm73_of_match,
},
.probe_new = lm73_probe,
.probe = lm73_probe,
.id_table = lm73_ids,
.detect = lm73_detect,
.address_list = normal_i2c,

View file

@ -548,7 +548,7 @@ static const struct regmap_config lm75_regmap_config = {
.writeable_reg = lm75_is_writeable_reg,
.volatile_reg = lm75_is_volatile_reg,
.val_format_endian = REGMAP_ENDIAN_BIG,
.cache_type = REGCACHE_RBTREE,
.cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@ -945,7 +945,7 @@ static struct i2c_driver lm75_driver = {
.of_match_table = of_match_ptr(lm75_of_match),
.pm = LM75_DEV_PM_OPS,
},
.probe_new = lm75_probe,
.probe = lm75_probe,
.id_table = lm75_ids,
.detect = lm75_detect,
.address_list = normal_i2c,

View file

@ -348,7 +348,7 @@ static struct i2c_driver lm77_driver = {
.driver = {
.name = "lm77",
},
.probe_new = lm77_probe,
.probe = lm77_probe,
.id_table = lm77_id,
.detect = lm77_detect,
.address_list = normal_i2c,

View file

@ -662,7 +662,7 @@ static struct i2c_driver lm78_driver = {
.driver = {
.name = "lm78",
},
.probe_new = lm78_i2c_probe,
.probe = lm78_i2c_probe,
.id_table = lm78_i2c_id,
.detect = lm78_i2c_detect,
.address_list = normal_i2c,

View file

@ -633,7 +633,7 @@ static struct i2c_driver lm80_driver = {
.driver = {
.name = "lm80",
},
.probe_new = lm80_probe,
.probe = lm80_probe,
.id_table = lm80_id,
.detect = lm80_detect,
.address_list = normal_i2c,

View file

@ -454,7 +454,7 @@ static struct i2c_driver lm83_driver = {
.driver = {
.name = "lm83",
},
.probe_new = lm83_probe,
.probe = lm83_probe,
.id_table = lm83_id,
.detect = lm83_detect,
.address_list = normal_i2c,

View file

@ -1698,7 +1698,7 @@ static struct i2c_driver lm85_driver = {
.name = "lm85",
.of_match_table = of_match_ptr(lm85_of_match),
},
.probe_new = lm85_probe,
.probe = lm85_probe,
.id_table = lm85_id,
.detect = lm85_detect,
.address_list = normal_i2c,

View file

@ -994,7 +994,7 @@ static struct i2c_driver lm87_driver = {
.name = "lm87",
.of_match_table = lm87_of_match,
},
.probe_new = lm87_probe,
.probe = lm87_probe,
.id_table = lm87_id,
.detect = lm87_detect,
.address_list = normal_i2c,

View file

@ -2972,7 +2972,7 @@ static struct i2c_driver lm90_driver = {
.of_match_table = of_match_ptr(lm90_of_match),
.pm = pm_sleep_ptr(&lm90_pm_ops),
},
.probe_new = lm90_probe,
.probe = lm90_probe,
.alert = lm90_alert,
.id_table = lm90_id,
.detect = lm90_detect,

View file

@ -330,7 +330,7 @@ static struct i2c_driver lm92_driver = {
.driver = {
.name = "lm92",
},
.probe_new = lm92_probe,
.probe = lm92_probe,
.id_table = lm92_id,
.detect = lm92_detect,
.address_list = normal_i2c,

View file

@ -2635,7 +2635,7 @@ static struct i2c_driver lm93_driver = {
.driver = {
.name = "lm93",
},
.probe_new = lm93_probe,
.probe = lm93_probe,
.id_table = lm93_id,
.detect = lm93_detect,
.address_list = normal_i2c,

View file

@ -720,7 +720,7 @@ static struct i2c_driver lm95234_driver = {
.driver = {
.name = DRVNAME,
},
.probe_new = lm95234_probe,
.probe = lm95234_probe,
.id_table = lm95234_id,
.detect = lm95234_detect,
.address_list = normal_i2c,

View file

@ -468,7 +468,7 @@ static struct i2c_driver lm95241_driver = {
.driver = {
.name = DEVNAME,
},
.probe_new = lm95241_probe,
.probe = lm95241_probe,
.id_table = lm95241_id,
.detect = lm95241_detect,
.address_list = normal_i2c,

View file

@ -518,7 +518,7 @@ static const struct regmap_config lm95245_regmap_config = {
.val_bits = 8,
.writeable_reg = lm95245_is_writeable_reg,
.volatile_reg = lm95245_is_volatile_reg,
.cache_type = REGCACHE_RBTREE,
.cache_type = REGCACHE_MAPLE,
.use_single_read = true,
.use_single_write = true,
};
@ -597,7 +597,7 @@ static struct i2c_driver lm95245_driver = {
.name = "lm95245",
.of_match_table = of_match_ptr(lm95245_of_match),
},
.probe_new = lm95245_probe,
.probe = lm95245_probe,
.id_table = lm95245_id,
.detect = lm95245_detect,
.address_list = normal_i2c,

View file

@ -519,7 +519,7 @@ static struct i2c_driver ltc2945_driver = {
.name = "ltc2945",
.of_match_table = of_match_ptr(ltc2945_of_match),
},
.probe_new = ltc2945_probe,
.probe = ltc2945_probe,
.id_table = ltc2945_id,
};

View file

@ -38,7 +38,7 @@ static struct i2c_driver ltc2947_driver = {
.of_match_table = ltc2947_of_match,
.pm = pm_sleep_ptr(&ltc2947_pm_ops),
},
.probe_new = ltc2947_probe,
.probe = ltc2947_probe,
.id_table = ltc2947_id,
};
module_i2c_driver(ltc2947_driver);

View file

@ -268,7 +268,7 @@ static struct i2c_driver ltc2990_i2c_driver = {
.driver = {
.name = "ltc2990",
},
.probe_new = ltc2990_i2c_probe,
.probe = ltc2990_i2c_probe,
.id_table = ltc2990_i2c_id,
};

View file

@ -928,7 +928,7 @@ static struct i2c_driver ltc2992_i2c_driver = {
.name = "ltc2992",
.of_match_table = ltc2992_of_match,
},
.probe_new = ltc2992_i2c_probe,
.probe = ltc2992_i2c_probe,
.id_table = ltc2992_i2c_id,
};

View file

@ -205,7 +205,7 @@ static struct i2c_driver ltc4151_driver = {
.name = "ltc4151",
.of_match_table = of_match_ptr(ltc4151_match),
},
.probe_new = ltc4151_probe,
.probe = ltc4151_probe,
.id_table = ltc4151_id,
};

View file

@ -255,7 +255,7 @@ static struct i2c_driver ltc4215_driver = {
.driver = {
.name = "ltc4215",
},
.probe_new = ltc4215_probe,
.probe = ltc4215_probe,
.id_table = ltc4215_id,
};

View file

@ -210,7 +210,7 @@ static struct i2c_driver ltc4222_driver = {
.driver = {
.name = "ltc4222",
},
.probe_new = ltc4222_probe,
.probe = ltc4222_probe,
.id_table = ltc4222_id,
};

View file

@ -479,7 +479,7 @@ static struct i2c_driver ltc4245_driver = {
.driver = {
.name = "ltc4245",
},
.probe_new = ltc4245_probe,
.probe = ltc4245_probe,
.id_table = ltc4245_id,
};

View file

@ -173,7 +173,7 @@ static struct i2c_driver ltc4260_driver = {
.driver = {
.name = "ltc4260",
},
.probe_new = ltc4260_probe,
.probe = ltc4260_probe,
.id_table = ltc4260_id,
};

View file

@ -233,7 +233,7 @@ static struct i2c_driver ltc4261_driver = {
.driver = {
.name = "ltc4261",
},
.probe_new = ltc4261_probe,
.probe = ltc4261_probe,
.id_table = ltc4261_id,
};

View file

@ -339,7 +339,7 @@ static struct i2c_driver max127_driver = {
.driver = {
.name = "max127",
},
.probe_new = max127_probe,
.probe = max127_probe,
.id_table = max127_id,
};

View file

@ -600,7 +600,7 @@ static struct i2c_driver max16065_driver = {
.driver = {
.name = "max16065",
},
.probe_new = max16065_probe,
.probe = max16065_probe,
.id_table = max16065_id,
};

View file

@ -305,7 +305,7 @@ static struct i2c_driver max1619_driver = {
.name = "max1619",
.of_match_table = of_match_ptr(max1619_of_match),
},
.probe_new = max1619_probe,
.probe = max1619_probe,
.id_table = max1619_id,
.detect = max1619_detect,
.address_list = normal_i2c,

View file

@ -435,7 +435,7 @@ static struct i2c_driver max1668_driver = {
.driver = {
.name = "max1668",
},
.probe_new = max1668_probe,
.probe = max1668_probe,
.id_table = max1668_id,
.detect = max1668_detect,
.address_list = max1668_addr_list,

View file

@ -427,7 +427,7 @@ static struct i2c_driver max31730_driver = {
.of_match_table = of_match_ptr(max31730_of_match),
.pm = pm_sleep_ptr(&max31730_pm_ops),
},
.probe_new = max31730_probe,
.probe = max31730_probe,
.id_table = max31730_ids,
.detect = max31730_detect,
.address_list = normal_i2c,

View file

@ -584,7 +584,7 @@ static struct i2c_driver max31760_driver = {
.of_match_table = max31760_of_match,
.pm = pm_ptr(&max31760_pm_ops)
},
.probe_new = max31760_probe,
.probe = max31760_probe,
.id_table = max31760_id
};
module_i2c_driver(max31760_driver);

View file

@ -544,7 +544,7 @@ MODULE_DEVICE_TABLE(i2c, max31790_id);
static struct i2c_driver max31790_driver = {
.class = I2C_CLASS_HWMON,
.probe_new = max31790_probe,
.probe = max31790_probe,
.driver = {
.name = "max31790",
},

466
drivers/hwmon/max31827.c Normal file
View file

@ -0,0 +1,466 @@
// SPDX-License-Identifier: GPL-2.0
/*
* max31827.c - Support for Maxim Low-Power Switch
*
* Copyright (c) 2023 Daniel Matyas <daniel.matyas@analog.com>
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#define MAX31827_T_REG 0x0
#define MAX31827_CONFIGURATION_REG 0x2
#define MAX31827_TH_REG 0x4
#define MAX31827_TL_REG 0x6
#define MAX31827_TH_HYST_REG 0x8
#define MAX31827_TL_HYST_REG 0xA
#define MAX31827_CONFIGURATION_1SHOT_MASK BIT(0)
#define MAX31827_CONFIGURATION_CNV_RATE_MASK GENMASK(3, 1)
#define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK BIT(14)
#define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK BIT(15)
#define MAX31827_12_BIT_CNV_TIME 141
#define MAX31827_CNV_1_DIV_64_HZ 0x1
#define MAX31827_CNV_1_DIV_32_HZ 0x2
#define MAX31827_CNV_1_DIV_16_HZ 0x3
#define MAX31827_CNV_1_DIV_4_HZ 0x4
#define MAX31827_CNV_1_HZ 0x5
#define MAX31827_CNV_4_HZ 0x6
#define MAX31827_CNV_8_HZ 0x7
#define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16)
#define MAX31827_M_DGR_TO_16_BIT(x) (((x) << 4) / 1000)
#define MAX31827_DEVICE_ENABLE(x) ((x) ? 0xA : 0x0)
struct max31827_state {
/*
* Prevent simultaneous access to the i2c client.
*/
struct mutex lock;
struct regmap *regmap;
bool enable;
};
static const struct regmap_config max31827_regmap = {
.reg_bits = 8,
.val_bits = 16,
.max_register = 0xA,
};
static int write_alarm_val(struct max31827_state *st, unsigned int reg,
long val)
{
unsigned int cfg;
unsigned int tmp;
int ret;
val = MAX31827_M_DGR_TO_16_BIT(val);
/*
* Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold
* register values are changed over I2C, the part must be in shutdown
* mode.
*
* Mutex is used to ensure, that some other process doesn't change the
* configuration register.
*/
mutex_lock(&st->lock);
if (!st->enable) {
ret = regmap_write(st->regmap, reg, val);
goto unlock;
}
ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg);
if (ret)
goto unlock;
tmp = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK |
MAX31827_CONFIGURATION_CNV_RATE_MASK);
ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, tmp);
if (ret)
goto unlock;
ret = regmap_write(st->regmap, reg, val);
if (ret)
goto unlock;
ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
unlock:
mutex_unlock(&st->lock);
return ret;
}
static umode_t max31827_is_visible(const void *state,
enum hwmon_sensor_types type, u32 attr,
int channel)
{
if (type == hwmon_temp) {
switch (attr) {
case hwmon_temp_enable:
case hwmon_temp_max:
case hwmon_temp_min:
case hwmon_temp_max_hyst:
case hwmon_temp_min_hyst:
return 0644;
case hwmon_temp_input:
case hwmon_temp_min_alarm:
case hwmon_temp_max_alarm:
return 0444;
default:
return 0;
}
} else if (type == hwmon_chip) {
if (attr == hwmon_chip_update_interval)
return 0644;
}
return 0;
}
static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct max31827_state *st = dev_get_drvdata(dev);
unsigned int uval;
int ret = 0;
switch (type) {
case hwmon_temp:
switch (attr) {
case hwmon_temp_enable:
ret = regmap_read(st->regmap,
MAX31827_CONFIGURATION_REG, &uval);
if (ret)
break;
uval = FIELD_GET(MAX31827_CONFIGURATION_1SHOT_MASK |
MAX31827_CONFIGURATION_CNV_RATE_MASK,
uval);
*val = !!uval;
break;
case hwmon_temp_input:
mutex_lock(&st->lock);
if (!st->enable) {
/*
* This operation requires mutex protection,
* because the chip configuration should not
* be changed during the conversion process.
*/
ret = regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_1SHOT_MASK,
1);
if (ret) {
mutex_unlock(&st->lock);
return ret;
}
msleep(MAX31827_12_BIT_CNV_TIME);
}
ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
mutex_unlock(&st->lock);
if (ret)
break;
*val = MAX31827_16_BIT_TO_M_DGR(uval);
break;
case hwmon_temp_max:
ret = regmap_read(st->regmap, MAX31827_TH_REG, &uval);
if (ret)
break;
*val = MAX31827_16_BIT_TO_M_DGR(uval);
break;
case hwmon_temp_max_hyst:
ret = regmap_read(st->regmap, MAX31827_TH_HYST_REG,
&uval);
if (ret)
break;
*val = MAX31827_16_BIT_TO_M_DGR(uval);
break;
case hwmon_temp_max_alarm:
ret = regmap_read(st->regmap,
MAX31827_CONFIGURATION_REG, &uval);
if (ret)
break;
*val = FIELD_GET(MAX31827_CONFIGURATION_O_TEMP_STAT_MASK,
uval);
break;
case hwmon_temp_min:
ret = regmap_read(st->regmap, MAX31827_TL_REG, &uval);
if (ret)
break;
*val = MAX31827_16_BIT_TO_M_DGR(uval);
break;
case hwmon_temp_min_hyst:
ret = regmap_read(st->regmap, MAX31827_TL_HYST_REG,
&uval);
if (ret)
break;
*val = MAX31827_16_BIT_TO_M_DGR(uval);
break;
case hwmon_temp_min_alarm:
ret = regmap_read(st->regmap,
MAX31827_CONFIGURATION_REG, &uval);
if (ret)
break;
*val = FIELD_GET(MAX31827_CONFIGURATION_U_TEMP_STAT_MASK,
uval);
break;
default:
ret = -EOPNOTSUPP;
break;
}
break;
case hwmon_chip:
if (attr == hwmon_chip_update_interval) {
ret = regmap_read(st->regmap,
MAX31827_CONFIGURATION_REG, &uval);
if (ret)
break;
uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK,
uval);
switch (uval) {
case MAX31827_CNV_1_DIV_64_HZ:
*val = 64000;
break;
case MAX31827_CNV_1_DIV_32_HZ:
*val = 32000;
break;
case MAX31827_CNV_1_DIV_16_HZ:
*val = 16000;
break;
case MAX31827_CNV_1_DIV_4_HZ:
*val = 4000;
break;
case MAX31827_CNV_1_HZ:
*val = 1000;
break;
case MAX31827_CNV_4_HZ:
*val = 250;
break;
case MAX31827_CNV_8_HZ:
*val = 125;
break;
default:
*val = 0;
break;
}
}
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
struct max31827_state *st = dev_get_drvdata(dev);
int ret;
switch (type) {
case hwmon_temp:
switch (attr) {
case hwmon_temp_enable:
if (val >> 1)
return -EINVAL;
mutex_lock(&st->lock);
/**
* The chip should not be enabled while a conversion is
* performed. Neither should the chip be enabled when
* the alarm values are changed.
*/
st->enable = val;
ret = regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_1SHOT_MASK |
MAX31827_CONFIGURATION_CNV_RATE_MASK,
MAX31827_DEVICE_ENABLE(val));
mutex_unlock(&st->lock);
return ret;
case hwmon_temp_max:
return write_alarm_val(st, MAX31827_TH_REG, val);
case hwmon_temp_max_hyst:
return write_alarm_val(st, MAX31827_TH_HYST_REG, val);
case hwmon_temp_min:
return write_alarm_val(st, MAX31827_TL_REG, val);
case hwmon_temp_min_hyst:
return write_alarm_val(st, MAX31827_TL_HYST_REG, val);
default:
return -EOPNOTSUPP;
}
case hwmon_chip:
if (attr == hwmon_chip_update_interval) {
if (!st->enable)
return -EINVAL;
switch (val) {
case 125:
val = MAX31827_CNV_8_HZ;
break;
case 250:
val = MAX31827_CNV_4_HZ;
break;
case 1000:
val = MAX31827_CNV_1_HZ;
break;
case 4000:
val = MAX31827_CNV_1_DIV_4_HZ;
break;
case 16000:
val = MAX31827_CNV_1_DIV_16_HZ;
break;
case 32000:
val = MAX31827_CNV_1_DIV_32_HZ;
break;
case 64000:
val = MAX31827_CNV_1_DIV_64_HZ;
break;
default:
return -EINVAL;
}
val = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
val);
return regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_CNV_RATE_MASK,
val);
}
break;
default:
return -EOPNOTSUPP;
}
return -EOPNOTSUPP;
}
static int max31827_init_client(struct max31827_state *st)
{
st->enable = true;
return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_1SHOT_MASK |
MAX31827_CONFIGURATION_CNV_RATE_MASK,
MAX31827_DEVICE_ENABLE(1));
}
static const struct hwmon_channel_info *max31827_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN |
HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX | HWMON_T_MAX_HYST |
HWMON_T_MAX_ALARM),
HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
NULL,
};
static const struct hwmon_ops max31827_hwmon_ops = {
.is_visible = max31827_is_visible,
.read = max31827_read,
.write = max31827_write,
};
static const struct hwmon_chip_info max31827_chip_info = {
.ops = &max31827_hwmon_ops,
.info = max31827_info,
};
static int max31827_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct max31827_state *st;
int err;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EOPNOTSUPP;
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
mutex_init(&st->lock);
st->regmap = devm_regmap_init_i2c(client, &max31827_regmap);
if (IS_ERR(st->regmap))
return dev_err_probe(dev, PTR_ERR(st->regmap),
"Failed to allocate regmap.\n");
err = max31827_init_client(st);
if (err)
return err;
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st,
&max31827_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max31827_i2c_ids[] = {
{ "max31827", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids);
static const struct of_device_id max31827_of_match[] = {
{ .compatible = "adi,max31827" },
{ }
};
MODULE_DEVICE_TABLE(of, max31827_of_match);
static struct i2c_driver max31827_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max31827",
.of_match_table = max31827_of_match,
},
.probe = max31827_probe,
.id_table = max31827_i2c_ids,
};
module_i2c_driver(max31827_driver);
MODULE_AUTHOR("Daniel Matyas <daniel.matyas@analog.com>");
MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver");
MODULE_LICENSE("GPL");

View file

@ -503,7 +503,7 @@ static struct i2c_driver max6620_driver = {
.driver = {
.name = "max6620",
},
.probe_new = max6620_probe,
.probe = max6620_probe,
.id_table = max6620_id,
};

View file

@ -554,7 +554,7 @@ static struct i2c_driver max6621_driver = {
.name = MAX6621_DRV_NAME,
.of_match_table = of_match_ptr(max6621_of_match),
},
.probe_new = max6621_probe,
.probe = max6621_probe,
.id_table = max6621_id,
};

View file

@ -624,7 +624,7 @@ static struct i2c_driver max6639_driver = {
.name = "max6639",
.pm = pm_sleep_ptr(&max6639_pm_ops),
},
.probe_new = max6639_probe,
.probe = max6639_probe,
.id_table = max6639_id,
.detect = max6639_detect,
.address_list = normal_i2c,

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