Merge tag 'hwmon-for-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 29 Jun 2023 17:01:25 +0000 (10:01 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 29 Jun 2023 17:01:25 +0000 (10:01 -0700)
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
  ...

193 files changed:
Documentation/devicetree/bindings/hwmon/adi,max31827.yaml [new file with mode: 0644]
Documentation/hwmon/aht10.rst
Documentation/hwmon/aquacomputer_d5next.rst
Documentation/hwmon/asus_ec_sensors.rst
Documentation/hwmon/corsair-psu.rst
Documentation/hwmon/hp-wmi-sensors.rst [new file with mode: 0644]
Documentation/hwmon/hwmon-kernel-api.rst
Documentation/hwmon/index.rst
Documentation/hwmon/max31827.rst [new file with mode: 0644]
Documentation/hwmon/oxp-sensors.rst
Documentation/hwmon/sht3x.rst
MAINTAINERS
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ad7414.c
drivers/hwmon/ad7418.c
drivers/hwmon/adc128d818.c
drivers/hwmon/adm1021.c
drivers/hwmon/adm1025.c
drivers/hwmon/adm1026.c
drivers/hwmon/adm1029.c
drivers/hwmon/adm1031.c
drivers/hwmon/adm1177.c
drivers/hwmon/adm9240.c
drivers/hwmon/ads7828.c
drivers/hwmon/adt7410.c
drivers/hwmon/adt7411.c
drivers/hwmon/adt7462.c
drivers/hwmon/adt7470.c
drivers/hwmon/adt7475.c
drivers/hwmon/aht10.c
drivers/hwmon/amc6821.c
drivers/hwmon/aquacomputer_d5next.c
drivers/hwmon/asb100.c
drivers/hwmon/asc7621.c
drivers/hwmon/asus-ec-sensors.c
drivers/hwmon/atxp1.c
drivers/hwmon/corsair-psu.c
drivers/hwmon/dme1737.c
drivers/hwmon/ds1621.c
drivers/hwmon/ds620.c
drivers/hwmon/emc1403.c
drivers/hwmon/emc2103.c
drivers/hwmon/emc2305.c
drivers/hwmon/emc6w201.c
drivers/hwmon/f71882fg.c
drivers/hwmon/f75375s.c
drivers/hwmon/fschmd.c
drivers/hwmon/ftsteutates.c
drivers/hwmon/g760a.c
drivers/hwmon/g762.c
drivers/hwmon/gl518sm.c
drivers/hwmon/gl520sm.c
drivers/hwmon/gsc-hwmon.c
drivers/hwmon/hih6130.c
drivers/hwmon/hp-wmi-sensors.c [new file with mode: 0644]
drivers/hwmon/hwmon.c
drivers/hwmon/ina209.c
drivers/hwmon/ina238.c
drivers/hwmon/ina2xx.c
drivers/hwmon/ina3221.c
drivers/hwmon/it87.c
drivers/hwmon/jc42.c
drivers/hwmon/lineage-pem.c
drivers/hwmon/lm63.c
drivers/hwmon/lm73.c
drivers/hwmon/lm75.c
drivers/hwmon/lm77.c
drivers/hwmon/lm78.c
drivers/hwmon/lm80.c
drivers/hwmon/lm83.c
drivers/hwmon/lm85.c
drivers/hwmon/lm87.c
drivers/hwmon/lm90.c
drivers/hwmon/lm92.c
drivers/hwmon/lm93.c
drivers/hwmon/lm95234.c
drivers/hwmon/lm95241.c
drivers/hwmon/lm95245.c
drivers/hwmon/ltc2945.c
drivers/hwmon/ltc2947-i2c.c
drivers/hwmon/ltc2990.c
drivers/hwmon/ltc2992.c
drivers/hwmon/ltc4151.c
drivers/hwmon/ltc4215.c
drivers/hwmon/ltc4222.c
drivers/hwmon/ltc4245.c
drivers/hwmon/ltc4260.c
drivers/hwmon/ltc4261.c
drivers/hwmon/max127.c
drivers/hwmon/max16065.c
drivers/hwmon/max1619.c
drivers/hwmon/max1668.c
drivers/hwmon/max31730.c
drivers/hwmon/max31760.c
drivers/hwmon/max31790.c
drivers/hwmon/max31827.c [new file with mode: 0644]
drivers/hwmon/max6620.c
drivers/hwmon/max6621.c
drivers/hwmon/max6639.c
drivers/hwmon/max6642.c
drivers/hwmon/max6650.c
drivers/hwmon/max6697.c
drivers/hwmon/mc34vr500.c
drivers/hwmon/mcp3021.c
drivers/hwmon/nct6683.c
drivers/hwmon/nct6775-core.c
drivers/hwmon/nct6775-i2c.c
drivers/hwmon/nct6775-platform.c
drivers/hwmon/nct6775.h
drivers/hwmon/nct7802.c
drivers/hwmon/nct7904.c
drivers/hwmon/occ/p8_i2c.c
drivers/hwmon/oxp-sensors.c
drivers/hwmon/pcf8591.c
drivers/hwmon/pmbus/acbel-fsg032.c
drivers/hwmon/pmbus/adm1266.c
drivers/hwmon/pmbus/adm1275.c
drivers/hwmon/pmbus/bel-pfe.c
drivers/hwmon/pmbus/bpa-rs600.c
drivers/hwmon/pmbus/delta-ahe50dc-fan.c
drivers/hwmon/pmbus/dps920ab.c
drivers/hwmon/pmbus/fsp-3y.c
drivers/hwmon/pmbus/ibm-cffps.c
drivers/hwmon/pmbus/inspur-ipsps.c
drivers/hwmon/pmbus/ir35221.c
drivers/hwmon/pmbus/ir36021.c
drivers/hwmon/pmbus/ir38064.c
drivers/hwmon/pmbus/irps5401.c
drivers/hwmon/pmbus/isl68137.c
drivers/hwmon/pmbus/lm25066.c
drivers/hwmon/pmbus/lt7182s.c
drivers/hwmon/pmbus/ltc2978.c
drivers/hwmon/pmbus/ltc3815.c
drivers/hwmon/pmbus/max15301.c
drivers/hwmon/pmbus/max16064.c
drivers/hwmon/pmbus/max16601.c
drivers/hwmon/pmbus/max20730.c
drivers/hwmon/pmbus/max20751.c
drivers/hwmon/pmbus/max31785.c
drivers/hwmon/pmbus/max34440.c
drivers/hwmon/pmbus/max8688.c
drivers/hwmon/pmbus/mp2888.c
drivers/hwmon/pmbus/mp2975.c
drivers/hwmon/pmbus/mp5023.c
drivers/hwmon/pmbus/mpq7932.c
drivers/hwmon/pmbus/pim4328.c
drivers/hwmon/pmbus/pli1209bc.c
drivers/hwmon/pmbus/pm6764tr.c
drivers/hwmon/pmbus/pmbus.c
drivers/hwmon/pmbus/pxe1610.c
drivers/hwmon/pmbus/q54sj108a2.c
drivers/hwmon/pmbus/stpddc60.c
drivers/hwmon/pmbus/tda38640.c
drivers/hwmon/pmbus/tps40422.c
drivers/hwmon/pmbus/tps53679.c
drivers/hwmon/pmbus/tps546d24.c
drivers/hwmon/pmbus/ucd9000.c
drivers/hwmon/pmbus/ucd9200.c
drivers/hwmon/pmbus/xdpe12284.c
drivers/hwmon/pmbus/xdpe152c4.c
drivers/hwmon/pmbus/zl6100.c
drivers/hwmon/powr1220.c
drivers/hwmon/sbrmi.c
drivers/hwmon/sbtsi_temp.c
drivers/hwmon/sht21.c
drivers/hwmon/sht3x.c
drivers/hwmon/sht4x.c
drivers/hwmon/shtc1.c
drivers/hwmon/smm665.c
drivers/hwmon/smsc47m192.c
drivers/hwmon/stts751.c
drivers/hwmon/tc654.c
drivers/hwmon/tc74.c
drivers/hwmon/thmc50.c
drivers/hwmon/tmp102.c
drivers/hwmon/tmp103.c
drivers/hwmon/tmp108.c
drivers/hwmon/tmp401.c
drivers/hwmon/tmp421.c
drivers/hwmon/tmp464.c
drivers/hwmon/tmp513.c
drivers/hwmon/tps23861.c
drivers/hwmon/w83773g.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/hwmon/w83795.c
drivers/hwmon/w83l785ts.c
drivers/hwmon/w83l786ng.c
include/linux/hwmon.h
include/linux/platform_data/sht3x.h [deleted file]

diff --git a/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml
new file mode 100644 (file)
index 0000000..2dc8b07
--- /dev/null
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/adi,max31827.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch
+
+maintainers:
+  - Daniel Matyas <daniel.matyas@analog.com>
+
+description: |
+  Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch with
+  I2C Interface
+  https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf
+
+properties:
+  compatible:
+    oneOf:
+      - const: adi,max31827
+      - items:
+          - enum:
+              - adi,max31828
+              - adi,max31829
+          - const: adi,max31827
+
+  reg:
+    maxItems: 1
+
+  vref-supply:
+    description:
+      Must have values in the interval (1.6V; 3.6V) in order for the device to
+      function correctly.
+
+required:
+  - compatible
+  - reg
+  - vref-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        temperature-sensor@42 {
+            compatible = "adi,max31827";
+            reg = <0x42>;
+            vref-supply = <&reg_vdd>;
+        };
+    };
+...
index 4e198c5..213644b 100644 (file)
@@ -5,32 +5,42 @@ Kernel driver aht10
 
 Supported chips:
 
-  * Aosong AHT10
+  * Aosong AHT10/AHT20
 
     Prefix: 'aht10'
 
     Addresses scanned: None
 
-    Datasheet:
+    Datasheet(AHT10):
 
       Chinese: http://www.aosong.com/userfiles/files/media/AHT10%E4%BA%A7%E5%93%81%E6%89%8B%E5%86%8C%20A3%2020201210.pdf
       English: https://server4.eca.ir/eshop/AHT10/Aosong_AHT10_en_draft_0c.pdf
 
+    Datasheet(AHT20):
+
+      English: http://www.aosong.com/userfiles/files/media/Data%20Sheet%20AHT20.pdf
+
 Author: Johannes Cornelis Draaijer <jcdra1@gmail.com>
 
 
 Description
 -----------
 
-The AHT10 is a Temperature and Humidity sensor
+The AHT10/AHT20 is a Temperature and Humidity sensor
 
 The address of this i2c device may only be 0x38
 
+Special Features
+----------------
+
+AHT20 has additional CRC8 support which is sent as the last byte of the sensor
+values.
+
 Usage Notes
 -----------
 
-This driver does not probe for AHT10 devices, as there is no reliable
-way to determine if an i2c chip is or isn't an AHT10. The device has
+This driver does not probe for AHT10/ATH20 devices, as there is no reliable
+way to determine if an i2c chip is or isn't an AHT10/AHT20. The device has
 to be instantiated explicitly with the address 0x38. See
 Documentation/i2c/instantiating-devices.rst for details.
 
index 14b3785..94dc2d9 100644 (file)
@@ -12,6 +12,7 @@ Supported devices:
 * Aquacomputer Octo fan controller
 * Aquacomputer Quadro fan controller
 * Aquacomputer High Flow Next sensor
+* Aquacomputer Leakshield leak prevention system
 * Aquacomputer Aquastream XT watercooling pump
 * Aquacomputer Aquastream Ultimate watercooling pump
 * Aquacomputer Poweradjust 3 fan controller
@@ -57,6 +58,11 @@ The High Flow Next exposes +5V voltages, water quality, conductivity and flow re
 A temperature sensor can be connected to it, in which case it provides its reading
 and an estimation of the dissipated/absorbed power in the liquid cooling loop.
 
+The Leakshield exposes two temperature sensors and coolant pressure (current, min, max and
+target readings). It also exposes the estimated reservoir volume and how much of it is
+filled with coolant. Pump RPM and flow can be set to enhance on-device calculations,
+but this is not yet implemented here.
+
 The Aquastream XT pump exposes temperature readings for the coolant, external sensor
 and fan IC. It also exposes pump and fan speeds (in RPM), voltages, as well as pump
 current.
@@ -83,6 +89,9 @@ Sysfs entries
 temp[1-20]_input Physical/virtual temperature sensors (in millidegrees Celsius)
 temp[1-8]_offset Temperature sensor correction offset (in millidegrees Celsius)
 fan[1-8]_input   Pump/fan speed (in RPM) / Flow speed (in dL/h)
+fan1_min         Minimal fan speed (in RPM)
+fan1_max         Maximal fan speed (in RPM)
+fan1_target      Target fan speed (in RPM)
 fan5_pulses      Quadro flow sensor pulses
 power[1-8]_input Pump/fan power (in micro Watts)
 in[0-7]_input    Pump/fan voltage (in milli Volts)
index c92c1d3..7e3cd5b 100644 (file)
@@ -14,6 +14,7 @@ Supported boards:
  * ROG CROSSHAIR VIII FORMULA
  * ROG CROSSHAIR VIII HERO
  * ROG CROSSHAIR VIII IMPACT
+ * ROG CROSSHAIR X670E HERO
  * ROG MAXIMUS XI HERO
  * ROG MAXIMUS XI HERO (WI-FI)
  * ROG STRIX B550-E GAMING
index c389bd2..16db34d 100644 (file)
@@ -15,11 +15,11 @@ Supported devices:
 
   Corsair HX850i
 
-  Corsair HX1000i (revision 1 and 2)
+  Corsair HX1000i (Series 2022 and 2023)
 
   Corsair HX1200i
 
-  Corsair HX1500i
+  Corsair HX1500i (Series 2022 and 2023)
 
   Corsair RM550i
 
@@ -69,6 +69,8 @@ power1_input          Total power usage
 power2_input           Power usage of the 12v psu rail
 power3_input           Power usage of the 5v psu rail
 power4_input           Power usage of the 3.3v psu rail
+pwm1                   PWM value, read only
+pwm1_enable            PWM mode, read only
 temp1_input            Temperature of the psu vrm component
 temp1_crit             Temperature max cirtical value of the psu vrm component
 temp2_input            Temperature of the psu case
@@ -78,11 +80,14 @@ temp2_crit          Temperature max critical value of psu case
 Usage Notes
 -----------
 
-It is an USB HID device, so it is auto-detected and supports hot-swapping.
+It is an USB HID device, so it is auto-detected, supports hot-swapping and
+several devices at once.
 
 Flickering values in the rail voltage levels can be an indicator for a failing
-PSU. The driver also provides some additional useful values via debugfs, which
-do not fit into the hwmon class.
+PSU. Accordingly to the default automatic fan speed plan the fan starts at about
+30% of the wattage rating. If this does not happen, a fan failure is likely. The
+driver also provides some additional useful values via debugfs, which do not fit
+into the hwmon class.
 
 Debugfs entries
 ---------------
diff --git a/Documentation/hwmon/hp-wmi-sensors.rst b/Documentation/hwmon/hp-wmi-sensors.rst
new file mode 100644 (file)
index 0000000..a6bca9a
--- /dev/null
@@ -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
index c2d1e02..6cacf7d 100644 (file)
@@ -66,7 +66,7 @@ hwmon_device_register_with_info.
 
 devm_hwmon_device_unregister does not normally have to be called. It is only
 needed for error handling, and only needed if the driver probe fails after
-the call to hwmon_device_register_with_info and if the automatic (device
+the call to devm_hwmon_device_register_with_info and if the automatic (device
 managed) removal would be too late.
 
 All supported hwmon device registration functions only accept valid device
index fa1208c..042e1cf 100644 (file)
@@ -9,7 +9,6 @@ Hardware Monitoring
 
    hwmon-kernel-api
    pmbus-core
-   inspur-ipsps1
    submitting-patches
    sysfs-interface
    userspace-tools
@@ -78,6 +77,7 @@ Hardware Monitoring Kernel Drivers
    gl518sm
    gxp-fan-ctrl
    hih6130
+   hp-wmi-sensors
    ibmaem
    ibm-cffps
    ibmpowernv
@@ -85,6 +85,7 @@ Hardware Monitoring Kernel Drivers
    ina2xx
    ina238
    ina3221
+   inspur-ipsps1
    intel-m10-bmc-hwmon
    ir35221
    ir38064
@@ -140,6 +141,7 @@ Hardware Monitoring Kernel Drivers
    max31760
    max31785
    max31790
+   max31827
    max34440
    max6620
    max6639
diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst
new file mode 100644 (file)
index 0000000..b0971d0
--- /dev/null
@@ -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.
index 566a8d5..3adeb74 100644 (file)
@@ -19,18 +19,32 @@ out the EC registers and values to write to since the EC layout and model is
 different. Aya Neo devices preceding the AIR may not be supportable as the EC
 model is different and do not appear to have manual control capabilities.
 
+Some models have a toggle for changing the behaviour of the "Turbo/Silent"
+button of the device. It will change the key event that it triggers with
+a flip of the `tt_toggle` attribute. See below for boards that support this
+function.
+
 Supported devices
 -----------------
 
 Currently the driver supports the following handhelds:
 
  - AOK ZOE A1
+ - AOK ZOE A1 PRO
+ - Aya Neo 2
  - Aya Neo AIR
  - Aya Neo AIR Pro
+ - Aya Neo Geek
  - OneXPlayer AMD
  - OneXPlayer mini AMD
  - OneXPlayer mini AMD PRO
 
+"Turbo/Silent" button behaviour toggle is only supported on:
+ - AOK ZOE A1
+ - AOK ZOE A1 PRO
+ - OneXPlayer mini AMD (only with updated alpha BIOS)
+ - OneXPlayer mini AMD PRO
+
 Sysfs entries
 -------------
 
@@ -47,3 +61,10 @@ pwm1
   Read Write. Read this attribute to see current duty cycle in the range [0-255].
   When pwm1_enable is set to "1" (manual) write any value in the range [0-255]
   to set fan speed.
+
+tt_toggle
+  Read Write. Read this attribute to check the status of the turbo/silent
+  button behaviour function. Write "1" to activate the switch and "0" to
+  deactivate it. The specific keycodes and behaviour is specific to the device
+  both with this function on and off. This attribute is attached to the platform
+  driver and not to the hwmon driver (/sys/devices/platform/oxp-platform/tt_toggle)
index 95a850d..87864ff 100644 (file)
@@ -28,15 +28,8 @@ The device communicates with the I2C protocol. Sensors can have the I2C
 addresses 0x44 or 0x45, depending on the wiring. See
 Documentation/i2c/instantiating-devices.rst for methods to instantiate the device.
 
-There are two options configurable by means of sht3x_platform_data:
-
-1. blocking (pull the I2C clock line down while performing the measurement) or
-   non-blocking mode. Blocking mode will guarantee the fastest result but
-   the I2C bus will be busy during that time. By default, non-blocking mode
-   is used. Make sure clock-stretching works properly on your device if you
-   want to use blocking mode.
-2. high or low accuracy. High accuracy is used by default and using it is
-   strongly recommended.
+Even if sht3x sensor supports clock-strech(blocking mode) and non-strench
+(non-blocking mode) in single-shot mode, this driver only supports the latter.
 
 The sht3x sensor supports a single shot mode as well as 5 periodic measure
 modes, which can be controlled with the update_interval sysfs interface.
@@ -85,4 +78,11 @@ heater_enable:      heater enable, heating element removes excess humidity from
 update_interval:    update interval, 0 for single shot, interval in msec
                    for periodic measurement. If the interval is not supported
                    by the sensor, the next faster interval is chosen
+repeatability:      write or read repeatability, higher repeatability means
+                    longer measurement duration, lower noise level and
+                    larger energy consumption:
+
+                        - 0: low repeatability
+                        - 1: medium repeatability
+                        - 2: high repeatability
 =================== ============================================================
index acbe540..98ee410 100644 (file)
@@ -9473,6 +9473,13 @@ L:       platform-driver-x86@vger.kernel.org
 S:     Orphan
 F:     drivers/platform/x86/hp/tc1100-wmi.c
 
+HP WMI HARDWARE MONITOR DRIVER
+M:     James Seo <james@equiv.tech>
+L:     linux-hwmon@vger.kernel.org
+S:     Maintained
+F:     Documentation/hwmon/hp-wmi-sensors.rst
+F:     drivers/hwmon/hp-wmi-sensors.c
+
 HPET:  High Precision Event Timers driver
 M:     Clemens Ladisch <clemens@ladisch.de>
 S:     Maintained
@@ -12671,6 +12678,15 @@ F:     Documentation/userspace-api/media/drivers/max2175.rst
 F:     drivers/media/i2c/max2175*
 F:     include/uapi/linux/max2175.h
 
+MAX31827 TEMPERATURE SWITCH DRIVER
+M:     Daniel Matyas <daniel.matyas@analog.com>
+L:     linux-hwmon@vger.kernel.org
+S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/devicetree/bindings/hwmon/adi,max31827.yaml
+F:     Documentation/hwmon/max31827.rst
+F:     drivers/hwmon/max31827.c
+
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
 L:     linux-hwmon@vger.kernel.org
 S:     Orphan
index fc64020..307477b 100644 (file)
@@ -255,10 +255,11 @@ config SENSORS_ADT7475
          will be called adt7475.
 
 config SENSORS_AHT10
-       tristate "Aosong AHT10"
+       tristate "Aosong AHT10, AHT20"
        depends on I2C
+       select CRC8
        help
-         If you say yes here, you get support for the Aosong AHT10
+         If you say yes here, you get support for the Aosong AHT10 and AHT20
          temperature and humidity sensors
 
          This driver can also be built as a module. If so, the module
@@ -1097,6 +1098,17 @@ config SENSORS_MAX31760
          This driver can also be built as a module. If so, the module
          will be called max31760.
 
+config MAX31827
+       tristate "MAX31827 low-power temperature switch and similar devices"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for MAX31827, MAX31828 and
+         MAX31829 low-power temperature switches and sensors connected with I2C.
+
+         This driver can also be built as a module.  If so, the module
+         will be called max31827.
+
 config SENSORS_MAX6620
        tristate "Maxim MAX6620 fan controller"
        depends on I2C
@@ -2409,6 +2421,18 @@ config SENSORS_ASUS_EC
          This driver can also be built as a module. If so, the module
          will be called asus_ec_sensors.
 
+config SENSORS_HP_WMI
+       tristate "HP WMI Sensors"
+       depends on ACPI_WMI
+       help
+         If you say yes here you get support for the ACPI hardware monitoring
+         interface found in HP (and some HP Compaq) business-class computers.
+         Available sensors vary between systems. Temperature and fan speed
+         sensors are the most common.
+
+         This driver can also be built as a module. If so, the module
+         will be called hp_wmi_sensors.
+
 endif # ACPI
 
 endif # HWMON
index cd8c568..3f4b0fd 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o
 obj-$(CONFIG_SENSORS_ATK0110)  += asus_atk0110.o
 obj-$(CONFIG_SENSORS_ASUS_EC)  += asus-ec-sensors.o
 obj-$(CONFIG_SENSORS_ASUS_WMI) += asus_wmi_sensors.o
+obj-$(CONFIG_SENSORS_HP_WMI)   += hp-wmi-sensors.o
 
 # Native drivers
 # asb100, then w83781d go first, as they can override other drivers' addresses.
@@ -149,6 +150,7 @@ obj-$(CONFIG_SENSORS_MAX6642)       += max6642.o
 obj-$(CONFIG_SENSORS_MAX6650)  += max6650.o
 obj-$(CONFIG_SENSORS_MAX6697)  += max6697.o
 obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
+obj-$(CONFIG_MAX31827) += max31827.o
 obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
 obj-$(CONFIG_SENSORS_MC34VR500)        += mc34vr500.o
 obj-$(CONFIG_SENSORS_MCP3021)  += mcp3021.o
@@ -224,4 +226,3 @@ obj-$(CONFIG_SENSORS_PECI)  += peci/
 obj-$(CONFIG_PMBUS)            += pmbus/
 
 ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
-
index 0afb89c..7f1bef5 100644 (file)
@@ -221,7 +221,7 @@ static struct i2c_driver ad7414_driver = {
                .name   = "ad7414",
                .of_match_table = of_match_ptr(ad7414_of_match),
        },
-       .probe_new = ad7414_probe,
+       .probe = ad7414_probe,
        .id_table = ad7414_id,
 };
 
index 22bdb7e..ffe81e4 100644 (file)
@@ -306,7 +306,7 @@ static struct i2c_driver ad7418_driver = {
                .name   = "ad7418",
                .of_match_table = ad7418_dt_ids,
        },
-       .probe_new      = ad7418_probe,
+       .probe          = ad7418_probe,
        .id_table       = ad7418_id,
 };
 
index 97b330b..46e3c8c 100644 (file)
@@ -521,7 +521,7 @@ static struct i2c_driver adc128_driver = {
                .name   = "adc128d818",
                .of_match_table = of_match_ptr(adc128_of_match),
        },
-       .probe_new      = adc128_probe,
+       .probe          = adc128_probe,
        .remove         = adc128_remove,
        .id_table       = adc128_id,
        .detect         = adc128_detect,
