diff options
author | Linus Torvalds | 2023-06-29 10:01:25 -0700 |
---|---|---|
committer | Linus Torvalds | 2023-06-29 10:01:25 -0700 |
commit | acd1d46b0ddec686d4170b2205bc08c88d5d4d74 (patch) | |
tree | 8f5e09da7840ce204310168f70bda9a23732064f | |
parent | e8c716bc6812202ccf4ce0f0bad3428b794fb39c (diff) | |
parent | 90fc660e8479c5da5bb99a4fb3e0d266fa041b15 (diff) |
Merge tag 'hwmon-for-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck:
"New drivers:
- Driver for MAX31827
- Driver to support HP WMI Sensors
Added support to existing drivers:
- aht10: Support for AHT20
- aquacomputer_d5next: Support for Aquacomputer Leakshield
- asus-ec-sensors: Support for ROG Crosshair X670E Hero
- corsair-psu: Cleanups and support for series 2022 and 2023
- it87: Various improvements and support for IT8732F
- nct6683: Support customer ID of some MSI boards.
- nct6755: Support for NCT6799D
- oxp-sensors: Various cleanups; support for AYANEO 2, Geek, OXP
Mini, and AOKZOE A1 PRO
- pmbus/max16601: Support for new revisions of MAX16508
- pmbus/adm1275: Disable ADC while updating PMON_CONFIG, and fix
problems with temperature monitoring on ADM1272
- sht3x: Various cleanups; support for medium repeatability
Other notable changes:
- Switched regmap drivers to Maple tree support where appropriate
Various other minor fixes and improvements"
* tag 'hwmon-for-v6.5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (54 commits)
hwmon: max31827: Switch back to use struct i2c_driver::probe
hwmon: (oxp-sensors) Add support for AOKZOE A1 PRO
hwmon: (corsair-psu) update Series 2022 and 2023 support
hwmon: (corsair-psu) various cleanups
hwmon: (corsair-psu) add support for reading PWM values and mode
hwmon: (pmbus/adm1275) Disable ADC while updating PMON_CONFIG
hwmon: (pmbus/adm1275) Prepare for protected write to PMON_CONFIG
hwmon: (oxp-sensors) Simplify logic of error return
hwmon: (oxp-sensors) Remove unused header
hwmon: (nct6755) Add support for NCT6799D
hwmon: (oxp-sensors) Add tt_toggle attribute on supported boards
hwmon: (sht3x) complement sysfs interface for sts3x
hwmon: (sht3x) Add new non-stardard sysfs attribute
hwmon: (sht3x) add medium repeatability support
hwmon: (sht3x)replace "high-precision" property to "repeatability"
hwmon: (sht3x) remove blocking_io property
hwmon: (sht3x) remove sht3x_platform_data
hwmon: (pmbus/max16601) Add support for new revisions of MAX16508
Documentation/hwmon: Fix description of devm_hwmon_device_unregister()
hwmon: (tmp464) Use maple tree register cache
...
193 files changed, 3911 insertions, 444 deletions
diff --git a/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml new file mode 100644 index 000000000000..2dc8b07b4d3b --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/adi,max31827.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/adi,max31827.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch + +maintainers: + - Daniel Matyas <daniel.matyas@analog.com> + +description: | + Analog Devices MAX31827, MAX31828, MAX31829 Low-Power Temperature Switch with + I2C Interface + https://www.analog.com/media/en/technical-documentation/data-sheets/MAX31827-MAX31829.pdf + +properties: + compatible: + oneOf: + - const: adi,max31827 + - items: + - enum: + - adi,max31828 + - adi,max31829 + - const: adi,max31827 + + reg: + maxItems: 1 + + vref-supply: + description: + Must have values in the interval (1.6V; 3.6V) in order for the device to + function correctly. + +required: + - compatible + - reg + - vref-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + temperature-sensor@42 { + compatible = "adi,max31827"; + reg = <0x42>; + vref-supply = <®_vdd>; + }; + }; +... diff --git a/Documentation/hwmon/aht10.rst b/Documentation/hwmon/aht10.rst index 4e198c5eb683..213644b4ecba 100644 --- a/Documentation/hwmon/aht10.rst +++ b/Documentation/hwmon/aht10.rst @@ -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. diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index 14b37851af0c..94dc2d93d180 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -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) diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst index c92c1d3839e4..7e3cd5b6686f 100644 --- a/Documentation/hwmon/asus_ec_sensors.rst +++ b/Documentation/hwmon/asus_ec_sensors.rst @@ -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 diff --git a/Documentation/hwmon/corsair-psu.rst b/Documentation/hwmon/corsair-psu.rst index c389bd21f4f2..16db34d464dd 100644 --- a/Documentation/hwmon/corsair-psu.rst +++ b/Documentation/hwmon/corsair-psu.rst @@ -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 index 000000000000..a6bca9aecdde --- /dev/null +++ b/Documentation/hwmon/hp-wmi-sensors.rst @@ -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 diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst index c2d1e0299d8d..6cacf7daf25c 100644 --- a/Documentation/hwmon/hwmon-kernel-api.rst +++ b/Documentation/hwmon/hwmon-kernel-api.rst @@ -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 diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index fa1208c62855..042e1cf9501b 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -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 index 000000000000..b0971d05b8a4 --- /dev/null +++ b/Documentation/hwmon/max31827.rst @@ -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. diff --git a/Documentation/hwmon/oxp-sensors.rst b/Documentation/hwmon/oxp-sensors.rst index 566a8d5bde08..3adeb7406243 100644 --- a/Documentation/hwmon/oxp-sensors.rst +++ b/Documentation/hwmon/oxp-sensors.rst @@ -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) diff --git a/Documentation/hwmon/sht3x.rst b/Documentation/hwmon/sht3x.rst index 95a850d5b2c1..87864ffd1777 100644 --- a/Documentation/hwmon/sht3x.rst +++ b/Documentation/hwmon/sht3x.rst @@ -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 =================== ============================================================ diff --git a/MAINTAINERS b/MAINTAINERS index acbe54087d1c..98ee41083632 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9473,6 +9473,13 @@ L: platform-driver-x86@vger.kernel.org S: Orphan F: drivers/platform/x86/hp/tc1100-wmi.c +HP WMI HARDWARE MONITOR DRIVER +M: James Seo <james@equiv.tech> +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/hp-wmi-sensors.rst +F: drivers/hwmon/hp-wmi-sensors.c + HPET: High Precision Event Timers driver M: Clemens Ladisch <clemens@ladisch.de> S: Maintained @@ -12671,6 +12678,15 @@ F: Documentation/userspace-api/media/drivers/max2175.rst F: drivers/media/i2c/max2175* F: include/uapi/linux/max2175.h +MAX31827 TEMPERATURE SWITCH DRIVER +M: Daniel Matyas <daniel.matyas@analog.com> +L: linux-hwmon@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/devicetree/bindings/hwmon/adi,max31827.yaml +F: Documentation/hwmon/max31827.rst +F: drivers/hwmon/max31827.c + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER L: linux-hwmon@vger.kernel.org S: Orphan diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index fc640201a2de..307477b8a371 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -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 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index cd8c568c80a9..3f4b0fda0998 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -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 - diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index 0afb89c4629d..7f1bef59046f 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -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, }; diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index 22bdb7e5b9e0..ffe81e445010 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -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, }; diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index 97b330b6c165..46e3c8c50765 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -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, diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 2dc45e958730..7c15398ebb37 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -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, diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 2984c4f98496..389382d54752 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -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, diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 1f084f708743..581d8edf70ea 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -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, diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index eaf6e5e04aac..9a465f3f71c8 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -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, diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index b42797bcb5b4..88c7e0d62d08 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -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, diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c index bfe070a1b501..60a893f27159 100644 --- a/drivers/hwmon/adm1177.c +++ b/drivers/hwmon/adm1177.c @@ -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); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 9eb973a38e4b..6dfbeb6acf00 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -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, diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index 7246198f0901..1932613ec095 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -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); diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 0cebf6777239..952506779336 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -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), }; diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 6ba84921614f..45fe4e8aae4e 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -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, diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 9c0235849d4b..429566c4245d 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -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, diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 64f801b859ff..c4b3a4a18670 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -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, diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 6a6ebcc896b1..c0ce88324ea6 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -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, diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c index b8fe3f7248ba..f136bf3ff40a 100644 --- a/drivers/hwmon/aht10.c +++ b/drivers/hwmon/aht10.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * aht10.c - Linux hwmon driver for AHT10 Temperature and Humidity sensor + * aht10.c - Linux hwmon driver for AHT10/AHT20 Temperature and Humidity sensors * Copyright (C) 2020 Johannes Cornelis Draaijer */ @@ -10,9 +10,13 @@ #include <linux/i2c.h> #include <linux/ktime.h> #include <linux/module.h> +#include <linux/crc8.h> #define AHT10_MEAS_SIZE 6 +#define AHT20_MEAS_SIZE 7 +#define AHT20_CRC8_POLY 0x31 + /* * Poll intervals (in milliseconds) */ @@ -44,9 +48,18 @@ #define AHT10_MAX_POLL_INTERVAL_LEN 30 +enum aht10_variant { aht10, aht20 }; + +static const struct i2c_device_id aht10_id[] = { + { "aht10", aht10 }, + { "aht20", aht20 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, aht10_id); + /** - * struct aht10_data - All the data required to operate an AHT10 chip - * @client: the i2c client associated with the AHT10 + * struct aht10_data - All the data required to operate an AHT10/AHT20 chip + * @client: the i2c client associated with the AHT10/AHT20 * @lock: a mutex that is used to prevent parallel access to the * i2c client * @min_poll_interval: the minimum poll interval @@ -56,12 +69,14 @@ * the chip from warming up due to the heat it generates. * If it's unwanted, it can be ignored setting it to * it to 0. Default value is 2000 ms - * @previous_poll_time: the previous time that the AHT10 + * @previous_poll_time: the previous time that the AHT10/AHT20 * was polled * @temperature: the latest temperature value received from - * the AHT10 + * the AHT10/AHT20 * @humidity: the latest humidity value received from the - * AHT10 + * AHT10/AHT20 + * @crc8: crc8 support flag + * @meas_size: measurements data size */ struct aht10_data { @@ -75,12 +90,14 @@ struct aht10_data { ktime_t previous_poll_time; int temperature; int humidity; + bool crc8; + unsigned int meas_size; }; /** - * aht10_init() - Initialize an AHT10 chip - * @data: the data associated with this AHT10 chip - * Return: 0 if succesfull, 1 if not + * aht10_init() - Initialize an AHT10/AHT20 chip + * @data: the data associated with this AHT10/AHT20 chip + * Return: 0 if successful, 1 if not */ static int aht10_init(struct aht10_data *data) { @@ -121,54 +138,78 @@ static int aht10_polltime_expired(struct aht10_data *data) return ktime_after(difference, data->min_poll_interval); } +DECLARE_CRC8_TABLE(crc8_table); + /** - * aht10_read_values() - read and parse the raw data from the AHT10 + * crc8_check() - check crc of the sensor's measurements + * @raw_data: data frame received from sensor(including crc as the last byte) + * @count: size of the data frame + * Return: 0 if successful, 1 if not + */ +static int crc8_check(u8 *raw_data, int count) +{ + /* + * crc calculated on the whole frame(including crc byte) should yield + * zero in case of correctly received bytes + */ + return crc8(crc8_table, raw_data, count, CRC8_INIT_VALUE); +} + +/** + * aht10_read_values() - read and parse the raw data from the AHT10/AHT20 * @data: the struct aht10_data to use for the lock - * Return: 0 if succesfull, 1 if not + * Return: 0 if successful, 1 if not */ static int aht10_read_values(struct aht10_data *data) { const u8 cmd_meas[] = {AHT10_CMD_MEAS, 0x33, 0x00}; u32 temp, hum; int res; - u8 raw_data[AHT10_MEAS_SIZE]; + u8 raw_data[AHT20_MEAS_SIZE]; struct i2c_client *client = data->client; mutex_lock(&data->lock); - if (aht10_polltime_expired(data)) { - res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas)); - if (res < 0) { - mutex_unlock(&data->lock); - return res; - } - - usleep_range(AHT10_MEAS_DELAY, - AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA); - - res = i2c_master_recv(client, raw_data, AHT10_MEAS_SIZE); - if (res != AHT10_MEAS_SIZE) { - mutex_unlock(&data->lock); - if (res >= 0) - return -ENODATA; - else - return res; - } - - hum = ((u32)raw_data[1] << 12u) | - ((u32)raw_data[2] << 4u) | - ((raw_data[3] & 0xF0u) >> 4u); - - temp = ((u32)(raw_data[3] & 0x0Fu) << 16u) | - ((u32)raw_data[4] << 8u) | - raw_data[5]; - - temp = ((temp * 625) >> 15u) * 10; - hum = ((hum * 625) >> 16u) * 10; - - data->temperature = (int)temp - 50000; - data->humidity = hum; - data->previous_poll_time = ktime_get_boottime(); + if (!aht10_polltime_expired(data)) { + mutex_unlock(&data->lock); + return 0; + } + + res = i2c_master_send(client, cmd_meas, sizeof(cmd_meas)); + if (res < 0) { + mutex_unlock(&data->lock); + return res; } + + usleep_range(AHT10_MEAS_DELAY, AHT10_MEAS_DELAY + AHT10_DELAY_EXTRA); + + res = i2c_master_recv(client, raw_data, data->meas_size); + if (res != data->meas_size) { + mutex_unlock(&data->lock); + if (res >= 0) + return -ENODATA; + return res; + } + + if (data->crc8 && crc8_check(raw_data, data->meas_size)) { + mutex_unlock(&data->lock); + return -EIO; + } + + hum = ((u32)raw_data[1] << 12u) | + ((u32)raw_data[2] << 4u) | + ((raw_data[3] & 0xF0u) >> 4u); + + temp = ((u32)(raw_data[3] & 0x0Fu) << 16u) | + ((u32)raw_data[4] << 8u) | + raw_data[5]; + + temp = ((temp * 625) >> 15u) * 10; + hum = ((hum * 625) >> 16u) * 10; + + data->temperature = (int)temp - 50000; + data->humidity = hum; + data->previous_poll_time = ktime_get_boottime(); + mutex_unlock(&data->lock); return 0; } @@ -290,6 +331,8 @@ static const struct hwmon_chip_info aht10_chip_info = { static int aht10_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_match_id(aht10_id, client); + enum aht10_variant variant = id->driver_data; struct device *device = &client->dev; struct device *hwmon_dev; struct aht10_data *data; @@ -305,6 +348,17 @@ static int aht10_probe(struct i2c_client *client) data->min_poll_interval = ms_to_ktime(AHT10_DEFAULT_MIN_POLL_INTERVAL); data->client = client; + switch (variant) { + case aht20: + data->meas_size = AHT20_MEAS_SIZE; + data->crc8 = true; + crc8_populate_msb(crc8_table, AHT20_CRC8_POLY); + break; + default: + data->meas_size = AHT10_MEAS_SIZE; + break; + } + mutex_init(&data->lock); res = aht10_init(data); @@ -324,23 +378,17 @@ static int aht10_probe(struct i2c_client *client) return PTR_ERR_OR_ZERO(hwmon_dev); } -static const struct i2c_device_id aht10_id[] = { - { "aht10", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, aht10_id); - static struct i2c_driver aht10_driver = { .driver = { .name = "aht10", }, - .probe_new = aht10_probe, + .probe = aht10_probe, .id_table = aht10_id, }; module_i2c_driver(aht10_driver); MODULE_AUTHOR("Johannes Cornelis Draaijer <jcdra1@gmail.com>"); -MODULE_DESCRIPTION("AHT10 Temperature and Humidity sensor driver"); +MODULE_DESCRIPTION("AHT10/AHT20 Temperature and Humidity sensor driver"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 3bfd12ff4b3c..2a7a4b6b0094 100644 --- a/drivers/hwmon/amc6821.c +++ b/drivers/hwmon/amc6821.c @@ -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, diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index a4fcd4ebf76c..a981f7086114 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -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) }, diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index ce4da836765c..974521e9b6b4 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -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, diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c index 54595454537b..87e186700849 100644 --- a/drivers/hwmon/asc7621.c +++ b/drivers/hwmon/asc7621.c @@ -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, diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index e5be0cf472fc..f52a539eb33e 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -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; diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 118297ea1dcf..d1de020abec6 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -288,7 +288,7 @@ static struct i2c_driver atxp1_driver = { .driver = { .name = "atxp1", }, - .probe_new = atxp1_probe, + .probe = atxp1_probe, .id_table = atxp1_id, }; diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c index dc24c566d08b..904890598c11 100644 --- a/drivers/hwmon/corsair-psu.c +++ b/drivers/hwmon/corsair-psu.c @@ -32,23 +32,25 @@ * but it is better to not rely on this (it is also hard to parse) * - the driver uses raw events to be accessible from userspace (though this is not really * supported, it is just there for convenience, may be removed in the future) - * - a reply always start with the length and command in the same order the request used it + * - a reply always starts with the length and command in the same order the request used it * - length of the reply data is specific to the command used * - some of the commands work on a rail and can be switched to a specific rail (0 = 12v, * 1 = 5v, 2 = 3.3v) * - the format of the init command 0xFE is swapped length/command bytes * - parameter bytes amount and values are specific to the command (rail setting is the only - * for now that uses non-zero values) - * - there are much more commands, especially for configuring the device, but they are not - * supported because a wrong command/length can lockup the micro-controller + * one for now that uses non-zero values) * - the driver supports debugfs for values not fitting into the hwmon class - * - not every device class (HXi, RMi or AXi) supports all commands - * - it is a pure sensors reading driver (will not support configuring) + * - not every device class (HXi or RMi) supports all commands + * - if configured wrong the PSU resets or shuts down, often before actually hitting the + * reported critical temperature + * - new models like HX1500i Series 2023 have changes in the reported vendor and product + * strings, both are slightly longer now, report vendor and product in one string and are + * the same now */ #define DRIVER_NAME "corsair-psu" -#define REPLY_SIZE 16 /* max length of a reply to a single command */ +#define REPLY_SIZE 24 /* max length of a reply to a single command */ #define CMD_BUFFER_SIZE 64 #define CMD_TIMEOUT_MS 250 #define SECONDS_PER_HOUR (60 * 60) @@ -58,7 +60,8 @@ #define OCP_MULTI_RAIL 0x02 #define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */ -#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 /* the rest of the commands expect length 3 */ +#define PSU_CMD_FAN_PWM 0x3B /* the rest of the commands expect length 3 */ +#define PSU_CMD_RAIL_VOLTS_HCRIT 0x40 #define PSU_CMD_RAIL_VOLTS_LCRIT 0x44 #define PSU_CMD_RAIL_AMPS_HCRIT 0x46 #define PSU_CMD_TEMP_HCRIT 0x4F @@ -76,6 +79,7 @@ #define PSU_CMD_UPTIME 0xD2 #define PSU_CMD_OCPMODE 0xD8 #define PSU_CMD_TOTAL_WATTS 0xEE +#define PSU_CMD_FAN_PWM_ENABLE 0xF0 #define PSU_CMD_INIT 0xFE #define L_IN_VOLTS "v_in" @@ -145,6 +149,14 @@ static int corsairpsu_linear11_to_int(const u16 val, const int scale) return (exp >= 0) ? (result << exp) : (result >> -exp); } +/* the micro-controller uses percentage values to control pwm */ +static int corsairpsu_dutycycle_to_pwm(const long dutycycle) +{ + const int result = (256 << 16) / 100; + + return (result * dutycycle) >> 16; +} + static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data) { unsigned long time; @@ -244,8 +256,8 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l /* * the biggest value here comes from the uptime command and to exceed MAXINT total uptime * needs to be about 68 years, the rest are u16 values and the biggest value coming out of - * the LINEAR11 conversion are the watts values which are about 1200 for the strongest psu - * supported (HX1200i) + * the LINEAR11 conversion are the watts values which are about 1500 for the strongest psu + * supported (HX1500i) */ tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]; switch (cmd) { @@ -264,6 +276,24 @@ static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, l case PSU_CMD_FAN: *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); break; + case PSU_CMD_FAN_PWM_ENABLE: + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); + /* + * 0 = automatic mode, means the micro-controller controls the fan using a plan + * which can be modified, but changing this plan is not supported by this + * driver, the matching PWM mode is automatic fan speed control = PWM 2 + * 1 = fixed mode, fan runs at a fixed speed represented by a percentage + * value 0-100, this matches the PWM manual fan speed control = PWM 1 + * technically there is no PWM no fan speed control mode, it would be a combination + * of 1 at 100% + */ + if (*val == 0) + *val = 2; + break; + case PSU_CMD_FAN_PWM: + *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1); + *val = corsairpsu_dutycycle_to_pwm(*val); + break; case PSU_CMD_RAIL_WATTS: case PSU_CMD_TOTAL_WATTS: *val = corsairpsu_linear11_to_int(tmp & 0xFFFF, 1000000); @@ -349,6 +379,18 @@ static umode_t corsairpsu_hwmon_fan_is_visible(const struct corsairpsu_data *pri } } +static umode_t corsairpsu_hwmon_pwm_is_visible(const struct corsairpsu_data *priv, u32 attr, + int channel) +{ + switch (attr) { + case hwmon_pwm_input: + case hwmon_pwm_enable: + return 0444; + default: + return 0; + } +} + static umode_t corsairpsu_hwmon_power_is_visible(const struct corsairpsu_data *priv, u32 attr, int channel) { @@ -416,6 +458,8 @@ static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sens return corsairpsu_hwmon_temp_is_visible(priv, attr, channel); case hwmon_fan: return corsairpsu_hwmon_fan_is_visible(priv, attr, channel); + case hwmon_pwm: + return corsairpsu_hwmon_pwm_is_visible(priv, attr, channel); case hwmon_power: return corsairpsu_hwmon_power_is_visible(priv, attr, channel); case hwmon_in: @@ -447,6 +491,20 @@ static int corsairpsu_hwmon_temp_read(struct corsairpsu_data *priv, u32 attr, in return err; } +static int corsairpsu_hwmon_pwm_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val) +{ + switch (attr) { + case hwmon_pwm_input: + return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM, 0, val); + case hwmon_pwm_enable: + return corsairpsu_get_value(priv, PSU_CMD_FAN_PWM_ENABLE, 0, val); + default: + break; + } + + return -EOPNOTSUPP; +} + static int corsairpsu_hwmon_power_read(struct corsairpsu_data *priv, u32 attr, int channel, long *val) { @@ -531,6 +589,8 @@ static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types if (attr == hwmon_fan_input) return corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val); return -EOPNOTSUPP; + case hwmon_pwm: + return corsairpsu_hwmon_pwm_read(priv, attr, channel, val); case hwmon_power: return corsairpsu_hwmon_power_read(priv, attr, channel, val); case hwmon_in: @@ -571,7 +631,7 @@ static const struct hwmon_ops corsairpsu_hwmon_ops = { .read_string = corsairpsu_hwmon_ops_read_string, }; -static const struct hwmon_channel_info * const corsairpsu_info[] = { +static const struct hwmon_channel_info *const corsairpsu_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, @@ -579,6 +639,8 @@ static const struct hwmon_channel_info * const corsairpsu_info[] = { HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_CRIT), HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE), HWMON_CHANNEL_INFO(power, HWMON_P_INPUT | HWMON_P_LABEL, HWMON_P_INPUT | HWMON_P_LABEL, @@ -813,15 +875,15 @@ static const struct hid_device_id corsairpsu_idtable[] = { { HID_USB_DEVICE(0x1b1c, 0x1c04) }, /* Corsair HX650i */ { HID_USB_DEVICE(0x1b1c, 0x1c05) }, /* Corsair HX750i */ { HID_USB_DEVICE(0x1b1c, 0x1c06) }, /* Corsair HX850i */ - { HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i revision 1 */ + { HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i Series 2022 */ { HID_USB_DEVICE(0x1b1c, 0x1c08) }, /* Corsair HX1200i */ { HID_USB_DEVICE(0x1b1c, 0x1c09) }, /* Corsair RM550i */ { HID_USB_DEVICE(0x1b1c, 0x1c0a) }, /* Corsair RM650i */ { HID_USB_DEVICE(0x1b1c, 0x1c0b) }, /* Corsair RM750i */ { HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */ { HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */ - { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i revision 2 */ - { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i */ + { HID_USB_DEVICE(0x1b1c, 0x1c1e) }, /* Corsair HX1000i Series 2023 */ + { HID_USB_DEVICE(0x1b1c, 0x1c1f) }, /* Corsair HX1500i Series 2022 and 2023 */ { }, }; MODULE_DEVICE_TABLE(hid, corsairpsu_idtable); diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 66c48f70fae7..cdbf3dff9172 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -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, diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index e803d6393b9e..21b635046521 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -384,7 +384,7 @@ static struct i2c_driver ds1621_driver = { .driver = { .name = "ds1621", }, - .probe_new = ds1621_probe, + .probe = ds1621_probe, .id_table = ds1621_id, }; diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 82d7c3d58f49..2b09536630cb 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -245,7 +245,7 @@ static struct i2c_driver ds620_driver = { .driver = { .name = "ds620", }, - .probe_new = ds620_probe, + .probe = ds620_probe, .id_table = ds620_id, }; diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 61d59189a6d1..bb7c859e799d 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -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, }; diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 361cf9292456..b59472bbe5bf 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -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, diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index 723f57518c9a..29f0e4945f19 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -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, diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c index bcd93f0fe982..9a4f868bf1e6 100644 --- a/drivers/hwmon/emc6w201.c +++ b/drivers/hwmon/emc6w201.c @@ -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, diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 70121482a617..27207ec6f7fe 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -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); diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 64fbb8cf687c..8c572bb64f5d 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -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, diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index e1f426e86f36..b30512a705a7 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -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, diff --git a/drivers/hwmon/ftsteutates.c b/drivers/hwmon/ftsteutates.c index f5a4d91a7e90..b74a2665e733 100644 --- a/drivers/hwmon/ftsteutates.c +++ b/drivers/hwmon/ftsteutates.c @@ -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, }; diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index 36717b524dbd..b5edee00267b 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -206,7 +206,7 @@ static struct i2c_driver g760a_driver = { .driver = { .name = "g760a", }, - .probe_new = g760a_probe, + .probe = g760a_probe, .id_table = g760a_id, }; diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index e2c3c34f06e8..1b6ff4712138 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -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, }; diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 95286c40f55a..03db6158b13a 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -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, diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 394da4ac977c..8bbc6a4f2928 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -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, diff --git a/drivers/hwmon/gsc-hwmon.c b/drivers/hwmon/gsc-hwmon.c index 73e5d92b200b..1501ceb551e7 100644 --- a/drivers/hwmon/gsc-hwmon.c +++ b/drivers/hwmon/gsc-hwmon.c @@ -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); diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index 3a7582824f94..a9726b5370fb 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -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 index 000000000000..ebe2fb513480 --- /dev/null +++ b/drivers/hwmon/hp-wmi-sensors.c @@ -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, ¤t_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, ¤t_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"); diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 573b83b6c08c..c7dd3f5b2bd5 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -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; diff --git a/drivers/hwmon/ina209.c b/drivers/hwmon/ina209.c index 9b58655d2de4..c558143e5285 100644 --- a/drivers/hwmon/ina209.c +++ b/drivers/hwmon/ina209.c @@ -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, }; diff --git a/drivers/hwmon/ina238.c b/drivers/hwmon/ina238.c index 8af07bc0c50e..f519c22d3907 100644 --- a/drivers/hwmon/ina238.c +++ b/drivers/hwmon/ina238.c @@ -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, }; diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index fd50d9785ccb..cfd7efef5cdf 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -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, }; diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 2735e3782ffb..5ab944056ec0 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -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, diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index eb38f54ebeb6..5deff5e5f693 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -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 */ diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 4c60dc520b12..f958e830b23c 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -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, diff --git a/drivers/hwmon/lineage-pem.c b/drivers/hwmon/lineage-pem.c index ef5a49cd9149..df69c380cde7 100644 --- a/drivers/hwmon/lineage-pem.c +++ b/drivers/hwmon/lineage-pem.c @@ -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, }; diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 9ab2cab4c710..6972454eb4e0 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -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, diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c index b6433ae2d75c..637d35c5ae23 100644 --- a/drivers/hwmon/lm73.c +++ b/drivers/hwmon/lm73.c @@ -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, diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index dbb99ea4a0ec..72e634d1b857 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -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, diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 645cb2191abe..8b9862519178 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -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, diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 694e171cab7f..b739c354311b 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -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, diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 35db0b97f912..63c7831bd3e1 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -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, diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index bcaf31ec176e..5befedca6abb 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -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, diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 8d33c2484755..8540178f5b74 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -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, diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 818fb6195245..2195a735d28e 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -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, diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 6498d5acf705..90101c236f35 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -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, diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 2ff3044a677d..46579a3e1715 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -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, diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 4cf50d5f4f59..75bca805720e 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -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, diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index b4a9d0c223c4..67b9d7636ee4 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -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, diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c index 647a90570bc6..475551f5024b 100644 --- a/drivers/hwmon/lm95241.c +++ b/drivers/hwmon/lm95241.c @@ -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, diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c index 4236d1e0544d..17ff54bd4015 100644 --- a/drivers/hwmon/lm95245.c +++ b/drivers/hwmon/lm95245.c @@ -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, diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index 3494f7261ebf..45b87a863cae 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -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, }; diff --git a/drivers/hwmon/ltc2947-i2c.c b/drivers/hwmon/ltc2947-i2c.c index 96852bc8a964..33f574bf2ce7 100644 --- a/drivers/hwmon/ltc2947-i2c.c +++ b/drivers/hwmon/ltc2947-i2c.c @@ -38,7 +38,7 @@ static struct i2c_driver ltc2947_driver = { .of_match_table = ltc2947_of_match, .pm = pm_sleep_ptr(<c2947_pm_ops), }, - .probe_new = ltc2947_probe, + .probe = ltc2947_probe, .id_table = ltc2947_id, }; module_i2c_driver(ltc2947_driver); diff --git a/drivers/hwmon/ltc2990.c b/drivers/hwmon/ltc2990.c index 689f788b8563..1ad362c0fd2c 100644 --- a/drivers/hwmon/ltc2990.c +++ b/drivers/hwmon/ltc2990.c @@ -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, }; diff --git a/drivers/hwmon/ltc2992.c b/drivers/hwmon/ltc2992.c index 429a7f5837f0..589bcd07ce7f 100644 --- a/drivers/hwmon/ltc2992.c +++ b/drivers/hwmon/ltc2992.c @@ -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, }; diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index e3ac004c1ed1..f42ac3c9475e 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -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, }; diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c index fa43d26ddd4f..66fd28f713ab 100644 --- a/drivers/hwmon/ltc4215.c +++ b/drivers/hwmon/ltc4215.c @@ -255,7 +255,7 @@ static struct i2c_driver ltc4215_driver = { .driver = { .name = "ltc4215", }, - .probe_new = ltc4215_probe, + .probe = ltc4215_probe, .id_table = ltc4215_id, }; diff --git a/drivers/hwmon/ltc4222.c b/drivers/hwmon/ltc4222.c index d2027ca5c925..9098ef521739 100644 --- a/drivers/hwmon/ltc4222.c +++ b/drivers/hwmon/ltc4222.c @@ -210,7 +210,7 @@ static struct i2c_driver ltc4222_driver = { .driver = { .name = "ltc4222", }, - .probe_new = ltc4222_probe, + .probe = ltc4222_probe, .id_table = ltc4222_id, }; diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index fb9bc8dbe99b..b90184a3e0ec 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -479,7 +479,7 @@ static struct i2c_driver ltc4245_driver = { .driver = { .name = "ltc4245", }, - .probe_new = ltc4245_probe, + .probe = ltc4245_probe, .id_table = ltc4245_id, }; diff --git a/drivers/hwmon/ltc4260.c b/drivers/hwmon/ltc4260.c index 75e89cec381e..52f7a809b27b 100644 --- a/drivers/hwmon/ltc4260.c +++ b/drivers/hwmon/ltc4260.c @@ -173,7 +173,7 @@ static struct i2c_driver ltc4260_driver = { .driver = { .name = "ltc4260", }, - .probe_new = ltc4260_probe, + .probe = ltc4260_probe, .id_table = ltc4260_id, }; diff --git a/drivers/hwmon/ltc4261.c b/drivers/hwmon/ltc4261.c index b91cc4fe84e5..509e68176c7a 100644 --- a/drivers/hwmon/ltc4261.c +++ b/drivers/hwmon/ltc4261.c @@ -233,7 +233,7 @@ static struct i2c_driver ltc4261_driver = { .driver = { .name = "ltc4261", }, - .probe_new = ltc4261_probe, + .probe = ltc4261_probe, .id_table = ltc4261_id, }; diff --git a/drivers/hwmon/max127.c b/drivers/hwmon/max127.c index 49de1d2be294..ee5ead06d612 100644 --- a/drivers/hwmon/max127.c +++ b/drivers/hwmon/max127.c @@ -339,7 +339,7 @@ static struct i2c_driver max127_driver = { .driver = { .name = "max127", }, - .probe_new = max127_probe, + .probe = max127_probe, .id_table = max127_id, }; diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c index daa5d8af1e69..aa38c45adc09 100644 --- a/drivers/hwmon/max16065.c +++ b/drivers/hwmon/max16065.c @@ -600,7 +600,7 @@ static struct i2c_driver max16065_driver = { .driver = { .name = "max16065", }, - .probe_new = max16065_probe, + .probe = max16065_probe, .id_table = max16065_id, }; diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 445c77197f69..500dc926a7a7 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -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, diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index 9f748973d6a3..c4a02edefbee 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -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, diff --git a/drivers/hwmon/max31730.c b/drivers/hwmon/max31730.c index 924333d89ce4..b1300ca9db1f 100644 --- a/drivers/hwmon/max31730.c +++ b/drivers/hwmon/max31730.c @@ -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, diff --git a/drivers/hwmon/max31760.c b/drivers/hwmon/max31760.c index 4489110f109c..79945eb466ae 100644 --- a/drivers/hwmon/max31760.c +++ b/drivers/hwmon/max31760.c @@ -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); diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c index 6caba6e8ee8f..0cd44c1e998a 100644 --- a/drivers/hwmon/max31790.c +++ b/drivers/hwmon/max31790.c @@ -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 index 000000000000..602f4e4f81ff --- /dev/null +++ b/drivers/hwmon/max31827.c @@ -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"); diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c index 0f277d945ea2..5d12fb9c9786 100644 --- a/drivers/hwmon/max6620.c +++ b/drivers/hwmon/max6620.c @@ -503,7 +503,7 @@ static struct i2c_driver max6620_driver = { .driver = { .name = "max6620", }, - .probe_new = max6620_probe, + .probe = max6620_probe, .id_table = max6620_id, }; diff --git a/drivers/hwmon/max6621.c b/drivers/hwmon/max6621.c index 0656eb1e7959..7f709fd1af89 100644 --- a/drivers/hwmon/max6621.c +++ b/drivers/hwmon/max6621.c @@ -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, }; diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 9b895402c80d..caf527154fca 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -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, diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c index 47ea34ff78f3..8b2e4d6101a2 100644 --- a/drivers/hwmon/max6642.c +++ b/drivers/hwmon/max6642.c @@ -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, diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 19e2c762ed2d..cc8428a3045d 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -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, }; diff --git a/drivers/hwmon/max6697.c b/drivers/hwmon/max6697.c index 2895cea54193..3a67778f111c 100644 --- a/drivers/hwmon/max6697.c +++ b/drivers/hwmon/max6697.c @@ -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, }; diff --git a/drivers/hwmon/mc34vr500.c b/drivers/hwmon/mc34vr500.c index 6a7a950a9332..0c8fd3fce83e 100644 --- a/drivers/hwmon/mc34vr500.c +++ b/drivers/hwmon/mc34vr500.c @@ -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, }; diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index a5f7a294f33d..127e15ff3e76 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -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, }; diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index a872f783e9cc..f673f7d07941 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -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: diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index c54233f0369b..236dc97f4d22 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -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], ®); 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; diff --git a/drivers/hwmon/nct6775-i2c.c b/drivers/hwmon/nct6775-i2c.c index e1bcd1146191..87a4fc78c571 100644 --- a/drivers/hwmon/nct6775-i2c.c +++ b/drivers/hwmon/nct6775-i2c.c @@ -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, }; diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c index 5782acfb4ee1..ada867d6b98a 100644 --- a/drivers/hwmon/nct6775-platform.c +++ b/drivers/hwmon/nct6775-platform.c @@ -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); diff --git a/drivers/hwmon/nct6775.h b/drivers/hwmon/nct6775.h index be41848c3cd2..44f79c5726a9 100644 --- a/drivers/hwmon/nct6775.h +++ b/drivers/hwmon/nct6775.h @@ -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*/ diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index a175f8283695..9339bfc02a3e 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -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, }; diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index 007bae4c7028..8f867d4570e1 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c @@ -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, diff --git a/drivers/hwmon/occ/p8_i2c.c b/drivers/hwmon/occ/p8_i2c.c index 9e1744fccb35..06095975f5c8 100644 --- a/drivers/hwmon/occ/p8_i2c.c +++ b/drivers/hwmon/occ/p8_i2c.c @@ -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, }; diff --git a/drivers/hwmon/oxp-sensors.c b/drivers/hwmon/oxp-sensors.c index ae67207030e8..e1a907cae820 100644 --- a/drivers/hwmon/oxp-sensors.c +++ b/drivers/hwmon/oxp-sensors.c @@ -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); diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index 1dbe209ae13f..66c76b28c9e0 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/acbel-fsg032.c b/drivers/hwmon/pmbus/acbel-fsg032.c index 28a25f30e2cf..0a0ef4ce3493 100644 --- a/drivers/hwmon/pmbus/acbel-fsg032.c +++ b/drivers/hwmon/pmbus/acbel-fsg032.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c index 1ac2b2f4c570..ed0a7b9fae4b 100644 --- a/drivers/hwmon/pmbus/adm1266.c +++ b/drivers/hwmon/pmbus/adm1266.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 3b07bfb43e93..e2c61d6fa521 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/bel-pfe.c b/drivers/hwmon/pmbus/bel-pfe.c index 4100eefb7ac3..fa5070ae26bc 100644 --- a/drivers/hwmon/pmbus/bel-pfe.c +++ b/drivers/hwmon/pmbus/bel-pfe.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/bpa-rs600.c b/drivers/hwmon/pmbus/bpa-rs600.c index f2d4e378a775..0dce26c35556 100644 --- a/drivers/hwmon/pmbus/bpa-rs600.c +++ b/drivers/hwmon/pmbus/bpa-rs600.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/delta-ahe50dc-fan.c b/drivers/hwmon/pmbus/delta-ahe50dc-fan.c index f546f0c12497..4dd3b6686d6a 100644 --- a/drivers/hwmon/pmbus/delta-ahe50dc-fan.c +++ b/drivers/hwmon/pmbus/delta-ahe50dc-fan.c @@ -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); diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c index d3941f6eb29a..f7ff3e4650b7 100644 --- a/drivers/hwmon/pmbus/dps920ab.c +++ b/drivers/hwmon/pmbus/dps920ab.c @@ -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); diff --git a/drivers/hwmon/pmbus/fsp-3y.c b/drivers/hwmon/pmbus/fsp-3y.c index c7469d2cdedc..72a7c261ef06 100644 --- a/drivers/hwmon/pmbus/fsp-3y.c +++ b/drivers/hwmon/pmbus/fsp-3y.c @@ -282,7 +282,7 @@ static struct i2c_driver fsp3y_driver = { .driver = { .name = "fsp3y", }, - .probe_new = fsp3y_probe, + .probe = fsp3y_probe, .id_table = fsp3y_id }; diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index 76e72e9acda7..c791925b8907 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c index 0f614e8d95f6..dfeae68b5e52 100644 --- a/drivers/hwmon/pmbus/inspur-ipsps.c +++ b/drivers/hwmon/pmbus/inspur-ipsps.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c index a6cf98e49666..e3ee5c1bd967 100644 --- a/drivers/hwmon/pmbus/ir35221.c +++ b/drivers/hwmon/pmbus/ir35221.c @@ -136,7 +136,7 @@ static struct i2c_driver ir35221_driver = { .driver = { .name = "ir35221", }, - .probe_new = ir35221_probe, + .probe = ir35221_probe, .id_table = ir35221_id, }; diff --git a/drivers/hwmon/pmbus/ir36021.c b/drivers/hwmon/pmbus/ir36021.c index 4dca4767f571..382ba6b6031a 100644 --- a/drivers/hwmon/pmbus/ir36021.c +++ b/drivers/hwmon/pmbus/ir36021.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/ir38064.c b/drivers/hwmon/pmbus/ir38064.c index 09276e397194..871c322d3d51 100644 --- a/drivers/hwmon/pmbus/ir38064.c +++ b/drivers/hwmon/pmbus/ir38064.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/irps5401.c b/drivers/hwmon/pmbus/irps5401.c index de3449e4d77a..146d32a35a7c 100644 --- a/drivers/hwmon/pmbus/irps5401.c +++ b/drivers/hwmon/pmbus/irps5401.c @@ -54,7 +54,7 @@ static struct i2c_driver irps5401_driver = { .driver = { .name = "irps5401", }, - .probe_new = irps5401_probe, + .probe = irps5401_probe, .id_table = irps5401_id, }; diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index 1a8caff1ac5f..7e53fb1d5ea3 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index 09792cd03d9f..929fa6d34efd 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/lt7182s.c b/drivers/hwmon/pmbus/lt7182s.c index 4cfe476fc92d..28afc5f15ae8 100644 --- a/drivers/hwmon/pmbus/lt7182s.c +++ b/drivers/hwmon/pmbus/lt7182s.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 91df8e895147..73a86f4d6472 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c index 8e13a7ddcb42..f2023b17aa8d 100644 --- a/drivers/hwmon/pmbus/ltc3815.c +++ b/drivers/hwmon/pmbus/ltc3815.c @@ -199,7 +199,7 @@ static struct i2c_driver ltc3815_driver = { .driver = { .name = "ltc3815", }, - .probe_new = ltc3815_probe, + .probe = ltc3815_probe, .id_table = ltc3815_id, }; diff --git a/drivers/hwmon/pmbus/max15301.c b/drivers/hwmon/pmbus/max15301.c index 0b6f88428ea8..2cfaa62aedd6 100644 --- a/drivers/hwmon/pmbus/max15301.c +++ b/drivers/hwmon/pmbus/max15301.c @@ -178,7 +178,7 @@ static struct i2c_driver max15301_driver = { .driver = { .name = "max15301", }, - .probe_new = max15301_probe, + .probe = max15301_probe, .id_table = max15301_id, }; diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index 94f869039071..a573a0ab9e48 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c @@ -102,7 +102,7 @@ static struct i2c_driver max16064_driver = { .driver = { .name = "max16064", }, - .probe_new = max16064_probe, + .probe = max16064_probe, .id_table = max16064_id, }; diff --git a/drivers/hwmon/pmbus/max16601.c b/drivers/hwmon/pmbus/max16601.c index 6724f723f74c..3ab219504600 100644 --- a/drivers/hwmon/pmbus/max16601.c +++ b/drivers/hwmon/pmbus/max16601.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/max20730.c b/drivers/hwmon/pmbus/max20730.c index ba39f03c6374..7bcf27995033 100644 --- a/drivers/hwmon/pmbus/max20730.c +++ b/drivers/hwmon/pmbus/max20730.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/max20751.c b/drivers/hwmon/pmbus/max20751.c index 2272dc8c2e38..6ebd71cd081b 100644 --- a/drivers/hwmon/pmbus/max20751.c +++ b/drivers/hwmon/pmbus/max20751.c @@ -42,7 +42,7 @@ static struct i2c_driver max20751_driver = { .driver = { .name = "max20751", }, - .probe_new = max20751_probe, + .probe = max20751_probe, .id_table = max20751_id, }; diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c index 95d79a64b483..f9aa576495a5 100644 --- a/drivers/hwmon/pmbus/max31785.c +++ b/drivers/hwmon/pmbus/max31785.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index ea7609058a12..fe7f6b1b0985 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c @@ -520,7 +520,7 @@ static struct i2c_driver max34440_driver = { .driver = { .name = "max34440", }, - .probe_new = max34440_probe, + .probe = max34440_probe, .id_table = max34440_id, }; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index 5e66c28c0b71..ae8573fdf5ba 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -182,7 +182,7 @@ static struct i2c_driver max8688_driver = { .driver = { .name = "max8688", }, - .probe_new = max8688_probe, + .probe = max8688_probe, .id_table = max8688_id, }; diff --git a/drivers/hwmon/pmbus/mp2888.c b/drivers/hwmon/pmbus/mp2888.c index 24e5194706cf..50662ed8e3d5 100644 --- a/drivers/hwmon/pmbus/mp2888.c +++ b/drivers/hwmon/pmbus/mp2888.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c index 51986adfbf47..2109b0458a8b 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/mp5023.c b/drivers/hwmon/pmbus/mp5023.c index 791a06c3c54a..c4c4324d2b74 100644 --- a/drivers/hwmon/pmbus/mp5023.c +++ b/drivers/hwmon/pmbus/mp5023.c @@ -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); diff --git a/drivers/hwmon/pmbus/mpq7932.c b/drivers/hwmon/pmbus/mpq7932.c index ff939881dc3b..865d42edda1a 100644 --- a/drivers/hwmon/pmbus/mpq7932.c +++ b/drivers/hwmon/pmbus/mpq7932.c @@ -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); diff --git a/drivers/hwmon/pmbus/pim4328.c b/drivers/hwmon/pmbus/pim4328.c index 273ff6e57654..31d9ae06379a 100644 --- a/drivers/hwmon/pmbus/pim4328.c +++ b/drivers/hwmon/pmbus/pim4328.c @@ -221,7 +221,7 @@ static struct i2c_driver pim4328_driver = { .driver = { .name = "pim4328", }, - .probe_new = pim4328_probe, + .probe = pim4328_probe, .id_table = pim4328_id, }; diff --git a/drivers/hwmon/pmbus/pli1209bc.c b/drivers/hwmon/pmbus/pli1209bc.c index 05b4ee35ba27..7d8bd3167b21 100644 --- a/drivers/hwmon/pmbus/pli1209bc.c +++ b/drivers/hwmon/pmbus/pli1209bc.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/pm6764tr.c b/drivers/hwmon/pmbus/pm6764tr.c index e0bbc8a30d21..2a16504c85b7 100644 --- a/drivers/hwmon/pmbus/pm6764tr.c +++ b/drivers/hwmon/pmbus/pm6764tr.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index d0d386990af5..ec40c5c59954 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -252,7 +252,7 @@ static struct i2c_driver pmbus_driver = { .driver = { .name = "pmbus", }, - .probe_new = pmbus_probe, + .probe = pmbus_probe, .id_table = pmbus_id, }; diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index 52bee5de2988..e2790a682dc8 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -139,7 +139,7 @@ static struct i2c_driver pxe1610_driver = { .driver = { .name = "pxe1610", }, - .probe_new = pxe1610_probe, + .probe = pxe1610_probe, .id_table = pxe1610_id, }; diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c index d3ba12951324..b830f3b02bcc 100644 --- a/drivers/hwmon/pmbus/q54sj108a2.c +++ b/drivers/hwmon/pmbus/q54sj108a2.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/stpddc60.c b/drivers/hwmon/pmbus/stpddc60.c index 357b9d9d896b..be9076dcc2db 100644 --- a/drivers/hwmon/pmbus/stpddc60.c +++ b/drivers/hwmon/pmbus/stpddc60.c @@ -237,7 +237,7 @@ static struct i2c_driver stpddc60_driver = { .driver = { .name = "stpddc60", }, - .probe_new = stpddc60_probe, + .probe = stpddc60_probe, .id_table = stpddc60_id, }; diff --git a/drivers/hwmon/pmbus/tda38640.c b/drivers/hwmon/pmbus/tda38640.c index c3e781319cd1..450b0273fb59 100644 --- a/drivers/hwmon/pmbus/tda38640.c +++ b/drivers/hwmon/pmbus/tda38640.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/tps40422.c b/drivers/hwmon/pmbus/tps40422.c index 31bb83c0ef3e..ea0074a6b9fc 100644 --- a/drivers/hwmon/pmbus/tps40422.c +++ b/drivers/hwmon/pmbus/tps40422.c @@ -42,7 +42,7 @@ static struct i2c_driver tps40422_driver = { .driver = { .name = "tps40422", }, - .probe_new = tps40422_probe, + .probe = tps40422_probe, .id_table = tps40422_id, }; diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 81b9d813655a..ef99005a3af5 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/tps546d24.c b/drivers/hwmon/pmbus/tps546d24.c index 435f94304ad8..69bbdb6c680b 100644 --- a/drivers/hwmon/pmbus/tps546d24.c +++ b/drivers/hwmon/pmbus/tps546d24.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 3daaf2237832..c404d306e8f7 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index 3ad375a76f3e..a82847945508 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/xdpe12284.c b/drivers/hwmon/pmbus/xdpe12284.c index 32bc7736d609..37d08dd427d5 100644 --- a/drivers/hwmon/pmbus/xdpe12284.c +++ b/drivers/hwmon/pmbus/xdpe12284.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/xdpe152c4.c b/drivers/hwmon/pmbus/xdpe152c4.c index b8a36ef73e45..235e6b41ae4c 100644 --- a/drivers/hwmon/pmbus/xdpe152c4.c +++ b/drivers/hwmon/pmbus/xdpe152c4.c @@ -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, }; diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c index e9df0c56d91e..83458df0d0cf 100644 --- a/drivers/hwmon/pmbus/zl6100.c +++ b/drivers/hwmon/pmbus/zl6100.c @@ -461,7 +461,7 @@ static struct i2c_driver zl6100_driver = { .driver = { .name = "zl6100", }, - .probe_new = zl6100_probe, + .probe = zl6100_probe, .id_table = zl6100_id, }; diff --git a/drivers/hwmon/powr1220.c b/drivers/hwmon/powr1220.c index 9cb0c2de5219..4120cadb00ae 100644 --- a/drivers/hwmon/powr1220.c +++ b/drivers/hwmon/powr1220.c @@ -327,7 +327,7 @@ static struct i2c_driver powr1220_driver = { .driver = { .name = "powr1220", }, - .probe_new = powr1220_probe, + .probe = powr1220_probe, .id_table = powr1220_ids, }; diff --git a/drivers/hwmon/sbrmi.c b/drivers/hwmon/sbrmi.c index 529f0e766319..484703f0ea5f 100644 --- a/drivers/hwmon/sbrmi.c +++ b/drivers/hwmon/sbrmi.c @@ -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, }; diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c index 7049d9464ac6..b79cece4ac9a 100644 --- a/drivers/hwmon/sbtsi_temp.c +++ b/drivers/hwmon/sbtsi_temp.c @@ -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, }; diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index f50b90198f23..55c179475208 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -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, }; diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c index 8305e44d9ab2..bf18630619e0 100644 --- a/drivers/hwmon/sht3x.c +++ b/drivers/hwmon/sht3x.c @@ -20,15 +20,15 @@ #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, }; diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 5bbe09135ab9..7ee797410458 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -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, }; diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index 18546ebc8e9f..1f96e94967ee 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -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, }; diff --git a/drivers/hwmon/smm665.c b/drivers/hwmon/smm665.c index c36bdbe423de..026c76f8c22e 100644 --- a/drivers/hwmon/smm665.c +++ b/drivers/hwmon/smm665.c @@ -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, }; diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 70d2152234e2..d20800a1f02b 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -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, diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c index 2f67c6747ead..847c99376930 100644 --- a/drivers/hwmon/stts751.c +++ b/drivers/hwmon/stts751.c @@ -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, diff --git a/drivers/hwmon/tc654.c b/drivers/hwmon/tc654.c index 54cd33d09688..42a9658f1bc2 100644 --- a/drivers/hwmon/tc654.c +++ b/drivers/hwmon/tc654.c @@ -561,7 +561,7 @@ static struct i2c_driver tc654_driver = { .driver = { .name = "tc654", }, - .probe_new = tc654_probe, + .probe = tc654_probe, .id_table = tc654_id, }; diff --git a/drivers/hwmon/tc74.c b/drivers/hwmon/tc74.c index ace55da97fc2..03950670bd78 100644 --- a/drivers/hwmon/tc74.c +++ b/drivers/hwmon/tc74.c @@ -160,7 +160,7 @@ static struct i2c_driver tc74_driver = { .driver = { .name = "tc74", }, - .probe_new = tc74_probe, + .probe = tc74_probe, .id_table = tc74_id, }; diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 81cdb012993c..68ba26bc9014 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -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, diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index e271556efe0b..2506c78590af 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -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, }; diff --git a/drivers/hwmon/tmp103.c b/drivers/hwmon/tmp103.c index d257bb91fc69..a84c29a3a765 100644 --- a/drivers/hwmon/tmp103.c +++ b/drivers/hwmon/tmp103.c @@ -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, }; diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 43784c289a9e..d7a09ab2bc11 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -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, }; diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index f358ba679626..91f2314568cf 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -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, diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c index 45fd7fb5ee01..3cde3916ab6d 100644 --- a/drivers/hwmon/tmp421.c +++ b/drivers/hwmon/tmp421.c @@ -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, diff --git a/drivers/hwmon/tmp464.c b/drivers/hwmon/tmp464.c index 9213a493a590..4b79c3f4d9fe 100644 --- a/drivers/hwmon/tmp464.c +++ b/drivers/hwmon/tmp464.c @@ -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, diff --git a/drivers/hwmon/tmp513.c b/drivers/hwmon/tmp513.c index 0693eaee054f..bff10f4b56e1 100644 --- a/drivers/hwmon/tmp513.c +++ b/drivers/hwmon/tmp513.c @@ -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, }; diff --git a/drivers/hwmon/tps23861.c b/drivers/hwmon/tps23861.c index 85a75f551148..8fbbb29ae11d 100644 --- a/drivers/hwmon/tps23861.c +++ b/drivers/hwmon/tps23861.c @@ -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", diff --git a/drivers/hwmon/w83773g.c b/drivers/hwmon/w83773g.c index 8dbcd05abd9a..7f3615f5587c 100644 --- a/drivers/hwmon/w83773g.c +++ b/drivers/hwmon/w83773g.c @@ -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, }; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index dacabf25e83f..b33f382f238d 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -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, diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index eaf691365023..9681eaa06c8e 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -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, diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 6d160eee1446..69ce379a9e13 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -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, diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index a4926d907198..96bab94ba899 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -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, diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c index 84ff5c57e98c..c446e00db658 100644 --- a/drivers/hwmon/w83795.c +++ b/drivers/hwmon/w83795.c @@ -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, diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index f3622de0d96f..9c11ed69c055 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -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, diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c index 5597e1c2d95c..75874cf7851c 100644 --- a/drivers/hwmon/w83l786ng.c +++ b/drivers/hwmon/w83l786ng.c @@ -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, diff --git a/include/linux/hwmon.h b/include/linux/hwmon.h index 492dd27a5dd8..8cd6a6b33593 100644 --- a/include/linux/hwmon.h +++ b/include/linux/hwmon.h @@ -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 index 14680d2a98f7..000000000000 --- a/include/linux/platform_data/sht3x.h +++ /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_ */ |