mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-20 12:54:36 +08:00
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:
commit
acd1d46b0d
54
Documentation/devicetree/bindings/hwmon/adi,max31827.yaml
Normal file
54
Documentation/devicetree/bindings/hwmon/adi,max31827.yaml
Normal 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 = <®_vdd>;
|
||||
};
|
||||
};
|
||||
...
|
@ -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.
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
---------------
|
||||
|
140
Documentation/hwmon/hp-wmi-sensors.rst
Normal file
140
Documentation/hwmon/hp-wmi-sensors.rst
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
90
Documentation/hwmon/max31827.rst
Normal file
90
Documentation/hwmon/max31827.rst
Normal 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.
|
@ -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)
|
||||
|
@ -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
|
||||
=================== ============================================================
|
||||
|
16
MAINTAINERS
16
MAINTAINERS
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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) },
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -288,7 +288,7 @@ static struct i2c_driver atxp1_driver = {
|
||||
.driver = {
|
||||
.name = "atxp1",
|
||||
},
|
||||
.probe_new = atxp1_probe,
|
||||
.probe = atxp1_probe,
|
||||
.id_table = atxp1_id,
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -384,7 +384,7 @@ static struct i2c_driver ds1621_driver = {
|
||||
.driver = {
|
||||
.name = "ds1621",
|
||||
},
|
||||
.probe_new = ds1621_probe,
|
||||
.probe = ds1621_probe,
|
||||
.id_table = ds1621_id,
|
||||
};
|
||||
|
||||
|
@ -245,7 +245,7 @@ static struct i2c_driver ds620_driver = {
|
||||
.driver = {
|
||||
.name = "ds620",
|
||||
},
|
||||
.probe_new = ds620_probe,
|
||||
.probe = ds620_probe,
|
||||
.id_table = ds620_id,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -206,7 +206,7 @@ static struct i2c_driver g760a_driver = {
|
||||
.driver = {
|
||||
.name = "g760a",
|
||||
},
|
||||
.probe_new = g760a_probe,
|
||||
.probe = g760a_probe,
|
||||
.id_table = g760a_id,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
2004
drivers/hwmon/hp-wmi-sensors.c
Normal file
2004
drivers/hwmon/hp-wmi-sensors.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -38,7 +38,7 @@ static struct i2c_driver ltc2947_driver = {
|
||||
.of_match_table = ltc2947_of_match,
|
||||
.pm = pm_sleep_ptr(<c2947_pm_ops),
|
||||
},
|
||||
.probe_new = ltc2947_probe,
|
||||
.probe = ltc2947_probe,
|
||||
.id_table = ltc2947_id,
|
||||
};
|
||||
module_i2c_driver(ltc2947_driver);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -255,7 +255,7 @@ static struct i2c_driver ltc4215_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4215",
|
||||
},
|
||||
.probe_new = ltc4215_probe,
|
||||
.probe = ltc4215_probe,
|
||||
.id_table = ltc4215_id,
|
||||
};
|
||||
|
||||
|
@ -210,7 +210,7 @@ static struct i2c_driver ltc4222_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4222",
|
||||
},
|
||||
.probe_new = ltc4222_probe,
|
||||
.probe = ltc4222_probe,
|
||||
.id_table = ltc4222_id,
|
||||
};
|
||||
|
||||
|
@ -479,7 +479,7 @@ static struct i2c_driver ltc4245_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4245",
|
||||
},
|
||||
.probe_new = ltc4245_probe,
|
||||
.probe = ltc4245_probe,
|
||||
.id_table = ltc4245_id,
|
||||
};
|
||||
|
||||
|
@ -173,7 +173,7 @@ static struct i2c_driver ltc4260_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4260",
|
||||
},
|
||||
.probe_new = ltc4260_probe,
|
||||
.probe = ltc4260_probe,
|
||||
.id_table = ltc4260_id,
|
||||
};
|
||||
|
||||
|
@ -233,7 +233,7 @@ static struct i2c_driver ltc4261_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4261",
|
||||
},
|
||||
.probe_new = ltc4261_probe,
|
||||
.probe = ltc4261_probe,
|
||||
.id_table = ltc4261_id,
|
||||
};
|
||||
|
||||
|
@ -339,7 +339,7 @@ static struct i2c_driver max127_driver = {
|
||||
.driver = {
|
||||
.name = "max127",
|
||||
},
|
||||
.probe_new = max127_probe,
|
||||
.probe = max127_probe,
|
||||
.id_table = max127_id,
|
||||
};
|
||||
|
||||
|
@ -600,7 +600,7 @@ static struct i2c_driver max16065_driver = {
|
||||
.driver = {
|
||||
.name = "max16065",
|
||||
},
|
||||
.probe_new = max16065_probe,
|
||||
.probe = max16065_probe,
|
||||
.id_table = max16065_id,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
466
drivers/hwmon/max31827.c
Normal 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");
|
@ -503,7 +503,7 @@ static struct i2c_driver max6620_driver = {
|
||||
.driver = {
|
||||
.name = "max6620",
|
||||
},
|
||||
.probe_new = max6620_probe,
|
||||
.probe = max6620_probe,
|
||||
.id_table = max6620_id,
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user