index 2dc45e9..7c15398 100644 (file)
@@ -488,7 +488,7 @@ static struct i2c_driver adm1021_driver = {
        .driver = {
                .name   = "adm1021",
        },
-       .probe_new      = adm1021_probe,
+       .probe          = adm1021_probe,
        .id_table       = adm1021_id,
        .detect         = adm1021_detect,
        .address_list   = normal_i2c,
index 2984c4f..389382d 100644 (file)
@@ -559,7 +559,7 @@ static struct i2c_driver adm1025_driver = {
        .driver = {
                .name   = "adm1025",
        },
-       .probe_new      = adm1025_probe,
+       .probe          = adm1025_probe,
        .id_table       = adm1025_id,
        .detect         = adm1025_detect,
        .address_list   = normal_i2c,
index 1f084f7..581d8ed 100644 (file)
@@ -1859,7 +1859,7 @@ static struct i2c_driver adm1026_driver = {
        .driver = {
                .name   = "adm1026",
        },
-       .probe_new      = adm1026_probe,
+       .probe          = adm1026_probe,
        .id_table       = adm1026_id,
        .detect         = adm1026_detect,
        .address_list   = normal_i2c,
index eaf6e5e..9a465f3 100644 (file)
@@ -389,7 +389,7 @@ static struct i2c_driver adm1029_driver = {
        .driver = {
                .name = "adm1029",
        },
-       .probe_new      = adm1029_probe,
+       .probe          = adm1029_probe,
        .id_table       = adm1029_id,
        .detect         = adm1029_detect,
        .address_list   = normal_i2c,
index b42797b..88c7e0d 100644 (file)
@@ -1068,7 +1068,7 @@ static struct i2c_driver adm1031_driver = {
        .driver = {
                .name = "adm1031",
        },
-       .probe_new      = adm1031_probe,
+       .probe          = adm1031_probe,
        .id_table       = adm1031_id,
        .detect         = adm1031_detect,
        .address_list   = normal_i2c,
index bfe070a..60a893f 100644 (file)
@@ -255,7 +255,7 @@ static struct i2c_driver adm1177_driver = {
                .name = "adm1177",
                .of_match_table = adm1177_dt_ids,
        },
-       .probe_new = adm1177_probe,
+       .probe = adm1177_probe,
        .id_table = adm1177_id,
 };
 module_i2c_driver(adm1177_driver);
index 9eb973a..6dfbeb6 100644 (file)
@@ -819,7 +819,7 @@ static struct i2c_driver adm9240_driver = {
        .driver = {
                .name   = "adm9240",
        },
-       .probe_new      = adm9240_probe,
+       .probe          = adm9240_probe,
        .id_table       = adm9240_id,
        .detect         = adm9240_detect,
        .address_list   = normal_i2c,
index 7246198..1932613 100644 (file)
@@ -208,7 +208,7 @@ static struct i2c_driver ads7828_driver = {
        },
 
        .id_table = ads7828_device_ids,
-       .probe_new = ads7828_probe,
+       .probe = ads7828_probe,
 };
 
 module_i2c_driver(ads7828_driver);
index 0cebf67..9525067 100644 (file)
@@ -100,7 +100,7 @@ static struct i2c_driver adt7410_driver = {
                .name   = "adt7410",
                .pm     = pm_sleep_ptr(&adt7x10_dev_pm_ops),
        },
-       .probe_new      = adt7410_i2c_probe,
+       .probe          = adt7410_i2c_probe,
        .id_table       = adt7410_ids,
        .address_list   = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
 };
index 6ba8492..45fe4e8 100644 (file)
@@ -706,7 +706,7 @@ static struct i2c_driver adt7411_driver = {
        .driver         = {
                .name           = "adt7411",
        },
-       .probe_new = adt7411_probe,
+       .probe = adt7411_probe,
        .id_table = adt7411_id,
        .detect = adt7411_detect,
        .address_list = normal_i2c,
index 9c02358..429566c 100644 (file)
@@ -1819,7 +1819,7 @@ static struct i2c_driver adt7462_driver = {
        .driver = {
                .name   = "adt7462",
        },
-       .probe_new      = adt7462_probe,
+       .probe          = adt7462_probe,
        .id_table       = adt7462_id,
        .detect         = adt7462_detect,
        .address_list   = normal_i2c,
index 64f801b..c4b3a4a 100644 (file)
@@ -1314,7 +1314,7 @@ static struct i2c_driver adt7470_driver = {
        .driver = {
                .name   = "adt7470",
        },
-       .probe_new      = adt7470_probe,
+       .probe          = adt7470_probe,
        .remove         = adt7470_remove,
        .id_table       = adt7470_id,
        .detect         = adt7470_detect,
index 6a6ebcc..c0ce883 100644 (file)
@@ -1468,7 +1468,7 @@ static int load_config3(const struct i2c_client *client, const char *propname)
        u8 config3;
        int ret;
 
-       ret = of_property_read_string(client->dev.of_node, propname, &function);
+       ret = device_property_read_string(&client->dev, propname, &function);
        if (!ret) {
                ret = adt7475_read(REG_CONFIG3);
                if (ret < 0)
@@ -1494,7 +1494,7 @@ static int load_config4(const struct i2c_client *client, const char *propname)
        u8 config4;
        int ret;
 
-       ret = of_property_read_string(client->dev.of_node, propname, &function);
+       ret = device_property_read_string(&client->dev, propname, &function);
        if (!ret) {
                ret = adt7475_read(REG_CONFIG4);
                if (ret < 0)
@@ -1556,8 +1556,8 @@ static int set_property_bit(const struct i2c_client *client, char *property,
                            u8 *config, u8 bit_index)
 {
        u32 prop_value = 0;
-       int ret = of_property_read_u32(client->dev.of_node, property,
-                                       &prop_value);
+       int ret = device_property_read_u32(&client->dev, property,
+                                          &prop_value);
 
        if (!ret) {
                if (prop_value)
@@ -1821,7 +1821,7 @@ static struct i2c_driver adt7475_driver = {
                .name   = "adt7475",
                .of_match_table = of_match_ptr(adt7475_of_match),
        },
-       .probe_new      = adt7475_probe,
+       .probe          = adt7475_probe,
        .id_table       = adt7475_id,
        .detect         = adt7475_detect,
        .address_list   = normal_i2c,
index b8fe3f7..f136bf3 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
 /*
- * aht10.c - Linux hwmon driver for AHT10 Temperature and Humidity sensor
+ * aht10.c - Linux hwmon driver for AHT10/AHT20 Temperature and Humidity sensors
  * Copyright (C) 2020 Johannes Cornelis Draaijer
  */
 
 #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)
  */
 
 #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
  *                   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");
index 3bfd12f..2a7a4b6 100644 (file)
@@ -939,7 +939,7 @@ static struct i2c_driver amc6821_driver = {
        .driver = {
                .name   = "amc6821",
        },
-       .probe_new = amc6821_probe,
+       .probe = amc6821_probe,
        .id_table = amc6821_id,
        .detect = amc6821_detect,
        .address_list = normal_i2c,
index a4fcd4e..a981f70 100644 (file)
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * hwmon driver for Aquacomputer devices (D5 Next, Farbwerk, Farbwerk 360, Octo,
- * Quadro, High Flow Next, Aquaero, Aquastream Ultimate)
+ * Quadro, High Flow Next, Aquaero, Aquastream Ultimate, Leakshield)
  *
  * Aquacomputer devices send HID reports (with ID 0x01) every second to report
  * sensor values, except for devices that communicate through the
@@ -29,6 +29,7 @@
 #define USB_PRODUCT_ID_FARBWERK360     0xf010
 #define USB_PRODUCT_ID_OCTO            0xf011
 #define USB_PRODUCT_ID_HIGHFLOWNEXT    0xf012
+#define USB_PRODUCT_ID_LEAKSHIELD      0xf014
 #define USB_PRODUCT_ID_AQUASTREAMXT    0xf0b6
 #define USB_PRODUCT_ID_AQUASTREAMULT   0xf00b
 #define USB_PRODUCT_ID_POWERADJUST3    0xf0bd
@@ -36,7 +37,7 @@
 enum kinds {
        d5next, farbwerk, farbwerk360, octo, quadro,
        highflownext, aquaero, poweradjust3, aquastreamult,
-       aquastreamxt
+       aquastreamxt, leakshield
 };
 
 static const char *const aqc_device_names[] = {
@@ -46,6 +47,7 @@ static const char *const aqc_device_names[] = {
        [octo] = "octo",
        [quadro] = "quadro",
        [highflownext] = "highflownext",
+       [leakshield] = "leakshield",
        [aquastreamxt] = "aquastreamxt",
        [aquaero] = "aquaero",
        [aquastreamult] = "aquastreamultimate",
@@ -93,7 +95,7 @@ static u8 aquaero_secondary_ctrl_report[] = {
 #define AQC_FIRMWARE_VERSION           0xD
 
 #define AQC_SENSOR_SIZE                        0x02
-#define AQC_TEMP_SENSOR_DISCONNECTED   0x7FFF
+#define AQC_SENSOR_NA                  0x7FFF
 #define AQC_FAN_PERCENT_OFFSET         0x00
 #define AQC_FAN_VOLTAGE_OFFSET         0x02
 #define AQC_FAN_CURRENT_OFFSET         0x04
@@ -236,6 +238,21 @@ static u16 quadro_ctrl_fan_offsets[] = { 0x37, 0x8c, 0xe1, 0x136 }; /* Fan speed
 #define HIGHFLOWNEXT_5V_VOLTAGE                97
 #define HIGHFLOWNEXT_5V_VOLTAGE_USB    99
 
+/* Specs of the Leakshield */
+#define LEAKSHIELD_NUM_SENSORS         2
+
+/* Sensor report offsets for Leakshield */
+#define LEAKSHIELD_PRESSURE_ADJUSTED   285
+#define LEAKSHIELD_TEMPERATURE_1       265
+#define LEAKSHIELD_TEMPERATURE_2       287
+#define LEAKSHIELD_PRESSURE_MIN                291
+#define LEAKSHIELD_PRESSURE_TARGET     293
+#define LEAKSHIELD_PRESSURE_MAX                295
+#define LEAKSHIELD_PUMP_RPM_IN         101
+#define LEAKSHIELD_FLOW_IN             111
+#define LEAKSHIELD_RESERVOIR_VOLUME    313
+#define LEAKSHIELD_RESERVOIR_FILLED    311
+
 /* Specs of the Aquastream XT pump */
 #define AQUASTREAMXT_SERIAL_START              0x3a
 #define AQUASTREAMXT_FIRMWARE_VERSION          0x32
@@ -411,6 +428,20 @@ static const char *const label_highflownext_voltage[] = {
        "+5V USB voltage"
 };
 
+/* Labels for Leakshield */
+static const char *const label_leakshield_temp_sensors[] = {
+       "Temperature 1",
+       "Temperature 2"
+};
+
+static const char *const label_leakshield_fan_speed[] = {
+       "Pressure [ubar]",
+       "User-Provided Pump Speed",
+       "User-Provided Flow [dL/h]",
+       "Reservoir Volume [ml]",
+       "Reservoir Filled [ml]",
+};
+
 /* Labels for Aquastream XT */
 static const char *const label_aquastreamxt_temp_sensors[] = {
        "Fan IC temp",
@@ -529,7 +560,10 @@ struct aqc_data {
 
        /* Sensor values */
        s32 temp_input[20];     /* Max 4 physical and 16 virtual or 8 physical and 12 virtual */
-       u16 speed_input[8];
+       s32 speed_input[8];
+       u32 speed_input_min[1];
+       u32 speed_input_target[1];
+       u32 speed_input_max[1];
        u32 power_input[8];
        u16 voltage_input[8];
        u16 current_input[8];
@@ -747,6 +781,11 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
                                if (channel < 3)
                                        return 0444;
                                break;
+                       case leakshield:
+                               /* Special case for Leakshield sensors */
+                               if (channel < 5)
+                                       return 0444;
+                               break;
                        case aquaero:
                        case quadro:
                                /* Special case to support flow sensors */
@@ -764,6 +803,13 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
                        if (priv->kind == quadro && channel == priv->num_fans)
                                return 0644;
                        break;
+               case hwmon_fan_min:
+               case hwmon_fan_max:
+               case hwmon_fan_target:
+                       /* Special case for Leakshield pressure sensor */
+                       if (priv->kind == leakshield && channel == 0)
+                               return 0444;
+                       break;
                default:
                        break;
                }
@@ -938,8 +984,20 @@ static int aqc_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
        case hwmon_fan:
                switch (attr) {
                case hwmon_fan_input:
+                       if (priv->speed_input[channel] == -ENODATA)
+                               return -ENODATA;
+
                        *val = priv->speed_input[channel];
                        break;
+               case hwmon_fan_min:
+                       *val = priv->speed_input_min[channel];
+                       break;
+               case hwmon_fan_max:
+                       *val = priv->speed_input_max[channel];
+                       break;
+               case hwmon_fan_target:
+                       *val = priv->speed_input_target[channel];
+                       break;
                case hwmon_fan_pulses:
                        ret = aqc_get_ctrl_val(priv, priv->flow_pulses_ctrl_offset,
                                               val, AQC_BE16);
@@ -1151,7 +1209,8 @@ static const struct hwmon_channel_info * const aqc_info[] = {
                           HWMON_T_INPUT | HWMON_T_LABEL,
                           HWMON_T_INPUT | HWMON_T_LABEL),
        HWMON_CHANNEL_INFO(fan,
-                          HWMON_F_INPUT | HWMON_F_LABEL,
+                          HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
+                          HWMON_F_TARGET,
                           HWMON_F_INPUT | HWMON_F_LABEL,
                           HWMON_F_INPUT | HWMON_F_LABEL,
                           HWMON_F_INPUT | HWMON_F_LABEL,
@@ -1224,7 +1283,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
                sensor_value = get_unaligned_be16(data +
                                                  priv->temp_sensor_start_offset +
                                                  i * AQC_SENSOR_SIZE);
-               if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
+               if (sensor_value == AQC_SENSOR_NA)
                        priv->temp_input[i] = -ENODATA;
                else
                        priv->temp_input[i] = sensor_value * 10;
@@ -1235,7 +1294,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
                sensor_value = get_unaligned_be16(data +
                                                  priv->virtual_temp_sensor_start_offset +
                                                  j * AQC_SENSOR_SIZE);
-               if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
+               if (sensor_value == AQC_SENSOR_NA)
                        priv->temp_input[i] = -ENODATA;
                else
                        priv->temp_input[i] = sensor_value * 10;
@@ -1277,7 +1336,7 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
                        sensor_value = get_unaligned_be16(data +
                                        priv->calc_virt_temp_sensor_start_offset +
                                        j * AQC_SENSOR_SIZE);
-                       if (sensor_value == AQC_TEMP_SENSOR_DISCONNECTED)
+                       if (sensor_value == AQC_SENSOR_NA)
                                priv->temp_input[i] = -ENODATA;
                        else
                                priv->temp_input[i] = sensor_value * 10;
@@ -1314,6 +1373,28 @@ static int aqc_raw_event(struct hid_device *hdev, struct hid_report *report, u8
                priv->speed_input[1] = get_unaligned_be16(data + HIGHFLOWNEXT_WATER_QUALITY);
                priv->speed_input[2] = get_unaligned_be16(data + HIGHFLOWNEXT_CONDUCTIVITY);
                break;
+       case leakshield:
+               priv->speed_input[0] =
+                   ((s16)get_unaligned_be16(data + LEAKSHIELD_PRESSURE_ADJUSTED)) * 100;
+               priv->speed_input_min[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MIN) * 100;
+               priv->speed_input_target[0] =
+                   get_unaligned_be16(data + LEAKSHIELD_PRESSURE_TARGET) * 100;
+               priv->speed_input_max[0] = get_unaligned_be16(data + LEAKSHIELD_PRESSURE_MAX) * 100;
+
+               priv->speed_input[1] = get_unaligned_be16(data + LEAKSHIELD_PUMP_RPM_IN);
+               if (priv->speed_input[1] == AQC_SENSOR_NA)
+                       priv->speed_input[1] = -ENODATA;
+
+               priv->speed_input[2] = get_unaligned_be16(data + LEAKSHIELD_FLOW_IN);
+               if (priv->speed_input[2] == AQC_SENSOR_NA)
+                       priv->speed_input[2] = -ENODATA;
+
+               priv->speed_input[3] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_VOLUME);
+               priv->speed_input[4] = get_unaligned_be16(data + LEAKSHIELD_RESERVOIR_FILLED);
+
+               /* Second temp sensor is not positioned after the first one, read it here */
+               priv->temp_input[1] = get_unaligned_be16(data + LEAKSHIELD_TEMPERATURE_2) * 10;
+               break;
        default:
                break;
        }
@@ -1571,6 +1652,25 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
                priv->power_label = label_highflownext_power;
                priv->voltage_label = label_highflownext_voltage;
                break;
+       case USB_PRODUCT_ID_LEAKSHIELD:
+               /*
+                * Choose the right Leakshield device, because
+                * the other one acts as a keyboard
+                */
+               if (hdev->type != 2) {
+                       ret = -ENODEV;
+                       goto fail_and_close;
+               }
+
+               priv->kind = leakshield;
+
+               priv->num_fans = 0;
+               priv->num_temp_sensors = LEAKSHIELD_NUM_SENSORS;
+               priv->temp_sensor_start_offset = LEAKSHIELD_TEMPERATURE_1;
+
+               priv->temp_label = label_leakshield_temp_sensors;
+               priv->speed_label = label_leakshield_fan_speed;
+               break;
        case USB_PRODUCT_ID_AQUASTREAMXT:
                priv->kind = aquastreamxt;
 
@@ -1707,6 +1807,7 @@ static const struct hid_device_id aqc_table[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_OCTO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_QUADRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_HIGHFLOWNEXT) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_LEAKSHIELD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMXT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_AQUASTREAMULT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AQUACOMPUTER, USB_PRODUCT_ID_POWERADJUST3) },
index ce4da83..974521e 100644 (file)
@@ -223,7 +223,7 @@ static struct i2c_driver asb100_driver = {
        .driver = {
                .name   = "asb100",
        },
-       .probe_new      = asb100_probe,
+       .probe          = asb100_probe,
        .remove         = asb100_remove,
        .id_table       = asb100_id,
        .detect         = asb100_detect,
index 5459545..87e1867 100644 (file)
@@ -1191,7 +1191,7 @@ static struct i2c_driver asc7621_driver = {
        .driver = {
                .name = "asc7621",
        },
-       .probe_new = asc7621_probe,
+       .probe = asc7621_probe,
        .remove = asc7621_remove,
        .id_table = asc7621_id,
        .detect = asc7621_detect,
index e5be0cf..f52a539 100644 (file)
@@ -101,6 +101,8 @@ enum ec_sensors {
        ec_sensor_temp_chipset,
        /* CPU temperature [℃] */
        ec_sensor_temp_cpu,
+       /* CPU package temperature [℃] */
+       ec_sensor_temp_cpu_package,
        /* motherboard temperature [℃] */
        ec_sensor_temp_mb,
        /* "T_Sensor" temperature sensor reading [℃] */
@@ -139,6 +141,7 @@ enum ec_sensors {
 
 #define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset)
 #define SENSOR_TEMP_CPU BIT(ec_sensor_temp_cpu)
+#define SENSOR_TEMP_CPU_PACKAGE BIT(ec_sensor_temp_cpu_package)
 #define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb)
 #define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor)
 #define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm)
@@ -161,6 +164,7 @@ enum board_family {
        family_unknown,
        family_amd_400_series,
        family_amd_500_series,
+       family_amd_600_series,
        family_intel_300_series,
        family_intel_600_series
 };
@@ -233,6 +237,19 @@ static const struct ec_sensor_info sensors_family_amd_500[] = {
                EC_SENSOR("Extra_3", hwmon_temp, 1, 0x01, 0x0c),
 };
 
+static const struct ec_sensor_info sensors_family_amd_600[] = {
+       [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x30),
+       [ec_sensor_temp_cpu_package] = EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31),
+       [ec_sensor_temp_mb] =
+       EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x32),
+       [ec_sensor_temp_vrm] =
+               EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33),
+       [ec_sensor_temp_water_in] =
+               EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
+       [ec_sensor_temp_water_out] =
+               EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
+};
+
 static const struct ec_sensor_info sensors_family_intel_300[] = {
        [ec_sensor_temp_chipset] =
                EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
@@ -319,6 +336,14 @@ static const struct ec_board_info board_info_pro_ws_x570_ace = {
        .family = family_amd_500_series,
 };
 
+static const struct ec_board_info board_info_crosshair_x670e_hero = {
+       .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
+               SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
+               SENSOR_SET_TEMP_WATER,
+       .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
+       .family = family_amd_600_series,
+};
+
 static const struct ec_board_info board_info_crosshair_viii_dark_hero = {
        .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
                SENSOR_TEMP_T_SENSOR |
@@ -463,6 +488,8 @@ static const struct dmi_system_id dmi_table[] = {
                                        &board_info_crosshair_viii_hero),
        DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO (WI-FI)",
                                        &board_info_crosshair_viii_hero),
+       DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO",
+                                       &board_info_crosshair_x670e_hero),
        DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO",
                                        &board_info_maximus_xi_hero),
        DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)",
@@ -946,6 +973,9 @@ static int asus_ec_probe(struct platform_device *pdev)
        case family_amd_500_series:
                ec_data->sensors_info = sensors_family_amd_500;
                break;
+       case family_amd_600_series:
+               ec_data->sensors_info = sensors_family_amd_600;
+               break;
        case family_intel_300_series:
                ec_data->sensors_info = sensors_family_intel_300;
                break;
index 118297e..d1de020 100644 (file)
@@ -288,7 +288,7 @@ static struct i2c_driver atxp1_driver = {
        .driver = {
                .name   = "atxp1",
        },
-       .probe_new      = atxp1_probe,
+       .probe          = atxp1_probe,
        .id_table       = atxp1_id,
 };
 
index dc24c56..9048905 100644 (file)
  *       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);
index 66c48f7..cdbf3df 100644 (file)
@@ -2528,7 +2528,7 @@ static struct i2c_driver dme1737_i2c_driver = {
        .driver = {
                .name = "dme1737",
        },
-       .probe_new = dme1737_i2c_probe,
+       .probe = dme1737_i2c_probe,
        .remove = dme1737_i2c_remove,
        .id_table = dme1737_id,
        .detect = dme1737_i2c_detect,
index e803d63..21b6350 100644 (file)
@@ -384,7 +384,7 @@ static struct i2c_driver ds1621_driver = {
        .driver = {
                .name   = "ds1621",
        },
-       .probe_new      = ds1621_probe,
+       .probe          = ds1621_probe,
        .id_table       = ds1621_id,
 };
 
index 82d7c3d..2b09536 100644 (file)
@@ -245,7 +245,7 @@ static struct i2c_driver ds620_driver = {
        .driver = {
                   .name = "ds620",
        },
-       .probe_new = ds620_probe,
+       .probe = ds620_probe,
        .id_table = ds620_id,
 };
 
index 61d5918..bb7c859 100644 (file)
@@ -454,7 +454,7 @@ static struct i2c_driver sensor_emc1403 = {
                .name = "emc1403",
        },
        .detect = emc1403_detect,
-       .probe_new = emc1403_probe,
+       .probe = emc1403_probe,
        .id_table = emc1403_idtable,
        .address_list = emc1403_address_list,
 };
index 361cf92..b59472b 100644 (file)
@@ -653,7 +653,7 @@ static struct i2c_driver emc2103_driver = {
        .driver = {
                .name   = "emc2103",
        },
-       .probe_new      = emc2103_probe,
+       .probe          = emc2103_probe,
        .id_table       = emc2103_ids,
        .detect         = emc2103_detect,
        .address_list   = normal_i2c,
index 723f575..29f0e49 100644 (file)
@@ -615,7 +615,7 @@ static struct i2c_driver emc2305_driver = {
        .driver = {
                .name = "emc2305",
        },
-       .probe_new = emc2305_probe,
+       .probe = emc2305_probe,
        .remove   = emc2305_remove,
        .id_table = emc2305_ids,
        .address_list = emc2305_normal_i2c,
index bcd93f0..9a4f868 100644 (file)
@@ -474,7 +474,7 @@ static struct i2c_driver emc6w201_driver = {
        .driver = {
                .name   = "emc6w201",
        },
-       .probe_new      = emc6w201_probe,
+       .probe          = emc6w201_probe,
        .id_table       = emc6w201_id,
        .detect         = emc6w201_detect,
        .address_list   = normal_i2c,
index 7012148..27207ec 100644 (file)
@@ -1096,8 +1096,11 @@ static ssize_t show_pwm(struct device *dev,
                val = data->pwm[nr];
        else {
                /* RPM mode */
-               val = 255 * fan_from_reg(data->fan_target[nr])
-                       / fan_from_reg(data->fan_full_speed[nr]);
+               if (fan_from_reg(data->fan_full_speed[nr]))
+                       val = 255 * fan_from_reg(data->fan_target[nr])
+                               / fan_from_reg(data->fan_full_speed[nr]);
+               else
+                       val = 0;
        }
        mutex_unlock(&data->update_lock);
        return sprintf(buf, "%d\n", val);
index 64fbb8c..8c572bb 100644 (file)
@@ -129,7 +129,7 @@ static struct i2c_driver f75375_driver = {
        .driver = {
                .name = "f75375",
        },
-       .probe_new = f75375_probe,
+       .probe = f75375_probe,
        .remove = f75375_remove,
        .id_table = f75375_id,
        .detect = f75375_detect,
index e1f426e..b30512a 100644 (file)
@@ -241,7 +241,7 @@ static struct i2c_driver fschmd_driver = {
        .driver = {
                .name   = "fschmd",
        },
-       .probe_new      = fschmd_probe,
+       .probe          = fschmd_probe,
        .remove         = fschmd_remove,
        .id_table       = fschmd_id,
        .detect         = fschmd_detect,
index f5a4d91..b74a266 100644 (file)
@@ -678,7 +678,7 @@ static struct i2c_driver fts_driver = {
                .name = "ftsteutates",
        },
        .id_table = fts_id,
-       .probe_new = fts_probe,
+       .probe = fts_probe,
        .detect = fts_detect,
        .address_list = normal_i2c,
 };
index 36717b5..b5edee0 100644 (file)
@@ -206,7 +206,7 @@ static struct i2c_driver g760a_driver = {
        .driver = {
                .name   = "g760a",
        },
-       .probe_new = g760a_probe,
+       .probe = g760a_probe,
        .id_table = g760a_id,
 };
 
index e2c3c34..1b6ff47 100644 (file)
@@ -1084,7 +1084,7 @@ static struct i2c_driver g762_driver = {
                .name = DRVNAME,
                .of_match_table = of_match_ptr(g762_dt_match),
        },
-       .probe_new = g762_probe,
+       .probe = g762_probe,
        .id_table = g762_id,
 };
 
index 95286c4..03db615 100644 (file)
@@ -652,7 +652,7 @@ static struct i2c_driver gl518_driver = {
        .driver = {
                .name   = "gl518sm",
        },
-       .probe_new      = gl518_probe,
+       .probe          = gl518_probe,
        .id_table       = gl518_id,
        .detect         = gl518_detect,
        .address_list   = normal_i2c,
index 394da4a..8bbc6a4 100644 (file)
@@ -895,7 +895,7 @@ static struct i2c_driver gl520_driver = {
        .driver = {
                .name   = "gl520sm",
        },
-       .probe_new      = gl520_probe,
+       .probe          = gl520_probe,
        .id_table       = gl520_id,
        .detect         = gl520_detect,
        .address_list   = normal_i2c,
index 73e5d92..1501ceb 100644 (file)
@@ -82,8 +82,8 @@ static ssize_t pwm_auto_point_temp_store(struct device *dev,
        if (kstrtol(buf, 10, &temp))
                return -EINVAL;
 
-       temp = clamp_val(temp, 0, 10000);
-       temp = DIV_ROUND_CLOSEST(temp, 10);
+       temp = clamp_val(temp, 0, 100000);
+       temp = DIV_ROUND_CLOSEST(temp, 100);
 
        regs[0] = temp & 0xff;
        regs[1] = (temp >> 8) & 0xff;
@@ -100,7 +100,7 @@ static ssize_t pwm_auto_point_pwm_show(struct device *dev,
 {
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
 
-       return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)) / 100);
+       return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)));
 }
 
 static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0);
index 3a75828..a9726b5 100644 (file)
@@ -249,7 +249,7 @@ static struct i2c_driver hih6130_driver = {
                .name = "hih6130",
                .of_match_table = of_match_ptr(hih6130_of_match),
        },
-       .probe_new   = hih6130_probe,
+       .probe       = hih6130_probe,
        .id_table    = hih6130_id,
 };
 
diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c
new file mode 100644 (file)
index 0000000..ebe2fb5
--- /dev/null
@@ -0,0 +1,2004 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * hwmon driver for HP (and some HP Compaq) business-class computers that
+ * report numeric sensor data via Windows Management Instrumentation (WMI).
+ *
+ * Copyright (C) 2023 James Seo <james@equiv.tech>
+ *
+ * References:
+ * [1] 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
+ * [2] Hewlett-Packard Development Company, L.P.,
+ *     "HP Retail Manageability", 2012. [Online].
+ *     Available: http://h10032.www1.hp.com/ctg/Manual/c03291135.pdf
+ * [3] Linux Hardware Project, A. Ponomarenko et al.,
+ *     "linuxhw/ACPI - Collect ACPI table dumps", 2018. [Online].
+ *     Available: https://github.com/linuxhw/ACPI
+ * [4] P. Rohár, "bmfdec - Decompile binary MOF file (BMF) from WMI buffer",
+ *     2017. [Online]. Available: https://github.com/pali/bmfdec
+ */
+
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/units.h>
+#include <linux/wmi.h>
+
+#define HP_WMI_EVENT_NAMESPACE         "root\\WMI"
+#define HP_WMI_EVENT_CLASS             "HPBIOS_BIOSEvent"
+#define HP_WMI_EVENT_GUID              "95F24279-4D7B-4334-9387-ACCDC67EF61C"
+#define HP_WMI_NUMERIC_SENSOR_GUID     "8F1F6435-9F42-42C8-BADC-0E9424F20C9A"
+#define HP_WMI_PLATFORM_EVENTS_GUID    "41227C2D-80E1-423F-8B8E-87E32755A0EB"
+
+/* Patterns for recognizing sensors and matching events to channels. */
+
+#define HP_WMI_PATTERN_SYS_TEMP                "Chassis Thermal Index"
+#define HP_WMI_PATTERN_SYS_TEMP2       "System Ambient Temperature"
+#define HP_WMI_PATTERN_CPU_TEMP                "CPU Thermal Index"
+#define HP_WMI_PATTERN_CPU_TEMP2       "CPU Temperature"
+#define HP_WMI_PATTERN_TEMP_SENSOR     "Thermal Index"
+#define HP_WMI_PATTERN_TEMP_ALARM      "Thermal Critical"
+#define HP_WMI_PATTERN_INTRUSION_ALARM "Hood Intrusion"
+#define HP_WMI_PATTERN_FAN_ALARM       "Stall"
+#define HP_WMI_PATTERN_TEMP            "Temperature"
+#define HP_WMI_PATTERN_CPU             "CPU"
+
+/* These limits are arbitrary. The WMI implementation may vary by system. */
+
+#define HP_WMI_MAX_STR_SIZE            128U
+#define HP_WMI_MAX_PROPERTIES          32U
+#define HP_WMI_MAX_INSTANCES           32U
+
+enum hp_wmi_type {
+       HP_WMI_TYPE_OTHER                       = 1,
+       HP_WMI_TYPE_TEMPERATURE                 = 2,
+       HP_WMI_TYPE_VOLTAGE                     = 3,
+       HP_WMI_TYPE_CURRENT                     = 4,
+       HP_WMI_TYPE_AIR_FLOW                    = 12,
+       HP_WMI_TYPE_INTRUSION                   = 0xabadb01, /* Custom. */
+};
+
+enum hp_wmi_category {
+       HP_WMI_CATEGORY_SENSOR                  = 3,
+};
+
+enum hp_wmi_severity {
+       HP_WMI_SEVERITY_UNKNOWN                 = 0,
+       HP_WMI_SEVERITY_OK                      = 5,
+       HP_WMI_SEVERITY_DEGRADED_WARNING        = 10,
+       HP_WMI_SEVERITY_MINOR_FAILURE           = 15,
+       HP_WMI_SEVERITY_MAJOR_FAILURE           = 20,
+       HP_WMI_SEVERITY_CRITICAL_FAILURE        = 25,
+       HP_WMI_SEVERITY_NON_RECOVERABLE_ERROR   = 30,
+};
+
+enum hp_wmi_status {
+       HP_WMI_STATUS_OK                        = 2,
+       HP_WMI_STATUS_DEGRADED                  = 3,
+       HP_WMI_STATUS_STRESSED                  = 4,
+       HP_WMI_STATUS_PREDICTIVE_FAILURE        = 5,
+       HP_WMI_STATUS_ERROR                     = 6,
+       HP_WMI_STATUS_NON_RECOVERABLE_ERROR     = 7,
+       HP_WMI_STATUS_NO_CONTACT                = 12,
+       HP_WMI_STATUS_LOST_COMMUNICATION        = 13,
+       HP_WMI_STATUS_ABORTED                   = 14,
+       HP_WMI_STATUS_SUPPORTING_ENTITY_IN_ERROR = 16,
+
+       /* Occurs combined with one of "OK", "Degraded", and "Error" [1]. */
+       HP_WMI_STATUS_COMPLETED                 = 17,
+};
+
+enum hp_wmi_units {
+       HP_WMI_UNITS_OTHER                      = 1,
+       HP_WMI_UNITS_DEGREES_C                  = 2,
+       HP_WMI_UNITS_DEGREES_F                  = 3,
+       HP_WMI_UNITS_DEGREES_K                  = 4,
+       HP_WMI_UNITS_VOLTS                      = 5,
+       HP_WMI_UNITS_AMPS                       = 6,
+       HP_WMI_UNITS_RPM                        = 19,
+};
+
+enum hp_wmi_property {
+       HP_WMI_PROPERTY_NAME                    = 0,
+       HP_WMI_PROPERTY_DESCRIPTION             = 1,
+       HP_WMI_PROPERTY_SENSOR_TYPE             = 2,
+       HP_WMI_PROPERTY_OTHER_SENSOR_TYPE       = 3,
+       HP_WMI_PROPERTY_OPERATIONAL_STATUS      = 4,
+       HP_WMI_PROPERTY_SIZE                    = 5,
+       HP_WMI_PROPERTY_POSSIBLE_STATES         = 6,
+       HP_WMI_PROPERTY_CURRENT_STATE           = 7,
+       HP_WMI_PROPERTY_BASE_UNITS              = 8,
+       HP_WMI_PROPERTY_UNIT_MODIFIER           = 9,
+       HP_WMI_PROPERTY_CURRENT_READING         = 10,
+       HP_WMI_PROPERTY_RATE_UNITS              = 11,
+};
+
+static const acpi_object_type hp_wmi_property_map[] = {
+       [HP_WMI_PROPERTY_NAME]                  = ACPI_TYPE_STRING,
+       [HP_WMI_PROPERTY_DESCRIPTION]           = ACPI_TYPE_STRING,
+       [HP_WMI_PROPERTY_SENSOR_TYPE]           = ACPI_TYPE_INTEGER,
+       [HP_WMI_PROPERTY_OTHER_SENSOR_TYPE]     = ACPI_TYPE_STRING,
+       [HP_WMI_PROPERTY_OPERATIONAL_STATUS]    = ACPI_TYPE_INTEGER,
+       [HP_WMI_PROPERTY_SIZE]                  = ACPI_TYPE_INTEGER,
+       [HP_WMI_PROPERTY_POSSIBLE_STATES]       = ACPI_TYPE_STRING,
+       [HP_WMI_PROPERTY_CURRENT_STATE]         = ACPI_TYPE_STRING,
+       [HP_WMI_PROPERTY_BASE_UNITS]            = ACPI_TYPE_INTEGER,
+       [HP_WMI_PROPERTY_UNIT_MODIFIER]         = ACPI_TYPE_INTEGER,
+       [HP_WMI_PROPERTY_CURRENT_READING]       = ACPI_TYPE_INTEGER,
+       [HP_WMI_PROPERTY_RATE_UNITS]            = ACPI_TYPE_INTEGER,
+};
+
+enum hp_wmi_platform_events_property {
+       HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME                = 0,
+       HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION         = 1,
+       HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE    = 2,
+       HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS        = 3,
+       HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY            = 4,
+       HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY   = 5,
+       HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS     = 6,
+};
+
+static const acpi_object_type hp_wmi_platform_events_property_map[] = {
+       [HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME]              = ACPI_TYPE_STRING,
+       [HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION]       = ACPI_TYPE_STRING,
+       [HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE]  = ACPI_TYPE_STRING,
+       [HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS]      = ACPI_TYPE_STRING,
+       [HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY]          = ACPI_TYPE_INTEGER,
+       [HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY] = ACPI_TYPE_INTEGER,
+       [HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS]   = ACPI_TYPE_INTEGER,
+};
+
+enum hp_wmi_event_property {
+       HP_WMI_EVENT_PROPERTY_NAME              = 0,
+       HP_WMI_EVENT_PROPERTY_DESCRIPTION       = 1,
+       HP_WMI_EVENT_PROPERTY_CATEGORY          = 2,
+       HP_WMI_EVENT_PROPERTY_SEVERITY          = 3,
+       HP_WMI_EVENT_PROPERTY_STATUS            = 4,
+};
+
+static const acpi_object_type hp_wmi_event_property_map[] = {
+       [HP_WMI_EVENT_PROPERTY_NAME]            = ACPI_TYPE_STRING,
+       [HP_WMI_EVENT_PROPERTY_DESCRIPTION]     = ACPI_TYPE_STRING,
+       [HP_WMI_EVENT_PROPERTY_CATEGORY]        = ACPI_TYPE_INTEGER,
+       [HP_WMI_EVENT_PROPERTY_SEVERITY]        = ACPI_TYPE_INTEGER,
+       [HP_WMI_EVENT_PROPERTY_STATUS]          = ACPI_TYPE_INTEGER,
+};
+
+static const enum hwmon_sensor_types hp_wmi_hwmon_type_map[] = {
+       [HP_WMI_TYPE_TEMPERATURE]               = hwmon_temp,
+       [HP_WMI_TYPE_VOLTAGE]                   = hwmon_in,
+       [HP_WMI_TYPE_CURRENT]                   = hwmon_curr,
+       [HP_WMI_TYPE_AIR_FLOW]                  = hwmon_fan,
+};
+
+static const u32 hp_wmi_hwmon_attributes[hwmon_max] = {
+       [hwmon_chip]      = HWMON_C_REGISTER_TZ,
+       [hwmon_temp]      = HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_FAULT,
+       [hwmon_in]        = HWMON_I_INPUT | HWMON_I_LABEL,
+       [hwmon_curr]      = HWMON_C_INPUT | HWMON_C_LABEL,
+       [hwmon_fan]       = HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_FAULT,
+       [hwmon_intrusion] = HWMON_INTRUSION_ALARM,
+};
+
+/*
+ * struct hp_wmi_numeric_sensor - a HPBIOS_BIOSNumericSensor instance
+ *
+ * Two variants of HPBIOS_BIOSNumericSensor are known. The first is specified
+ * in [1] and appears to be much more widespread. The second was discovered by
+ * decoding BMOF blobs [4], seems to be found only in some newer ZBook systems
+ * [3], and has two new properties and a slightly different property order.
+ *
+ * These differences don't matter on Windows, where WMI object properties are
+ * accessed by name. For us, supporting both variants gets ugly and hacky at
+ * times. The fun begins now; this struct is defined as per the new variant.
+ *
+ * Effective MOF definition:
+ *
+ *   #pragma namespace("\\\\.\\root\\HP\\InstrumentedBIOS");
+ *   class HPBIOS_BIOSNumericSensor {
+ *     [read] string Name;
+ *     [read] string Description;
+ *     [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
+ *      "10","11","12"}, Values {"Unknown","Other","Temperature",
+ *      "Voltage","Current","Tachometer","Counter","Switch","Lock",
+ *      "Humidity","Smoke Detection","Presence","Air Flow"}]
+ *     uint32 SensorType;
+ *     [read] string OtherSensorType;
+ *     [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
+ *      "10","11","12","13","14","15","16","17","18","..",
+ *      "0x8000.."}, Values {"Unknown","Other","OK","Degraded",
+ *      "Stressed","Predictive Failure","Error",
+ *      "Non-Recoverable Error","Starting","Stopping","Stopped",
+ *      "In Service","No Contact","Lost Communication","Aborted",
+ *      "Dormant","Supporting Entity in Error","Completed",
+ *      "Power Mode","DMTF Reserved","Vendor Reserved"}]
+ *     uint32 OperationalStatus;
+ *     [read] uint32 Size;
+ *     [read] string PossibleStates[];
+ *     [read] string CurrentState;
+ *     [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
+ *      "10","11","12","13","14","15","16","17","18","19","20",
+ *      "21","22","23","24","25","26","27","28","29","30","31",
+ *      "32","33","34","35","36","37","38","39","40","41","42",
+ *      "43","44","45","46","47","48","49","50","51","52","53",
+ *      "54","55","56","57","58","59","60","61","62","63","64",
+ *      "65"}, Values {"Unknown","Other","Degrees C","Degrees F",
+ *      "Degrees K","Volts","Amps","Watts","Joules","Coulombs",
+ *      "VA","Nits","Lumens","Lux","Candelas","kPa","PSI",
+ *      "Newtons","CFM","RPM","Hertz","Seconds","Minutes",
+ *      "Hours","Days","Weeks","Mils","Inches","Feet",
+ *      "Cubic Inches","Cubic Feet","Meters","Cubic Centimeters",
+ *      "Cubic Meters","Liters","Fluid Ounces","Radians",
+ *      "Steradians","Revolutions","Cycles","Gravities","Ounces",
+ *      "Pounds","Foot-Pounds","Ounce-Inches","Gauss","Gilberts",
+ *      "Henries","Farads","Ohms","Siemens","Moles","Becquerels",
+ *      "PPM (parts/million)","Decibels","DbA","DbC","Grays",
+ *      "Sieverts","Color Temperature Degrees K","Bits","Bytes",
+ *      "Words (data)","DoubleWords","QuadWords","Percentage"}]
+ *     uint32 BaseUnits;
+ *     [read] sint32 UnitModifier;
+ *     [read] uint32 CurrentReading;
+ *     [read] uint32 RateUnits;
+ *   };
+ *
+ * Effective MOF definition of old variant [1] (sans redundant info):
+ *
+ *   class HPBIOS_BIOSNumericSensor {
+ *     [read] string Name;
+ *     [read] string Description;
+ *     [read] uint32 SensorType;
+ *     [read] string OtherSensorType;
+ *     [read] uint32 OperationalStatus;
+ *     [read] string CurrentState;
+ *     [read] string PossibleStates[];
+ *     [read] uint32 BaseUnits;
+ *     [read] sint32 UnitModifier;
+ *     [read] uint32 CurrentReading;
+ *   };
+ */
+struct hp_wmi_numeric_sensor {
+       const char *name;
+       const char *description;
+       u32 sensor_type;
+       const char *other_sensor_type;  /* Explains "Other" SensorType. */
+       u32 operational_status;
+       u8 size;                        /* Count of PossibleStates[]. */
+       const char **possible_states;
+       const char *current_state;
+       u32 base_units;
+       s32 unit_modifier;
+       u32 current_reading;
+       u32 rate_units;
+};
+
+/*
+ * struct hp_wmi_platform_events - a HPBIOS_PlatformEvents instance
+ *
+ * Instances of this object reveal the set of possible HPBIOS_BIOSEvent
+ * instances for the current system, but it may not always be present.
+ *
+ * Effective MOF definition:
+ *
+ *   #pragma namespace("\\\\.\\root\\HP\\InstrumentedBIOS");
+ *   class HPBIOS_PlatformEvents {
+ *     [read] string Name;
+ *     [read] string Description;
+ *     [read] string SourceNamespace;
+ *     [read] string SourceClass;
+ *     [read, ValueMap {"0","1","2","3","4",".."}, Values {
+ *      "Unknown","Configuration Change","Button Pressed",
+ *      "Sensor","BIOS Settings","Reserved"}]
+ *     uint32 Category;
+ *     [read, ValueMap{"0","5","10","15","20","25","30",".."},
+ *      Values{"Unknown","OK","Degraded/Warning","Minor Failure",
+ *      "Major Failure","Critical Failure","Non-recoverable Error",
+ *      "DMTF Reserved"}]
+ *     uint32 PossibleSeverity;
+ *     [read, ValueMap {"0","1","2","3","4","5","6","7","8","9",
+ *      "10","11","12","13","14","15","16","17","18","..",
+ *      "0x8000.."}, Values {"Unknown","Other","OK","Degraded",
+ *      "Stressed","Predictive Failure","Error",
+ *      "Non-Recoverable Error","Starting","Stopping","Stopped",
+ *      "In Service","No Contact","Lost Communication","Aborted",
+ *      "Dormant","Supporting Entity in Error","Completed",
+ *      "Power Mode","DMTF Reserved","Vendor Reserved"}]
+ *     uint32 PossibleStatus;
+ *   };
+ */
+struct hp_wmi_platform_events {
+       const char *name;
+       const char *description;
+       const char *source_namespace;
+       const char *source_class;
+       u32 category;
+       u32 possible_severity;
+       u32 possible_status;
+};
+
+/*
+ * struct hp_wmi_event - a HPBIOS_BIOSEvent instance
+ *
+ * Effective MOF definition [1] (corrected below from original):
+ *
+ *   #pragma namespace("\\\\.\\root\\WMI");
+ *   class HPBIOS_BIOSEvent : WMIEvent {
+ *     [read] string Name;
+ *     [read] string Description;
+ *     [read ValueMap {"0","1","2","3","4"}, Values {"Unknown",
+ *      "Configuration Change","Button Pressed","Sensor",
+ *      "BIOS Settings"}]
+ *     uint32 Category;
+ *     [read, ValueMap {"0","5","10","15","20","25","30"},
+ *      Values {"Unknown","OK","Degraded/Warning",
+ *      "Minor Failure","Major Failure","Critical Failure",
+ *      "Non-recoverable Error"}]
+ *     uint32 Severity;
+ *     [read, ValueMap {"0","1","2","3","4","5","6","7","8",
+ *      "9","10","11","12","13","14","15","16","17","18","..",
+ *      "0x8000.."}, Values {"Unknown","Other","OK","Degraded",
+ *      "Stressed","Predictive Failure","Error",
+ *      "Non-Recoverable Error","Starting","Stopping","Stopped",
+ *      "In Service","No Contact","Lost Communication","Aborted",
+ *      "Dormant","Supporting Entity in Error","Completed",
+ *      "Power Mode","DMTF Reserved","Vendor Reserved"}]
+ *     uint32 Status;
+ *   };
+ */
+struct hp_wmi_event {
+       const char *name;
+       const char *description;
+       u32 category;
+};
+
+/*
+ * struct hp_wmi_info - sensor info
+ * @nsensor: numeric sensor properties
+ * @instance: its WMI instance number
+ * @state: pointer to driver state
+ * @has_alarm: whether sensor has an alarm flag
+ * @alarm: alarm flag
+ * @type: its hwmon sensor type
+ * @cached_val: current sensor reading value, scaled for hwmon
+ * @last_updated: when these readings were last updated
+ */
+struct hp_wmi_info {
+       struct hp_wmi_numeric_sensor nsensor;
+       u8 instance;
+       void *state;                    /* void *: Avoid forward declaration. */
+       bool has_alarm;
+       bool alarm;
+       enum hwmon_sensor_types type;
+       long cached_val;
+       unsigned long last_updated;     /* In jiffies. */
+
+};
+
+/*
+ * struct hp_wmi_sensors - driver state
+ * @wdev: pointer to the parent WMI device
+ * @info_map: sensor info structs by hwmon type and channel number
+ * @channel_count: count of hwmon channels by hwmon type
+ * @has_intrusion: whether an intrusion sensor is present
+ * @intrusion: intrusion flag
+ * @lock: mutex to lock polling WMI and changes to driver state
+ */
+struct hp_wmi_sensors {
+       struct wmi_device *wdev;
+       struct hp_wmi_info **info_map[hwmon_max];
+       u8 channel_count[hwmon_max];
+       bool has_intrusion;
+       bool intrusion;
+
+       struct mutex lock;      /* Lock polling WMI and driver state changes. */
+};
+
+/* hp_wmi_strdup - devm_kstrdup, but length-limited */
+static char *hp_wmi_strdup(struct device *dev, const char *src)
+{
+       char *dst;
+       size_t len;
+
+       len = strnlen(src, HP_WMI_MAX_STR_SIZE - 1);
+
+       dst = devm_kmalloc(dev, (len + 1) * sizeof(*dst), GFP_KERNEL);
+       if (!dst)
+               return NULL;
+
+       strscpy(dst, src, len + 1);
+
+       return dst;
+}
+
+/*
+ * hp_wmi_get_wobj - poll WMI for a WMI object instance
+ * @guid: WMI object GUID
+ * @instance: WMI object instance number
+ *
+ * Returns a new WMI object instance on success, or NULL on error.
+ * Caller must kfree() the result.
+ */
+static union acpi_object *hp_wmi_get_wobj(const char *guid, u8 instance)
+{
+       struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status err;
+
+       err = wmi_query_block(guid, instance, &out);
+       if (ACPI_FAILURE(err))
+               return NULL;
+
+       return out.pointer;
+}
+
+/* hp_wmi_wobj_instance_count - find count of WMI object instances */
+static u8 hp_wmi_wobj_instance_count(const char *guid)
+{
+       u8 hi = HP_WMI_MAX_INSTANCES;
+       union acpi_object *wobj;
+       u8 lo = 0;
+       u8 mid;
+
+       while (lo < hi) {
+               mid = (lo + hi) / 2;
+
+               wobj = hp_wmi_get_wobj(guid, mid);
+               if (!wobj) {
+                       hi = mid;
+                       continue;
+               }
+
+               lo = mid + 1;
+               kfree(wobj);
+       }
+
+       return lo;
+}
+
+static int check_wobj(const union acpi_object *wobj,
+                     const acpi_object_type property_map[], int last_prop)
+{
+       acpi_object_type type = wobj->type;
+       acpi_object_type valid_type;
+       union acpi_object *elements;
+       u32 elem_count;
+       int prop;
+
+       if (type != ACPI_TYPE_PACKAGE)
+               return -EINVAL;
+
+       elem_count = wobj->package.count;
+       if (elem_count != last_prop + 1)
+               return -EINVAL;
+
+       elements = wobj->package.elements;
+       for (prop = 0; prop <= last_prop; prop++) {
+               type = elements[prop].type;
+               valid_type = property_map[prop];
+               if (type != valid_type)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int extract_acpi_value(struct device *dev,
+                             union acpi_object *element,
+                             acpi_object_type type,
+                             u32 *out_value, char **out_string)
+{
+       switch (type) {
+       case ACPI_TYPE_INTEGER:
+               *out_value = element->integer.value;
+               break;
+
+       case ACPI_TYPE_STRING:
+               *out_string = hp_wmi_strdup(dev, strim(element->string.pointer));
+               if (!*out_string)
+                       return -ENOMEM;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * check_numeric_sensor_wobj - validate a HPBIOS_BIOSNumericSensor instance
+ * @wobj: pointer to WMI object instance to check
+ * @out_size: out pointer to count of possible states
+ * @out_is_new: out pointer to whether this is a "new" variant object
+ *
+ * Returns 0 on success, or a negative error code on error.
+ */
+static int check_numeric_sensor_wobj(const union acpi_object *wobj,
+                                    u8 *out_size, bool *out_is_new)
+{
+       acpi_object_type type = wobj->type;
+       int prop = HP_WMI_PROPERTY_NAME;
+       acpi_object_type valid_type;
+       union acpi_object *elements;
+       u32 elem_count;
+       int last_prop;
+       bool is_new;
+       u8 count;
+       u32 j;
+       u32 i;
+
+       if (type != ACPI_TYPE_PACKAGE)
+               return -EINVAL;
+
+       /*
+        * elements is a variable-length array of ACPI objects, one for
+        * each property of the WMI object instance, except that the
+        * strings in PossibleStates[] are flattened into this array
+        * as if each individual string were a property by itself.
+        */
+       elements = wobj->package.elements;
+
+       elem_count = wobj->package.count;
+       if (elem_count <= HP_WMI_PROPERTY_SIZE ||
+           elem_count > HP_WMI_MAX_PROPERTIES)
+               return -EINVAL;
+
+       type = elements[HP_WMI_PROPERTY_SIZE].type;
+       switch (type) {
+       case ACPI_TYPE_INTEGER:
+               is_new = true;
+               last_prop = HP_WMI_PROPERTY_RATE_UNITS;
+               break;
+
+       case ACPI_TYPE_STRING:
+               is_new = false;
+               last_prop = HP_WMI_PROPERTY_CURRENT_READING;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * In general, the count of PossibleStates[] must be > 0.
+        * Also, the old variant lacks the Size property, so we may need to
+        * reduce the value of last_prop by 1 when doing arithmetic with it.
+        */
+       if (elem_count < last_prop - !is_new + 1)
+               return -EINVAL;
+
+       count = elem_count - (last_prop - !is_new);
+
+       for (i = 0; i < elem_count && prop <= last_prop; i++, prop++) {
+               type = elements[i].type;
+               valid_type = hp_wmi_property_map[prop];
+               if (type != valid_type)
+                       return -EINVAL;
+
+               switch (prop) {
+               case HP_WMI_PROPERTY_OPERATIONAL_STATUS:
+                       /* Old variant: CurrentState follows OperationalStatus. */
+                       if (!is_new)
+                               prop = HP_WMI_PROPERTY_CURRENT_STATE - 1;
+                       break;
+
+               case HP_WMI_PROPERTY_SIZE:
+                       /* New variant: Size == count of PossibleStates[]. */
+                       if (count != elements[i].integer.value)
+                               return -EINVAL;
+                       break;
+
+               case HP_WMI_PROPERTY_POSSIBLE_STATES:
+                       /* PossibleStates[0] has already been type-checked. */
+                       for (j = 0; i + 1 < elem_count && j + 1 < count; j++) {
+                               type = elements[++i].type;
+                               if (type != valid_type)
+                                       return -EINVAL;
+                       }
+
+                       /* Old variant: BaseUnits follows PossibleStates[]. */
+                       if (!is_new)
+                               prop = HP_WMI_PROPERTY_BASE_UNITS - 1;
+                       break;
+
+               case HP_WMI_PROPERTY_CURRENT_STATE:
+                       /* Old variant: PossibleStates[] follows CurrentState. */
+                       if (!is_new)
+                               prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1;
+                       break;
+               }
+       }
+
+       if (prop != last_prop + 1)
+               return -EINVAL;
+
+       *out_size = count;
+       *out_is_new = is_new;
+
+       return 0;
+}
+
+static int
+numeric_sensor_is_connected(const struct hp_wmi_numeric_sensor *nsensor)
+{
+       u32 operational_status = nsensor->operational_status;
+
+       return operational_status != HP_WMI_STATUS_NO_CONTACT;
+}
+
+static int numeric_sensor_has_fault(const struct hp_wmi_numeric_sensor *nsensor)
+{
+       u32 operational_status = nsensor->operational_status;
+
+       switch (operational_status) {
+       case HP_WMI_STATUS_DEGRADED:
+       case HP_WMI_STATUS_STRESSED:            /* e.g. Overload, overtemp. */
+       case HP_WMI_STATUS_PREDICTIVE_FAILURE:  /* e.g. Fan removed. */
+       case HP_WMI_STATUS_ERROR:
+       case HP_WMI_STATUS_NON_RECOVERABLE_ERROR:
+       case HP_WMI_STATUS_NO_CONTACT:
+       case HP_WMI_STATUS_LOST_COMMUNICATION:
+       case HP_WMI_STATUS_ABORTED:
+       case HP_WMI_STATUS_SUPPORTING_ENTITY_IN_ERROR:
+
+       /* Assume combination by addition; bitwise OR doesn't make sense. */
+       case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_DEGRADED:
+       case HP_WMI_STATUS_COMPLETED + HP_WMI_STATUS_ERROR:
+               return true;
+       }
+
+       return false;
+}
+
+/* scale_numeric_sensor - scale sensor reading for hwmon */
+static long scale_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)
+{
+       u32 current_reading = nsensor->current_reading;
+       s32 unit_modifier = nsensor->unit_modifier;
+       u32 sensor_type = nsensor->sensor_type;
+       u32 base_units = nsensor->base_units;
+       s32 target_modifier;
+       long val;
+
+       /* Fan readings are in RPM units; others are in milliunits. */
+       target_modifier = sensor_type == HP_WMI_TYPE_AIR_FLOW ? 0 : -3;
+
+       val = current_reading;
+
+       for (; unit_modifier < target_modifier; unit_modifier++)
+               val = DIV_ROUND_CLOSEST(val, 10);
+
+       for (; unit_modifier > target_modifier; unit_modifier--) {
+               if (val > LONG_MAX / 10) {
+                       val = LONG_MAX;
+                       break;
+               }
+               val *= 10;
+       }
+
+       if (sensor_type == HP_WMI_TYPE_TEMPERATURE) {
+               switch (base_units) {
+               case HP_WMI_UNITS_DEGREES_F:
+                       val -= MILLI * 32;
+                       val = val <= LONG_MAX / 5 ?
+                                     DIV_ROUND_CLOSEST(val * 5, 9) :
+                                     DIV_ROUND_CLOSEST(val, 9) * 5;
+                       break;
+
+               case HP_WMI_UNITS_DEGREES_K:
+                       val = milli_kelvin_to_millicelsius(val);
+                       break;
+               }
+       }
+
+       return val;
+}
+
+/*
+ * classify_numeric_sensor - classify a numeric sensor
+ * @nsensor: pointer to numeric sensor struct
+ *
+ * Returns an enum hp_wmi_type value on success,
+ * or a negative value if the sensor type is unsupported.
+ */
+static int classify_numeric_sensor(const struct hp_wmi_numeric_sensor *nsensor)
+{
+       u32 sensor_type = nsensor->sensor_type;
+       u32 base_units = nsensor->base_units;
+       const char *name = nsensor->name;
+
+       switch (sensor_type) {
+       case HP_WMI_TYPE_TEMPERATURE:
+               /*
+                * Some systems have sensors named "X Thermal Index" in "Other"
+                * units. Tested CPU sensor examples were found to be in Â°C,
+                * albeit perhaps "differently" accurate; e.g. readings were
+                * reliably -6°C vs. coretemp on a HP Compaq Elite 8300, and
+                * +8°C on an EliteOne G1 800. But this is still within the
+                * realm of plausibility for cheaply implemented motherboard
+                * sensors, and chassis readings were about as expected.
+                */
+               if ((base_units == HP_WMI_UNITS_OTHER &&
+                    strstr(name, HP_WMI_PATTERN_TEMP_SENSOR)) ||
+                   base_units == HP_WMI_UNITS_DEGREES_C ||
+                   base_units == HP_WMI_UNITS_DEGREES_F ||
+                   base_units == HP_WMI_UNITS_DEGREES_K)
+                       return HP_WMI_TYPE_TEMPERATURE;
+               break;
+
+       case HP_WMI_TYPE_VOLTAGE:
+               if (base_units == HP_WMI_UNITS_VOLTS)
+                       return HP_WMI_TYPE_VOLTAGE;
+               break;
+
+       case HP_WMI_TYPE_CURRENT:
+               if (base_units == HP_WMI_UNITS_AMPS)
+                       return HP_WMI_TYPE_CURRENT;
+               break;
+
+       case HP_WMI_TYPE_AIR_FLOW:
+               /*
+                * Strangely, HP considers fan RPM sensor type to be
+                * "Air Flow" instead of the more intuitive "Tachometer".
+                */
+               if (base_units == HP_WMI_UNITS_RPM)
+                       return HP_WMI_TYPE_AIR_FLOW;
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static int
+populate_numeric_sensor_from_wobj(struct device *dev,
+                                 struct hp_wmi_numeric_sensor *nsensor,
+                                 union acpi_object *wobj, bool *out_is_new)
+{
+       int last_prop = HP_WMI_PROPERTY_RATE_UNITS;
+       int prop = HP_WMI_PROPERTY_NAME;
+       const char **possible_states;
+       union acpi_object *element;
+       acpi_object_type type;
+       char *string;
+       bool is_new;
+       u32 value;
+       u8 size;
+       int err;
+
+       err = check_numeric_sensor_wobj(wobj, &size, &is_new);
+       if (err)
+               return err;
+
+       possible_states = devm_kcalloc(dev, size, sizeof(*possible_states),
+                                      GFP_KERNEL);
+       if (!possible_states)
+               return -ENOMEM;
+
+       element = wobj->package.elements;
+       nsensor->possible_states = possible_states;
+       nsensor->size = size;
+
+       if (!is_new)
+               last_prop = HP_WMI_PROPERTY_CURRENT_READING;
+
+       for (; prop <= last_prop; prop++) {
+               type = hp_wmi_property_map[prop];
+
+               err = extract_acpi_value(dev, element, type, &value, &string);
+               if (err)
+                       return err;
+
+               element++;
+
+               switch (prop) {
+               case HP_WMI_PROPERTY_NAME:
+                       nsensor->name = string;
+                       break;
+
+               case HP_WMI_PROPERTY_DESCRIPTION:
+                       nsensor->description = string;
+                       break;
+
+               case HP_WMI_PROPERTY_SENSOR_TYPE:
+                       if (value > HP_WMI_TYPE_AIR_FLOW)
+                               return -EINVAL;
+
+                       nsensor->sensor_type = value;
+                       break;
+
+               case HP_WMI_PROPERTY_OTHER_SENSOR_TYPE:
+                       nsensor->other_sensor_type = string;
+                       break;
+
+               case HP_WMI_PROPERTY_OPERATIONAL_STATUS:
+                       nsensor->operational_status = value;
+
+                       /* Old variant: CurrentState follows OperationalStatus. */
+                       if (!is_new)
+                               prop = HP_WMI_PROPERTY_CURRENT_STATE - 1;
+                       break;
+
+               case HP_WMI_PROPERTY_SIZE:
+                       break;                  /* Already set. */
+
+               case HP_WMI_PROPERTY_POSSIBLE_STATES:
+                       *possible_states++ = string;
+                       if (--size)
+                               prop--;
+
+                       /* Old variant: BaseUnits follows PossibleStates[]. */
+                       if (!is_new && !size)
+                               prop = HP_WMI_PROPERTY_BASE_UNITS - 1;
+                       break;
+
+               case HP_WMI_PROPERTY_CURRENT_STATE:
+                       nsensor->current_state = string;
+
+                       /* Old variant: PossibleStates[] follows CurrentState. */
+                       if (!is_new)
+                               prop = HP_WMI_PROPERTY_POSSIBLE_STATES - 1;
+                       break;
+
+               case HP_WMI_PROPERTY_BASE_UNITS:
+                       nsensor->base_units = value;
+                       break;
+
+               case HP_WMI_PROPERTY_UNIT_MODIFIER:
+                       /* UnitModifier is signed. */
+                       nsensor->unit_modifier = (s32)value;
+                       break;
+
+               case HP_WMI_PROPERTY_CURRENT_READING:
+                       nsensor->current_reading = value;
+                       break;
+
+               case HP_WMI_PROPERTY_RATE_UNITS:
+                       nsensor->rate_units = value;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       *out_is_new = is_new;
+
+       return 0;
+}
+
+/* update_numeric_sensor_from_wobj - update fungible sensor properties */
+static void
+update_numeric_sensor_from_wobj(struct device *dev,
+                               struct hp_wmi_numeric_sensor *nsensor,
+                               const union acpi_object *wobj)
+{
+       const union acpi_object *elements;
+       const union acpi_object *element;
+       const char *string;
+       bool is_new;
+       int offset;
+       u8 size;
+       int err;
+
+       err = check_numeric_sensor_wobj(wobj, &size, &is_new);
+       if (err)
+               return;
+
+       elements = wobj->package.elements;
+
+       element = &elements[HP_WMI_PROPERTY_OPERATIONAL_STATUS];
+       nsensor->operational_status = element->integer.value;
+
+       /*
+        * In general, an index offset is needed after PossibleStates[0].
+        * On a new variant, CurrentState is after PossibleStates[]. This is
+        * not the case on an old variant, but we still need to offset the
+        * read because CurrentState is where Size would be on a new variant.
+        */
+       offset = is_new ? size - 1 : -2;
+
+       element = &elements[HP_WMI_PROPERTY_CURRENT_STATE + offset];
+       string = strim(element->string.pointer);
+
+       if (strcmp(string, nsensor->current_state)) {
+               devm_kfree(dev, nsensor->current_state);
+               nsensor->current_state = hp_wmi_strdup(dev, string);
+       }
+
+       /* Old variant: -2 (not -1) because it lacks the Size property. */
+       if (!is_new)
+               offset = (int)size - 2; /* size is > 0, i.e. may be 1. */
+
+       element = &elements[HP_WMI_PROPERTY_UNIT_MODIFIER + offset];
+       nsensor->unit_modifier = (s32)element->integer.value;
+
+       element = &elements[HP_WMI_PROPERTY_CURRENT_READING + offset];
+       nsensor->current_reading = element->integer.value;
+}
+
+/*
+ * check_platform_events_wobj - validate a HPBIOS_PlatformEvents instance
+ * @wobj: pointer to WMI object instance to check
+ *
+ * Returns 0 on success, or a negative error code on error.
+ */
+static int check_platform_events_wobj(const union acpi_object *wobj)
+{
+       return check_wobj(wobj, hp_wmi_platform_events_property_map,
+                         HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS);
+}
+
+static int
+populate_platform_events_from_wobj(struct device *dev,
+                                  struct hp_wmi_platform_events *pevents,
+                                  union acpi_object *wobj)
+{
+       int last_prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS;
+       int prop = HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME;
+       union acpi_object *element;
+       acpi_object_type type;
+       char *string;
+       u32 value;
+       int err;
+
+       err = check_platform_events_wobj(wobj);
+       if (err)
+               return err;
+
+       element = wobj->package.elements;
+
+       for (; prop <= last_prop; prop++, element++) {
+               type = hp_wmi_platform_events_property_map[prop];
+
+               err = extract_acpi_value(dev, element, type, &value, &string);
+               if (err)
+                       return err;
+
+               switch (prop) {
+               case HP_WMI_PLATFORM_EVENTS_PROPERTY_NAME:
+                       pevents->name = string;
+                       break;
+
+               case HP_WMI_PLATFORM_EVENTS_PROPERTY_DESCRIPTION:
+                       pevents->description = string;
+                       break;
+
+               case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_NAMESPACE:
+                       if (strcasecmp(HP_WMI_EVENT_NAMESPACE, string))
+                               return -EINVAL;
+
+                       pevents->source_namespace = string;
+                       break;
+
+               case HP_WMI_PLATFORM_EVENTS_PROPERTY_SOURCE_CLASS:
+                       if (strcasecmp(HP_WMI_EVENT_CLASS, string))
+                               return -EINVAL;
+
+                       pevents->source_class = string;
+                       break;
+
+               case HP_WMI_PLATFORM_EVENTS_PROPERTY_CATEGORY:
+                       pevents->category = value;
+                       break;
+
+               case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_SEVERITY:
+                       pevents->possible_severity = value;
+                       break;
+
+               case HP_WMI_PLATFORM_EVENTS_PROPERTY_POSSIBLE_STATUS:
+                       pevents->possible_status = value;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * check_event_wobj - validate a HPBIOS_BIOSEvent instance
+ * @wobj: pointer to WMI object instance to check
+ *
+ * Returns 0 on success, or a negative error code on error.
+ */
+static int check_event_wobj(const union acpi_object *wobj)
+{
+       return check_wobj(wobj, hp_wmi_event_property_map,
+                         HP_WMI_EVENT_PROPERTY_STATUS);
+}
+
+static int populate_event_from_wobj(struct hp_wmi_event *event,
+                                   union acpi_object *wobj)
+{
+       int prop = HP_WMI_EVENT_PROPERTY_NAME;
+       union acpi_object *element;
+       int err;
+
+       err = check_event_wobj(wobj);
+       if (err)
+               return err;
+
+       element = wobj->package.elements;
+
+       /* Extracted strings are NOT device-managed copies. */
+
+       for (; prop <= HP_WMI_EVENT_PROPERTY_CATEGORY; prop++, element++) {
+               switch (prop) {
+               case HP_WMI_EVENT_PROPERTY_NAME:
+                       event->name = strim(element->string.pointer);
+                       break;
+
+               case HP_WMI_EVENT_PROPERTY_DESCRIPTION:
+                       event->description = strim(element->string.pointer);
+                       break;
+
+               case HP_WMI_EVENT_PROPERTY_CATEGORY:
+                       event->category = element->integer.value;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * classify_event - classify an event
+ * @name: event name
+ * @category: event category
+ *
+ * Classify instances of both HPBIOS_PlatformEvents and HPBIOS_BIOSEvent from
+ * property values. Recognition criteria are based on multiple ACPI dumps [3].
+ *
+ * Returns an enum hp_wmi_type value on success,
+ * or a negative value if the event type is unsupported.
+ */
+static int classify_event(const char *event_name, u32 category)
+{
+       if (category != HP_WMI_CATEGORY_SENSOR)
+               return -EINVAL;
+
+       /* Fan events have Name "X Stall". */
+       if (strstr(event_name, HP_WMI_PATTERN_FAN_ALARM))
+               return HP_WMI_TYPE_AIR_FLOW;
+
+       /* Intrusion events have Name "Hood Intrusion". */
+       if (!strcmp(event_name, HP_WMI_PATTERN_INTRUSION_ALARM))
+               return HP_WMI_TYPE_INTRUSION;
+
+       /*
+        * Temperature events have Name either "Thermal Caution" or
+        * "Thermal Critical". Deal only with "Thermal Critical" events.
+        *
+        * "Thermal Caution" events have Status "Stressed", informing us that
+        * the OperationalStatus of the related sensor has become "Stressed".
+        * However, this is already a fault condition that will clear itself
+        * when the sensor recovers, so we have no further interest in them.
+        */
+       if (!strcmp(event_name, HP_WMI_PATTERN_TEMP_ALARM))
+               return HP_WMI_TYPE_TEMPERATURE;
+
+       return -EINVAL;
+}
+
+/*
+ * interpret_info - interpret sensor for hwmon
+ * @info: pointer to sensor info struct
+ *
+ * Should be called after the numeric sensor member has been updated.
+ */
+static void interpret_info(struct hp_wmi_info *info)
+{
+       const struct hp_wmi_numeric_sensor *nsensor = &info->nsensor;
+
+       info->cached_val = scale_numeric_sensor(nsensor);
+       info->last_updated = jiffies;
+}
+
+/*
+ * hp_wmi_update_info - poll WMI to update sensor info
+ * @state: pointer to driver state
+ * @info: pointer to sensor info struct
+ *
+ * Returns 0 on success, or a negative error code on error.
+ */
+static int hp_wmi_update_info(struct hp_wmi_sensors *state,
+                             struct hp_wmi_info *info)
+{
+       struct hp_wmi_numeric_sensor *nsensor = &info->nsensor;
+       struct device *dev = &state->wdev->dev;
+       const union acpi_object *wobj;
+       u8 instance = info->instance;
+       int ret = 0;
+
+       if (time_after(jiffies, info->last_updated + HZ)) {
+               mutex_lock(&state->lock);
+
+               wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, instance);
+               if (!wobj) {
+                       ret = -EIO;
+                       goto out_unlock;
+               }
+
+               update_numeric_sensor_from_wobj(dev, nsensor, wobj);
+
+               interpret_info(info);
+
+               kfree(wobj);
+
+out_unlock:
+               mutex_unlock(&state->lock);
+       }
+
+       return ret;
+}
+
+static int basic_string_show(struct seq_file *seqf, void *ignored)
+{
+       const char *str = seqf->private;
+
+       seq_printf(seqf, "%s\n", str);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(basic_string);
+
+static int fungible_show(struct seq_file *seqf, enum hp_wmi_property prop)
+{
+       struct hp_wmi_numeric_sensor *nsensor;
+       struct hp_wmi_sensors *state;
+       struct hp_wmi_info *info;
+       int err;
+
+       info = seqf->private;
+       state = info->state;
+       nsensor = &info->nsensor;
+
+       err = hp_wmi_update_info(state, info);
+       if (err)
+               return err;
+
+       switch (prop) {
+       case HP_WMI_PROPERTY_OPERATIONAL_STATUS:
+               seq_printf(seqf, "%u\n", nsensor->operational_status);
+               break;
+
+       case HP_WMI_PROPERTY_CURRENT_STATE:
+               seq_printf(seqf, "%s\n", nsensor->current_state);
+               break;
+
+       case HP_WMI_PROPERTY_UNIT_MODIFIER:
+               seq_printf(seqf, "%d\n", nsensor->unit_modifier);
+               break;
+
+       case HP_WMI_PROPERTY_CURRENT_READING:
+               seq_printf(seqf, "%u\n", nsensor->current_reading);
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static int operational_status_show(struct seq_file *seqf, void *ignored)
+{
+       return fungible_show(seqf, HP_WMI_PROPERTY_OPERATIONAL_STATUS);
+}
+DEFINE_SHOW_ATTRIBUTE(operational_status);
+
+static int current_state_show(struct seq_file *seqf, void *ignored)
+{
+       return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_STATE);
+}
+DEFINE_SHOW_ATTRIBUTE(current_state);
+
+static int possible_states_show(struct seq_file *seqf, void *ignored)
+{
+       struct hp_wmi_numeric_sensor *nsensor = seqf->private;
+       u8 i;
+
+       for (i = 0; i < nsensor->size; i++)
+               seq_printf(seqf, "%s%s", i ? "," : "",
+                          nsensor->possible_states[i]);
+
+       seq_puts(seqf, "\n");
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(possible_states);
+
+static int unit_modifier_show(struct seq_file *seqf, void *ignored)
+{
+       return fungible_show(seqf, HP_WMI_PROPERTY_UNIT_MODIFIER);
+}
+DEFINE_SHOW_ATTRIBUTE(unit_modifier);
+
+static int current_reading_show(struct seq_file *seqf, void *ignored)
+{
+       return fungible_show(seqf, HP_WMI_PROPERTY_CURRENT_READING);
+}
+DEFINE_SHOW_ATTRIBUTE(current_reading);
+
+/* hp_wmi_devm_debugfs_remove - devm callback for debugfs cleanup */
+static void hp_wmi_devm_debugfs_remove(void *res)
+{
+       debugfs_remove_recursive(res);
+}
+
+/* hp_wmi_debugfs_init - create and populate debugfs directory tree */
+static void hp_wmi_debugfs_init(struct device *dev, struct hp_wmi_info *info,
+                               struct hp_wmi_platform_events *pevents,
+                               u8 icount, u8 pcount, bool is_new)
+{
+       struct hp_wmi_numeric_sensor *nsensor;
+       char buf[HP_WMI_MAX_STR_SIZE];
+       struct dentry *debugfs;
+       struct dentry *entries;
+       struct dentry *dir;
+       int err;
+       u8 i;
+
+       /* dev_name() gives a not-very-friendly GUID for WMI devices. */
+       scnprintf(buf, sizeof(buf), "hp-wmi-sensors-%u", dev->id);
+
+       debugfs = debugfs_create_dir(buf, NULL);
+       if (IS_ERR(debugfs))
+               return;
+
+       err = devm_add_action_or_reset(dev, hp_wmi_devm_debugfs_remove,
+                                      debugfs);
+       if (err)
+               return;
+
+       entries = debugfs_create_dir("sensor", debugfs);
+
+       for (i = 0; i < icount; i++, info++) {
+               nsensor = &info->nsensor;
+
+               scnprintf(buf, sizeof(buf), "%u", i);
+               dir = debugfs_create_dir(buf, entries);
+
+               debugfs_create_file("name", 0444, dir,
+                                   (void *)nsensor->name,
+                                   &basic_string_fops);
+
+               debugfs_create_file("description", 0444, dir,
+                                   (void *)nsensor->description,
+                                   &basic_string_fops);
+
+               debugfs_create_u32("sensor_type", 0444, dir,
+                                  &nsensor->sensor_type);
+
+               debugfs_create_file("other_sensor_type", 0444, dir,
+                                   (void *)nsensor->other_sensor_type,
+                                   &basic_string_fops);
+
+               debugfs_create_file("operational_status", 0444, dir,
+                                   info, &operational_status_fops);
+
+               debugfs_create_file("possible_states", 0444, dir,
+                                   nsensor, &possible_states_fops);
+
+               debugfs_create_file("current_state", 0444, dir,
+                                   info, &current_state_fops);
+
+               debugfs_create_u32("base_units", 0444, dir,
+                                  &nsensor->base_units);
+
+               debugfs_create_file("unit_modifier", 0444, dir,
+                                   info, &unit_modifier_fops);
+
+               debugfs_create_file("current_reading", 0444, dir,
+                                   info, &current_reading_fops);
+
+               if (is_new)
+                       debugfs_create_u32("rate_units", 0444, dir,
+                                          &nsensor->rate_units);
+       }
+
+       if (!pcount)
+               return;
+
+       entries = debugfs_create_dir("platform_events", debugfs);
+
+       for (i = 0; i < pcount; i++, pevents++) {
+               scnprintf(buf, sizeof(buf), "%u", i);
+               dir = debugfs_create_dir(buf, entries);
+
+               debugfs_create_file("name", 0444, dir,
+                                   (void *)pevents->name,
+                                   &basic_string_fops);
+
+               debugfs_create_file("description", 0444, dir,
+                                   (void *)pevents->description,
+                                   &basic_string_fops);
+
+               debugfs_create_file("source_namespace", 0444, dir,
+                                   (void *)pevents->source_namespace,
+                                   &basic_string_fops);
+
+               debugfs_create_file("source_class", 0444, dir,
+                                   (void *)pevents->source_class,
+                                   &basic_string_fops);
+
+               debugfs_create_u32("category", 0444, dir,
+                                  &pevents->category);
+
+               debugfs_create_u32("possible_severity", 0444, dir,
+                                  &pevents->possible_severity);
+
+               debugfs_create_u32("possible_status", 0444, dir,
+                                  &pevents->possible_status);
+       }
+}
+
+static umode_t hp_wmi_hwmon_is_visible(const void *drvdata,
+                                      enum hwmon_sensor_types type,
+                                      u32 attr, int channel)
+{
+       const struct hp_wmi_sensors *state = drvdata;
+       const struct hp_wmi_info *info;
+
+       if (type == hwmon_intrusion)
+               return state->has_intrusion ? 0644 : 0;
+
+       if (!state->info_map[type] || !state->info_map[type][channel])
+               return 0;
+
+       info = state->info_map[type][channel];
+
+       if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
+           (type == hwmon_fan  && attr == hwmon_fan_alarm))
+               return info->has_alarm ? 0444 : 0;
+
+       return 0444;
+}
+
+static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+                            u32 attr, int channel, long *out_val)
+{
+       struct hp_wmi_sensors *state = dev_get_drvdata(dev);
+       const struct hp_wmi_numeric_sensor *nsensor;
+       struct hp_wmi_info *info;
+       int err;
+
+       if (type == hwmon_intrusion) {
+               *out_val = state->intrusion ? 1 : 0;
+
+               return 0;
+       }
+
+       info = state->info_map[type][channel];
+
+       if ((type == hwmon_temp && attr == hwmon_temp_alarm) ||
+           (type == hwmon_fan  && attr == hwmon_fan_alarm)) {
+               *out_val = info->alarm ? 1 : 0;
+               info->alarm = false;
+
+               return 0;
+       }
+
+       nsensor = &info->nsensor;
+
+       err = hp_wmi_update_info(state, info);
+       if (err)
+               return err;
+
+       if ((type == hwmon_temp && attr == hwmon_temp_fault) ||
+           (type == hwmon_fan  && attr == hwmon_fan_fault))
+               *out_val = numeric_sensor_has_fault(nsensor);
+       else
+               *out_val = info->cached_val;
+
+       return 0;
+}
+
+static int hp_wmi_hwmon_read_string(struct device *dev,
+                                   enum hwmon_sensor_types type, u32 attr,
+                                   int channel, const char **out_str)
+{
+       const struct hp_wmi_sensors *state = dev_get_drvdata(dev);
+       const struct hp_wmi_info *info;
+
+       info = state->info_map[type][channel];
+       *out_str = info->nsensor.name;
+
+       return 0;
+}
+
+static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+                             u32 attr, int channel, long val)
+{
+       struct hp_wmi_sensors *state = dev_get_drvdata(dev);
+
+       if (val)
+               return -EINVAL;
+
+       mutex_lock(&state->lock);
+
+       state->intrusion = false;
+
+       mutex_unlock(&state->lock);
+
+       return 0;
+}
+
+static const struct hwmon_ops hp_wmi_hwmon_ops = {
+       .is_visible  = hp_wmi_hwmon_is_visible,
+       .read        = hp_wmi_hwmon_read,
+       .read_string = hp_wmi_hwmon_read_string,
+       .write       = hp_wmi_hwmon_write,
+};
+
+static struct hwmon_chip_info hp_wmi_chip_info = {
+       .ops         = &hp_wmi_hwmon_ops,
+       .info        = NULL,
+};
+
+static struct hp_wmi_info *match_fan_event(struct hp_wmi_sensors *state,
+                                          const char *event_description)
+{
+       struct hp_wmi_info **ptr_info = state->info_map[hwmon_fan];
+       u8 fan_count = state->channel_count[hwmon_fan];
+       struct hp_wmi_info *info;
+       const char *name;
+       u8 i;
+
+       /* Fan event has Description "X Speed". Sensor has Name "X[ Speed]". */
+
+       for (i = 0; i < fan_count; i++, ptr_info++) {
+               info = *ptr_info;
+               name = info->nsensor.name;
+
+               if (strstr(event_description, name))
+                       return info;
+       }
+
+       return NULL;
+}
+
+static u8 match_temp_events(struct hp_wmi_sensors *state,
+                           const char *event_description,
+                           struct hp_wmi_info *temp_info[])
+{
+       struct hp_wmi_info **ptr_info = state->info_map[hwmon_temp];
+       u8 temp_count = state->channel_count[hwmon_temp];
+       struct hp_wmi_info *info;
+       const char *name;
+       u8 count = 0;
+       bool is_cpu;
+       bool is_sys;
+       u8 i;
+
+       /* Description is either "CPU Thermal Index" or "Chassis Thermal Index". */
+
+       is_cpu = !strcmp(event_description, HP_WMI_PATTERN_CPU_TEMP);
+       is_sys = !strcmp(event_description, HP_WMI_PATTERN_SYS_TEMP);
+       if (!is_cpu && !is_sys)
+               return 0;
+
+       /*
+        * CPU event: Match one sensor with Name either "CPU Thermal Index" or
+        * "CPU Temperature", or multiple with Name(s) "CPU[#] Temperature".
+        *
+        * Chassis event: Match one sensor with Name either
+        * "Chassis Thermal Index" or "System Ambient Temperature".
+        */
+
+       for (i = 0; i < temp_count; i++, ptr_info++) {
+               info = *ptr_info;
+               name = info->nsensor.name;
+
+               if ((is_cpu && (!strcmp(name, HP_WMI_PATTERN_CPU_TEMP) ||
+                               !strcmp(name, HP_WMI_PATTERN_CPU_TEMP2))) ||
+                   (is_sys && (!strcmp(name, HP_WMI_PATTERN_SYS_TEMP) ||
+                               !strcmp(name, HP_WMI_PATTERN_SYS_TEMP2)))) {
+                       temp_info[0] = info;
+                       return 1;
+               }
+
+               if (is_cpu && (strstr(name, HP_WMI_PATTERN_CPU) &&
+                              strstr(name, HP_WMI_PATTERN_TEMP)))
+                       temp_info[count++] = info;
+       }
+
+       return count;
+}
+
+/* hp_wmi_devm_debugfs_remove - devm callback for WMI event handler removal */
+static void hp_wmi_devm_notify_remove(void *ignored)
+{
+       wmi_remove_notify_handler(HP_WMI_EVENT_GUID);
+}
+
+/* hp_wmi_notify - WMI event notification handler */
+static void hp_wmi_notify(u32 value, void *context)
+{
+       struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {};
+       struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct hp_wmi_sensors *state = context;
+       struct device *dev = &state->wdev->dev;
+       struct hp_wmi_info *fan_info;
+       struct hp_wmi_event event;
+       union acpi_object *wobj;
+       acpi_status err;
+       int event_type;
+       u8 count;
+
+       /*
+        * The following warning may occur in the kernel log:
+        *
+        *   ACPI Warning: \_SB.WMID._WED: Return type mismatch -
+        *     found Package, expected Integer/String/Buffer
+        *
+        * After using [4] to decode BMOF blobs found in [3], careless copying
+        * of BIOS code seems the most likely explanation for this warning.
+        * HP_WMI_EVENT_GUID refers to \\.\root\WMI\HPBIOS_BIOSEvent on
+        * business-class systems, but it refers to \\.\root\WMI\hpqBEvnt on
+        * non-business-class systems. Per the existing hp-wmi driver, it
+        * looks like an instance of hpqBEvnt delivered as event data may
+        * indeed take the form of a raw ACPI_BUFFER on non-business-class
+        * systems ("may" because ASL shows some BIOSes do strange things).
+        *
+        * In any case, we can ignore this warning, because we always validate
+        * the event data to ensure it is an ACPI_PACKAGE containing a
+        * HPBIOS_BIOSEvent instance.
+        */
+
+       mutex_lock(&state->lock);
+
+       err = wmi_get_event_data(value, &out);
+       if (ACPI_FAILURE(err))
+               goto out_unlock;
+
+       wobj = out.pointer;
+
+       err = populate_event_from_wobj(&event, wobj);
+       if (err) {
+               dev_warn(dev, "Bad event data (ACPI type %d)\n", wobj->type);
+               goto out_free_wobj;
+       }
+
+       event_type = classify_event(event.name, event.category);
+       switch (event_type) {
+       case HP_WMI_TYPE_AIR_FLOW:
+               fan_info = match_fan_event(state, event.description);
+               if (fan_info)
+                       fan_info->alarm = true;
+               break;
+
+       case HP_WMI_TYPE_INTRUSION:
+               state->intrusion = true;
+               break;
+
+       case HP_WMI_TYPE_TEMPERATURE:
+               count = match_temp_events(state, event.description, temp_info);
+               while (count)
+                       temp_info[--count]->alarm = true;
+               break;
+
+       default:
+               break;
+       }
+
+out_free_wobj:
+       kfree(wobj);
+
+out_unlock:
+       mutex_unlock(&state->lock);
+}
+
+static int init_platform_events(struct device *dev,
+                               struct hp_wmi_platform_events **out_pevents,
+                               u8 *out_pcount)
+{
+       struct hp_wmi_platform_events *pevents_arr;
+       struct hp_wmi_platform_events *pevents;
+       union acpi_object *wobj;
+       u8 count;
+       int err;
+       u8 i;
+
+       count = hp_wmi_wobj_instance_count(HP_WMI_PLATFORM_EVENTS_GUID);
+       if (!count) {
+               *out_pcount = 0;
+
+               dev_dbg(dev, "No platform events\n");
+
+               return 0;
+       }
+
+       pevents_arr = devm_kcalloc(dev, count, sizeof(*pevents), GFP_KERNEL);
+       if (!pevents_arr)
+               return -ENOMEM;
+
+       for (i = 0, pevents = pevents_arr; i < count; i++, pevents++) {
+               wobj = hp_wmi_get_wobj(HP_WMI_PLATFORM_EVENTS_GUID, i);
+               if (!wobj)
+                       return -EIO;
+
+               err = populate_platform_events_from_wobj(dev, pevents, wobj);
+
+               kfree(wobj);
+
+               if (err)
+                       return err;
+       }
+
+       *out_pevents = pevents_arr;
+       *out_pcount = count;
+
+       dev_dbg(dev, "Found %u platform events\n", count);
+
+       return 0;
+}
+
+static int init_numeric_sensors(struct hp_wmi_sensors *state,
+                               struct hp_wmi_info *connected[],
+                               struct hp_wmi_info **out_info,
+                               u8 *out_icount, u8 *out_count,
+                               bool *out_is_new)
+{
+       struct hp_wmi_info ***info_map = state->info_map;
+       u8 *channel_count = state->channel_count;
+       struct device *dev = &state->wdev->dev;
+       struct hp_wmi_numeric_sensor *nsensor;
+       u8 channel_index[hwmon_max] = {};
+       enum hwmon_sensor_types type;
+       struct hp_wmi_info *info_arr;
+       struct hp_wmi_info *info;
+       union acpi_object *wobj;
+       u8 count = 0;
+       bool is_new;
+       u8 icount;
+       int wtype;
+       int err;
+       u8 c;
+       u8 i;
+
+       icount = hp_wmi_wobj_instance_count(HP_WMI_NUMERIC_SENSOR_GUID);
+       if (!icount)
+               return -ENODATA;
+
+       info_arr = devm_kcalloc(dev, icount, sizeof(*info), GFP_KERNEL);
+       if (!info_arr)
+               return -ENOMEM;
+
+       for (i = 0, info = info_arr; i < icount; i++, info++) {
+               wobj = hp_wmi_get_wobj(HP_WMI_NUMERIC_SENSOR_GUID, i);
+               if (!wobj)
+                       return -EIO;
+
+               info->instance = i;
+               info->state = state;
+               nsensor = &info->nsensor;
+
+               err = populate_numeric_sensor_from_wobj(dev, nsensor, wobj,
+                                                       &is_new);
+
+               kfree(wobj);
+
+               if (err)
+                       return err;
+
+               if (!numeric_sensor_is_connected(nsensor))
+                       continue;
+
+               wtype = classify_numeric_sensor(nsensor);
+               if (wtype < 0)
+                       continue;
+
+               type = hp_wmi_hwmon_type_map[wtype];
+
+               channel_count[type]++;
+
+               info->type = type;
+
+               interpret_info(info);
+
+               connected[count++] = info;
+       }
+
+       dev_dbg(dev, "Found %u sensors (%u connected)\n", i, count);
+
+       for (i = 0; i < count; i++) {
+               info = connected[i];
+               type = info->type;
+               c = channel_index[type]++;
+
+               if (!info_map[type]) {
+                       info_map[type] = devm_kcalloc(dev, channel_count[type],
+                                                     sizeof(*info_map),
+                                                     GFP_KERNEL);
+                       if (!info_map[type])
+                               return -ENOMEM;
+               }
+
+               info_map[type][c] = info;
+       }
+
+       *out_info = info_arr;
+       *out_icount = icount;
+       *out_count = count;
+       *out_is_new = is_new;
+
+       return 0;
+}
+
+static bool find_event_attributes(struct hp_wmi_sensors *state,
+                                 struct hp_wmi_platform_events *pevents,
+                                 u8 pevents_count)
+{
+       /*
+        * The existence of this HPBIOS_PlatformEvents instance:
+        *
+        *   {
+        *     Name = "Rear Chassis Fan0 Stall";
+        *     Description = "Rear Chassis Fan0 Speed";
+        *     Category = 3;           // "Sensor"
+        *     PossibleSeverity = 25;  // "Critical Failure"
+        *     PossibleStatus = 5;     // "Predictive Failure"
+        *     [...]
+        *   }
+        *
+        * means that this HPBIOS_BIOSEvent instance may occur:
+        *
+        *   {
+        *     Name = "Rear Chassis Fan0 Stall";
+        *     Description = "Rear Chassis Fan0 Speed";
+        *     Category = 3;           // "Sensor"
+        *     Severity = 25;          // "Critical Failure"
+        *     Status = 5;             // "Predictive Failure"
+        *   }
+        *
+        * After the event occurs (e.g. because the fan was unplugged),
+        * polling the related HPBIOS_BIOSNumericSensor instance gives:
+        *
+        *   {
+        *      Name = "Rear Chassis Fan0";
+        *      Description = "Reports rear chassis fan0 speed";
+        *      OperationalStatus = 5; // "Predictive Failure", was 3 ("OK")
+        *      CurrentReading = 0;
+        *      [...]
+        *   }
+        *
+        * In this example, the hwmon fan channel for "Rear Chassis Fan0"
+        * should support the alarm flag and have it be set if the related
+        * HPBIOS_BIOSEvent instance occurs.
+        *
+        * In addition to fan events, temperature (CPU/chassis) and intrusion
+        * events are relevant to hwmon [2]. Note that much information in [2]
+        * is unreliable; it is referenced in addition to ACPI dumps [3] merely
+        * to support the conclusion that sensor and event names/descriptions
+        * are systematic enough to allow this driver to match them.
+        *
+        * Complications and limitations:
+        *
+        * - Strings are freeform and may vary, cf. sensor Name "CPU0 Fan"
+        *   on a Z420 vs. "CPU Fan Speed" on an EliteOne 800 G1.
+        * - Leading/trailing whitespace is a rare but real possibility [3].
+        * - The HPBIOS_PlatformEvents object may not exist or its instances
+        *   may show that the system only has e.g. BIOS setting-related
+        *   events (cf. the ProBook 4540s and ProBook 470 G0 [3]).
+        */
+
+       struct hp_wmi_info *temp_info[HP_WMI_MAX_INSTANCES] = {};
+       const char *event_description;
+       struct hp_wmi_info *fan_info;
+       bool has_events = false;
+       const char *event_name;
+       u32 event_category;
+       int event_type;
+       u8 count;
+       u8 i;
+
+       for (i = 0; i < pevents_count; i++, pevents++) {
+               event_name = pevents->name;
+               event_description = pevents->description;
+               event_category = pevents->category;
+
+               event_type = classify_event(event_name, event_category);
+               switch (event_type) {
+               case HP_WMI_TYPE_AIR_FLOW:
+                       fan_info = match_fan_event(state, event_description);
+                       if (!fan_info)
+                               break;
+
+                       fan_info->has_alarm = true;
+                       has_events = true;
+                       break;
+
+               case HP_WMI_TYPE_INTRUSION:
+                       state->has_intrusion = true;
+                       has_events = true;
+                       break;
+
+               case HP_WMI_TYPE_TEMPERATURE:
+                       count = match_temp_events(state, event_description,
+                                                 temp_info);
+                       if (!count)
+                               break;
+
+                       while (count)
+                               temp_info[--count]->has_alarm = true;
+                       has_events = true;
+                       break;
+
+               default:
+                       break;
+               }
+       }
+
+       return has_events;
+}
+
+static int make_chip_info(struct hp_wmi_sensors *state, bool has_events)
+{
+       const struct hwmon_channel_info **ptr_channel_info;
+       struct hp_wmi_info ***info_map = state->info_map;
+       u8 *channel_count = state->channel_count;
+       struct hwmon_channel_info *channel_info;
+       struct device *dev = &state->wdev->dev;
+       enum hwmon_sensor_types type;
+       u8 type_count = 0;
+       u32 *config;
+       u32 attr;
+       u8 count;
+       u8 i;
+
+       if (channel_count[hwmon_temp])
+               channel_count[hwmon_chip] = 1;
+
+       if (has_events && state->has_intrusion)
+               channel_count[hwmon_intrusion] = 1;
+
+       for (type = hwmon_chip; type < hwmon_max; type++)
+               if (channel_count[type])
+                       type_count++;
+
+       channel_info = devm_kcalloc(dev, type_count,
+                                   sizeof(*channel_info), GFP_KERNEL);
+       if (!channel_info)
+               return -ENOMEM;
+
+       ptr_channel_info = devm_kcalloc(dev, type_count + 1,
+                                       sizeof(*ptr_channel_info), GFP_KERNEL);
+       if (!ptr_channel_info)
+               return -ENOMEM;
+
+       hp_wmi_chip_info.info = ptr_channel_info;
+
+       for (type = hwmon_chip; type < hwmon_max; type++) {
+               count = channel_count[type];
+               if (!count)
+                       continue;
+
+               config = devm_kcalloc(dev, count + 1,
+                                     sizeof(*config), GFP_KERNEL);
+               if (!config)
+                       return -ENOMEM;
+
+               attr = hp_wmi_hwmon_attributes[type];
+               channel_info->type = type;
+               channel_info->config = config;
+               memset32(config, attr, count);
+
+               *ptr_channel_info++ = channel_info++;
+
+               if (!has_events || (type != hwmon_temp && type != hwmon_fan))
+                       continue;
+
+               attr = type == hwmon_temp ? HWMON_T_ALARM : HWMON_F_ALARM;
+
+               for (i = 0; i < count; i++)
+                       if (info_map[type][i]->has_alarm)
+                               config[i] |= attr;
+       }
+
+       return 0;
+}
+
+static bool add_event_handler(struct hp_wmi_sensors *state)
+{
+       struct device *dev = &state->wdev->dev;
+       int err;
+
+       err = wmi_install_notify_handler(HP_WMI_EVENT_GUID,
+                                        hp_wmi_notify, state);
+       if (err) {
+               dev_info(dev, "Failed to subscribe to WMI event\n");
+               return false;
+       }
+
+       err = devm_add_action_or_reset(dev, hp_wmi_devm_notify_remove, NULL);
+       if (err)
+               return false;
+
+       return true;
+}
+
+static int hp_wmi_sensors_init(struct hp_wmi_sensors *state)
+{
+       struct hp_wmi_info *connected[HP_WMI_MAX_INSTANCES];
+       struct hp_wmi_platform_events *pevents;
+       struct device *dev = &state->wdev->dev;
+       struct hp_wmi_info *info;
+       struct device *hwdev;
+       bool has_events;
+       bool is_new;
+       u8 icount;
+       u8 pcount;
+       u8 count;
+       int err;
+
+       err = init_platform_events(dev, &pevents, &pcount);
+       if (err)
+               return err;
+
+       err = init_numeric_sensors(state, connected, &info,
+                                  &icount, &count, &is_new);
+       if (err)
+               return err;
+
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+               hp_wmi_debugfs_init(dev, info, pevents, icount, pcount, is_new);
+
+       if (!count)
+               return 0;       /* No connected sensors; debugfs only. */
+
+       has_events = find_event_attributes(state, pevents, pcount);
+
+       /* Survive failure to install WMI event handler. */
+       if (has_events && !add_event_handler(state))
+               has_events = false;
+
+       err = make_chip_info(state, has_events);
+       if (err)
+               return err;
+
+       hwdev = devm_hwmon_device_register_with_info(dev, "hp_wmi_sensors",
+                                                    state, &hp_wmi_chip_info,
+                                                    NULL);
+       return PTR_ERR_OR_ZERO(hwdev);
+}
+
+static int hp_wmi_sensors_probe(struct wmi_device *wdev, const void *context)
+{
+       struct device *dev = &wdev->dev;
+       struct hp_wmi_sensors *state;
+
+       state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       state->wdev = wdev;
+
+       mutex_init(&state->lock);
+
+       dev_set_drvdata(dev, state);
+
+       return hp_wmi_sensors_init(state);
+}
+
+static const struct wmi_device_id hp_wmi_sensors_id_table[] = {
+       { HP_WMI_NUMERIC_SENSOR_GUID, NULL },
+       {},
+};
+
+static struct wmi_driver hp_wmi_sensors_driver = {
+       .driver   = { .name = "hp-wmi-sensors" },
+       .id_table = hp_wmi_sensors_id_table,
+       .probe    = hp_wmi_sensors_probe,
+};
+module_wmi_driver(hp_wmi_sensors_driver);
+
+MODULE_AUTHOR("James Seo <james@equiv.tech>");
+MODULE_DESCRIPTION("HP WMI Sensors driver");
+MODULE_LICENSE("GPL");
index 573b83b..c7dd3f5 100644 (file)
@@ -456,6 +456,7 @@ static const char * const hwmon_chip_attrs[] = {
        [hwmon_chip_in_samples] = "in_samples",
        [hwmon_chip_power_samples] = "power_samples",
        [hwmon_chip_temp_samples] = "temp_samples",
+       [hwmon_chip_beep_enable] = "beep_enable",
 };
 
 static const char * const hwmon_temp_attr_templates[] = {
@@ -486,6 +487,7 @@ static const char * const hwmon_temp_attr_templates[] = {
        [hwmon_temp_reset_history] = "temp%d_reset_history",
        [hwmon_temp_rated_min] = "temp%d_rated_min",
        [hwmon_temp_rated_max] = "temp%d_rated_max",
+       [hwmon_temp_beep] = "temp%d_beep",
 };
 
 static const char * const hwmon_in_attr_templates[] = {
@@ -507,6 +509,7 @@ static const char * const hwmon_in_attr_templates[] = {
        [hwmon_in_crit_alarm] = "in%d_crit_alarm",
        [hwmon_in_rated_min] = "in%d_rated_min",
        [hwmon_in_rated_max] = "in%d_rated_max",
+       [hwmon_in_beep] = "in%d_beep",
 };
 
 static const char * const hwmon_curr_attr_templates[] = {
@@ -528,6 +531,7 @@ static const char * const hwmon_curr_attr_templates[] = {
        [hwmon_curr_crit_alarm] = "curr%d_crit_alarm",
        [hwmon_curr_rated_min] = "curr%d_rated_min",
        [hwmon_curr_rated_max] = "curr%d_rated_max",
+       [hwmon_curr_beep] = "curr%d_beep",
 };
 
 static const char * const hwmon_power_attr_templates[] = {
@@ -597,6 +601,7 @@ static const char * const hwmon_fan_attr_templates[] = {
        [hwmon_fan_min_alarm] = "fan%d_min_alarm",
        [hwmon_fan_max_alarm] = "fan%d_max_alarm",
        [hwmon_fan_fault] = "fan%d_fault",
+       [hwmon_fan_beep] = "fan%d_beep",
 };
 
 static const char * const hwmon_pwm_attr_templates[] = {
@@ -1029,7 +1034,7 @@ EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups);
  * @name:      hwmon name attribute
  * @drvdata:   driver data to attach to created device
  * @chip:      pointer to hwmon chip information
- * @groups:    pointer to list of driver specific attribute groups
+ * @extra_groups: pointer to list of driver specific attribute groups
  *
  * Returns the pointer to the new device. The new device is automatically
  * unregistered with the parent device.
@@ -1038,7 +1043,7 @@ struct device *
 devm_hwmon_device_register_with_info(struct device *dev, const char *name,
                                     void *drvdata,
                                     const struct hwmon_chip_info *chip,
-                                    const struct attribute_group **groups)
+                                    const struct attribute_group **extra_groups)
 {
        struct device **ptr, *hwdev;
 
@@ -1050,7 +1055,7 @@ devm_hwmon_device_register_with_info(struct device *dev, const char *name,
                return ERR_PTR(-ENOMEM);
 
        hwdev = hwmon_device_register_with_info(dev, name, drvdata, chip,
-                                               groups);
+                                               extra_groups);
        if (IS_ERR(hwdev))
                goto error;
 
index 9b58655..c558143 100644 (file)
@@ -594,7 +594,7 @@ static struct i2c_driver ina209_driver = {
                .name   = "ina209",
                .of_match_table = of_match_ptr(ina209_of_match),
        },
-       .probe_new      = ina209_probe,
+       .probe          = ina209_probe,
        .remove         = ina209_remove,
        .id_table       = ina209_id,
 };
index 8af07bc..f519c22 100644 (file)
@@ -633,7 +633,7 @@ static struct i2c_driver ina238_driver = {
                .name   = "ina238",
                .of_match_table = of_match_ptr(ina238_of_match),
        },
-       .probe_new      = ina238_probe,
+       .probe          = ina238_probe,
        .id_table       = ina238_id,
 };
 
index fd50d97..cfd7efe 100644 (file)
@@ -721,7 +721,7 @@ static struct i2c_driver ina2xx_driver = {
                .name   = "ina2xx",
                .of_match_table = of_match_ptr(ina2xx_of_match),
        },
-       .probe_new      = ina2xx_probe,
+       .probe          = ina2xx_probe,
        .id_table       = ina2xx_id,
 };
 
index 2735e37..5ab9440 100644 (file)
@@ -1010,7 +1010,7 @@ static const struct i2c_device_id ina3221_ids[] = {
 MODULE_DEVICE_TABLE(i2c, ina3221_ids);
 
 static struct i2c_driver ina3221_i2c_driver = {
-       .probe_new = ina3221_probe,
+       .probe = ina3221_probe,
        .remove = ina3221_remove,
        .driver = {
                .name = INA3221_DRIVER_NAME,
index eb38f54..5deff5e 100644 (file)
@@ -317,31 +317,37 @@ struct it87_devices {
  * chips to avoid the problem.
  */
 #define FEAT_CONF_NOEXIT       BIT(19) /* Chip should not exit conf mode */
+#define FEAT_FOUR_FANS         BIT(20) /* Supports four fans */
+#define FEAT_FOUR_PWM          BIT(21) /* Supports four fan controls */
+#define FEAT_FOUR_TEMP         BIT(22)
+#define FEAT_FANCTL_ONOFF      BIT(23) /* chip has FAN_CTL ON/OFF */
 
 static const struct it87_devices it87_devices[] = {
        [it87] = {
                .name = "it87",
                .model = "IT87F",
-               .features = FEAT_OLD_AUTOPWM,   /* may need to overwrite */
+               .features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF,
+               /* may need to overwrite */
        },
        [it8712] = {
                .name = "it8712",
                .model = "IT8712F",
-               .features = FEAT_OLD_AUTOPWM | FEAT_VID,
-                                               /* may need to overwrite */
+               .features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF,
+               /* may need to overwrite */
        },
        [it8716] = {
                .name = "it8716",
                .model = "IT8716F",
                .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
-                 | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2,
+                 | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2
+                 | FEAT_FANCTL_ONOFF,
        },
        [it8718] = {
                .name = "it8718",
                .model = "IT8718F",
                .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
                  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .old_peci_mask = 0x4,
        },
        [it8720] = {
@@ -349,7 +355,7 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8720F",
                .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
                  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .old_peci_mask = 0x4,
        },
        [it8721] = {
@@ -358,7 +364,7 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
                  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .peci_mask = 0x05,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -367,7 +373,8 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8728F",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
-                 | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
+                 | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
+                 | FEAT_FANCTL_ONOFF,
                .peci_mask = 0x07,
        },
        [it8732] = {
@@ -375,7 +382,8 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8732F",
                .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
-                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
+                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
+                 | FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
                .peci_mask = 0x07,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -384,7 +392,7 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8771E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                                /* PECI: guesswork */
                                /* 12mV ADC (OHM) */
                                /* 16 bit fans (OHM) */
@@ -396,7 +404,7 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8772E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                                /* PECI (coreboot) */
                                /* 12mV ADC (HWSensors4, OHM) */
                                /* 16 bit fans (HWSensors4, OHM) */
@@ -407,21 +415,24 @@ static const struct it87_devices it87_devices[] = {
                .name = "it8781",
                .model = "IT8781F",
                .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
-                 | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
+                 | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
+                 | FEAT_FANCTL_ONOFF,
                .old_peci_mask = 0x4,
        },
        [it8782] = {
                .name = "it8782",
                .model = "IT8782F",
                .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
-                 | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
+                 | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
+                 | FEAT_FANCTL_ONOFF,
                .old_peci_mask = 0x4,
        },
        [it8783] = {
                .name = "it8783",
                .model = "IT8783E/F",
                .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
-                 | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
+                 | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
+                 | FEAT_FANCTL_ONOFF,
                .old_peci_mask = 0x4,
        },
        [it8786] = {
@@ -429,7 +440,7 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8786E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2,
+                 | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
                .peci_mask = 0x07,
        },
        [it8790] = {
@@ -437,7 +448,7 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8790E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
-                 | FEAT_PWM_FREQ2 | FEAT_CONF_NOEXIT,
+                 | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_CONF_NOEXIT,
                .peci_mask = 0x07,
        },
        [it8792] = {
@@ -445,7 +456,8 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT8792E/IT8795E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
-                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
+                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
+                 | FEAT_CONF_NOEXIT,
                .peci_mask = 0x07,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -463,7 +475,7 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
                  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
-                 | FEAT_SIX_TEMP | FEAT_VIN3_5V,
+                 | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
                .peci_mask = 0x07,
        },
        [it8622] = {
@@ -472,7 +484,7 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
                  | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
-                 | FEAT_AVCC3 | FEAT_VIN3_5V,
+                 | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP,
                .peci_mask = 0x07,
                .smbus_bitmap = BIT(1) | BIT(2),
        },
@@ -482,7 +494,7 @@ static const struct it87_devices it87_devices[] = {
                .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
                  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
-                 | FEAT_SIX_TEMP | FEAT_VIN3_5V,
+                 | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
                .peci_mask = 0x07,
        },
        [it87952] = {
@@ -490,7 +502,8 @@ static const struct it87_devices it87_devices[] = {
                .model = "IT87952E",
                .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
                  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
-                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
+                 | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
+                 | FEAT_CONF_NOEXIT,
                .peci_mask = 0x07,
                .old_peci_mask = 0x02,  /* Actually reports PCH */
        },
@@ -508,21 +521,29 @@ static const struct it87_devices it87_devices[] = {
                                (((data)->features & FEAT_TEMP_OLD_PECI) && \
                                 ((data)->old_peci_mask & BIT(nr)))
 #define has_fan16_config(data) ((data)->features & FEAT_FAN16_CONFIG)
+#define has_four_fans(data)    ((data)->features & (FEAT_FOUR_FANS | \
+                                                    FEAT_FIVE_FANS | \
+                                                    FEAT_SIX_FANS))
 #define has_five_fans(data)    ((data)->features & (FEAT_FIVE_FANS | \
                                                     FEAT_SIX_FANS))
+#define has_six_fans(data)     ((data)->features & FEAT_SIX_FANS)
 #define has_vid(data)          ((data)->features & FEAT_VID)
 #define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL)
-#define has_six_fans(data)     ((data)->features & FEAT_SIX_FANS)
 #define has_avcc3(data)                ((data)->features & FEAT_AVCC3)
-#define has_five_pwm(data)     ((data)->features & (FEAT_FIVE_PWM \
-                                                    | FEAT_SIX_PWM))
+#define has_four_pwm(data)     ((data)->features & (FEAT_FOUR_PWM | \
+                                                    FEAT_FIVE_PWM | \
+                                                    FEAT_SIX_PWM))
+#define has_five_pwm(data)     ((data)->features & (FEAT_FIVE_PWM | \
+                                                    FEAT_SIX_PWM))
 #define has_six_pwm(data)      ((data)->features & FEAT_SIX_PWM)
 #define has_pwm_freq2(data)    ((data)->features & FEAT_PWM_FREQ2)
+#define has_four_temp(data)    ((data)->features & FEAT_FOUR_TEMP)
 #define has_six_temp(data)     ((data)->features & FEAT_SIX_TEMP)
 #define has_vin3_5v(data)      ((data)->features & FEAT_VIN3_5V)
 #define has_conf_noexit(data)  ((data)->features & FEAT_CONF_NOEXIT)
 #define has_scaling(data)      ((data)->features & (FEAT_12MV_ADC | \
                                                     FEAT_10_9MV_ADC))
+#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF)
 
 struct it87_sio_data {
        int sioaddr;
@@ -1229,11 +1250,12 @@ static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
 
 static int pwm_mode(const struct it87_data *data, int nr)
 {
-       if (data->type != it8603 && nr < 3 && !(data->fan_main_ctrl & BIT(nr)))
-               return 0;                               /* Full speed */
+       if (has_fanctl_onoff(data) && nr < 3 &&
+           !(data->fan_main_ctrl & BIT(nr)))
+               return 0;                       /* Full speed */
        if (data->pwm_ctrl[nr] & 0x80)
-               return 2;                               /* Automatic mode */
-       if ((data->type == it8603 || nr >= 3) &&
+               return 2;                       /* Automatic mode */
+       if ((!has_fanctl_onoff(data) || nr >= 3) &&
            data->pwm_duty[nr] == pwm_to_reg(data, 0xff))
                return 0;                       /* Full speed */
 
@@ -1470,7 +1492,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
                return err;
 
        if (val == 0) {
-               if (nr < 3 && data->type != it8603) {
+               if (nr < 3 && has_fanctl_onoff(data)) {
                        int tmp;
                        /* make sure the fan is on when in on/off mode */
                        tmp = it87_read_value(data, IT87_REG_FAN_CTL);
@@ -1510,7 +1532,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
                data->pwm_ctrl[nr] = ctrl;
                it87_write_value(data, IT87_REG_PWM[nr], ctrl);
 
-               if (data->type != it8603 && nr < 3) {
+               if (has_fanctl_onoff(data) && nr < 3) {
                        /* set SmartGuardian mode */
                        data->fan_main_ctrl |= BIT(nr);
                        it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
@@ -2730,8 +2752,10 @@ static int __init it87_find(int sioaddr, unsigned short *address,
        else
                sio_data->skip_in |= BIT(9);
 
-       if (!has_five_pwm(config))
+       if (!has_four_pwm(config))
                sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);
+       else if (!has_five_pwm(config))
+               sio_data->skip_pwm |= BIT(4) | BIT(5);
        else if (!has_six_pwm(config))
                sio_data->skip_pwm |= BIT(5);
 
@@ -2924,6 +2948,34 @@ static int __init it87_find(int sioaddr, unsigned short *address,
 
                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 {
                int reg;
                bool uart6;
@@ -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);
-
-               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 */
-       }
+       tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
+
+       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 */
index 4c60dc5..f958e83 100644 (file)
@@ -629,7 +629,7 @@ static struct i2c_driver jc42_driver = {
                .pm = JC42_DEV_PM_OPS,
                .of_match_table = of_match_ptr(jc42_of_ids),
        },
-       .probe_new      = jc42_probe,
+       .probe          = jc42_probe,
        .remove         = jc42_remove,
        .id_table       = jc42_id,
        .detect         = jc42_detect,
index ef5a49c..df69c38 100644 (file)
@@ -511,7 +511,7 @@ static struct i2c_driver pem_driver = {
        .driver = {
                   .name = "lineage_pem",
                   },
-       .probe_new = pem_probe,
+       .probe = pem_probe,
        .id_table = pem_id,
 };
 
index 9ab2cab..6972454 100644 (file)
@@ -1164,7 +1164,7 @@ static struct i2c_driver lm63_driver = {
                .name   = "lm63",
                .of_match_table = of_match_ptr(lm63_of_match),
        },
-       .probe_new      = lm63_probe,
+       .probe          = lm63_probe,
        .id_table       = lm63_id,
        .detect         = lm63_detect,
        .address_list   = normal_i2c,
index b6433ae..637d35c 100644 (file)
@@ -277,7 +277,7 @@ static struct i2c_driver lm73_driver = {
                .name   = "lm73",
                .of_match_table = lm73_of_match,
        },
-       .probe_new      = lm73_probe,
+       .probe          = lm73_probe,
        .id_table       = lm73_ids,
        .detect         = lm73_detect,
        .address_list   = normal_i2c,
index dbb99ea..72e634d 100644 (file)
@@ -548,7 +548,7 @@ static const struct regmap_config lm75_regmap_config = {
        .writeable_reg = lm75_is_writeable_reg,
        .volatile_reg = lm75_is_volatile_reg,
        .val_format_endian = REGMAP_ENDIAN_BIG,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .use_single_read = true,
        .use_single_write = true,
 };
@@ -945,7 +945,7 @@ static struct i2c_driver lm75_driver = {
                .of_match_table = of_match_ptr(lm75_of_match),
                .pm     = LM75_DEV_PM_OPS,
        },
-       .probe_new      = lm75_probe,
+       .probe          = lm75_probe,
        .id_table       = lm75_ids,
        .detect         = lm75_detect,
        .address_list   = normal_i2c,
index 645cb21..8b98625 100644 (file)
@@ -348,7 +348,7 @@ static struct i2c_driver lm77_driver = {
        .driver = {
                .name   = "lm77",
        },
-       .probe_new      = lm77_probe,
+       .probe          = lm77_probe,
        .id_table       = lm77_id,
        .detect         = lm77_detect,
        .address_list   = normal_i2c,
index 694e171..b739c35 100644 (file)
@@ -662,7 +662,7 @@ static struct i2c_driver lm78_driver = {
        .driver = {
                .name   = "lm78",
        },
-       .probe_new      = lm78_i2c_probe,
+       .probe          = lm78_i2c_probe,
        .id_table       = lm78_i2c_id,
        .detect         = lm78_i2c_detect,
        .address_list   = normal_i2c,
index 35db0b9..63c7831 100644 (file)
@@ -633,7 +633,7 @@ static struct i2c_driver lm80_driver = {
        .driver = {
                .name   = "lm80",
        },
-       .probe_new      = lm80_probe,
+       .probe          = lm80_probe,
        .id_table       = lm80_id,
        .detect         = lm80_detect,
        .address_list   = normal_i2c,
index bcaf31e..5befedc 100644 (file)
@@ -454,7 +454,7 @@ static struct i2c_driver lm83_driver = {
        .driver = {
                .name   = "lm83",
        },
-       .probe_new      = lm83_probe,
+       .probe          = lm83_probe,
        .id_table       = lm83_id,
        .detect         = lm83_detect,
        .address_list   = normal_i2c,
index 8d33c24..8540178 100644 (file)
@@ -1698,7 +1698,7 @@ static struct i2c_driver lm85_driver = {
                .name   = "lm85",
                .of_match_table = of_match_ptr(lm85_of_match),
        },
-       .probe_new      = lm85_probe,
+       .probe          = lm85_probe,
        .id_table       = lm85_id,
        .detect         = lm85_detect,
        .address_list   = normal_i2c,
index 818fb61..2195a73 100644 (file)
@@ -994,7 +994,7 @@ static struct i2c_driver lm87_driver = {
                .name   = "lm87",
                .of_match_table = lm87_of_match,
        },
-       .probe_new      = lm87_probe,
+       .probe          = lm87_probe,
        .id_table       = lm87_id,
        .detect         = lm87_detect,
        .address_list   = normal_i2c,
index 6498d5a..90101c2 100644 (file)
@@ -2972,7 +2972,7 @@ static struct i2c_driver lm90_driver = {
                .of_match_table = of_match_ptr(lm90_of_match),
                .pm     = pm_sleep_ptr(&lm90_pm_ops),
        },
-       .probe_new      = lm90_probe,
+       .probe          = lm90_probe,
        .alert          = lm90_alert,
        .id_table       = lm90_id,
        .detect         = lm90_detect,
index 2ff3044..46579a3 100644 (file)
@@ -330,7 +330,7 @@ static struct i2c_driver lm92_driver = {
        .driver = {
                .name   = "lm92",
        },
-       .probe_new      = lm92_probe,
+       .probe          = lm92_probe,
        .id_table       = lm92_id,
        .detect         = lm92_detect,
        .address_list   = normal_i2c,
index 4cf50d5..75bca80 100644 (file)
@@ -2635,7 +2635,7 @@ static struct i2c_driver lm93_driver = {
        .driver = {
                .name   = "lm93",
        },
-       .probe_new      = lm93_probe,
+       .probe          = lm93_probe,
        .id_table       = lm93_id,
        .detect         = lm93_detect,
        .address_list   = normal_i2c,
index b4a9d0c..67b9d76 100644 (file)
@@ -720,7 +720,7 @@ static struct i2c_driver lm95234_driver = {
        .driver = {
                .name   = DRVNAME,
        },
-       .probe_new      = lm95234_probe,
+       .probe          = lm95234_probe,
        .id_table       = lm95234_id,
        .detect         = lm95234_detect,
        .address_list   = normal_i2c,
index 647a905..475551f 100644 (file)
@@ -468,7 +468,7 @@ static struct i2c_driver lm95241_driver = {
        .driver = {
                .name   = DEVNAME,
        },
-       .probe_new      = lm95241_probe,
+       .probe          = lm95241_probe,
        .id_table       = lm95241_id,
        .detect         = lm95241_detect,
        .address_list   = normal_i2c,
index 4236d1e..17ff54b 100644 (file)
@@ -518,7 +518,7 @@ static const struct regmap_config lm95245_regmap_config = {
        .val_bits = 8,
        .writeable_reg = lm95245_is_writeable_reg,
        .volatile_reg = lm95245_is_volatile_reg,
-       .cache_type = REGCACHE_RBTREE,
+       .cache_type = REGCACHE_MAPLE,
        .use_single_read = true,
        .use_single_write = true,
 };
@@ -597,7 +597,7 @@ static struct i2c_driver lm95245_driver = {
                .name   = "lm95245",
                .of_match_table = of_match_ptr(lm95245_of_match),
        },
-       .probe_new      = lm95245_probe,
+       .probe          = lm95245_probe,
        .id_table       = lm95245_id,
        .detect         = lm95245_detect,
        .address_list   = normal_i2c,
index 3494f72..45b87a8 100644 (file)
@@ -519,7 +519,7 @@ static struct i2c_driver ltc2945_driver = {
                .name = "ltc2945",
                .of_match_table = of_match_ptr(ltc2945_of_match),
        },
-       .probe_new = ltc2945_probe,
+       .probe = ltc2945_probe,
        .id_table = ltc2945_id,
 };
 
index 96852bc..33f574b 100644 (file)
@@ -38,7 +38,7 @@ static struct i2c_driver ltc2947_driver = {
                .of_match_table = ltc2947_of_match,
                .pm = pm_sleep_ptr(&ltc2947_pm_ops),
        },
-       .probe_new = ltc2947_probe,
+       .probe = ltc2947_probe,
        .id_table = ltc2947_id,
 };
 module_i2c_driver(ltc2947_driver);
index 689f788..1ad362c 100644 (file)
@@ -268,7 +268,7 @@ static struct i2c_driver ltc2990_i2c_driver = {
        .driver = {
                .name = "ltc2990",
        },
-       .probe_new = ltc2990_i2c_probe,
+       .probe = ltc2990_i2c_probe,
        .id_table = ltc2990_i2c_id,
 };
 
index 429a7f5..589bcd0 100644 (file)
@@ -928,7 +928,7 @@ static struct i2c_driver ltc2992_i2c_driver = {
                .name = "ltc2992",
                .of_match_table = ltc2992_of_match,
        },
-       .probe_new = ltc2992_i2c_probe,
+       .probe = ltc2992_i2c_probe,
        .id_table = ltc2992_i2c_id,
 };
 
index e3ac004..f42ac3c 100644 (file)
@@ -205,7 +205,7 @@ static struct i2c_driver ltc4151_driver = {
                .name   = "ltc4151",
                .of_match_table = of_match_ptr(ltc4151_match),
        },
-       .probe_new      = ltc4151_probe,
+       .probe          = ltc4151_probe,
        .id_table       = ltc4151_id,
 };
 
index fa43d26..66fd28f 100644 (file)
@@ -255,7 +255,7 @@ static struct i2c_driver ltc4215_driver = {
        .driver = {
                .name   = "ltc4215",
        },
-       .probe_new      = ltc4215_probe,
+       .probe          = ltc4215_probe,
        .id_table       = ltc4215_id,
 };
 
index d2027ca..9098ef5 100644 (file)
@@ -210,7 +210,7 @@ static struct i2c_driver ltc4222_driver = {
        .driver = {
                   .name = "ltc4222",
                   },
-       .probe_new = ltc4222_probe,
+       .probe = ltc4222_probe,
        .id_table = ltc4222_id,
 };
 
index fb9bc8d..b90184a 100644 (file)
@@ -479,7 +479,7 @@ static struct i2c_driver ltc4245_driver = {
        .driver = {
                .name   = "ltc4245",
        },
-       .probe_new      = ltc4245_probe,
+       .probe          = ltc4245_probe,
        .id_table       = ltc4245_id,
 };
 
index 75e89ce..52f7a80 100644 (file)
@@ -173,7 +173,7 @@ static struct i2c_driver ltc4260_driver = {
        .driver = {
                   .name = "ltc4260",
                   },
-       .probe_new = ltc4260_probe,
+       .probe = ltc4260_probe,
        .id_table = ltc4260_id,
 };
 
index b91cc4f..509e681 100644 (file)
@@ -233,7 +233,7 @@ static struct i2c_driver ltc4261_driver = {
        .driver = {
                   .name = "ltc4261",
                   },
-       .probe_new = ltc4261_probe,
+       .probe = ltc4261_probe,
        .id_table = ltc4261_id,
 };
 
index 49de1d2..ee5ead0 100644 (file)
@@ -339,7 +339,7 @@ static struct i2c_driver max127_driver = {
        .driver = {
                .name   = "max127",
        },
-       .probe_new      = max127_probe,
+       .probe          = max127_probe,
        .id_table       = max127_id,
 };
 
index daa5d8a..aa38c45 100644 (file)
@@ -600,7 +600,7 @@ static struct i2c_driver max16065_driver = {
        .driver = {
                .name = "max16065",
        },
-       .probe_new = max16065_probe,
+       .probe = max16065_probe,
        .id_table = max16065_id,
 };
 
index 445c771..500dc92 100644 (file)
@@ -305,7 +305,7 @@ static struct i2c_driver max1619_driver = {
                .name   = "max1619",
                .of_match_table = of_match_ptr(max1619_of_match),
        },
-       .probe_new      = max1619_probe,
+       .probe          = max1619_probe,
        .id_table       = max1619_id,
        .detect         = max1619_detect,
        .address_list   = normal_i2c,
index 9f74897..c4a02ed 100644 (file)
@@ -435,7 +435,7 @@ static struct i2c_driver max1668_driver = {
        .driver = {
                  .name = "max1668",
                  },
-       .probe_new = max1668_probe,
+       .probe = max1668_probe,
        .id_table = max1668_id,
        .detect = max1668_detect,
        .address_list = max1668_addr_list,
index 924333d..b1300ca 100644 (file)
@@ -427,7 +427,7 @@ static struct i2c_driver max31730_driver = {
                .of_match_table = of_match_ptr(max31730_of_match),
                .pm     = pm_sleep_ptr(&max31730_pm_ops),
        },
-       .probe_new      = max31730_probe,
+       .probe          = max31730_probe,
        .id_table       = max31730_ids,
        .detect         = max31730_detect,
        .address_list   = normal_i2c,
index 4489110..79945eb 100644 (file)
@@ -584,7 +584,7 @@ static struct i2c_driver max31760_driver = {
                .of_match_table = max31760_of_match,
                .pm = pm_ptr(&max31760_pm_ops)
        },
-       .probe_new      = max31760_probe,
+       .probe          = max31760_probe,
        .id_table       = max31760_id
 };
 module_i2c_driver(max31760_driver);
index 6caba6e..0cd44c1 100644 (file)
@@ -544,7 +544,7 @@ MODULE_DEVICE_TABLE(i2c, max31790_id);
 
 static struct i2c_driver max31790_driver = {
        .class          = I2C_CLASS_HWMON,
-       .probe_new      = max31790_probe,
+       .probe          = max31790_probe,
        .driver = {
                .name   = "max31790",
        },
diff --git a/drivers/hwmon/max31827.c b/drivers/hwmon/max31827.c
new file mode 100644 (file)
index 0000000..602f4e4
--- /dev/null
@@ -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");
index 0f277d9..5d12fb9 100644 (file)
@@ -503,7 +503,7 @@ static struct i2c_driver max6620_driver = {
        .driver = {
                .name   = "max6620",
        },
-       .probe_new      = max6620_probe,
+       .probe          = max6620_probe,
        .id_table       = max6620_id,
 };
 
index 0656eb1..7f709fd 100644 (file)
@@ -554,7 +554,7 @@ static struct i2c_driver max6621_driver = {
                .name = MAX6621_DRV_NAME,
                .of_match_table = of_match_ptr(max6621_of_match),
        },
-       .probe_new      = max6621_probe,
+       .probe          = max6621_probe,
        .id_table       = max6621_id,
 };
 
index 9b89540..caf5271 100644 (file)
@@ -624,7 +624,7 @@ static struct i2c_driver max6639_driver = {
                   .name = "max6639",
                   .pm = pm_sleep_ptr(&max6639_pm_ops),
                   },
-       .probe_new = max6639_probe,
+       .probe = max6639_probe,
        .id_table = max6639_id,
        .detect = max6639_detect,
        .address_list = normal_i2c,
index 47ea34f..8b2e4d6 100644 (file)
@@ -301,7 +301,7 @@ static struct i2c_driver max6642_driver = {
        .driver = {
                .name   = "max6642",
        },
-       .probe_new      = max6642_probe,
+       .probe          = max6642_probe,
        .id_table       = max6642_id,
        .detect         = max6642_detect,
        .address_list   = normal_i2c,
index 19e2c76..cc8428a 100644 (file)
@@ -819,7 +819,7 @@ static struct i2c_driver max6650_driver = {
                .name   = "max6650",
                .of_match_table = of_match_ptr(max6650_dt_match),
        },
-       .probe_new      = max6650_probe,
+       .probe          = max6650_probe,
        .id_table       = max6650_id,
 };
 
index 2895cea..3a67778 100644 (file)
@@ -786,7 +786,7 @@ static struct i2c_driver max6697_driver = {
                .name   = "max6697",
                .of_match_table = of_match_ptr(max6697_of_match),
        },
-       .probe_new = max6697_probe,
+       .probe = max6697_probe,
        .id_table = max6697_id,
 };
 
index 6a7a950..0c8fd3f 100644 (file)
@@ -251,7 +251,7 @@ static struct i2c_driver mc34vr500_driver = {
                   .name = "mc34vr500",
                   .of_match_table = of_match_ptr(mc34vr500_of_match),
                    },
-       .probe_new = mc34vr500_probe,
+       .probe = mc34vr500_probe,
        .id_table = mc34vr500_id,
 };
 
index a5f7a29..127e15f 100644 (file)
@@ -198,7 +198,7 @@ static struct i2c_driver mcp3021_driver = {
                .name = "mcp3021",
                .of_match_table = of_match_ptr(of_mcp3021_match),
        },
-       .probe_new = mcp3021_probe,
+       .probe = mcp3021_probe,
        .id_table = mcp3021_id,
 };
 
index a872f78..f673f7d 100644 (file)
@@ -173,6 +173,7 @@ superio_exit(int ioreg)
 #define NCT6683_CUSTOMER_ID_INTEL      0x805
 #define NCT6683_CUSTOMER_ID_MITAC      0xa0e
 #define NCT6683_CUSTOMER_ID_MSI                0x201
+#define NCT6683_CUSTOMER_ID_MSI2       0x200
 #define NCT6683_CUSTOMER_ID_ASROCK             0xe2c
 #define NCT6683_CUSTOMER_ID_ASROCK2    0xe1b
 
@@ -1220,6 +1221,8 @@ static int nct6683_probe(struct platform_device *pdev)
                break;
        case NCT6683_CUSTOMER_ID_MSI:
                break;
+       case NCT6683_CUSTOMER_ID_MSI2:
+               break;
        case NCT6683_CUSTOMER_ID_ASROCK:
                break;
        case NCT6683_CUSTOMER_ID_ASROCK2:
index c54233f..236dc97 100644 (file)
@@ -33,6 +33,7 @@
  *                                           (0xd451)
  * nct6798d    14      7       7       2+6    0xd428 0xc1    0x5ca3
  *                                           (0xd429)
+ * nct6799d    14      7       7       2+6    0xd802 0xc1    0x5ca3
  *
  * #temp lists the number of monitored temperature sources (first value) plus
  * the number of directly connectable temperature sensors (second value).
@@ -73,6 +74,7 @@ static const char * const nct6775_device_names[] = {
        "nct6796",
        "nct6797",
        "nct6798",
+       "nct6799",
 };
 
 /* Common and NCT6775 specific data */
@@ -381,7 +383,7 @@ static const u16 NCT6779_REG_TEMP_OVER[ARRAY_SIZE(NCT6779_REG_TEMP)] = {
        0x39, 0x155 };
 
 static const u16 NCT6779_REG_TEMP_OFFSET[] = {
-       0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c };
+       0x454, 0x455, 0x456, 0x44a, 0x44b, 0x44c, 0x44d, 0x449 };
 
 static const char *const nct6779_temp_label[] = {
        "",
@@ -654,6 +656,44 @@ static const char *const nct6798_temp_label[] = {
 #define NCT6798_TEMP_MASK      0xbfff0ffe
 #define NCT6798_VIRT_TEMP_MASK 0x80000c00
 
+static const char *const nct6799_temp_label[] = {
+       "",
+       "SYSTIN",
+       "CPUTIN",
+       "AUXTIN0",
+       "AUXTIN1",
+       "AUXTIN2",
+       "AUXTIN3",
+       "AUXTIN4",
+       "SMBUSMASTER 0",
+       "SMBUSMASTER 1",
+       "Virtual_TEMP",
+       "Virtual_TEMP",
+       "",
+       "AUXTIN5",
+       "",
+       "",
+       "PECI Agent 0",
+       "PECI Agent 1",
+       "PCH_CHIP_CPU_MAX_TEMP",
+       "PCH_CHIP_TEMP",
+       "PCH_CPU_TEMP",
+       "PCH_MCH_TEMP",
+       "Agent0 Dimm0",
+       "Agent0 Dimm1",
+       "Agent1 Dimm0",
+       "Agent1 Dimm1",
+       "BYTE_TEMP0",
+       "BYTE_TEMP1",
+       "PECI Agent 0 Calibration",     /* undocumented */
+       "PECI Agent 1 Calibration",     /* undocumented */
+       "",
+       "Virtual_TEMP"
+};
+
+#define NCT6799_TEMP_MASK      0xbfff2ffe
+#define NCT6799_VIRT_TEMP_MASK 0x80000c00
+
 /* NCT6102D/NCT6106D specific data */
 
 #define NCT6106_REG_VBAT       0x318
@@ -1109,6 +1149,7 @@ bool nct6775_reg_is_word_sized(struct nct6775_data *data, u16 reg)
        case nct6796:
        case nct6797:
        case nct6798:
+       case nct6799:
                return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
                  (reg & 0xfff0) == 0x4c0 ||
                  reg == 0x402 ||
@@ -1462,6 +1503,7 @@ static int nct6775_update_pwm_limits(struct device *dev)
                case nct6796:
                case nct6797:
                case nct6798:
+               case nct6799:
                        err = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i], &reg);
                        if (err)
                                return err;
@@ -3109,6 +3151,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
                case nct6796:
                case nct6797:
                case nct6798:
+               case nct6799:
                        err = nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val);
                        if (err)
                                break;
@@ -3807,10 +3850,12 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
        case nct6796:
        case nct6797:
        case nct6798:
+       case nct6799:
                data->in_num = 15;
                data->pwm_num = (data->kind == nct6796 ||
                                 data->kind == nct6797 ||
-                                data->kind == nct6798) ? 7 : 6;
+                                data->kind == nct6798 ||
+                                data->kind == nct6799) ? 7 : 6;
                data->auto_pwm_num = 4;
                data->has_fan_div = false;
                data->temp_fixed_num = 6;
@@ -3859,6 +3904,11 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                        data->temp_mask = NCT6798_TEMP_MASK;
                        data->virt_temp_mask = NCT6798_VIRT_TEMP_MASK;
                        break;
+               case nct6799:
+                       data->temp_label = nct6799_temp_label;
+                       data->temp_mask = NCT6799_TEMP_MASK;
+                       data->virt_temp_mask = NCT6799_VIRT_TEMP_MASK;
+                       break;
                }
 
                data->REG_CONFIG = NCT6775_REG_CONFIG;
@@ -3918,6 +3968,7 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
                case nct6796:
                case nct6797:
                case nct6798:
+               case nct6799:
                        data->REG_TSI_TEMP = NCT6796_REG_TSI_TEMP;
                        num_reg_tsi_temp = ARRAY_SIZE(NCT6796_REG_TSI_TEMP);
                        break;
index e1bcd11..87a4fc7 100644 (file)
@@ -87,6 +87,7 @@ static const struct of_device_id __maybe_unused nct6775_i2c_of_match[] = {
        { .compatible = "nuvoton,nct6796", .data = (void *)nct6796, },
        { .compatible = "nuvoton,nct6797", .data = (void *)nct6797, },
        { .compatible = "nuvoton,nct6798", .data = (void *)nct6798, },
+       { .compatible = "nuvoton,nct6799", .data = (void *)nct6799, },
        { },
 };
 MODULE_DEVICE_TABLE(of, nct6775_i2c_of_match);
@@ -104,6 +105,7 @@ static const struct i2c_device_id nct6775_i2c_id[] = {
        { "nct6796", nct6796 },
        { "nct6797", nct6797 },
        { "nct6798", nct6798 },
+       { "nct6799", nct6799 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, nct6775_i2c_id);
@@ -183,7 +185,7 @@ static struct i2c_driver nct6775_i2c_driver = {
                .name = "nct6775-i2c",
                .of_match_table = of_match_ptr(nct6775_i2c_of_match),
        },
-       .probe_new = nct6775_i2c_probe,
+       .probe = nct6775_i2c_probe,
        .id_table = nct6775_i2c_id,
 };
 
index 5782acf..ada867d 100644 (file)
@@ -35,6 +35,7 @@ static const char * const nct6775_sio_names[] __initconst = {
        "NCT6796D",
        "NCT6797D",
        "NCT6798D",
+       "NCT6799D",
 };
 
 static unsigned short force_id;
@@ -85,6 +86,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
 #define SIO_NCT6796_ID         0xd420
 #define SIO_NCT6797_ID         0xd450
 #define SIO_NCT6798_ID         0xd428
+#define SIO_NCT6799_ID         0xd800
 #define SIO_ID_MASK            0xFFF8
 
 /*
@@ -418,7 +420,7 @@ static int nct6775_resume(struct device *dev)
        if (data->kind == nct6791 || data->kind == nct6792 ||
            data->kind == nct6793 || data->kind == nct6795 ||
            data->kind == nct6796 || data->kind == nct6797 ||
-           data->kind == nct6798)
+           data->kind == nct6798 || data->kind == nct6799)
                nct6791_enable_io_mapping(sio_data);
 
        sio_data->sio_exit(sio_data);
@@ -565,7 +567,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio
        } else {
                /*
                 * NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
-                * NCT6797D, NCT6798D
+                * NCT6797D, NCT6798D, NCT6799D
                 */
                int cr1a = sio_data->sio_inb(sio_data, 0x1a);
                int cr1b = sio_data->sio_inb(sio_data, 0x1b);
@@ -575,12 +577,17 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio
                int cr2b = sio_data->sio_inb(sio_data, 0x2b);
                int cr2d = sio_data->sio_inb(sio_data, 0x2d);
                int cr2f = sio_data->sio_inb(sio_data, 0x2f);
+               bool vsb_ctl_en = cr2f & BIT(0);
                bool dsw_en = cr2f & BIT(3);
                bool ddr4_en = cr2f & BIT(4);
+               bool as_seq1_en = cr2f & BIT(7);
                int cre0;
+               int cre6;
                int creb;
                int cred;
 
+               cre6 = sio_data->sio_inb(sio_data, 0xe0);
+
                sio_data->sio_select(sio_data, NCT6775_LD_12);
                cre0 = sio_data->sio_inb(sio_data, 0xe0);
                creb = sio_data->sio_inb(sio_data, 0xeb);
@@ -684,6 +691,29 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio
                        pwm7pin |= cr2d & BIT(7);
                        pwm7pin |= creb & BIT(2);
                        break;
+               case nct6799:
+                       fan4pin = cr1c & BIT(6);
+                       fan5pin = cr1c & BIT(7);
+
+                       fan6pin = !(cr1b & BIT(0)) && (cre0 & BIT(3));
+                       fan6pin |= cre6 & BIT(5);
+                       fan6pin |= creb & BIT(5);
+                       fan6pin |= !as_seq1_en && (cr2a & BIT(4));
+
+                       fan7pin = cr1b & BIT(5);
+                       fan7pin |= !vsb_ctl_en && !(cr2b & BIT(2));
+                       fan7pin |= creb & BIT(3);
+
+                       pwm6pin = !(cr1b & BIT(0)) && (cre0 & BIT(4));
+                       pwm6pin |= !as_seq1_en && !(cred & BIT(2)) && (cr2a & BIT(3));
+                       pwm6pin |= (creb & BIT(4)) && !(cr2a & BIT(0));
+                       pwm6pin |= cre6 & BIT(3);
+
+                       pwm7pin = !vsb_ctl_en && !(cr1d & (BIT(2) | BIT(3)));
+                       pwm7pin |= creb & BIT(2);
+                       pwm7pin |= cr2d & BIT(7);
+
+                       break;
                default:        /* NCT6779D */
                        break;
                }
@@ -838,6 +868,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data)
        case nct6796:
        case nct6797:
        case nct6798:
+       case nct6799:
                break;
        }
 
@@ -876,6 +907,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data)
                case nct6796:
                case nct6797:
                case nct6798:
+               case nct6799:
                        tmp |= 0x7e;
                        break;
                }
@@ -1005,6 +1037,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
        case SIO_NCT6798_ID:
                sio_data->kind = nct6798;
                break;
+       case SIO_NCT6799_ID:
+               sio_data->kind = nct6799;
+               break;
        default:
                if (val != 0xffff)
                        pr_debug("unsupported chip ID: 0x%04x\n", val);
@@ -1033,7 +1068,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
        if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
            sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
            sio_data->kind == nct6796 || sio_data->kind == nct6797 ||
-           sio_data->kind == nct6798)
+           sio_data->kind == nct6798 || sio_data->kind == nct6799)
                nct6791_enable_io_mapping(sio_data);
 
        sio_data->sio_exit(sio_data);
index be41848..44f79c5 100644 (file)
@@ -5,7 +5,7 @@
 #include <linux/types.h>
 
 enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
-            nct6793, nct6795, nct6796, nct6797, nct6798 };
+            nct6793, nct6795, nct6796, nct6797, nct6798, nct6799 };
 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
 
 #define NUM_TEMP       10      /* Max number of temp attribute sets w/ limits*/
index a175f82..9339bfc 100644 (file)
@@ -1223,7 +1223,7 @@ static struct i2c_driver nct7802_driver = {
                .name = DRVNAME,
        },
        .detect = nct7802_detect,
-       .probe_new = nct7802_probe,
+       .probe = nct7802_probe,
        .id_table = nct7802_idtable,
        .address_list = nct7802_address_list,
 };
index 007bae4..8f867d4 100644 (file)
@@ -1171,7 +1171,7 @@ static struct i2c_driver nct7904_driver = {
        .driver = {
                .name = "nct7904",
        },
-       .probe_new = nct7904_probe,
+       .probe = nct7904_probe,
        .id_table = nct7904_id,
        .detect = nct7904_detect,
        .address_list = normal_i2c,
index 9e1744f..0609597 100644 (file)
@@ -246,7 +246,7 @@ static struct i2c_driver p8_i2c_occ_driver = {
                .name = "occ-hwmon",
                .of_match_table = p8_i2c_occ_of_match,
        },
-       .probe_new = p8_i2c_occ_probe,
+       .probe = p8_i2c_occ_probe,
        .remove = p8_i2c_occ_remove,
 };
 
index ae67207..e1a907c 100644 (file)
@@ -16,7 +16,6 @@
  */
 
 #include <linux/acpi.h>
-#include <linux/dev_printk.h>
 #include <linux/dmi.h>
 #include <linux/hwmon.h>
 #include <linux/init.h>
@@ -42,53 +41,97 @@ static bool unlock_global_acpi_lock(void)
 
 enum oxp_board {
        aok_zoe_a1 = 1,
+       aya_neo_2,
        aya_neo_air,
        aya_neo_air_pro,
+       aya_neo_geek,
        oxp_mini_amd,
+       oxp_mini_amd_a07,
        oxp_mini_amd_pro,
 };
 
 static enum oxp_board board;
 
+/* Fan reading and PWM */
 #define OXP_SENSOR_FAN_REG             0x76 /* Fan reading is 2 registers long */
 #define OXP_SENSOR_PWM_ENABLE_REG      0x4A /* PWM enable is 1 register long */
 #define OXP_SENSOR_PWM_REG             0x4B /* PWM reading is 1 register long */
 
+/* Turbo button takeover function
+ * Older boards have different values and EC registers
+ * for the same function
+ */
+#define OXP_OLD_TURBO_SWITCH_REG       0x1E
+#define OXP_OLD_TURBO_TAKE_VAL         0x01
+#define OXP_OLD_TURBO_RETURN_VAL       0x00
+
+#define OXP_TURBO_SWITCH_REG           0xF1
+#define OXP_TURBO_TAKE_VAL             0x40
+#define OXP_TURBO_RETURN_VAL           0x00
+
 static const struct dmi_system_id dmi_table[] = {
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
                },
-               .driver_data = (void *) &(enum oxp_board) {aok_zoe_a1},
+               .driver_data = (void *)aok_zoe_a1,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"),
+               },
+               .driver_data = (void *)aok_zoe_a1,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
+               },
+               .driver_data = (void *)aya_neo_2,
        },
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
                },
-               .driver_data = (void *) &(enum oxp_board) {aya_neo_air},
+               .driver_data = (void *)aya_neo_air,
        },
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
                },
-               .driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro},
+               .driver_data = (void *)aya_neo_air_pro,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "GEEK"),
+               },
+               .driver_data = (void *)aya_neo_geek,
        },
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
                },
-               .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd},
+               .driver_data = (void *)oxp_mini_amd,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
+                       DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
+               },
+               .driver_data = (void *)oxp_mini_amd_a07,
        },
        {
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
                        DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
                },
-               .driver_data = (void *) &(enum oxp_board) {oxp_mini_amd_pro},
+               .driver_data = (void *)oxp_mini_amd_pro,
        },
        {},
 };
@@ -118,7 +161,7 @@ static int read_from_ec(u8 reg, int size, long *val)
        return 0;
 }
 
-static int write_to_ec(const struct device *dev, u8 reg, u8 value)
+static int write_to_ec(u8 reg, u8 value)
 {
        int ret;
 
@@ -133,14 +176,109 @@ static int write_to_ec(const struct device *dev, u8 reg, u8 value)
        return ret;
 }
 
-static int oxp_pwm_enable(const struct device *dev)
+/* Turbo button toggle functions */
+static int tt_toggle_enable(void)
+{
+       u8 reg;
+       u8 val;
+
+       switch (board) {
+       case oxp_mini_amd_a07:
+               reg = OXP_OLD_TURBO_SWITCH_REG;
+               val = OXP_OLD_TURBO_TAKE_VAL;
+               break;
+       case oxp_mini_amd_pro:
+       case aok_zoe_a1:
+               reg = OXP_TURBO_SWITCH_REG;
+               val = OXP_TURBO_TAKE_VAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return write_to_ec(reg, val);
+}
+
+static int tt_toggle_disable(void)
+{
+       u8 reg;
+       u8 val;
+
+       switch (board) {
+       case oxp_mini_amd_a07:
+               reg = OXP_OLD_TURBO_SWITCH_REG;
+               val = OXP_OLD_TURBO_RETURN_VAL;
+               break;
+       case oxp_mini_amd_pro:
+       case aok_zoe_a1:
+               reg = OXP_TURBO_SWITCH_REG;
+               val = OXP_TURBO_RETURN_VAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return write_to_ec(reg, val);
+}
+
+/* Callbacks for turbo toggle attribute */
+static ssize_t tt_toggle_store(struct device *dev,
+                              struct device_attribute *attr, const char *buf,
+                              size_t count)
+{
+       int rval;
+       bool value;
+
+       rval = kstrtobool(buf, &value);
+       if (rval)
+               return rval;
+
+       if (value) {
+               rval = tt_toggle_enable();
+       } else {
+               rval = tt_toggle_disable();
+       }
+       if (rval)
+               return rval;
+
+       return count;
+}
+
+static ssize_t tt_toggle_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       int retval;
+       u8 reg;
+       long val;
+
+       switch (board) {
+       case oxp_mini_amd_a07:
+               reg = OXP_OLD_TURBO_SWITCH_REG;
+               break;
+       case oxp_mini_amd_pro:
+       case aok_zoe_a1:
+               reg = OXP_TURBO_SWITCH_REG;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       retval = read_from_ec(reg, 1, &val);
+       if (retval)
+               return retval;
+
+       return sysfs_emit(buf, "%d\n", !!val);
+}
+
+static DEVICE_ATTR_RW(tt_toggle);
+
+/* PWM enable/disable functions */
+static int oxp_pwm_enable(void)
 {
-       return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x01);
+       return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x01);
 }
 
-static int oxp_pwm_disable(const struct device *dev)
+static int oxp_pwm_disable(void)
 {
-       return write_to_ec(dev, OXP_SENSOR_PWM_ENABLE_REG, 0x00);
+       return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, 0x00);
 }
 
 /* Callbacks for hwmon interface */
@@ -178,9 +316,12 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
                        if (ret)
                                return ret;
                        switch (board) {
+                       case aya_neo_2:
                        case aya_neo_air:
                        case aya_neo_air_pro:
+                       case aya_neo_geek:
                        case oxp_mini_amd:
+                       case oxp_mini_amd_a07:
                                *val = (*val * 255) / 100;
                                break;
                        case oxp_mini_amd_pro:
@@ -209,17 +350,20 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
                switch (attr) {
                case hwmon_pwm_enable:
                        if (val == 1)
-                               return oxp_pwm_enable(dev);
+                               return oxp_pwm_enable();
                        else if (val == 0)
-                               return oxp_pwm_disable(dev);
+                               return oxp_pwm_disable();
                        return -EINVAL;
                case hwmon_pwm_input:
                        if (val < 0 || val > 255)
                                return -EINVAL;
                        switch (board) {
+                       case aya_neo_2:
                        case aya_neo_air:
                        case aya_neo_air_pro:
+                       case aya_neo_geek:
                        case oxp_mini_amd:
+                       case oxp_mini_amd_a07:
                                val = (val * 100) / 255;
                                break;
                        case aok_zoe_a1:
@@ -227,7 +371,7 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
                        default:
                                break;
                        }
-                       return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
+                       return write_to_ec(OXP_SENSOR_PWM_REG, val);
                default:
                        break;
                }
@@ -247,6 +391,13 @@ static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
        NULL,
 };
 
+static struct attribute *oxp_ec_attrs[] = {
+       &dev_attr_tt_toggle.attr,
+       NULL
+};
+
+ATTRIBUTE_GROUPS(oxp_ec);
+
 static const struct hwmon_ops oxp_ec_hwmon_ops = {
        .is_visible = oxp_ec_hwmon_is_visible,
        .read = oxp_platform_read,
@@ -264,6 +415,7 @@ static int oxp_platform_probe(struct platform_device *pdev)
        const struct dmi_system_id *dmi_entry;
        struct device *dev = &pdev->dev;
        struct device *hwdev;
+       int ret;
 
        /*
         * Have to check for AMD processor here because DMI strings are the
@@ -276,7 +428,19 @@ static int oxp_platform_probe(struct platform_device *pdev)
        if (!dmi_entry || boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
                return -ENODEV;
 
-       board = *((enum oxp_board *) dmi_entry->driver_data);
+       board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
+
+       switch (board) {
+       case aok_zoe_a1:
+       case oxp_mini_amd_a07:
+       case oxp_mini_amd_pro:
+               ret = devm_device_add_groups(dev, oxp_ec_groups);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               break;
+       }
 
        hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
                                                     &oxp_ec_chip_info, NULL);
index 1dbe209..66c76b2 100644 (file)
@@ -294,7 +294,7 @@ static struct i2c_driver pcf8591_driver = {
        .driver = {
                .name   = "pcf8591",
        },
-       .probe_new      = pcf8591_probe,
+       .probe          = pcf8591_probe,
        .remove         = pcf8591_remove,
        .id_table       = pcf8591_id,
 };
index 28a25f3..0a0ef4c 100644 (file)
@@ -73,7 +73,7 @@ static struct i2c_driver acbel_fsg032_driver = {
                .name = "acbel-fsg032",
                .of_match_table = acbel_fsg032_of_match,
        },
-       .probe_new = acbel_fsg032_probe,
+       .probe = acbel_fsg032_probe,
        .id_table = acbel_fsg032_id,
 };
 
index 1ac2b2f..ed0a7b9 100644 (file)
@@ -340,8 +340,6 @@ static void adm1266_init_debugfs(struct adm1266_data *data)
                return;
 
        data->debugfs_dir = debugfs_create_dir(data->client->name, root);
-       if (!data->debugfs_dir)
-               return;
 
        debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir,
                                    adm1266_state_read);
@@ -502,7 +500,7 @@ static struct i2c_driver adm1266_driver = {
                   .name = "adm1266",
                   .of_match_table = adm1266_of_match,
                  },
-       .probe_new = adm1266_probe,
+       .probe = adm1266_probe,
        .id_table = adm1266_id,
 };
 
index 3b07bfb..e2c61d6 100644 (file)
@@ -27,8 +27,11 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
 #define ADM1275_PEAK_IOUT              0xd0
 #define ADM1275_PEAK_VIN               0xd1
 #define ADM1275_PEAK_VOUT              0xd2
+#define ADM1275_PMON_CONTROL           0xd3
 #define ADM1275_PMON_CONFIG            0xd4
 
+#define ADM1275_CONVERT_EN             BIT(0)
+
 #define ADM1275_VIN_VOUT_SELECT                BIT(6)
 #define ADM1275_VRANGE                 BIT(5)
 #define ADM1075_IRANGE_50              BIT(4)
@@ -37,10 +40,13 @@ enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
 
 #define ADM1272_IRANGE                 BIT(0)
 
+#define ADM1278_TSFILT                 BIT(15)
 #define ADM1278_TEMP1_EN               BIT(3)
 #define ADM1278_VIN_EN                 BIT(2)
 #define ADM1278_VOUT_EN                        BIT(1)
 
+#define ADM1278_PMON_DEFCONFIG         (ADM1278_VOUT_EN | ADM1278_TEMP1_EN | ADM1278_TSFILT)
+
 #define ADM1293_IRANGE_25              0
 #define ADM1293_IRANGE_50              BIT(6)
 #define ADM1293_IRANGE_100             BIT(7)
@@ -170,8 +176,8 @@ static const struct coefficients adm1293_coefficients[] = {
        [18] = { 7658, 0, -3 },         /* power, 21V, irange200 */
 };
 
-static int adm1275_read_pmon_config(const struct adm1275_data *data,
-                                   struct i2c_client *client, bool is_power)
+static int adm1275_read_samples(const struct adm1275_data *data,
+                               struct i2c_client *client, bool is_power)
 {
        int shift, ret;
        u16 mask;
@@ -197,8 +203,36 @@ static int adm1275_read_pmon_config(const struct adm1275_data *data,
 }
 
 static int adm1275_write_pmon_config(const struct adm1275_data *data,
-                                    struct i2c_client *client,
-                                    bool is_power, u16 word)
+                                    struct i2c_client *client, u16 word)
+{
+       int ret, ret2;
+
+       ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL, 0);
+       if (ret)
+               return ret;
+
+       if (data->have_power_sampling)
+               ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG,
+                                               word);
+       else
+               ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG,
+                                               word);
+
+       /*
+        * We still want to re-enable conversions if writing into
+        * ADM1275_PMON_CONFIG failed.
+        */
+       ret2 = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONTROL,
+                                        ADM1275_CONVERT_EN);
+       if (!ret)
+               ret = ret2;
+
+       return ret;
+}
+
+static int adm1275_write_samples(const struct adm1275_data *data,
+                                struct i2c_client *client,
+                                bool is_power, u16 word)
 {
        int shift, ret;
        u16 mask;
@@ -216,14 +250,8 @@ static int adm1275_write_pmon_config(const struct adm1275_data *data,
                return ret;
 
        word = (ret & ~mask) | ((word << shift) & mask);
-       if (data->have_power_sampling)
-               ret = i2c_smbus_write_word_data(client, ADM1275_PMON_CONFIG,
-                                               word);
-       else
-               ret = i2c_smbus_write_byte_data(client, ADM1275_PMON_CONFIG,
-                                               word);
 
-       return ret;
+       return adm1275_write_pmon_config(data, client, word);
 }
 
 static int adm1275_read_word_data(struct i2c_client *client, int page,
@@ -318,14 +346,14 @@ static int adm1275_read_word_data(struct i2c_client *client, int page,
        case PMBUS_VIRT_POWER_SAMPLES:
                if (!data->have_power_sampling)
                        return -ENXIO;
-               ret = adm1275_read_pmon_config(data, client, true);
+               ret = adm1275_read_samples(data, client, true);
                if (ret < 0)
                        break;
                ret = BIT(ret);
                break;
        case PMBUS_VIRT_IN_SAMPLES:
        case PMBUS_VIRT_CURR_SAMPLES:
-               ret = adm1275_read_pmon_config(data, client, false);
+               ret = adm1275_read_samples(data, client, false);
                if (ret < 0)
                        break;
                ret = BIT(ret);
@@ -378,14 +406,12 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
                if (!data->have_power_sampling)
                        return -ENXIO;
                word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
-               ret = adm1275_write_pmon_config(data, client, true,
-                                               ilog2(word));
+               ret = adm1275_write_samples(data, client, true, ilog2(word));
                break;
        case PMBUS_VIRT_IN_SAMPLES:
        case PMBUS_VIRT_CURR_SAMPLES:
                word = clamp_val(word, 1, ADM1275_SAMPLES_AVG_MAX);
-               ret = adm1275_write_pmon_config(data, client, false,
-                                               ilog2(word));
+               ret = adm1275_write_samples(data, client, false, ilog2(word));
                break;
        default:
                ret = -ENODATA;
@@ -462,6 +488,23 @@ static const struct i2c_device_id adm1275_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, adm1275_id);
 
+/* Enable VOUT & TEMP1 if not enabled (disabled by default) */
+static int adm1275_enable_vout_temp(struct adm1275_data *data,
+                                   struct i2c_client *client, int config)
+{
+       int ret;
+
+       if ((config & ADM1278_PMON_DEFCONFIG) != ADM1278_PMON_DEFCONFIG) {
+               config |= ADM1278_PMON_DEFCONFIG;
+               ret = adm1275_write_pmon_config(data, client, config);
+               if (ret < 0) {
+                       dev_err(&client->dev, "Failed to enable VOUT/TEMP1 monitoring\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
 static int adm1275_probe(struct i2c_client *client)
 {
        s32 (*config_read_fn)(const struct i2c_client *client, u8 reg);
@@ -615,19 +658,10 @@ static int adm1275_probe(struct i2c_client *client)
                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
-               /* Enable VOUT & TEMP1 if not enabled (disabled by default) */
-               if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) !=
-                   (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) {
-                       config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN;
-                       ret = i2c_smbus_write_byte_data(client,
-                                                       ADM1275_PMON_CONFIG,
-                                                       config);
-                       if (ret < 0) {
-                               dev_err(&client->dev,
-                                       "Failed to enable VOUT monitoring\n");
-                               return -ENODEV;
-                       }
-               }
+               ret = adm1275_enable_vout_temp(data, client, config);
+               if (ret)
+                       return ret;
+
                if (config & ADM1278_VIN_EN)
                        info->func[0] |= PMBUS_HAVE_VIN;
                break;
@@ -684,19 +718,9 @@ static int adm1275_probe(struct i2c_client *client)
                        PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
                        PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
 
-               /* Enable VOUT & TEMP1 if not enabled (disabled by default) */
-               if ((config & (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) !=
-                   (ADM1278_VOUT_EN | ADM1278_TEMP1_EN)) {
-                       config |= ADM1278_VOUT_EN | ADM1278_TEMP1_EN;
-                       ret = i2c_smbus_write_word_data(client,
-                                                       ADM1275_PMON_CONFIG,
-                                                       config);
-                       if (ret < 0) {
-                               dev_err(&client->dev,
-                                       "Failed to enable VOUT monitoring\n");
-                               return -ENODEV;
-                       }
-               }
+               ret = adm1275_enable_vout_temp(data, client, config);
+               if (ret)
+                       return ret;
 
                if (config & ADM1278_VIN_EN)
                        info->func[0] |= PMBUS_HAVE_VIN;
@@ -766,8 +790,7 @@ static int adm1275_probe(struct i2c_client *client)
                                "Invalid number of power samples");
                        return -EINVAL;
                }
-               ret = adm1275_write_pmon_config(data, client, true,
-                                               ilog2(avg));
+               ret = adm1275_write_samples(data, client, true, ilog2(avg));
                if (ret < 0) {
                        dev_err(&client->dev,
                                "Setting power sample averaging failed with error %d",
@@ -784,8 +807,7 @@ static int adm1275_probe(struct i2c_client *client)
                                "Invalid number of voltage/current samples");
                        return -EINVAL;
                }
-               ret = adm1275_write_pmon_config(data, client, false,
-                                               ilog2(avg));
+               ret = adm1275_write_samples(data, client, false, ilog2(avg));
                if (ret < 0) {
                        dev_err(&client->dev,
                                "Setting voltage and current sample averaging failed with error %d",
@@ -832,7 +854,7 @@ static struct i2c_driver adm1275_driver = {
        .driver = {
                   .name = "adm1275",
                   },
-       .probe_new = adm1275_probe,
+       .probe = adm1275_probe,
        .id_table = adm1275_id,
 };
 
index 4100eef..fa5070a 100644 (file)
@@ -120,7 +120,7 @@ static struct i2c_driver pfe_pmbus_driver = {
        .driver = {
                   .name = "bel-pfe",
        },
-       .probe_new = pfe_pmbus_probe,
+       .probe = pfe_pmbus_probe,
        .id_table = pfe_device_id,
 };
 
index f2d4e37..0dce26c 100644 (file)
@@ -196,7 +196,7 @@ static struct i2c_driver bpa_rs600_driver = {
                .name = "bpa-rs600",
                .of_match_table = of_match_ptr(bpa_rs600_of_match),
        },
-       .probe_new = bpa_rs600_probe,
+       .probe = bpa_rs600_probe,
        .id_table = bpa_rs600_id,
 };
 
index f546f0c..4dd3b66 100644 (file)
@@ -119,7 +119,7 @@ static struct i2c_driver ahe50dc_fan_driver = {
                   .name = "ahe50dc_fan",
                   .of_match_table = of_match_ptr(ahe50dc_fan_of_match),
        },
-       .probe_new = ahe50dc_fan_probe,
+       .probe = ahe50dc_fan_probe,
        .id_table = ahe50dc_fan_id,
 };
 module_i2c_driver(ahe50dc_fan_driver);
index d3941f6..f7ff3e4 100644 (file)
@@ -195,7 +195,7 @@ static struct i2c_driver dps920ab_driver = {
                   .name = "dps920ab",
                   .of_match_table = of_match_ptr(dps920ab_of_match),
        },
-       .probe_new = dps920ab_probe,
+       .probe = dps920ab_probe,
 };
 
 module_i2c_driver(dps920ab_driver);
index c7469d2..72a7c26 100644 (file)
@@ -282,7 +282,7 @@ static struct i2c_driver fsp3y_driver = {
        .driver = {
                   .name = "fsp3y",
                   },
-       .probe_new = fsp3y_probe,
+       .probe = fsp3y_probe,
        .id_table = fsp3y_id
 };
 
index 76e72e9..c791925 100644 (file)
@@ -605,7 +605,7 @@ static struct i2c_driver ibm_cffps_driver = {
                .name = "ibm-cffps",
                .of_match_table = ibm_cffps_of_match,
        },
-       .probe_new = ibm_cffps_probe,
+       .probe = ibm_cffps_probe,
        .id_table = ibm_cffps_id,
 };
 
index 0f614e8..dfeae68 100644 (file)
@@ -215,7 +215,7 @@ static struct i2c_driver ipsps_driver = {
                .name = "inspur-ipsps",
                .of_match_table = of_match_ptr(ipsps_of_match),
        },
-       .probe_new = ipsps_probe,
+       .probe = ipsps_probe,
        .id_table = ipsps_id,
 };
 
index a6cf98e..e3ee5c1 100644 (file)
@@ -136,7 +136,7 @@ static struct i2c_driver ir35221_driver = {
        .driver = {
                .name   = "ir35221",
        },
-       .probe_new      = ir35221_probe,
+       .probe          = ir35221_probe,
        .id_table       = ir35221_id,
 };
 
index 4dca476..382ba6b 100644 (file)
@@ -68,7 +68,7 @@ static struct i2c_driver ir36021_driver = {
                .name = "ir36021",
                .of_match_table = of_match_ptr(ir36021_of_id),
        },
-       .probe_new = ir36021_probe,
+       .probe = ir36021_probe,
        .id_table = ir36021_id,
 };
 
index 09276e3..871c322 100644 (file)
@@ -78,7 +78,7 @@ static struct i2c_driver ir38064_driver = {
                   .name = "ir38064",
                   .of_match_table = of_match_ptr(ir38064_of_match),
                   },
-       .probe_new = ir38064_probe,
+       .probe = ir38064_probe,
        .id_table = ir38064_id,
 };
 
index de3449e..146d32a 100644 (file)
@@ -54,7 +54,7 @@ static struct i2c_driver irps5401_driver = {
        .driver = {
                   .name = "irps5401",
                   },
-       .probe_new = irps5401_probe,
+       .probe = irps5401_probe,
        .id_table = irps5401_id,
 };
 
index 1a8caff..7e53fb1 100644 (file)
@@ -323,7 +323,7 @@ static struct i2c_driver isl68137_driver = {
        .driver = {
                   .name = "isl68137",
                   },
-       .probe_new = isl68137_probe,
+       .probe = isl68137_probe,
        .id_table = raa_dmpvr_id,
 };
 
index 09792cd..929fa6d 100644 (file)
@@ -568,7 +568,7 @@ static struct i2c_driver lm25066_driver = {
                   .name = "lm25066",
                   .of_match_table = of_match_ptr(lm25066_of_match),
        },
-       .probe_new = lm25066_probe,
+       .probe = lm25066_probe,
        .id_table = lm25066_id,
 };
 
index 4cfe476..28afc5f 100644 (file)
@@ -183,7 +183,7 @@ static struct i2c_driver lt7182s_driver = {
                .name = "lt7182s",
                .of_match_table = of_match_ptr(lt7182s_of_match),
        },
-       .probe_new = lt7182s_probe,
+       .probe = lt7182s_probe,
        .id_table = lt7182s_id,
 };
 
index 91df8e8..73a86f4 100644 (file)
@@ -927,7 +927,7 @@ static struct i2c_driver ltc2978_driver = {
                   .name = "ltc2978",
                   .of_match_table = of_match_ptr(ltc2978_of_match),
                   },
-       .probe_new = ltc2978_probe,
+       .probe = ltc2978_probe,
        .id_table = ltc2978_id,
 };
 
index 8e13a7d..f2023b1 100644 (file)
@@ -199,7 +199,7 @@ static struct i2c_driver ltc3815_driver = {
        .driver = {
                   .name = "ltc3815",
                   },
-       .probe_new = ltc3815_probe,
+       .probe = ltc3815_probe,
        .id_table = ltc3815_id,
 };
 
index 0b6f884..2cfaa62 100644 (file)
@@ -178,7 +178,7 @@ static struct i2c_driver max15301_driver = {
        .driver = {
                   .name = "max15301",
                   },
-       .probe_new = max15301_probe,
+       .probe = max15301_probe,
        .id_table = max15301_id,
 };
 
index 94f8690..a573a0a 100644 (file)
@@ -102,7 +102,7 @@ static struct i2c_driver max16064_driver = {
        .driver = {
                   .name = "max16064",
                   },
-       .probe_new = max16064_probe,
+       .probe = max16064_probe,
        .id_table = max16064_id,
 };
 
index 6724f72..3ab2195 100644 (file)
@@ -283,10 +283,10 @@ static int max16601_get_id(struct i2c_client *client)
                return -ENODEV;
 
        /*
-        * PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx" or
-        * "MAX16500y.xx".cdxxcccccccccc
+        * PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx",
+        * "MAX16500y.xx".cdxxcccccccccc, or "MAX16508y.xx".
         */
-       if (!strncmp(buf, "MAX16500", 8)) {
+       if (!strncmp(buf, "MAX16500", 8) || !strncmp(buf, "MAX16508", 8)) {
                id = max16508;
        } else if (!strncmp(buf, "MAX16600", 8)) {
                id = max16600;
@@ -357,7 +357,7 @@ static struct i2c_driver max16601_driver = {
        .driver = {
                   .name = "max16601",
                   },
-       .probe_new = max16601_probe,
+       .probe = max16601_probe,
        .id_table = max16601_id,
 };
 
index ba39f03..7bcf279 100644 (file)
@@ -776,7 +776,7 @@ static struct i2c_driver max20730_driver = {
                .name = "max20730",
                .of_match_table = max20730_of_match,
        },
-       .probe_new = max20730_probe,
+       .probe = max20730_probe,
        .id_table = max20730_id,
 };
 
index 2272dc8..6ebd71c 100644 (file)
@@ -42,7 +42,7 @@ static struct i2c_driver max20751_driver = {
        .driver = {
                   .name = "max20751",
                   },
-       .probe_new = max20751_probe,
+       .probe = max20751_probe,
        .id_table = max20751_id,
 };
 
index 95d79a6..f9aa576 100644 (file)
@@ -394,7 +394,7 @@ static struct i2c_driver max31785_driver = {
                .name = "max31785",
                .of_match_table = max31785_of_match,
        },
-       .probe_new = max31785_probe,
+       .probe = max31785_probe,
        .id_table = max31785_id,
 };
 
index ea76090..fe7f6b1 100644 (file)
@@ -520,7 +520,7 @@ static struct i2c_driver max34440_driver = {
        .driver = {
                   .name = "max34440",
                   },
-       .probe_new = max34440_probe,
+       .probe = max34440_probe,
        .id_table = max34440_id,
 };
 
index 5e66c28..ae8573f 100644 (file)
@@ -182,7 +182,7 @@ static struct i2c_driver max8688_driver = {
        .driver = {
                   .name = "max8688",
                   },
-       .probe_new = max8688_probe,
+       .probe = max8688_probe,
        .id_table = max8688_id,
 };
 
index 24e5194..50662ed 100644 (file)
@@ -395,7 +395,7 @@ static struct i2c_driver mp2888_driver = {
                .name = "mp2888",
                .of_match_table = of_match_ptr(mp2888_of_match),
        },
-       .probe_new = mp2888_probe,
+       .probe = mp2888_probe,
        .id_table = mp2888_id,
 };
 
index 51986ad..2109b04 100644 (file)
@@ -757,7 +757,7 @@ static struct i2c_driver mp2975_driver = {
                .name = "mp2975",
                .of_match_table = of_match_ptr(mp2975_of_match),
        },
-       .probe_new = mp2975_probe,
+       .probe = mp2975_probe,
        .id_table = mp2975_id,
 };
 
index 791a06c..c4c4324 100644 (file)
@@ -56,7 +56,7 @@ static struct i2c_driver mp5023_driver = {
                   .name = "mp5023",
                   .of_match_table = of_match_ptr(mp5023_of_match),
        },
-       .probe_new = mp5023_probe,
+       .probe = mp5023_probe,
 };
 
 module_i2c_driver(mp5023_driver);
index ff93988..865d42e 100644 (file)
@@ -145,7 +145,7 @@ static struct i2c_driver mpq7932_regulator_driver = {
                .name = "mpq7932",
                .of_match_table = mpq7932_of_match,
        },
-       .probe_new = mpq7932_probe,
+       .probe = mpq7932_probe,
        .id_table = mpq7932_id,
 };
 module_i2c_driver(mpq7932_regulator_driver);
index 273ff6e..31d9ae0 100644 (file)
@@ -221,7 +221,7 @@ static struct i2c_driver pim4328_driver = {
        .driver = {
                   .name = "pim4328",
                   },
-       .probe_new = pim4328_probe,
+       .probe = pim4328_probe,
        .id_table = pim4328_id,
 };
 
index 05b4ee3..7d8bd31 100644 (file)
@@ -134,7 +134,7 @@ static struct i2c_driver pli1209bc_driver = {
                   .name = "pli1209bc",
                   .of_match_table = of_match_ptr(pli1209bc_of_match),
                   },
-       .probe_new = pli1209bc_probe,
+       .probe = pli1209bc_probe,
        .id_table = pli1209bc_id,
 };
 
index e0bbc8a..2a16504 100644 (file)
@@ -64,7 +64,7 @@ static struct i2c_driver pm6764tr_driver = {
                   .name = "pm6764tr",
                   .of_match_table = of_match_ptr(pm6764tr_of_match),
                   },
-       .probe_new = pm6764tr_probe,
+       .probe = pm6764tr_probe,
        .id_table = pm6764tr_id,
 };
 
index d0d3869..ec40c5c 100644 (file)
@@ -252,7 +252,7 @@ static struct i2c_driver pmbus_driver = {
        .driver = {
                   .name = "pmbus",
                   },
-       .probe_new = pmbus_probe,
+       .probe = pmbus_probe,
        .id_table = pmbus_id,
 };
 
index 52bee5d..e2790a6 100644 (file)
@@ -139,7 +139,7 @@ static struct i2c_driver pxe1610_driver = {
        .driver = {
                        .name = "pxe1610",
                        },
-       .probe_new = pxe1610_probe,
+       .probe = pxe1610_probe,
        .id_table = pxe1610_id,
 };
 
index d3ba129..b830f3b 100644 (file)
@@ -412,7 +412,7 @@ static struct i2c_driver q54sj108a2_driver = {
                .name = "q54sj108a2",
                .of_match_table = q54sj108a2_of_match,
        },
-       .probe_new = q54sj108a2_probe,
+       .probe = q54sj108a2_probe,
        .id_table = q54sj108a2_id,
 };
 
index 357b9d9..be9076d 100644 (file)
@@ -237,7 +237,7 @@ static struct i2c_driver stpddc60_driver = {
        .driver = {
                   .name = "stpddc60",
                   },
-       .probe_new = stpddc60_probe,
+       .probe = stpddc60_probe,
        .id_table = stpddc60_id,
 };
 
index c3e7813..450b027 100644 (file)
@@ -62,7 +62,7 @@ static struct i2c_driver tda38640_driver = {
                .name = "tda38640",
                .of_match_table = of_match_ptr(tda38640_of_match),
        },
-       .probe_new = tda38640_probe,
+       .probe = tda38640_probe,
        .id_table = tda38640_id,
 };
 
index 31bb83c..ea0074a 100644 (file)
@@ -42,7 +42,7 @@ static struct i2c_driver tps40422_driver = {
        .driver = {
                   .name = "tps40422",
                   },
-       .probe_new = tps40422_probe,
+       .probe = tps40422_probe,
        .id_table = tps40422_id,
 };
 
index 81b9d81..ef99005 100644 (file)
@@ -299,7 +299,7 @@ static struct i2c_driver tps53679_driver = {
                .name = "tps53679",
                .of_match_table = of_match_ptr(tps53679_of_match),
        },
-       .probe_new = tps53679_probe,
+       .probe = tps53679_probe,
        .id_table = tps53679_id,
 };
 
index 435f943..69bbdb6 100644 (file)
@@ -59,7 +59,7 @@ static struct i2c_driver tps546d24_driver = {
                   .name = "tps546d24",
                   .of_match_table = of_match_ptr(tps546d24_of_match),
           },
-       .probe_new = tps546d24_probe,
+       .probe = tps546d24_probe,
        .id_table = tps546d24_id,
 };
 
index 3daaf22..c404d30 100644 (file)
@@ -512,8 +512,6 @@ static int ucd9000_init_debugfs(struct i2c_client *client,
                return -ENOENT;
 
        data->debugfs = debugfs_create_dir(client->name, debugfs);
-       if (!data->debugfs)
-               return -ENOENT;
 
        /*
         * Of the chips this driver supports, only the UCD9090, UCD90160,
@@ -695,7 +693,7 @@ static struct i2c_driver ucd9000_driver = {
                .name = "ucd9000",
                .of_match_table = of_match_ptr(ucd9000_of_match),
        },
-       .probe_new = ucd9000_probe,
+       .probe = ucd9000_probe,
        .id_table = ucd9000_id,
 };
 
index 3ad375a..a828479 100644 (file)
@@ -200,7 +200,7 @@ static struct i2c_driver ucd9200_driver = {
                .name = "ucd9200",
                .of_match_table = of_match_ptr(ucd9200_of_match),
        },
-       .probe_new = ucd9200_probe,
+       .probe = ucd9200_probe,
        .id_table = ucd9200_id,
 };
 
index 32bc773..37d08dd 100644 (file)
@@ -185,7 +185,7 @@ static struct i2c_driver xdpe122_driver = {
                .name = "xdpe12284",
                .of_match_table = of_match_ptr(xdpe122_of_match),
        },
-       .probe_new = xdpe122_probe,
+       .probe = xdpe122_probe,
        .id_table = xdpe122_id,
 };
 
index b8a36ef..235e6b4 100644 (file)
@@ -63,7 +63,7 @@ static struct i2c_driver xdpe152_driver = {
                .name = "xdpe152c4",
                .of_match_table = of_match_ptr(xdpe152_of_match),
        },
-       .probe_new = xdpe152_probe,
+       .probe = xdpe152_probe,
        .id_table = xdpe152_id,
 };
 
index e9df0c5..83458df 100644 (file)
@@ -461,7 +461,7 @@ static struct i2c_driver zl6100_driver = {
        .driver = {
                   .name = "zl6100",
                   },
-       .probe_new = zl6100_probe,
+       .probe = zl6100_probe,
        .id_table = zl6100_id,
 };
 
index 9cb0c2d..4120cad 100644 (file)
@@ -327,7 +327,7 @@ static struct i2c_driver powr1220_driver = {
        .driver = {
                .name   = "powr1220",
        },
-       .probe_new      = powr1220_probe,
+       .probe          = powr1220_probe,
        .id_table       = powr1220_ids,
 };
 
index 529f0e7..484703f 100644 (file)
@@ -347,7 +347,7 @@ static struct i2c_driver sbrmi_driver = {
                .name = "sbrmi",
                .of_match_table = of_match_ptr(sbrmi_of_match),
        },
-       .probe_new = sbrmi_probe,
+       .probe = sbrmi_probe,
        .id_table = sbrmi_id,
 };
 
index 7049d94..b79cece 100644 (file)
@@ -238,7 +238,7 @@ static struct i2c_driver sbtsi_driver = {
                .name = "sbtsi",
                .of_match_table = of_match_ptr(sbtsi_of_match),
        },
-       .probe_new = sbtsi_probe,
+       .probe = sbtsi_probe,
        .id_table = sbtsi_id,
 };
 
index f50b901..55c1794 100644 (file)
@@ -285,7 +285,7 @@ MODULE_DEVICE_TABLE(i2c, sht21_id);
 
 static struct i2c_driver sht21_driver = {
        .driver.name = "sht21",
-       .probe_new   = sht21_probe,
+       .probe       = sht21_probe,
        .id_table    = sht21_id,
 };
 
index 8305e44..bf18630 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
-#include <linux/platform_data/sht3x.h>
 
-/* commands (high precision mode) */
-static const unsigned char sht3x_cmd_measure_blocking_hpm[]    = { 0x2c, 0x06 };
-static const unsigned char sht3x_cmd_measure_nonblocking_hpm[] = { 0x24, 0x00 };
+/* commands (high repeatability mode) */
+static const unsigned char sht3x_cmd_measure_single_hpm[] = { 0x24, 0x00 };
 
-/* commands (low power mode) */
-static const unsigned char sht3x_cmd_measure_blocking_lpm[]    = { 0x2c, 0x10 };
-static const unsigned char sht3x_cmd_measure_nonblocking_lpm[] = { 0x24, 0x16 };
+/* commands (medium repeatability mode) */
+static const unsigned char sht3x_cmd_measure_single_mpm[] = { 0x24, 0x0b };
+
+/* commands (low repeatability mode) */
+static const unsigned char sht3x_cmd_measure_single_lpm[] = { 0x24, 0x16 };
 
 /* commands for periodic mode */
 static const unsigned char sht3x_cmd_measure_periodic_mode[]   = { 0xe0, 0x00 };
@@ -42,9 +42,10 @@ static const unsigned char sht3x_cmd_heater_off[]              = { 0x30, 0x66 };
 static const unsigned char sht3x_cmd_read_status_reg[]         = { 0xf3, 0x2d };
 static const unsigned char sht3x_cmd_clear_status_reg[]        = { 0x30, 0x41 };
 
-/* delays for non-blocking i2c commands, both in us */
-#define SHT3X_NONBLOCKING_WAIT_TIME_HPM  15000
-#define SHT3X_NONBLOCKING_WAIT_TIME_LPM   4000
+/* delays for single-shot mode i2c commands, both in us */
+#define SHT3X_SINGLE_WAIT_TIME_HPM  15000
+#define SHT3X_SINGLE_WAIT_TIME_MPM   6000
+#define SHT3X_SINGLE_WAIT_TIME_LPM   4000
 
 #define SHT3X_WORD_LEN         2
 #define SHT3X_CMD_LENGTH       2
@@ -69,9 +70,15 @@ enum sht3x_limits {
        limit_min_hyst,
 };
 
+enum sht3x_repeatability {
+       low_repeatability,
+       medium_repeatability,
+       high_repeatability,
+};
+
 DECLARE_CRC8_TABLE(sht3x_crc8_table);
 
-/* periodic measure commands (high precision mode) */
+/* periodic measure commands (high repeatability mode) */
 static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = {
        /* 0.5 measurements per second */
        {0x20, 0x32},
@@ -85,7 +92,21 @@ static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = {
        {0x27, 0x37},
 };
 
-/* periodic measure commands (low power mode) */
+/* periodic measure commands (medium repeatability) */
+static const char periodic_measure_commands_mpm[][SHT3X_CMD_LENGTH] = {
+       /* 0.5 measurements per second */
+       {0x20, 0x24},
+       /* 1 measurements per second */
+       {0x21, 0x26},
+       /* 2 measurements per second */
+       {0x22, 0x20},
+       /* 4 measurements per second */
+       {0x23, 0x22},
+       /* 10 measurements per second */
+       {0x27, 0x21},
+};
+
+/* periodic measure commands (low repeatability mode) */
 static const char periodic_measure_commands_lpm[][SHT3X_CMD_LENGTH] = {
        /* 0.5 measurements per second */
        {0x20, 0x2f},
@@ -135,8 +156,7 @@ struct sht3x_data {
        const unsigned char *command;
        u32 wait_time;                  /* in us*/
        unsigned long last_update;      /* last update in periodic mode*/
-
-       struct sht3x_platform_data setup;
+       enum sht3x_repeatability repeatability;
 
        /*
         * cached values for temperature and humidity and limits
@@ -433,26 +453,22 @@ static ssize_t humidity1_limit_store(struct device *dev,
 static void sht3x_select_command(struct sht3x_data *data)
 {
        /*
-        * In blocking mode (clock stretching mode) the I2C bus
-        * is blocked for other traffic, thus the call to i2c_master_recv()
-        * will wait until the data is ready. For non blocking mode, we
-        * have to wait ourselves.
+        * For single-shot mode, only non blocking mode is support,
+        * we have to wait ourselves for result.
         */
        if (data->mode > 0) {
                data->command = sht3x_cmd_measure_periodic_mode;
                data->wait_time = 0;
-       } else if (data->setup.blocking_io) {
-               data->command = data->setup.high_precision ?
-                               sht3x_cmd_measure_blocking_hpm :
-                               sht3x_cmd_measure_blocking_lpm;
-               data->wait_time = 0;
        } else {
-               if (data->setup.high_precision) {
-                       data->command = sht3x_cmd_measure_nonblocking_hpm;
-                       data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_HPM;
+               if (data->repeatability == high_repeatability) {
+                       data->command = sht3x_cmd_measure_single_hpm;
+                       data->wait_time = SHT3X_SINGLE_WAIT_TIME_HPM;
+               } else if (data->repeatability ==  medium_repeatability) {
+                       data->command = sht3x_cmd_measure_single_mpm;
+                       data->wait_time = SHT3X_SINGLE_WAIT_TIME_MPM;
                } else {
-                       data->command = sht3x_cmd_measure_nonblocking_lpm;
-                       data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_LPM;
+                       data->command = sht3x_cmd_measure_single_lpm;
+                       data->wait_time = SHT3X_SINGLE_WAIT_TIME_LPM;
                }
        }
 }
@@ -595,8 +611,10 @@ static ssize_t update_interval_store(struct device *dev,
        }
 
        if (mode > 0) {
-               if (data->setup.high_precision)
+               if (data->repeatability == high_repeatability)
                        command = periodic_measure_commands_hpm[mode - 1];
+               else if (data->repeatability == medium_repeatability)
+                       command = periodic_measure_commands_mpm[mode - 1];
                else
                        command = periodic_measure_commands_lpm[mode - 1];
 
@@ -619,6 +637,37 @@ out:
        return count;
 }
 
+static ssize_t repeatability_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct sht3x_data *data = dev_get_drvdata(dev);
+
+       return sysfs_emit(buf, "%d\n", data->repeatability);
+}
+
+static ssize_t repeatability_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t count)
+{
+       int ret;
+       u8 val;
+
+       struct sht3x_data *data = dev_get_drvdata(dev);
+
+       ret = kstrtou8(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       if (val > 2)
+               return -EINVAL;
+
+       data->repeatability = val;
+
+       return count;
+}
+
 static SENSOR_DEVICE_ATTR_RO(temp1_input, temp1_input, 0);
 static SENSOR_DEVICE_ATTR_RO(humidity1_input, humidity1_input, 0);
 static SENSOR_DEVICE_ATTR_RW(temp1_max, temp1_limit, limit_max);
@@ -635,6 +684,7 @@ static SENSOR_DEVICE_ATTR_RO(temp1_alarm, temp1_alarm, 0);
 static SENSOR_DEVICE_ATTR_RO(humidity1_alarm, humidity1_alarm, 0);
 static SENSOR_DEVICE_ATTR_RW(heater_enable, heater_enable, 0);
 static SENSOR_DEVICE_ATTR_RW(update_interval, update_interval, 0);
+static SENSOR_DEVICE_ATTR_RW(repeatability, repeatability, 0);
 
 static struct attribute *sht3x_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
@@ -651,11 +701,20 @@ static struct attribute *sht3x_attrs[] = {
        &sensor_dev_attr_humidity1_alarm.dev_attr.attr,
        &sensor_dev_attr_heater_enable.dev_attr.attr,
        &sensor_dev_attr_update_interval.dev_attr.attr,
+       &sensor_dev_attr_repeatability.dev_attr.attr,
        NULL
 };
 
 static struct attribute *sts3x_attrs[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+       &sensor_dev_attr_heater_enable.dev_attr.attr,
+       &sensor_dev_attr_update_interval.dev_attr.attr,
+       &sensor_dev_attr_repeatability.dev_attr.attr,
        NULL
 };
 
@@ -690,16 +749,12 @@ static int sht3x_probe(struct i2c_client *client)
        if (!data)
                return -ENOMEM;
 
-       data->setup.blocking_io = false;
-       data->setup.high_precision = true;
+       data->repeatability = high_repeatability;
        data->mode = 0;
        data->last_update = jiffies - msecs_to_jiffies(3000);
        data->client = client;
        crc8_populate_msb(sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL);
 
-       if (client->dev.platform_data)
-               data->setup = *(struct sht3x_platform_data *)dev->platform_data;
-
        sht3x_select_command(data);
 
        mutex_init(&data->i2c_lock);
@@ -743,7 +798,7 @@ MODULE_DEVICE_TABLE(i2c, sht3x_ids);
 
 static struct i2c_driver sht3x_i2c_driver = {
        .driver.name = "sht3x",
-       .probe_new   = sht3x_probe,
+       .probe       = sht3x_probe,
        .id_table    = sht3x_ids,
 };
 
index 5bbe091..7ee7974 100644 (file)
@@ -291,7 +291,7 @@ static struct i2c_driver sht4x_driver = {
                .name = "sht4x",
                .of_match_table = sht4x_of_match,
        },
-       .probe_new      = sht4x_probe,
+       .probe          = sht4x_probe,
        .id_table       = sht4x_id,
 };
 
index 18546eb..1f96e94 100644 (file)
@@ -279,7 +279,7 @@ static struct i2c_driver shtc1_i2c_driver = {
                .name = "shtc1",
                .of_match_table = shtc1_of_match,
        },
-       .probe_new    = shtc1_probe,
+       .probe        = shtc1_probe,
        .id_table     = shtc1_id,
 };
 
index c36bdbe..026c76f 100644 (file)
@@ -694,7 +694,7 @@ static struct i2c_driver smm665_driver = {
        .driver = {
                   .name = "smm665",
                   },
-       .probe_new = smm665_probe,
+       .probe = smm665_probe,
        .remove = smm665_remove,
        .id_table = smm665_id,
 };
index 70d2152..d20800a 100644 (file)
@@ -628,7 +628,7 @@ static struct i2c_driver smsc47m192_driver = {
        .driver = {
                .name   = "smsc47m192",
        },
-       .probe_new      = smsc47m192_probe,
+       .probe          = smsc47m192_probe,
        .id_table       = smsc47m192_id,
        .detect         = smsc47m192_detect,
        .address_list   = normal_i2c,
index 2f67c67..847c993 100644 (file)
@@ -821,7 +821,7 @@ static struct i2c_driver stts751_driver = {
                .name   = DEVNAME,
                .of_match_table = of_match_ptr(stts751_of_match),
        },
-       .probe_new      = stts751_probe,
+       .probe          = stts751_probe,
        .id_table       = stts751_id,
        .detect         = stts751_detect,
        .alert          = stts751_alert,
index 54cd33d..42a9658 100644 (file)
@@ -561,7 +561,7 @@ static struct i2c_driver tc654_driver = {
        .driver = {
                   .name = "tc654",
                   },
-       .probe_new = tc654_probe,
+       .probe = tc654_probe,
        .id_table = tc654_id,
 };
 
index ace55da..0395067 100644 (file)
@@ -160,7 +160,7 @@ static struct i2c_driver tc74_driver = {
        .driver = {
                .name   = "tc74",
        },
-       .probe_new = tc74_probe,
+       .probe = tc74_probe,
        .id_table = tc74_id,
 };
 
index 81cdb01..68ba26b 100644 (file)
@@ -420,7 +420,7 @@ static struct i2c_driver thmc50_driver = {
        .driver = {
                .name = "thmc50",
        },
-       .probe_new = thmc50_probe,
+       .probe = thmc50_probe,
        .id_table = thmc50_id,
        .detect = thmc50_detect,
        .address_list = normal_i2c,
index e271556..2506c78 100644 (file)
@@ -184,7 +184,7 @@ static const struct regmap_config tmp102_regmap_config = {
        .writeable_reg = tmp102_is_writeable_reg,
        .volatile_reg = tmp102_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,
 };
@@ -301,7 +301,7 @@ static struct i2c_driver tmp102_driver = {
        .driver.name    = DRIVER_NAME,
        .driver.of_match_table = of_match_ptr(tmp102_of_match),
        .driver.pm      = pm_sleep_ptr(&tmp102_dev_pm_ops),
-       .probe_new      = tmp102_probe,
+       .probe          = tmp102_probe,
        .id_table       = tmp102_id,
 };
 
index d257bb9..a84c29a 100644 (file)
@@ -214,7 +214,7 @@ static struct i2c_driver tmp103_driver = {
                .of_match_table = of_match_ptr(tmp103_of_match),
                .pm     = pm_sleep_ptr(&tmp103_dev_pm_ops),
        },
-       .probe_new      = tmp103_probe,
+       .probe          = tmp103_probe,
        .id_table       = tmp103_id,
 };
 
index 43784c2..d7a09ab 100644 (file)
@@ -318,7 +318,7 @@ static const struct regmap_config tmp108_regmap_config = {
        .writeable_reg = tmp108_is_writeable_reg,
        .volatile_reg = tmp108_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,
 };
@@ -432,7 +432,7 @@ static struct i2c_driver tmp108_driver = {
                .pm     = pm_sleep_ptr(&tmp108_dev_pm_ops),
                .of_match_table = of_match_ptr(tmp108_of_ids),
        },
-       .probe_new      = tmp108_probe,
+       .probe          = tmp108_probe,
        .id_table       = tmp108_i2c_ids,
 };
 
index f358ba6..91f2314 100644 (file)
@@ -766,7 +766,7 @@ static struct i2c_driver tmp401_driver = {
                .name   = "tmp401",
                .of_match_table = of_match_ptr(tmp4xx_of_match),
        },
-       .probe_new      = tmp401_probe,
+       .probe          = tmp401_probe,
        .id_table       = tmp401_id,
        .detect         = tmp401_detect,
        .address_list   = normal_i2c,
index 45fd7fb..3cde391 100644 (file)
@@ -487,7 +487,7 @@ static struct i2c_driver tmp421_driver = {
                .name   = "tmp421",
                .of_match_table = of_match_ptr(tmp421_of_match),
        },
-       .probe_new = tmp421_probe,
+       .probe = tmp421_probe,
        .id_table = tmp421_id,
        .detect = tmp421_detect,
        .address_list = normal_i2c,
index 9213a49..4b79c3f 100644 (file)
@@ -644,7 +644,7 @@ static const struct regmap_config tmp464_regmap_config = {
        .max_register = TMP464_DEVICE_ID_REG,
        .volatile_reg = tmp464_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,
 };
@@ -699,7 +699,7 @@ static struct i2c_driver tmp464_driver = {
                .name   = "tmp464",
                .of_match_table = of_match_ptr(tmp464_of_match),
        },
-       .probe_new = tmp464_probe,
+       .probe = tmp464_probe,
        .id_table = tmp464_id,
        .detect = tmp464_detect,
        .address_list = normal_i2c,
index 0693eae..bff10f4 100644 (file)
@@ -760,7 +760,7 @@ static struct i2c_driver tmp51x_driver = {
                .name   = "tmp51x",
                .of_match_table = tmp51x_of_match,
        },
-       .probe_new      = tmp51x_probe,
+       .probe          = tmp51x_probe,
        .id_table       = tmp51x_id,
 };
 
index 85a75f5..8fbbb29 100644 (file)
@@ -581,7 +581,7 @@ static const struct of_device_id __maybe_unused tps23861_of_match[] = {
 MODULE_DEVICE_TABLE(of, tps23861_of_match);
 
 static struct i2c_driver tps23861_driver = {
-       .probe_new              = tps23861_probe,
+       .probe                  = tps23861_probe,
        .remove                 = tps23861_remove,
        .driver = {
                .name           = "tps23861",
index 8dbcd05..7f3615f 100644 (file)
@@ -295,7 +295,7 @@ static struct i2c_driver w83773_driver = {
                .name   = "w83773g",
                .of_match_table = of_match_ptr(w83773_of_match),
        },
-       .probe_new = w83773_probe,
+       .probe = w83773_probe,
        .id_table = w83773_id,
 };
 
index dacabf2..b33f382 100644 (file)
@@ -1585,7 +1585,7 @@ static struct i2c_driver w83781d_driver = {
                .name = "w83781d",
                .of_match_table = w83781d_of_match,
        },
-       .probe_new      = w83781d_probe,
+       .probe          = w83781d_probe,
        .remove         = w83781d_remove,
        .id_table       = w83781d_ids,
        .detect         = w83781d_detect,
index eaf6913..9681eaa 100644 (file)
@@ -338,7 +338,7 @@ static struct i2c_driver w83791d_driver = {
        .driver = {
                .name = "w83791d",
        },
-       .probe_new      = w83791d_probe,
+       .probe          = w83791d_probe,
        .remove         = w83791d_remove,
        .id_table       = w83791d_id,
        .detect         = w83791d_detect,
index 6d160ee..69ce379 100644 (file)
@@ -306,7 +306,7 @@ static struct i2c_driver w83792d_driver = {
        .driver = {
                .name = "w83792d",
        },
-       .probe_new      = w83792d_probe,
+       .probe          = w83792d_probe,
        .remove         = w83792d_remove,
        .id_table       = w83792d_id,
        .detect         = w83792d_detect,
index a4926d9..96bab94 100644 (file)
@@ -301,7 +301,7 @@ static struct i2c_driver w83793_driver = {
        .driver = {
                   .name = "w83793",
        },
-       .probe_new      = w83793_probe,
+       .probe          = w83793_probe,
        .remove         = w83793_remove,
        .id_table       = w83793_id,
        .detect         = w83793_detect,
index 84ff5c5..c446e00 100644 (file)
@@ -2255,7 +2255,7 @@ static struct i2c_driver w83795_driver = {
        .driver = {
                   .name = "w83795",
        },
-       .probe_new      = w83795_probe,
+       .probe          = w83795_probe,
        .remove         = w83795_remove,
        .id_table       = w83795_id,
 
index f3622de..9c11ed6 100644 (file)
@@ -84,7 +84,7 @@ static struct i2c_driver w83l785ts_driver = {
        .driver = {
                .name   = "w83l785ts",
        },
-       .probe_new      = w83l785ts_probe,
+       .probe          = w83l785ts_probe,
        .remove         = w83l785ts_remove,
        .id_table       = w83l785ts_id,
        .detect         = w83l785ts_detect,
index 5597e1c..75874cf 100644 (file)
@@ -751,7 +751,7 @@ static struct i2c_driver w83l786ng_driver = {
        .driver = {
                   .name = "w83l786ng",
        },
-       .probe_new      = w83l786ng_probe,
+       .probe          = w83l786ng_probe,
        .id_table       = w83l786ng_id,
        .detect         = w83l786ng_detect,
        .address_list   = normal_i2c,
index 492dd27..8cd6a6b 100644 (file)
@@ -44,6 +44,7 @@ enum hwmon_chip_attributes {
        hwmon_chip_in_samples,
        hwmon_chip_power_samples,
        hwmon_chip_temp_samples,
+       hwmon_chip_beep_enable,
 };
 
 #define HWMON_C_TEMP_RESET_HISTORY     BIT(hwmon_chip_temp_reset_history)
@@ -58,6 +59,7 @@ enum hwmon_chip_attributes {
 #define HWMON_C_IN_SAMPLES             BIT(hwmon_chip_in_samples)
 #define HWMON_C_POWER_SAMPLES          BIT(hwmon_chip_power_samples)
 #define HWMON_C_TEMP_SAMPLES           BIT(hwmon_chip_temp_samples)
+#define HWMON_C_BEEP_ENABLE            BIT(hwmon_chip_beep_enable)
 
 enum hwmon_temp_attributes {
        hwmon_temp_enable,
@@ -87,6 +89,7 @@ enum hwmon_temp_attributes {
        hwmon_temp_reset_history,
        hwmon_temp_rated_min,
        hwmon_temp_rated_max,
+       hwmon_temp_beep,
 };
 
 #define HWMON_T_ENABLE         BIT(hwmon_temp_enable)
@@ -116,6 +119,7 @@ enum hwmon_temp_attributes {
 #define HWMON_T_RESET_HISTORY  BIT(hwmon_temp_reset_history)
 #define HWMON_T_RATED_MIN      BIT(hwmon_temp_rated_min)
 #define HWMON_T_RATED_MAX      BIT(hwmon_temp_rated_max)
+#define HWMON_T_BEEP           BIT(hwmon_temp_beep)
 
 enum hwmon_in_attributes {
        hwmon_in_enable,
@@ -136,6 +140,7 @@ enum hwmon_in_attributes {
        hwmon_in_crit_alarm,
        hwmon_in_rated_min,
        hwmon_in_rated_max,
+       hwmon_in_beep,
 };
 
 #define HWMON_I_ENABLE         BIT(hwmon_in_enable)
@@ -156,6 +161,7 @@ enum hwmon_in_attributes {
 #define HWMON_I_CRIT_ALARM     BIT(hwmon_in_crit_alarm)
 #define HWMON_I_RATED_MIN      BIT(hwmon_in_rated_min)
 #define HWMON_I_RATED_MAX      BIT(hwmon_in_rated_max)
+#define HWMON_I_BEEP           BIT(hwmon_in_beep)
 
 enum hwmon_curr_attributes {
        hwmon_curr_enable,
@@ -176,6 +182,7 @@ enum hwmon_curr_attributes {
        hwmon_curr_crit_alarm,
        hwmon_curr_rated_min,
        hwmon_curr_rated_max,
+       hwmon_curr_beep,
 };
 
 #define HWMON_C_ENABLE         BIT(hwmon_curr_enable)
@@ -196,6 +203,7 @@ enum hwmon_curr_attributes {
 #define HWMON_C_CRIT_ALARM     BIT(hwmon_curr_crit_alarm)
 #define HWMON_C_RATED_MIN      BIT(hwmon_curr_rated_min)
 #define HWMON_C_RATED_MAX      BIT(hwmon_curr_rated_max)
+#define HWMON_C_BEEP           BIT(hwmon_curr_beep)
 
 enum hwmon_power_attributes {
        hwmon_power_enable,
@@ -312,6 +320,7 @@ enum hwmon_fan_attributes {
        hwmon_fan_min_alarm,
        hwmon_fan_max_alarm,
        hwmon_fan_fault,
+       hwmon_fan_beep,
 };
 
 #define HWMON_F_ENABLE                 BIT(hwmon_fan_enable)
@@ -326,6 +335,7 @@ enum hwmon_fan_attributes {
 #define HWMON_F_MIN_ALARM              BIT(hwmon_fan_min_alarm)
 #define HWMON_F_MAX_ALARM              BIT(hwmon_fan_max_alarm)
 #define HWMON_F_FAULT                  BIT(hwmon_fan_fault)
+#define HWMON_F_BEEP                   BIT(hwmon_fan_beep)
 
 enum hwmon_pwm_attributes {
        hwmon_pwm_input,
diff --git a/include/linux/platform_data/sht3x.h b/include/linux/platform_data/sht3x.h
deleted file mode 100644 (file)
index 14680d2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2016 Sensirion AG, Switzerland
- * Author: David Frey <david.frey@sensirion.com>
- * Author: Pascal Sachs <pascal.sachs@sensirion.com>
- */
-
-#ifndef __SHT3X_H_
-#define __SHT3X_H_
-
-struct sht3x_platform_data {
-       bool blocking_io;
-       bool high_precision;
-};
-#endif /* __SHT3X_H_ */