hwmon updates for v6.10

* New drivers
 
   - Infineon XDP710
 
   - EC Chip driver for Lenovo ThinkStation motherboards
 
   - Analog Devices ADP1050
 
 * Improved support for existing drivers
 
   - emc1403: Convert to with_info API; Support for EMC1428 and EMC1438
 
   - nzxt-kraken3: Support for NZXT Kraken 2023
 
   - aquacomputer_d5next: Support for Octo flow sensors
 
   - pmbus/adm1275: Support for ADM1281
 
   - dell-smm: Supportt for Precision 7540 and G5 5505
 
 * Other notable cleanup
 
   - max6639: Use regmap
 
   - Remove unused structure fields from multiple drivers
 
   - Drop explicit initialization of struct i2c_device_id::driver_data to 0
 
   - Improve configuration mode handling in it87 driver
 
   - jc42: Drop support for I2C_CLASS_SPD
 
   - Various conversions to devicetree schema
 
   - Add HAS_IOPORT dependencies as needed
 
 * Minor fixes and improvements to max31790, coretemp, aspeed-g6-pwm-tach,
   pwm-fan, pmbus/mp2975, acpi_power_meter, and lm70 drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmZCnOsACgkQyx8mb86f
 mYGGIg//Z/P2SNdU+WztPIpLLu19zGe0S0PskGmw/3Ox5Wu95hOyv2FkABkbLOnI
 a0Q69ntPjKtwhziVgws9hcqM33++yz4J8k7Y3UJ7yrGtua4OCLtlm4po9NxomxwR
 5/iNBwDD2fWxOMTfAKCKanYLk+tgvB1xV0SfGN7jmTSL5GLwWZGtHYKzmgbNvdAN
 tAZGF9RlO4bj4eORFaGvbMyrLZuvT2zWzpcuqyvrZQZzcrFJzQgKqeGl6Jv+0Hsm
 LUOIlB8u82hTmyTsZ2PW9TI8sd7Q++3WilVvxB44cmridyst3Ucrcr1KlDBOu6oO
 gxCzHF/MAkQWa8UVmc3OAkfH9+VM3JxOfYNWHpcVNtEqucrJn+ryCrO33ZjUSjLK
 GdvLs0vFoImx1XSjVs8fUIVcsBs7FgkLuruxxJg7uElfYRGMyDzPaTMW//Iwqul6
 RX8/8Td2kYPGdiRDymE/ONQ5LIzZtUvnQUJap5ehHuZmVEIeybBHRXAAn8iG4mUg
 fQAB1imybjsV1yfulfOcA3P+izh/2wpeVlrQDsbMdiUEhD7Xhsrr+GFfIPrvWuGd
 IDWjhu2YP6t9R6yeA9H2W9MhiGNTZmv6bZerhS5InoR93d92pxwkPehwdrwV+mC2
 Ou9ULI9hmJPqEIdCENTCNj1TFUhEZtNhJxjLpaxoMYjx0FMU9aI=
 =68su
 -----END PGP SIGNATURE-----

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

Pull hwmon updates from Guenter Roeck:
 "New drivers:

   - Infineon XDP710

   - EC Chip driver for Lenovo ThinkStation motherboards

   - Analog Devices ADP1050

  Improved support for existing drivers:

   - emc1403: Convert to with_info API; Support for EMC1428 and EMC1438

   - nzxt-kraken3: Support for NZXT Kraken 2023

   - aquacomputer_d5next: Support for Octo flow sensors

   - pmbus/adm1275: Support for ADM1281

   - dell-smm: Supportt for Precision 7540 and G5 5505

  Other notable cleanup:

   - max6639: Use regmap

   - Remove unused structure fields from multiple drivers

   - Drop explicit initialization of struct i2c_device_id::driver_data
     to zero

   - Improve configuration mode handling in it87 driver

   - jc42: Drop support for I2C_CLASS_SPD

   - Various conversions to devicetree schema

   - Add HAS_IOPORT dependencies as needed

  Minor fixes and improvements to max31790, coretemp, aspeed-g6-pwm-tach,
  pwm-fan, pmbus/mp2975, acpi_power_meter, and lm70 drivers"

* tag 'hwmon-for-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (52 commits)
  hwmon: (nzxt-kraken3) Bail out for unsupported device variants
  hwmon: (emc1403) Add support for EMC1428 and EMC1438.
  hwmon: Drop explicit initialization of struct i2c_device_id::driver_data to 0 (part 2)
  hwmon: (emc1403) Add support for conversion interval configuration
  hwmon: (emc1403) Support 11 bit accuracy
  hwmon: (emc1403) Convert to with_info API
  hwmon: (max6639) Use regmap
  hwmon: (npcm750-pwm-fan) Remove another unused field in struct npcm7xx_cooling_device
  hwmon: (npcm750-pwm-fan) Remove an unused field in struct npcm7xx_cooling_device
  hwmon: (stts751) Remove an unused field in struct stts751_priv
  hwmon: Drop explicit initialization of struct i2c_device_id::driver_data to 0
  hwmon: (max31790) revise the scale to write pwm
  hwmon: (nzxt-kraken3) Add support for NZXT Kraken 2023 (standard and Elite) models
  hwmon: (nzxt-kraken3) Decouple device names from kinds
  hwmon: (it87) Remove tests nolonger required
  hwmon: (it87) Test for chipset before entering configuration mode
  hwmon: (it87) Do not enter configuration mode for some chiptypes
  hwmon: (it87) Rename FEAT_CONF_NOEXIT to FEAT_NOCONF as more descriptive of requirement
  hwmon: (pmbus) Add support for Infineon XDP710
  dt-bindings: hwmon: Add infineon xdp710 driver bindings
  ...
This commit is contained in:
Linus Torvalds 2024-05-14 14:51:51 -07:00
commit a8cc7eb996
147 changed files with 2582 additions and 968 deletions

View File

@ -1,38 +0,0 @@
TI ADC128D818 ADC System Monitor With Temperature Sensor
--------------------------------------------------------
Operation modes:
- Mode 0: 7 single-ended voltage readings (IN0-IN6),
1 temperature reading (internal)
- Mode 1: 8 single-ended voltage readings (IN0-IN7),
no temperature
- Mode 2: 4 pseudo-differential voltage readings
(IN0-IN1, IN3-IN2, IN4-IN5, IN7-IN6),
1 temperature reading (internal)
- Mode 3: 4 single-ended voltage readings (IN0-IN3),
2 pseudo-differential voltage readings
(IN4-IN5, IN7-IN6),
1 temperature reading (internal)
If no operation mode is configured via device tree, the driver keeps the
currently active chip operation mode (default is mode 0).
Required node properties:
- compatible: must be set to "ti,adc128d818"
- reg: I2C address of the device
Optional node properties:
- ti,mode: Operation mode (u8) (see above).
Example (operation mode 2):
adc128d818@1d {
compatible = "ti,adc128d818";
reg = <0x1d>;
ti,mode = /bits/ 8 <2>;
};

View File

@ -5,7 +5,7 @@
$id: http://devicetree.org/schemas/hwmon/adi,adm1275.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADM1075/ADM127x/ADM129x digital power monitors
title: Analog Devices ADM1075/ADM127x/ADM1281/ADM129x digital power monitors
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
@ -27,6 +27,7 @@ properties:
- adi,adm1275
- adi,adm1276
- adi,adm1278
- adi,adm1281
- adi,adm1293
- adi,adm1294
@ -91,6 +92,7 @@ allOf:
contains:
enum:
- adi,adm1278
- adi,adm1281
- adi,adm1293
- adi,adm1294
then:

View File

@ -1,11 +0,0 @@
Bindings for Synaptics AS370 PVT sensors
Required properties:
- compatible : "syna,as370-hwmon"
- reg : address and length of the register set.
Example:
hwmon@ea0810 {
compatible = "syna,as370-hwmon";
reg = <0xea0810 0xc>;
};

View File

@ -0,0 +1,37 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ibm,opal-sensor.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: IBM POWERNV platform sensors
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
properties:
compatible:
enum:
- ibm,opal-sensor-cooling-fan
- ibm,opal-sensor-amb-temp
- ibm,opal-sensor-power-supply
- ibm,opal-sensor-power
sensor-id:
description:
An opaque id provided by the firmware to the kernel, identifies a
given sensor and its attribute data.
$ref: /schemas/types.yaml#/definitions/uint32
required:
- compatible
- sensor-id
additionalProperties: false
examples:
- |
sensor {
compatible = "ibm,opal-sensor-cooling-fan";
sensor-id = <0x7052107>;
};

View File

@ -1,25 +0,0 @@
Device-tree bindings for I2C-based On-Chip Controller hwmon device
------------------------------------------------------------------
Required properties:
- compatible = "ibm,p8-occ-hwmon";
- reg = <I2C address>; : I2C bus address
Examples:
i2c-bus@100 {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
< more properties >
occ-hwmon@1 {
compatible = "ibm,p8-occ-hwmon";
reg = <0x50>;
};
occ-hwmon@2 {
compatible = "ibm,p8-occ-hwmon";
reg = <0x51>;
};
};

View File

@ -1,23 +0,0 @@
IBM POWERNV platform sensors
----------------------------
Required node properties:
- compatible: must be one of
"ibm,opal-sensor-cooling-fan"
"ibm,opal-sensor-amb-temp"
"ibm,opal-sensor-power-supply"
"ibm,opal-sensor-power"
- sensor-id: an opaque id provided by the firmware to the kernel, identifies a
given sensor and its attribute data
Example sensors node:
cooling-fan#8-data {
sensor-id = <0x7052107>;
compatible = "ibm,opal-sensor-cooling-fan";
};
amb-temp#1-thrs {
sensor-id = <0x5096000>;
compatible = "ibm,opal-sensor-amb-temp";
};

View File

@ -1,30 +0,0 @@
*LM87 hwmon sensor.
Required properties:
- compatible: Should be
"ti,lm87"
- reg: I2C address
optional properties:
- has-temp3: This configures pins 18 and 19 to be used as a second
remote temperature sensing channel. By default the pins
are configured as voltage input pins in0 and in5.
- has-in6: When set, pin 5 is configured to be used as voltage input
in6. Otherwise the pin is set as FAN1 input.
- has-in7: When set, pin 6 is configured to be used as voltage input
in7. Otherwise the pin is set as FAN2 input.
- vcc-supply: a Phandle for the regulator supplying power, can be
configured to measure 5.0V power supply. Default is 3.3V.
Example:
lm87@2e {
compatible = "ti,lm87";
reg = <0x2e>;
has-temp3;
vcc-supply = <&reg_5v0>;
};

View File

@ -1,28 +0,0 @@
Bindings for MAX6651 and MAX6650 I2C fan controllers
Reference:
[1] https://datasheets.maximintegrated.com/en/ds/MAX6650-MAX6651.pdf
Required properties:
- compatible : One of "maxim,max6650" or "maxim,max6651"
- reg : I2C address, one of 0x1b, 0x1f, 0x4b, 0x48.
Optional properties, default is to retain the chip's current setting:
- maxim,fan-microvolt : The supply voltage of the fan, either 5000000 uV or
12000000 uV.
- maxim,fan-prescale : Pre-scaling value, as per datasheet [1]. Lower values
allow more fine-grained control of slower fans.
Valid: 1, 2, 4, 8, 16.
- maxim,fan-target-rpm: Initial requested fan rotation speed. If specified, the
driver selects closed-loop mode and the requested speed.
This ensures the fan is already running before userspace
takes over.
Example:
fan-max6650: max6650@1b {
reg = <0x1b>;
compatible = "maxim,max6650";
maxim,fan-microvolt = <12000000>;
maxim,fan-prescale = <4>;
maxim,fan-target-rpm = <1200>;
};

View File

@ -0,0 +1,70 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/maxim,max6650.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX6650 and MAX6651 I2C Fan Controllers
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
description: |
The MAX6650 and MAX6651 regulate and monitor the speed
of 5VDC/12VDC burshless fans with built-in tachometers.
Datasheets:
https://datasheets.maximintegrated.com/en/ds/MAX6650-MAX6651.pdf
properties:
compatible:
enum:
- maxim,max6650
- maxim,max6651
reg:
maxItems: 1
maxim,fan-microvolt:
description:
The supply voltage of the fan, either 5000000 uV or
12000000 uV.
enum: [5000000, 12000000]
maxim,fan-prescale:
description:
Pre-scaling value, as per datasheet. Lower values
allow more fine-grained control of slower fans.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16]
maxim,fan-target-rpm:
description:
Initial requested fan rotation speed. If specified, the
driver selects closed-loop mode and the requested speed.
This ensures the fan is already running before userspace
takes over.
$ref: /schemas/types.yaml#/definitions/uint32
maximum: 30000
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
fan-controller@1b {
compatible = "maxim,max6650";
reg = <0x1b>;
maxim,fan-microvolt = <12000000>;
maxim,fan-prescale = <4>;
maxim,fan-target-rpm = <1200>;
};
};

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/pmbus/adi,adp1050.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADP1050 digital controller with PMBus interface
maintainers:
- Radu Sabau <radu.sabau@analog.com>
description: |
The ADP1050 is used to monitor system voltages, currents and temperatures.
Through the PMBus interface, the ADP1050 targets isolated power supplies
and has four individual monitors for input/output voltage, input current
and temperature.
Datasheet:
https://www.analog.com/en/products/adp1050.html
properties:
compatible:
const: adi,adp1050
reg:
maxItems: 1
vcc-supply: true
required:
- compatible
- reg
- vcc-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <100000>;
hwmon@70 {
compatible = "adi,adp1050";
reg = <0x70>;
vcc-supply = <&vcc>;
};
};
...

View File

@ -1 +0,0 @@
This file has moved to pwm-fan.yaml.

View File

@ -0,0 +1,41 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/st,stts751.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STTS751 Thermometer
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
properties:
compatible:
const: st,stts751
reg:
maxItems: 1
smbus-timeout-disable:
description:
When set, the smbus timeout function will be disabled.
$ref: /schemas/types.yaml#/definitions/flag
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
thermometer@48 {
compatible = "st,stts751";
reg = <0x48>;
smbus-timeout-disable;
};
};

View File

@ -1,15 +0,0 @@
* STTS751 thermometer.
Required node properties:
- compatible: "stts751"
- reg: I2C bus address of the device
Optional properties:
- smbus-timeout-disable: when set, the smbus timeout function will be disabled
Example stts751 node:
temp-sensor {
compatible = "stts751";
reg = <0x48>;
}

View File

@ -0,0 +1,32 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/syna,as370.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synaptics AS370 PVT sensors
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
properties:
compatible:
const: syna,as370-hwmon
reg:
description:
Address and length of the register set.
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
sensor@ea0810 {
compatible = "syna,as370-hwmon";
reg = <0xea0810 0xc>;
};

View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,adc128d818.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADC128D818 ADC System Monitor With Temperature Sensor
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
description: |
The ADC128D818 is a 12-Bit, 8-Channel Analog to Digital Converter (ADC)
with a temperature sensor and an I2C interface.
Datasheets:
https://www.ti.com/product/ADC128D818
properties:
compatible:
const: ti,adc128d818
reg:
maxItems: 1
ti,mode:
$ref: /schemas/types.yaml#/definitions/uint8
description: |
Operation mode.
Mode 0 - 7 single-ended voltage readings (IN0-IN6), 1 temperature
reading (internal).
Mode 1 - 8 single-ended voltage readings (IN0-IN7), no temperature.
Mode 2 - 4 pseudo-differential voltage readings
(IN0-IN1, IN3-IN2, IN4-IN5, IN7-IN6), 1 temperature reading (internal).
Mode 3 - 4 single-ended voltage readings (IN0-IN3), 2 pseudo-differential
voltage readings (IN4-IN5, IN7-IN6), 1 temperature reading (internal).
default: 0
vref-supply:
description:
The regulator to use as an external reference. If it does not exist, the
internal reference will be used.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@1d {
compatible = "ti,adc128d818";
reg = <0x1d>;
vref-supply = <&vref>;
ti,mode = /bits/ 8 <2>;
};
};

View File

@ -0,0 +1,69 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,lm87.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments LM87 Hardware Monitor
maintainers:
- Javier Carrasco <javier.carrasco.cruz@gmail.com>
description: |
The LM87 is a serial interface system hardware monitor
with remote diode temperature sensing.
Datasheets:
https://www.ti.com/product/LM87
properties:
compatible:
const: ti,lm87
reg:
maxItems: 1
has-temp3:
$ref: /schemas/types.yaml#/definitions/flag
description:
This configures pins 18 and 19 to be used as a second
remote temperature sensing channel. By default the pins
are configured as voltage input pins in0 and in5.
has-in6:
$ref: /schemas/types.yaml#/definitions/flag
description:
When set, pin 5 is configured to be used as voltage input
in6. Otherwise the pin is set as FAN1 input.
has-in7:
$ref: /schemas/types.yaml#/definitions/flag
description:
When set, pin 6 is configured to be used as voltage input
in7. Otherwise the pin is set as FAN2 input.
vcc-supply:
description:
Regulator supplying power, can be configured to measure
5.0V power supply. Default is 3.3V.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
hwmon@2e {
compatible = "ti,lm87";
reg = <0x2e>;
has-temp3;
vcc-supply = <&reg_5v0>;
};
};

View File

@ -126,6 +126,8 @@ properties:
- ibm,cffps1
# IBM Common Form Factor Power Supply Versions 2
- ibm,cffps2
# IBM On-Chip Controller hwmon device
- ibm,p8-occ-hwmon
# Infineon barometric pressure and temperature sensor
- infineon,dps310
# Infineon IR36021 digital POL buck controller
@ -134,6 +136,8 @@ properties:
- infineon,irps5401
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
- infineon,tlv493d-a1b6
# Infineon Hot-swap controller xdp710
- infineon,xdp710
# Infineon Multi-phase Digital VR Controller xdpe11280
- infineon,xdpe11280
# Infineon Multi-phase Digital VR Controller xdpe12254

View File

@ -43,6 +43,14 @@ Supported chips:
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1278.pdf
* Analog Devices ADM1281
Prefix: 'adm1281'
Addresses scanned: -
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/adm1281.pdf
* Analog Devices ADM1293/ADM1294
Prefix: 'adm1293', 'adm1294'
@ -58,10 +66,10 @@ Description
-----------
This driver supports hardware monitoring for Analog Devices ADM1075, ADM1272,
ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 Hot-Swap Controller and
ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 Hot-Swap Controller and
Digital Power Monitors.
ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 are hot-swap
ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 are hot-swap
controllers that allow a circuit board to be removed from or inserted into
a live backplane. They also feature current and voltage readback via an
integrated 12 bit analog-to-digital converter (ADC), accessed using a
@ -144,5 +152,5 @@ temp1_highest Highest observed temperature.
temp1_reset_history Write any value to reset history.
Temperature attributes are supported on ADM1272 and
ADM1278.
ADM1278, and ADM1281.
======================= =======================================================

View File

@ -0,0 +1,64 @@
.. SPDX-License-Identifier: GPL-2.0
Kernel driver adp1050
=====================
Supported chips:
* Analog Devices ADP1050
Prefix: 'adp1050'
Addresses scanned: I2C 0x70 - 0x77
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADP1050.pdf
Authors:
- Radu Sabau <radu.sabau@analog.com>
Description
-----------
This driver supprts hardware monitoring for Analog Devices ADP1050 Digital
Controller for Isolated Power Supply with PMBus interface.
The ADP1050 is an advanced digital controller with a PMBus™
interface targeting high density, high efficiency dc-to-dc power
conversion used to monitor system temperatures, voltages and currents.
Through the PMBus interface, the device can monitor input/output voltages,
input current and temperature.
Usage Notes
-----------
This driver does not auto-detect devices. You will have to instantiate
the devices explicitly.
Please see Documentation/i2c/instantiating-devices.rst for details.
Platform data support
---------------------
The driver supports standard PMBus driver platform data.
Sysfs Attributes
----------------
================= ========================================
in1_label "vin"
in1_input Measured input voltage
in1_alarm Input voltage alarm
in2_label "vout1"
in2_input Measured output voltage
in2_crit Critical maximum output voltage
in2_crit_alarm Output voltage high alarm
in2_lcrit Critical minimum output voltage
in2_lcrit_alarm Output voltage critical low alarm
curr1_label "iin"
curr1_input Measured input current.
curr1_alarm Input current alarm
temp1_input Measured temperature
temp1_crit Critical high temperature
temp1_crit_alarm Chip temperature critical high alarm
================= ========================================

View File

@ -45,9 +45,9 @@ seems to require sending it a complete configuration. That includes addressable
RGB LEDs, for which there is no standard sysfs interface. Thus, that task is
better suited for userspace tools.
The Octo exposes four physical and sixteen virtual temperature sensors, as well as
eight PWM controllable fans, along with their speed (in RPM), power, voltage and
current.
The Octo exposes four physical and sixteen virtual temperature sensors, a flow sensor
as well as eight PWM controllable fans, along with their speed (in RPM), power, voltage
and current. Flow sensor pulses are also available.
The Quadro exposes four physical and sixteen virtual temperature sensors, a flow
sensor and four PWM controllable fans, along with their speed (in RPM), power,
@ -95,11 +95,12 @@ 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)
fan[1-9]_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
fan9_pulses Octo flow sensor pulses
power[1-8]_input Pump/fan power (in micro Watts)
in[0-7]_input Pump/fan voltage (in milli Volts)
curr[1-8]_input Pump/fan current (in milli Amperes)

View File

@ -45,6 +45,17 @@ Supported chips:
- https://ww1.microchip.com/downloads/en/DeviceDoc/1423_1424.pdf
* SMSC / Microchip EMC1428, EMC1438
Addresses scanned: I2C 0x18, 0x4c, 0x4d
Prefix: 'emc1428', 'emc1438'
Datasheets:
- https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/20005275A.pdf
- https://ww1.microchip.com/downloads/en/DeviceDoc/EMC1438%20DS%20Rev.%201.0%20(04-29-10).pdf
Author:
Kalhan Trisal <kalhan.trisal@intel.com
@ -53,10 +64,10 @@ Description
-----------
The Standard Microsystems Corporation (SMSC) / Microchip EMC14xx chips
contain up to four temperature sensors. EMC14x2 support two sensors
contain up to eight temperature sensors. EMC14x2 support two sensors
(one internal, one external). EMC14x3 support three sensors (one internal,
two external), and EMC14x4 support four sensors (one internal, three
external).
two external), EMC14x4 support four sensors (one internal, three external),
and EMC14x8 support eight sensors (one internal, seven external).
The chips implement three limits for each sensor: low (tempX_min), high
(tempX_max) and critical (tempX_crit.) The chips also implement an

View File

@ -33,6 +33,7 @@ Hardware Monitoring Kernel Drivers
adm1266
adm1275
adm9240
adp1050
ads7828
adt7410
adt7411
@ -250,6 +251,7 @@ Hardware Monitoring Kernel Drivers
wm831x
wm8350
xgene-hwmon
xdp710
xdpe12284
xdpe152c4
zl6100

View File

@ -5,7 +5,7 @@ Supported chips:
* National Semiconductor LM70
Datasheet: http://www.national.com/pf/LM/LM70.html
Datasheet: https://www.ti.com/product/LM70
* Texas Instruments TMP121/TMP123

View File

@ -11,17 +11,20 @@ Supported devices:
* NZXT Kraken Z53
* NZXT Kraken Z63
* NZXT Kraken Z73
* NZXT Kraken 2023
* NZXT Kraken 2023 Elite
Author: Jonas Malaco, Aleksa Savic
Description
-----------
This driver enables hardware monitoring support for NZXT Kraken X53/X63/X73 and
Z53/Z63/Z73 all-in-one CPU liquid coolers. All models expose liquid temperature
and pump speed (in RPM), as well as PWM control (either as a fixed value
or through a temp-PWM curve). The Z-series models additionally expose the speed
and duty of an optionally connected fan, with the same PWM control capabilities.
This driver enables hardware monitoring support for NZXT Kraken X53/X63/X73,
Z53/Z63/Z73 and Kraken 2023 (standard and Elite) all-in-one CPU liquid coolers.
All models expose liquid temperature and pump speed (in RPM), as well as PWM
control (either as a fixed value or through a temp-PWM curve). The Z-series and
Kraken 2023 models additionally expose the speed and duty of an optionally connected
fan, with the same PWM control capabilities.
Pump and fan duty control mode can be set through pwm[1-2]_enable, where 1 is
for the manual control mode and 2 is for the liquid temp to PWM curve mode.
@ -39,9 +42,9 @@ The devices can report if they are faulty. The driver supports that situation
and will issue a warning. This can also happen when the USB cable is connected,
but SATA power is not.
The addressable RGB LEDs and LCD screen (only on Z-series models) are not
supported in this driver, but can be controlled through existing userspace tools,
such as `liquidctl`_.
The addressable RGB LEDs and LCD screen (only on Z-series and Kraken 2023 models)
are not supported in this driver, but can be controlled through existing userspace
tools, such as `liquidctl`_.
.. _liquidctl: https://github.com/liquidctl/liquidctl

View File

@ -152,7 +152,7 @@ Emerson DS1200 power modules might look as follows::
}
static const struct i2c_device_id ds1200_id[] = {
{"ds1200", 0},
{"ds1200"},
{}
};

View File

@ -0,0 +1,83 @@
.. SPDX-License-Identifier: GPL-2.0
Kernel driver xdp710
====================
Supported chips:
* Infineon XDP710
Prefix: 'xdp710'
* Datasheet
Publicly available at the Infineon website : https://www.infineon.com/dgdl/Infineon-XDP710-001-DataSheet-v01_00-EN.pdf?fileId=8ac78c8c8412f8d301848a5316290b97
Author:
Peter Yin <peteryin.openbmc@gmail.com>
Description
-----------
This driver implements support for Infineon XDP710 Hot-Swap Controller.
Device compliant with:
- PMBus rev 1.3 interface.
Device supports direct and linear format for reading input voltage,
output voltage, output current, input power and temperature.
The driver exports the following attributes via the 'sysfs' files
for input voltage:
**in1_input**
**in1_label**
**in1_max**
**in1_max_alarm**
**in1_min**
**in1_min_alarm**
The driver provides the following attributes for output voltage:
**in2_input**
**in2_label**
**in2_alarm**
The driver provides the following attributes for output current:
**curr1_input**
**curr1_label**
**curr1_alarm**
**curr1_max**
The driver provides the following attributes for input power:
**power1_input**
**power1_label**
**power1_alarm**
The driver provides the following attributes for temperature:
**temp1_input**
**temp1_max**
**temp1_max_alarm**
**temp1_crit**
**temp1_crit_alarm**

View File

@ -479,6 +479,13 @@ L: linux-wireless@vger.kernel.org
S: Orphan
F: drivers/net/wireless/admtek/adm8211.*
ADP1050 HARDWARE MONITOR DRIVER
M: Radu Sabau <radu.sabau@analog.com>
L: linux-hwmon@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml
ADP1653 FLASH CONTROLLER DRIVER
M: Sakari Ailus <sakari.ailus@iki.fi>
L: linux-media@vger.kernel.org

View File

@ -22,6 +22,8 @@ MODULE_LICENSE("GPL");
/* the IPMI timeout is 5s */
#define IPMI_TIMEOUT (5000)
#define ACPI_IPMI_MAX_MSG_LENGTH 64
/* 2s should be suffient for SMI being selected */
#define ACPI_IPMI_SMI_SELECTION_TIMEOUT (2 * HZ)
struct acpi_ipmi_device {
/* the device list attached to driver_data.ipmi_devices */
@ -54,6 +56,7 @@ struct ipmi_driver_data {
* to this selected global IPMI system interface.
*/
struct acpi_ipmi_device *selected_smi;
struct completion smi_selection_done;
};
struct acpi_ipmi_msg {
@ -463,8 +466,10 @@ static void ipmi_register_bmc(int iface, struct device *dev)
if (temp->handle == handle)
goto err_lock;
}
if (!driver_data.selected_smi)
if (!driver_data.selected_smi) {
driver_data.selected_smi = ipmi_device;
complete(&driver_data.smi_selection_done);
}
list_add_tail(&ipmi_device->head, &driver_data.ipmi_devices);
mutex_unlock(&driver_data.ipmi_lock);
@ -578,6 +583,20 @@ out_msg:
return status;
}
int acpi_wait_for_acpi_ipmi(void)
{
long ret;
ret = wait_for_completion_interruptible_timeout(&driver_data.smi_selection_done,
ACPI_IPMI_SMI_SELECTION_TIMEOUT);
if (ret <= 0)
return -ETIMEDOUT;
return 0;
}
EXPORT_SYMBOL_GPL(acpi_wait_for_acpi_ipmi);
static int __init acpi_ipmi_init(void)
{
int result;
@ -586,6 +605,8 @@ static int __init acpi_ipmi_init(void)
if (acpi_disabled)
return 0;
init_completion(&driver_data.smi_selection_done);
status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_IPMI,
&acpi_ipmi_space_handler,

View File

@ -40,7 +40,7 @@ comment "Native drivers"
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
depends on (X86 && DMI) || COMPILE_TEST
depends on (X86 && DMI) || COMPILE_TEST && HAS_IOPORT
help
If you say yes here you get support for the sensor part of the first
and second revision of the Abit uGuru chip. The voltage and frequency
@ -55,7 +55,7 @@ config SENSORS_ABITUGURU
config SENSORS_ABITUGURU3
tristate "Abit uGuru (rev 3)"
depends on (X86 && DMI) || COMPILE_TEST
depends on (X86 && DMI) || COMPILE_TEST && HAS_IOPORT
help
If you say yes here you get support for the sensor part of the
third revision of the Abit uGuru chip. Only reading the sensors
@ -611,6 +611,7 @@ config SENSORS_SPARX5
config SENSORS_F71805F
tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG"
depends on HAS_IOPORT
depends on !PPC
help
If you say yes here you get support for hardware monitoring
@ -622,6 +623,7 @@ config SENSORS_F71805F
config SENSORS_F71882FG
tristate "Fintek F71882FG and compatibles"
depends on HAS_IOPORT
depends on !PPC
help
If you say yes here you get support for hardware monitoring
@ -854,6 +856,7 @@ config SENSORS_CORETEMP
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
depends on HAS_IOPORT
depends on !PPC
select HWMON_VID
help
@ -914,6 +917,16 @@ config SENSORS_LAN966X
This driver can also be built as a module. If so, the module
will be called lan966x-hwmon.
config SENSORS_LENOVO_EC
tristate "Sensor reader for Lenovo ThinkStations"
depends on X86
help
If you say yes here you get support for LENOVO
EC Sensor data on newer ThinkStation systems
This driver can also be built as a module. If so, the module
will be called lenovo_ec_sensors.
config SENSORS_LINEAGE
tristate "Lineage Compact Power Line Power Entry Module"
depends on I2C
@ -1220,6 +1233,7 @@ config SENSORS_MAX6621
config SENSORS_MAX6639
tristate "Maxim MAX6639 sensor chip"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for the MAX6639
sensor chips.
@ -1561,6 +1575,7 @@ config SENSORS_LM95245
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
depends on HAS_IOPORT
depends on !PPC
select HWMON_VID
help
@ -1575,6 +1590,7 @@ config SENSORS_PC87360
config SENSORS_PC87427
tristate "National Semiconductor PC87427"
depends on HAS_IOPORT
depends on !PPC
help
If you say yes here you get access to the hardware monitoring
@ -1606,6 +1622,7 @@ config SENSORS_NTC_THERMISTOR
config SENSORS_NCT6683
tristate "Nuvoton NCT6683D"
depends on HAS_IOPORT
depends on !PPC
help
If you say yes here you get support for the hardware monitoring
@ -1627,6 +1644,7 @@ config SENSORS_NCT6775_CORE
config SENSORS_NCT6775
tristate "Platform driver for Nuvoton NCT6775F and compatibles"
depends on HAS_IOPORT
depends on !PPC
depends on ACPI || ACPI=n
select HWMON_VID
@ -1778,7 +1796,7 @@ config SENSORS_PT5161L
config SENSORS_PWM_FAN
tristate "PWM fan"
depends on (PWM && OF) || COMPILE_TEST
depends on PWM || COMPILE_TEST
depends on THERMAL || THERMAL=n
help
If you say yes here you get support for fans connected to PWM lines.
@ -1883,7 +1901,7 @@ config SENSORS_SHTC1
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
depends on PCI
depends on PCI && HAS_IOPORT
help
If you say yes here you get support for the integrated sensors in
SiS5595 South Bridges.
@ -1903,6 +1921,7 @@ config SENSORS_SY7636A
config SENSORS_DME1737
tristate "SMSC DME1737, SCH311x and compatibles"
depends on HAS_IOPORT
depends on I2C && !PPC
select HWMON_VID
help
@ -1959,6 +1978,7 @@ config SENSORS_EMC6W201
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
depends on HAS_IOPORT
depends on !PPC
help
If you say yes here you get support for the integrated fan
@ -1993,6 +2013,7 @@ config SENSORS_SMSC47M192
config SENSORS_SMSC47B397
tristate "SMSC LPC47B397-NC"
depends on HAS_IOPORT
depends on !PPC
help
If you say yes here you get support for the SMSC LPC47B397-NC
@ -2007,6 +2028,7 @@ config SENSORS_SCH56XX_COMMON
config SENSORS_SCH5627
tristate "SMSC SCH5627"
depends on HAS_IOPORT
depends on !PPC && WATCHDOG
select SENSORS_SCH56XX_COMMON
select WATCHDOG_CORE
@ -2020,6 +2042,7 @@ config SENSORS_SCH5627
config SENSORS_SCH5636
tristate "SMSC SCH5636"
depends on HAS_IOPORT
depends on !PPC && WATCHDOG
select SENSORS_SCH56XX_COMMON
select WATCHDOG_CORE
@ -2272,7 +2295,7 @@ config SENSORS_VIA_CPUTEMP
config SENSORS_VIA686A
tristate "VIA686A"
depends on PCI
depends on PCI && HAS_IOPORT
help
If you say yes here you get support for the integrated sensors in
Via 686A/B South Bridges.
@ -2282,6 +2305,7 @@ config SENSORS_VIA686A
config SENSORS_VT1211
tristate "VIA VT1211"
depends on HAS_IOPORT
depends on !PPC
select HWMON_VID
help
@ -2293,7 +2317,7 @@ config SENSORS_VT1211
config SENSORS_VT8231
tristate "VIA VT8231"
depends on PCI
depends on PCI && HAS_IOPORT
select HWMON_VID
help
If you say yes here then you get support for the integrated sensors
@ -2401,6 +2425,7 @@ config SENSORS_W83L786NG
config SENSORS_W83627HF
tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
depends on HAS_IOPORT
depends on !PPC
select HWMON_VID
help
@ -2413,6 +2438,7 @@ config SENSORS_W83627HF
config SENSORS_W83627EHF
tristate "Winbond W83627EHF/EHG/DHG/UHG, W83667HG"
depends on HAS_IOPORT
depends on !PPC
select HWMON_VID
help

View File

@ -108,6 +108,7 @@ obj-$(CONFIG_SENSORS_JC42) += jc42.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o
obj-$(CONFIG_SENSORS_LAN966X) += lan966x-hwmon.o
obj-$(CONFIG_SENSORS_LENOVO_EC) += lenovo-ec-sensors.o
obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o
obj-$(CONFIG_SENSORS_LOCHNAGAR) += lochnagar-hwmon.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o

View File

@ -883,6 +883,22 @@ static int acpi_power_meter_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS);
device->driver_data = resource;
#if IS_REACHABLE(CONFIG_ACPI_IPMI)
/*
* On Dell systems several methods of acpi_power_meter access
* variables in IPMI region, so wait until IPMI space handler is
* installed by acpi_ipmi and also wait until SMI is selected to make
* the space handler fully functional.
*/
if (dmi_match(DMI_SYS_VENDOR, "Dell Inc.")) {
struct acpi_device *ipi_device = acpi_dev_get_first_match_dev("IPI0001", NULL, -1);
if (ipi_device && acpi_wait_for_acpi_ipmi())
dev_warn(&device->dev, "Waiting for ACPI IPMI timeout");
acpi_dev_put(ipi_device);
}
#endif
res = read_capabilities(resource);
if (res)
goto exit_free;

View File

@ -205,7 +205,7 @@ static int ad7414_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7414_id[] = {
{ "ad7414", 0 },
{ "ad7414" },
{}
};
MODULE_DEVICE_TABLE(i2c, ad7414_id);

View File

@ -480,7 +480,7 @@ static int adc128_probe(struct i2c_client *client)
}
static const struct i2c_device_id adc128_id[] = {
{ "adc128d818", 0 },
{ "adc128d818" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adc128_id);

View File

@ -1849,7 +1849,7 @@ static int adm1026_probe(struct i2c_client *client)
}
static const struct i2c_device_id adm1026_id[] = {
{ "adm1026", 0 },
{ "adm1026" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adm1026_id);

View File

@ -379,7 +379,7 @@ static int adm1029_probe(struct i2c_client *client)
}
static const struct i2c_device_id adm1029_id[] = {
{ "adm1029", 0 },
{ "adm1029" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adm1029_id);

View File

@ -238,7 +238,7 @@ static int adm1177_probe(struct i2c_client *client)
}
static const struct i2c_device_id adm1177_id[] = {
{"adm1177", 0},
{"adm1177"},
{}
};
MODULE_DEVICE_TABLE(i2c, adm1177_id);

View File

@ -88,8 +88,8 @@ static int adt7410_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adt7410_ids[] = {
{ "adt7410", 0 },
{ "adt7420", 0 },
{ "adt7410" },
{ "adt7420" },
{}
};
MODULE_DEVICE_TABLE(i2c, adt7410_ids);

View File

@ -697,7 +697,7 @@ static int adt7411_probe(struct i2c_client *client)
}
static const struct i2c_device_id adt7411_id[] = {
{ "adt7411", 0 },
{ "adt7411" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adt7411_id);

View File

@ -1809,7 +1809,7 @@ static int adt7462_probe(struct i2c_client *client)
}
static const struct i2c_device_id adt7462_id[] = {
{ "adt7462", 0 },
{ "adt7462" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adt7462_id);

View File

@ -1304,7 +1304,7 @@ static void adt7470_remove(struct i2c_client *client)
}
static const struct i2c_device_id adt7470_id[] = {
{ "adt7470", 0 },
{ "adt7470" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adt7470_id);

View File

@ -202,16 +202,19 @@ static u16 aquastreamult_sensor_fan_offsets[] = { AQUASTREAMULT_FAN_OFFSET };
#define OCTO_NUM_FANS 8
#define OCTO_NUM_SENSORS 4
#define OCTO_NUM_VIRTUAL_SENSORS 16
#define OCTO_NUM_FLOW_SENSORS 1
#define OCTO_CTRL_REPORT_SIZE 0x65F
/* Sensor report offsets for the Octo */
#define OCTO_POWER_CYCLES 0x18
#define OCTO_SENSOR_START 0x3D
#define OCTO_VIRTUAL_SENSORS_START 0x45
#define OCTO_FLOW_SENSOR_OFFSET 0x7B
static u16 octo_sensor_fan_offsets[] = { 0x7D, 0x8A, 0x97, 0xA4, 0xB1, 0xBE, 0xCB, 0xD8 };
/* Control report offsets for the Octo */
#define OCTO_TEMP_CTRL_OFFSET 0xA
#define OCTO_FLOW_PULSES_CTRL_OFFSET 0x6
/* Fan speed offsets (0-100%) */
static u16 octo_ctrl_fan_offsets[] = { 0x5B, 0xB0, 0x105, 0x15A, 0x1AF, 0x204, 0x259, 0x2AE };
@ -363,18 +366,6 @@ static const char *const label_aquaero_calc_temp_sensors[] = {
"Calc. virtual sensor 4"
};
/* Labels for Octo and Quadro (except speed) */
static const char *const label_fan_speed[] = {
"Fan 1 speed",
"Fan 2 speed",
"Fan 3 speed",
"Fan 4 speed",
"Fan 5 speed",
"Fan 6 speed",
"Fan 7 speed",
"Fan 8 speed"
};
static const char *const label_fan_power[] = {
"Fan 1 power",
"Fan 2 power",
@ -408,6 +399,19 @@ static const char *const label_fan_current[] = {
"Fan 8 current"
};
/* Labels for Octo fan speeds */
static const char *const label_octo_speeds[] = {
"Fan 1 speed",
"Fan 2 speed",
"Fan 3 speed",
"Fan 4 speed",
"Fan 5 speed",
"Fan 6 speed",
"Fan 7 speed",
"Fan 8 speed",
"Flow speed [dL/h]",
};
/* Labels for Quadro fan speeds */
static const char *const label_quadro_speeds[] = {
"Fan 1 speed",
@ -844,6 +848,7 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
return 0444;
break;
case aquaero:
case octo:
case quadro:
case highflow:
/* Special case to support flow sensors */
@ -857,9 +862,16 @@ static umode_t aqc_is_visible(const void *data, enum hwmon_sensor_types type, u3
}
break;
case hwmon_fan_pulses:
/* Special case for Quadro flow sensor */
if (priv->kind == quadro && channel == priv->num_fans)
return 0644;
/* Special case for Quadro/Octo flow sensor */
if (channel == priv->num_fans) {
switch (priv->kind) {
case quadro:
case octo:
return 0644;
default:
break;
}
}
break;
case hwmon_fan_min:
case hwmon_fan_max:
@ -1289,7 +1301,8 @@ static const struct hwmon_channel_info * const aqc_info[] = {
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_PULSES,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL),
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_PULSES),
HWMON_CHANNEL_INFO(power,
HWMON_P_INPUT | HWMON_P_LABEL,
HWMON_P_INPUT | HWMON_P_LABEL,
@ -1658,16 +1671,20 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
priv->temp_sensor_start_offset = OCTO_SENSOR_START;
priv->num_virtual_temp_sensors = OCTO_NUM_VIRTUAL_SENSORS;
priv->virtual_temp_sensor_start_offset = OCTO_VIRTUAL_SENSORS_START;
priv->num_flow_sensors = OCTO_NUM_FLOW_SENSORS;
priv->flow_sensors_start_offset = OCTO_FLOW_SENSOR_OFFSET;
priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET;
priv->buffer_size = OCTO_CTRL_REPORT_SIZE;
priv->ctrl_report_delay = CTRL_REPORT_DELAY;
priv->flow_pulses_ctrl_offset = OCTO_FLOW_PULSES_CTRL_OFFSET;
priv->power_cycle_count_offset = OCTO_POWER_CYCLES;
priv->temp_label = label_temp_sensors;
priv->virtual_temp_label = label_virtual_temp_sensors;
priv->speed_label = label_fan_speed;
priv->speed_label = label_octo_speeds;
priv->power_label = label_fan_power;
priv->voltage_label = label_fan_voltage;
priv->current_label = label_fan_current;

View File

@ -213,7 +213,7 @@ static struct asb100_data *asb100_update_device(struct device *dev);
static void asb100_init_client(struct i2c_client *client);
static const struct i2c_device_id asb100_id[] = {
{ "asb100", 0 },
{ "asb100" },
{ }
};
MODULE_DEVICE_TABLE(i2c, asb100_id);

View File

@ -516,13 +516,11 @@ static int aspeed_pwm_tach_probe(struct platform_device *pdev)
return 0;
}
static int aspeed_pwm_tach_remove(struct platform_device *pdev)
static void aspeed_pwm_tach_remove(struct platform_device *pdev)
{
struct aspeed_pwm_tach_data *priv = platform_get_drvdata(pdev);
reset_control_assert(priv->reset);
return 0;
}
static const struct of_device_id aspeed_pwm_tach_match[] = {
@ -535,7 +533,7 @@ MODULE_DEVICE_TABLE(of, aspeed_pwm_tach_match);
static struct platform_driver aspeed_pwm_tach_driver = {
.probe = aspeed_pwm_tach_probe,
.remove = aspeed_pwm_tach_remove,
.remove_new = aspeed_pwm_tach_remove,
.driver = {
.name = "aspeed-g6-pwm-tach",
.of_match_table = aspeed_pwm_tach_match,

View File

@ -278,7 +278,7 @@ static int atxp1_probe(struct i2c_client *client)
};
static const struct i2c_device_id atxp1_id[] = {
{ "atxp1", 0 },
{ "atxp1" },
{ }
};
MODULE_DEVICE_TABLE(i2c, atxp1_id);

View File

@ -411,7 +411,7 @@ static ssize_t show_temp(struct device *dev,
* Return it instead of reporting an error which doesn't
* really help at all.
*/
tdata->temp = tjmax - ((eax >> 16) & 0x7f) * 1000;
tdata->temp = tjmax - ((eax >> 16) & 0xff) * 1000;
tdata->last_updated = jiffies;
}

View File

@ -1214,6 +1214,13 @@ static const struct dmi_system_id i8k_dmi_table[] __initconst = {
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G5 5590"),
},
},
{
.ident = "Dell G5 5505",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G5 5505"),
},
},
{
.ident = "Dell Inspiron",
.matches = {
@ -1506,6 +1513,14 @@ static const struct dmi_system_id i8k_whitelist_fan_control[] __initconst = {
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{
.ident = "Dell Precision 7540",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Precision 7540"),
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{
.ident = "Dell XPS 13 7390",
.matches = {

View File

@ -233,7 +233,7 @@ static int ds620_probe(struct i2c_client *client)
}
static const struct i2c_device_id ds620_id[] = {
{"ds620", 0},
{"ds620"},
{}
};

View File

@ -19,302 +19,56 @@
#include <linux/sysfs.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/util_macros.h>
#define THERMAL_PID_REG 0xfd
#define THERMAL_SMSC_ID_REG 0xfe
#define THERMAL_REVISION_REG 0xff
enum emc1403_chip { emc1402, emc1403, emc1404 };
enum emc1403_chip { emc1402, emc1403, emc1404, emc1428 };
struct thermal_data {
enum emc1403_chip chip;
struct regmap *regmap;
struct mutex mutex;
const struct attribute_group *groups[4];
};
static ssize_t temp_show(struct device *dev, struct device_attribute *attr,
char *buf)
static ssize_t power_state_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct thermal_data *data = dev_get_drvdata(dev);
unsigned int val;
int retval;
retval = regmap_read(data->regmap, sda->index, &val);
retval = regmap_read(data->regmap, 0x03, &val);
if (retval < 0)
return retval;
return sprintf(buf, "%d000\n", val);
return sprintf(buf, "%d\n", !!(val & BIT(6)));
}
static ssize_t bit_show(struct device *dev, struct device_attribute *attr,
char *buf)
static ssize_t power_state_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
struct thermal_data *data = dev_get_drvdata(dev);
unsigned int val;
int retval;
retval = regmap_read(data->regmap, sda->nr, &val);
if (retval < 0)
return retval;
return sprintf(buf, "%d\n", !!(val & sda->index));
}
static ssize_t temp_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct thermal_data *data = dev_get_drvdata(dev);
unsigned long val;
int retval;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
retval = regmap_write(data->regmap, sda->index,
DIV_ROUND_CLOSEST(val, 1000));
retval = regmap_update_bits(data->regmap, 0x03, BIT(6),
val ? BIT(6) : 0);
if (retval < 0)
return retval;
return count;
}
static ssize_t bit_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
struct thermal_data *data = dev_get_drvdata(dev);
unsigned long val;
int retval;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
retval = regmap_update_bits(data->regmap, sda->nr, sda->index,
val ? sda->index : 0);
if (retval < 0)
return retval;
return count;
}
static ssize_t show_hyst_common(struct device *dev,
struct device_attribute *attr, char *buf,
bool is_min)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct thermal_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
unsigned int limit;
unsigned int hyst;
int retval;
retval = regmap_read(regmap, sda->index, &limit);
if (retval < 0)
return retval;
retval = regmap_read(regmap, 0x21, &hyst);
if (retval < 0)
return retval;
return sprintf(buf, "%d000\n", is_min ? limit + hyst : limit - hyst);
}
static ssize_t hyst_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return show_hyst_common(dev, attr, buf, false);
}
static ssize_t min_hyst_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return show_hyst_common(dev, attr, buf, true);
}
static ssize_t hyst_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct thermal_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
unsigned int limit;
int retval;
int hyst;
unsigned long val;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
mutex_lock(&data->mutex);
retval = regmap_read(regmap, sda->index, &limit);
if (retval < 0)
goto fail;
hyst = limit * 1000 - val;
hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255);
retval = regmap_write(regmap, 0x21, hyst);
if (retval == 0)
retval = count;
fail:
mutex_unlock(&data->mutex);
return retval;
}
/*
* Sensors. We pass the actual i2c register to the methods.
*/
static SENSOR_DEVICE_ATTR_RW(temp1_min, temp, 0x06);
static SENSOR_DEVICE_ATTR_RW(temp1_max, temp, 0x05);
static SENSOR_DEVICE_ATTR_RW(temp1_crit, temp, 0x20);
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0x00);
static SENSOR_DEVICE_ATTR_2_RO(temp1_min_alarm, bit, 0x36, 0x01);
static SENSOR_DEVICE_ATTR_2_RO(temp1_max_alarm, bit, 0x35, 0x01);
static SENSOR_DEVICE_ATTR_2_RO(temp1_crit_alarm, bit, 0x37, 0x01);
static SENSOR_DEVICE_ATTR_RO(temp1_min_hyst, min_hyst, 0x06);
static SENSOR_DEVICE_ATTR_RO(temp1_max_hyst, hyst, 0x05);
static SENSOR_DEVICE_ATTR_RW(temp1_crit_hyst, hyst, 0x20);
static SENSOR_DEVICE_ATTR_RW(temp2_min, temp, 0x08);
static SENSOR_DEVICE_ATTR_RW(temp2_max, temp, 0x07);
static SENSOR_DEVICE_ATTR_RW(temp2_crit, temp, 0x19);
static SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 0x01);
static SENSOR_DEVICE_ATTR_2_RO(temp2_fault, bit, 0x1b, 0x02);
static SENSOR_DEVICE_ATTR_2_RO(temp2_min_alarm, bit, 0x36, 0x02);
static SENSOR_DEVICE_ATTR_2_RO(temp2_max_alarm, bit, 0x35, 0x02);
static SENSOR_DEVICE_ATTR_2_RO(temp2_crit_alarm, bit, 0x37, 0x02);
static SENSOR_DEVICE_ATTR_RO(temp2_min_hyst, min_hyst, 0x08);
static SENSOR_DEVICE_ATTR_RO(temp2_max_hyst, hyst, 0x07);
static SENSOR_DEVICE_ATTR_RO(temp2_crit_hyst, hyst, 0x19);
static SENSOR_DEVICE_ATTR_RW(temp3_min, temp, 0x16);
static SENSOR_DEVICE_ATTR_RW(temp3_max, temp, 0x15);
static SENSOR_DEVICE_ATTR_RW(temp3_crit, temp, 0x1A);
static SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 0x23);
static SENSOR_DEVICE_ATTR_2_RO(temp3_fault, bit, 0x1b, 0x04);
static SENSOR_DEVICE_ATTR_2_RO(temp3_min_alarm, bit, 0x36, 0x04);
static SENSOR_DEVICE_ATTR_2_RO(temp3_max_alarm, bit, 0x35, 0x04);
static SENSOR_DEVICE_ATTR_2_RO(temp3_crit_alarm, bit, 0x37, 0x04);
static SENSOR_DEVICE_ATTR_RO(temp3_min_hyst, min_hyst, 0x16);
static SENSOR_DEVICE_ATTR_RO(temp3_max_hyst, hyst, 0x15);
static SENSOR_DEVICE_ATTR_RO(temp3_crit_hyst, hyst, 0x1A);
static SENSOR_DEVICE_ATTR_RW(temp4_min, temp, 0x2D);
static SENSOR_DEVICE_ATTR_RW(temp4_max, temp, 0x2C);
static SENSOR_DEVICE_ATTR_RW(temp4_crit, temp, 0x30);
static SENSOR_DEVICE_ATTR_RO(temp4_input, temp, 0x2A);
static SENSOR_DEVICE_ATTR_2_RO(temp4_fault, bit, 0x1b, 0x08);
static SENSOR_DEVICE_ATTR_2_RO(temp4_min_alarm, bit, 0x36, 0x08);
static SENSOR_DEVICE_ATTR_2_RO(temp4_max_alarm, bit, 0x35, 0x08);
static SENSOR_DEVICE_ATTR_2_RO(temp4_crit_alarm, bit, 0x37, 0x08);
static SENSOR_DEVICE_ATTR_RO(temp4_min_hyst, min_hyst, 0x2D);
static SENSOR_DEVICE_ATTR_RO(temp4_max_hyst, hyst, 0x2C);
static SENSOR_DEVICE_ATTR_RO(temp4_crit_hyst, hyst, 0x30);
static SENSOR_DEVICE_ATTR_2_RW(power_state, bit, 0x03, 0x40);
static struct attribute *emc1402_attrs[] = {
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_min_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
&sensor_dev_attr_power_state.dev_attr.attr,
NULL
};
static const struct attribute_group emc1402_group = {
.attrs = emc1402_attrs,
};
static DEVICE_ATTR_RW(power_state);
static struct attribute *emc1403_attrs[] = {
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_min_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
&dev_attr_power_state.attr,
NULL
};
static const struct attribute_group emc1403_group = {
.attrs = emc1403_attrs,
};
static struct attribute *emc1404_attrs[] = {
&sensor_dev_attr_temp4_min.dev_attr.attr,
&sensor_dev_attr_temp4_max.dev_attr.attr,
&sensor_dev_attr_temp4_crit.dev_attr.attr,
&sensor_dev_attr_temp4_input.dev_attr.attr,
&sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_min_hyst.dev_attr.attr,
&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp4_crit_hyst.dev_attr.attr,
NULL
};
static const struct attribute_group emc1404_group = {
.attrs = emc1404_attrs,
};
/*
* EMC14x2 uses a different register and different bits to report alarm and
* fault status. For simplicity, provide a separate attribute group for this
* chip series.
* Since we can not re-use the same attribute names, create a separate attribute
* array.
*/
static struct sensor_device_attribute_2 emc1402_alarms[] = {
SENSOR_ATTR_2_RO(temp1_min_alarm, bit, 0x02, 0x20),
SENSOR_ATTR_2_RO(temp1_max_alarm, bit, 0x02, 0x40),
SENSOR_ATTR_2_RO(temp1_crit_alarm, bit, 0x02, 0x01),
SENSOR_ATTR_2_RO(temp2_fault, bit, 0x02, 0x04),
SENSOR_ATTR_2_RO(temp2_min_alarm, bit, 0x02, 0x08),
SENSOR_ATTR_2_RO(temp2_max_alarm, bit, 0x02, 0x10),
SENSOR_ATTR_2_RO(temp2_crit_alarm, bit, 0x02, 0x02),
};
static struct attribute *emc1402_alarm_attrs[] = {
&emc1402_alarms[0].dev_attr.attr,
&emc1402_alarms[1].dev_attr.attr,
&emc1402_alarms[2].dev_attr.attr,
&emc1402_alarms[3].dev_attr.attr,
&emc1402_alarms[4].dev_attr.attr,
&emc1402_alarms[5].dev_attr.attr,
&emc1402_alarms[6].dev_attr.attr,
NULL,
};
static const struct attribute_group emc1402_alarm_group = {
.attrs = emc1402_alarm_attrs,
};
ATTRIBUTE_GROUPS(emc1403);
static int emc1403_detect(struct i2c_client *client,
struct i2c_board_info *info)
@ -346,6 +100,12 @@ static int emc1403_detect(struct i2c_client *client,
case 0x27:
strscpy(info->type, "emc1424", I2C_NAME_SIZE);
break;
case 0x29:
strscpy(info->type, "emc1428", I2C_NAME_SIZE);
break;
case 0x59:
strscpy(info->type, "emc1438", I2C_NAME_SIZE);
break;
case 0x60:
strscpy(info->type, "emc1442", I2C_NAME_SIZE);
break;
@ -376,6 +136,14 @@ static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg)
case 0x35: /* high limit status */
case 0x36: /* low limit status */
case 0x37: /* therm limit status */
case 0x41: /* external diode 4 high byte */
case 0x42: /* external diode 4 low byte */
case 0x43: /* external diode 5 high byte */
case 0x44: /* external diode 5 low byte */
case 0x45: /* external diode 6 high byte */
case 0x46: /* external diode 6 low byte */
case 0x47: /* external diode 7 high byte */
case 0x48: /* external diode 7 low byte */
return true;
default:
return false;
@ -389,51 +157,508 @@ static const struct regmap_config emc1403_regmap_config = {
.volatile_reg = emc1403_regmap_is_volatile,
};
static const struct i2c_device_id emc1403_idtable[];
enum emc1403_reg_map {temp_min, temp_max, temp_crit, temp_input};
static int emc1403_probe(struct i2c_client *client)
static u8 ema1403_temp_map[] = {
[hwmon_temp_min] = temp_min,
[hwmon_temp_max] = temp_max,
[hwmon_temp_crit] = temp_crit,
[hwmon_temp_input] = temp_input,
};
static u8 emc1403_temp_regs[][4] = {
[0] = {
[temp_min] = 0x06,
[temp_max] = 0x05,
[temp_crit] = 0x20,
[temp_input] = 0x00,
},
[1] = {
[temp_min] = 0x08,
[temp_max] = 0x07,
[temp_crit] = 0x19,
[temp_input] = 0x01,
},
[2] = {
[temp_min] = 0x16,
[temp_max] = 0x15,
[temp_crit] = 0x1a,
[temp_input] = 0x23,
},
[3] = {
[temp_min] = 0x2d,
[temp_max] = 0x2c,
[temp_crit] = 0x30,
[temp_input] = 0x2a,
},
[4] = {
[temp_min] = 0x51,
[temp_max] = 0x50,
[temp_crit] = 0x64,
[temp_input] = 0x41,
},
[5] = {
[temp_min] = 0x55,
[temp_max] = 0x54,
[temp_crit] = 0x65,
[temp_input] = 0x43
},
[6] = {
[temp_min] = 0x59,
[temp_max] = 0x58,
[temp_crit] = 0x66,
[temp_input] = 0x45,
},
[7] = {
[temp_min] = 0x5d,
[temp_max] = 0x5c,
[temp_crit] = 0x67,
[temp_input] = 0x47,
},
};
static s8 emc1403_temp_regs_low[][4] = {
[0] = {
[temp_min] = -1,
[temp_max] = -1,
[temp_crit] = -1,
[temp_input] = 0x29,
},
[1] = {
[temp_min] = 0x14,
[temp_max] = 0x13,
[temp_crit] = -1,
[temp_input] = 0x10,
},
[2] = {
[temp_min] = 0x18,
[temp_max] = 0x17,
[temp_crit] = -1,
[temp_input] = 0x24,
},
[3] = {
[temp_min] = 0x2f,
[temp_max] = 0x2e,
[temp_crit] = -1,
[temp_input] = 0x2b,
},
[4] = {
[temp_min] = 0x53,
[temp_max] = 0x52,
[temp_crit] = -1,
[temp_input] = 0x42,
},
[5] = {
[temp_min] = 0x57,
[temp_max] = 0x56,
[temp_crit] = -1,
[temp_input] = 0x44,
},
[6] = {
[temp_min] = 0x5b,
[temp_max] = 0x5a,
[temp_crit] = -1,
[temp_input] = 0x46,
},
[7] = {
[temp_min] = 0x5f,
[temp_max] = 0x5e,
[temp_crit] = -1,
[temp_input] = 0x48,
},
};
static int __emc1403_get_temp(struct thermal_data *data, int channel,
enum emc1403_reg_map map, long *val)
{
struct thermal_data *data;
struct device *hwmon_dev;
const struct i2c_device_id *id = i2c_match_id(emc1403_idtable, client);
unsigned int regvalh;
unsigned int regvall = 0;
int ret;
s8 reg;
data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
ret = regmap_read(data->regmap, emc1403_temp_regs[channel][map], &regvalh);
if (ret < 0)
return ret;
data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
mutex_init(&data->mutex);
switch (id->driver_data) {
case emc1404:
data->groups[2] = &emc1404_group;
fallthrough;
case emc1403:
data->groups[1] = &emc1403_group;
fallthrough;
case emc1402:
data->groups[0] = &emc1402_group;
reg = emc1403_temp_regs_low[channel][map];
if (reg >= 0) {
ret = regmap_read(data->regmap, reg, &regvall);
if (ret < 0)
return ret;
}
if (id->driver_data == emc1402)
data->groups[1] = &emc1402_alarm_group;
if (data->chip == emc1428)
*val = sign_extend32((regvalh << 3) | (regvall >> 5), 10) * 125;
else
*val = ((regvalh << 3) | (regvall >> 5)) * 125;
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
client->name, data,
data->groups);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
dev_info(&client->dev, "%s Thermal chip found\n", id->name);
return 0;
}
static const unsigned short emc1403_address_list[] = {
0x18, 0x1c, 0x29, 0x3c, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END
static int emc1403_get_temp(struct thermal_data *data, int channel,
enum emc1403_reg_map map, long *val)
{
int ret;
mutex_lock(&data->mutex);
ret = __emc1403_get_temp(data, channel, map, val);
mutex_unlock(&data->mutex);
return ret;
}
static int emc1403_get_hyst(struct thermal_data *data, int channel,
enum emc1403_reg_map map, long *val)
{
int hyst, ret;
long limit;
mutex_lock(&data->mutex);
ret = __emc1403_get_temp(data, channel, map, &limit);
if (ret < 0)
goto unlock;
ret = regmap_read(data->regmap, 0x21, &hyst);
if (ret < 0)
goto unlock;
if (map == temp_min)
*val = limit + hyst * 1000;
else
*val = limit - hyst * 1000;
unlock:
mutex_unlock(&data->mutex);
return ret;
}
static int emc1403_temp_read(struct thermal_data *data, u32 attr, int channel, long *val)
{
unsigned int regval;
int ret;
switch (attr) {
case hwmon_temp_min:
case hwmon_temp_max:
case hwmon_temp_crit:
case hwmon_temp_input:
ret = emc1403_get_temp(data, channel, ema1403_temp_map[attr], val);
break;
case hwmon_temp_min_hyst:
ret = emc1403_get_hyst(data, channel, temp_min, val);
break;
case hwmon_temp_max_hyst:
ret = emc1403_get_hyst(data, channel, temp_max, val);
break;
case hwmon_temp_crit_hyst:
ret = emc1403_get_hyst(data, channel, temp_crit, val);
break;
case hwmon_temp_min_alarm:
if (data->chip == emc1402) {
ret = regmap_read(data->regmap, 0x02, &regval);
if (ret < 0)
break;
*val = !!(regval & BIT(5 - 2 * channel));
} else {
ret = regmap_read(data->regmap, 0x36, &regval);
if (ret < 0)
break;
*val = !!(regval & BIT(channel));
}
break;
case hwmon_temp_max_alarm:
if (data->chip == emc1402) {
ret = regmap_read(data->regmap, 0x02, &regval);
if (ret < 0)
break;
*val = !!(regval & BIT(6 - 2 * channel));
} else {
ret = regmap_read(data->regmap, 0x35, &regval);
if (ret < 0)
break;
*val = !!(regval & BIT(channel));
}
break;
case hwmon_temp_crit_alarm:
if (data->chip == emc1402) {
ret = regmap_read(data->regmap, 0x02, &regval);
if (ret < 0)
break;
*val = !!(regval & BIT(channel));
} else {
ret = regmap_read(data->regmap, 0x37, &regval);
if (ret < 0)
break;
*val = !!(regval & BIT(channel));
}
break;
case hwmon_temp_fault:
ret = regmap_read(data->regmap, 0x1b, &regval);
if (ret < 0)
break;
*val = !!(regval & BIT(channel));
break;
default:
return -EOPNOTSUPP;
}
return ret;
}
static int emc1403_get_convrate(struct thermal_data *data, long *val)
{
unsigned int convrate;
int ret;
ret = regmap_read(data->regmap, 0x04, &convrate);
if (ret < 0)
return ret;
if (convrate > 10)
convrate = 4;
*val = 16000 >> convrate;
return 0;
}
static int emc1403_chip_read(struct thermal_data *data, u32 attr, long *val)
{
switch (attr) {
case hwmon_chip_update_interval:
return emc1403_get_convrate(data, val);
default:
return -EOPNOTSUPP;
}
}
static int emc1403_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct thermal_data *data = dev_get_drvdata(dev);
switch (type) {
case hwmon_temp:
return emc1403_temp_read(data, attr, channel, val);
case hwmon_chip:
return emc1403_chip_read(data, attr, val);
default:
return -EOPNOTSUPP;
}
}
static int emc1403_set_hyst(struct thermal_data *data, long val)
{
int hyst, ret;
long limit;
if (data->chip == emc1428)
val = clamp_val(val, -128000, 127000);
else
val = clamp_val(val, 0, 255000);
mutex_lock(&data->mutex);
ret = __emc1403_get_temp(data, 0, temp_crit, &limit);
if (ret < 0)
goto unlock;
hyst = limit - val;
if (data->chip == emc1428)
hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 127);
else
hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255);
ret = regmap_write(data->regmap, 0x21, hyst);
unlock:
mutex_unlock(&data->mutex);
return ret;
}
static int emc1403_set_temp(struct thermal_data *data, int channel,
enum emc1403_reg_map map, long val)
{
unsigned int regval;
int ret;
u8 regh;
s8 regl;
regh = emc1403_temp_regs[channel][map];
regl = emc1403_temp_regs_low[channel][map];
mutex_lock(&data->mutex);
if (regl >= 0) {
if (data->chip == emc1428)
val = clamp_val(val, -128000, 127875);
else
val = clamp_val(val, 0, 255875);
regval = DIV_ROUND_CLOSEST(val, 125);
ret = regmap_write(data->regmap, regh, (regval >> 3) & 0xff);
if (ret < 0)
goto unlock;
ret = regmap_write(data->regmap, regl, (regval & 0x07) << 5);
} else {
if (data->chip == emc1428)
val = clamp_val(val, -128000, 127000);
else
val = clamp_val(val, 0, 255000);
regval = DIV_ROUND_CLOSEST(val, 1000);
ret = regmap_write(data->regmap, regh, regval);
}
unlock:
mutex_unlock(&data->mutex);
return ret;
}
static int emc1403_temp_write(struct thermal_data *data, u32 attr, int channel, long val)
{
switch (attr) {
case hwmon_temp_min:
case hwmon_temp_max:
case hwmon_temp_crit:
return emc1403_set_temp(data, channel, ema1403_temp_map[attr], val);
case hwmon_temp_crit_hyst:
return emc1403_set_hyst(data, val);
default:
return -EOPNOTSUPP;
}
}
/* Lookup table for temperature conversion times in msec */
static const u16 ina3221_conv_time[] = {
16000, 8000, 4000, 2000, 1000, 500, 250, 125, 62, 31, 16
};
static int emc1403_set_convrate(struct thermal_data *data, unsigned int interval)
{
int convrate;
convrate = find_closest_descending(interval, ina3221_conv_time,
ARRAY_SIZE(ina3221_conv_time));
return regmap_write(data->regmap, 0x04, convrate);
}
static int emc1403_chip_write(struct thermal_data *data, u32 attr, long val)
{
switch (attr) {
case hwmon_chip_update_interval:
return emc1403_set_convrate(data, clamp_val(val, 0, 100000));
default:
return -EOPNOTSUPP;
}
}
static int emc1403_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
struct thermal_data *data = dev_get_drvdata(dev);
switch (type) {
case hwmon_temp:
return emc1403_temp_write(data, attr, channel, val);
case hwmon_chip:
return emc1403_chip_write(data, attr, val);
default:
return -EOPNOTSUPP;
}
}
static umode_t emc1403_temp_is_visible(const void *_data, u32 attr, int channel)
{
const struct thermal_data *data = _data;
if (data->chip == emc1402 && channel > 1)
return 0;
if (data->chip == emc1403 && channel > 2)
return 0;
if (data->chip != emc1428 && channel > 3)
return 0;
switch (attr) {
case hwmon_temp_input:
case hwmon_temp_min_alarm:
case hwmon_temp_max_alarm:
case hwmon_temp_crit_alarm:
case hwmon_temp_fault:
case hwmon_temp_min_hyst:
case hwmon_temp_max_hyst:
return 0444;
case hwmon_temp_min:
case hwmon_temp_max:
case hwmon_temp_crit:
return 0644;
case hwmon_temp_crit_hyst:
if (channel == 0)
return 0644;
return 0444;
default:
return 0;
}
}
static umode_t emc1403_chip_is_visible(const void *_data, u32 attr)
{
switch (attr) {
case hwmon_chip_update_interval:
return 0644;
default:
return 0;
}
}
static umode_t emc1403_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
switch (type) {
case hwmon_temp:
return emc1403_temp_is_visible(data, attr, channel);
case hwmon_chip:
return emc1403_chip_is_visible(data, attr);
default:
return 0;
}
}
static const struct hwmon_channel_info * const emc1403_info[] = {
HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT,
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_MIN_HYST | HWMON_T_MAX_HYST |
HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT
),
NULL
};
static const struct hwmon_ops emc1403_hwmon_ops = {
.is_visible = emc1403_is_visible,
.read = emc1403_read,
.write = emc1403_write,
};
static const struct hwmon_chip_info emc1403_chip_info = {
.ops = &emc1403_hwmon_ops,
.info = emc1403_info,
};
/* Last digit of chip name indicates number of channels */
@ -447,11 +672,42 @@ static const struct i2c_device_id emc1403_idtable[] = {
{ "emc1422", emc1402 },
{ "emc1423", emc1403 },
{ "emc1424", emc1404 },
{ "emc1428", emc1428 },
{ "emc1438", emc1428 },
{ "emc1442", emc1402 },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
static int emc1403_probe(struct i2c_client *client)
{
struct thermal_data *data;
struct device *hwmon_dev;
const struct i2c_device_id *id = i2c_match_id(emc1403_idtable, client);
data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
data->chip = id->driver_data;
data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
mutex_init(&data->mutex);
hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
client->name, data,
&emc1403_chip_info,
emc1403_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const unsigned short emc1403_address_list[] = {
0x18, 0x1c, 0x29, 0x3c, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END
};
static struct i2c_driver sensor_emc1403 = {
.class = I2C_CLASS_HWMON,
.driver = {

View File

@ -620,7 +620,7 @@ emc2103_probe(struct i2c_client *client)
}
static const struct i2c_device_id emc2103_ids[] = {
{ "emc2103", 0, },
{ "emc2103" },
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, emc2103_ids);

View File

@ -47,10 +47,10 @@ enum emc230x_product_id {
};
static const struct i2c_device_id emc2305_ids[] = {
{ "emc2305", 0 },
{ "emc2303", 0 },
{ "emc2302", 0 },
{ "emc2301", 0 },
{ "emc2305" },
{ "emc2303" },
{ "emc2302" },
{ "emc2301" },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc2305_ids);

View File

@ -464,7 +464,7 @@ static int emc6w201_probe(struct i2c_client *client)
}
static const struct i2c_device_id emc6w201_id[] = {
{ "emc6w201", 0 },
{ "emc6w201" },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc6w201_id);

View File

@ -50,7 +50,7 @@
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
static const struct i2c_device_id fts_id[] = {
{ "ftsteutates", 0 },
{ "ftsteutates" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fts_id);

View File

@ -197,7 +197,7 @@ static int g760a_probe(struct i2c_client *client)
}
static const struct i2c_device_id g760a_id[] = {
{ "g760a", 0 },
{ "g760a" },
{ }
};
MODULE_DEVICE_TABLE(i2c, g760a_id);

View File

@ -44,8 +44,8 @@
#define DRVNAME "g762"
static const struct i2c_device_id g762_id[] = {
{ "g762", 0 },
{ "g763", 0 },
{ "g762" },
{ "g763" },
{ }
};
MODULE_DEVICE_TABLE(i2c, g762_id);

View File

@ -642,7 +642,7 @@ static int gl518_probe(struct i2c_client *client)
}
static const struct i2c_device_id gl518_id[] = {
{ "gl518sm", 0 },
{ "gl518sm" },
{ }
};
MODULE_DEVICE_TABLE(i2c, gl518_id);

View File

@ -885,7 +885,7 @@ static int gl520_probe(struct i2c_client *client)
}
static const struct i2c_device_id gl520_id[] = {
{ "gl520sm", 0 },
{ "gl520sm" },
{ }
};
MODULE_DEVICE_TABLE(i2c, gl520_id);

View File

@ -233,7 +233,7 @@ static int hih6130_probe(struct i2c_client *client)
/* Device ID table */
static const struct i2c_device_id hih6130_id[] = {
{ "hih6130", 0 },
{ "hih6130" },
{ }
};
MODULE_DEVICE_TABLE(i2c, hih6130_id);

View File

@ -175,7 +175,7 @@ static const struct hwmon_chip_info hs3001_chip_info = {
/* device ID table */
static const struct i2c_device_id hs3001_ids[] = {
{ "hs3001", 0 },
{ "hs3001" },
{ },
};

View File

@ -576,7 +576,7 @@ static void ina209_remove(struct i2c_client *client)
}
static const struct i2c_device_id ina209_id[] = {
{ "ina209", 0 },
{ "ina209" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ina209_id);

View File

@ -616,7 +616,7 @@ static int ina238_probe(struct i2c_client *client)
}
static const struct i2c_device_id ina238_id[] = {
{ "ina238", 0 },
{ "ina238" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ina238_id);

View File

@ -1031,7 +1031,7 @@ static const struct of_device_id ina3221_of_match_table[] = {
MODULE_DEVICE_TABLE(of, ina3221_of_match_table);
static const struct i2c_device_id ina3221_ids[] = {
{ "ina3221", 0 },
{ "ina3221" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, ina3221_ids);

View File

@ -117,7 +117,7 @@ static inline void superio_select(int ioreg, int ldn)
outb(ldn, ioreg + 1);
}
static inline int superio_enter(int ioreg)
static inline int superio_enter(int ioreg, bool noentry)
{
/*
* Try to reserve ioreg and ioreg + 1 for exclusive access.
@ -125,7 +125,8 @@ static inline int superio_enter(int ioreg)
if (!request_muxed_region(ioreg, 2, DRVNAME))
return -EBUSY;
__superio_enter(ioreg);
if (!noentry)
__superio_enter(ioreg);
return 0;
}
@ -320,7 +321,7 @@ struct it87_devices {
* second SIO address. Never exit configuration mode on these
* chips to avoid the problem.
*/
#define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */
#define FEAT_NOCONF BIT(19) /* Chip conf mode enabled on startup */
#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)
@ -452,7 +453,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_FANCTL_ONOFF | FEAT_CONF_NOEXIT,
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_NOCONF,
.peci_mask = 0x07,
},
[it8792] = {
@ -461,7 +462,7 @@ static const struct it87_devices it87_devices[] = {
.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_FANCTL_ONOFF
| FEAT_CONF_NOEXIT,
| FEAT_NOCONF,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@ -507,7 +508,7 @@ static const struct it87_devices it87_devices[] = {
.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_FANCTL_ONOFF
| FEAT_CONF_NOEXIT,
| FEAT_NOCONF,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@ -544,7 +545,7 @@ static const struct it87_devices it87_devices[] = {
#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_noconf(data) ((data)->features & FEAT_NOCONF)
#define has_scaling(data) ((data)->features & (FEAT_12MV_ADC | \
FEAT_10_9MV_ADC))
#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF)
@ -742,13 +743,13 @@ static int smbus_disable(struct it87_data *data)
int err;
if (data->smbus_bitmap) {
err = superio_enter(data->sioaddr);
err = superio_enter(data->sioaddr, has_noconf(data));
if (err)
return err;
superio_select(data->sioaddr, PME);
superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
data->ec_special_config & ~data->smbus_bitmap);
superio_exit(data->sioaddr, has_conf_noexit(data));
superio_exit(data->sioaddr, has_noconf(data));
}
return 0;
}
@ -758,14 +759,14 @@ static int smbus_enable(struct it87_data *data)
int err;
if (data->smbus_bitmap) {
err = superio_enter(data->sioaddr);
err = superio_enter(data->sioaddr, has_noconf(data));
if (err)
return err;
superio_select(data->sioaddr, PME);
superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
data->ec_special_config);
superio_exit(data->sioaddr, has_conf_noexit(data));
superio_exit(data->sioaddr, has_noconf(data));
}
return 0;
}
@ -2666,6 +2667,27 @@ static const struct attribute_group it87_group_auto_pwm = {
.is_visible = it87_auto_pwm_is_visible,
};
/*
* Original explanation:
* On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip
* (IT8792E) needs to be in configuration mode before accessing the first
* due to a bug in IT8792E which otherwise results in LPC bus access errors.
* This needs to be done before accessing the first Super-IO chip since
* the second chip may have been accessed prior to loading this driver.
*
* The problem is also reported to affect IT8795E, which is used on X299 boards
* and has the same chip ID as IT8792E (0x8733). It also appears to affect
* systems with IT8790E, which is used on some Z97X-Gaming boards as well as
* Z87X-OC.
*
* From other information supplied:
* ChipIDs 0x8733, 0x8695 (early ID for IT87952E) and 0x8790 are initialized
* and left in configuration mode, and entering and/or exiting configuration
* mode is what causes the crash.
*
* The recommendation is to look up the chipID before doing any mode swap
* and then act accordingly.
*/
/* SuperIO detection - will change isa_address if a chip is found */
static int __init it87_find(int sioaddr, unsigned short *address,
struct it87_sio_data *sio_data, int chip_cnt)
@ -2673,16 +2695,25 @@ static int __init it87_find(int sioaddr, unsigned short *address,
int err;
u16 chip_type;
const struct it87_devices *config = NULL;
bool enabled = false;
err = superio_enter(sioaddr);
/* First step, lock memory but don't enter configuration mode */
err = superio_enter(sioaddr, true);
if (err)
return err;
err = -ENODEV;
chip_type = superio_inw(sioaddr, DEVID);
/* check first for a valid chip before forcing chip id */
if (chip_type == 0xffff)
goto exit;
/* Check for a valid chip before forcing chip id */
if (chip_type == 0xffff) {
/* Enter configuration mode */
__superio_enter(sioaddr);
enabled = true;
/* and then try again */
chip_type = superio_inw(sioaddr, DEVID);
if (chip_type == 0xffff)
goto exit;
}
if (force_id_cnt == 1) {
/* If only one value given use for all chips */
@ -2766,6 +2797,18 @@ static int __init it87_find(int sioaddr, unsigned short *address,
config = &it87_devices[sio_data->type];
/*
* If previously we didn't enter configuration mode and it isn't a
* chip we know is initialised in configuration mode, then enter
* configuration mode.
*
* I don't know if any such chips can exist but be defensive.
*/
if (!enabled && !has_noconf(config)) {
__superio_enter(sioaddr);
enabled = true;
}
superio_select(sioaddr, PME);
if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
pr_info("Device (chip %s ioreg 0x%x) not activated, skipping\n",
@ -3143,7 +3186,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
}
exit:
superio_exit(sioaddr, config ? has_conf_noexit(config) : false);
superio_exit(sioaddr, !enabled);
return err;
}
@ -3520,7 +3563,7 @@ static void it87_resume_sio(struct platform_device *pdev)
if (!data->need_in7_reroute)
return;
err = superio_enter(data->sioaddr);
err = superio_enter(data->sioaddr, has_noconf(data));
if (err) {
dev_warn(&pdev->dev,
"Unable to enter Super I/O to reroute in7 (%d)",
@ -3540,7 +3583,7 @@ static void it87_resume_sio(struct platform_device *pdev)
reg2c);
}
superio_exit(data->sioaddr, has_conf_noexit(data));
superio_exit(data->sioaddr, has_noconf(data));
}
static int it87_resume(struct device *dev)
@ -3640,27 +3683,6 @@ static int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
return 1;
}
/*
* On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip
* (IT8792E) needs to be in configuration mode before accessing the first
* due to a bug in IT8792E which otherwise results in LPC bus access errors.
* This needs to be done before accessing the first Super-IO chip since
* the second chip may have been accessed prior to loading this driver.
*
* The problem is also reported to affect IT8795E, which is used on X299 boards
* and has the same chip ID as IT8792E (0x8733). It also appears to affect
* systems with IT8790E, which is used on some Z97X-Gaming boards as well as
* Z87X-OC.
* DMI entries for those systems will be added as they become available and
* as the problem is confirmed to affect those boards.
*/
static int it87_sio_force(const struct dmi_system_id *dmi_entry)
{
__superio_enter(REG_4E);
return it87_dmi_cb(dmi_entry);
};
/*
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
* connected to a fan, but to something else. One user
@ -3683,34 +3705,7 @@ static struct it87_dmi_data nvidia_fn68pt = {
.driver_data = data, \
}
#define IT87_DMI_MATCH_GBT(name, cb, data) \
IT87_DMI_MATCH_VND("Gigabyte Technology Co., Ltd.", name, cb, data)
static const struct dmi_system_id it87_dmi_table[] __initconst = {
IT87_DMI_MATCH_GBT("AB350", it87_sio_force, NULL),
/* ? + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("AX370", it87_sio_force, NULL),
/* ? + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("Z97X-Gaming G1", it87_sio_force, NULL),
/* ? + IT8790E */
IT87_DMI_MATCH_GBT("TRX40 AORUS XTREME", it87_sio_force, NULL),
/* IT8688E + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("Z390 AORUS ULTRA-CF", it87_sio_force, NULL),
/* IT8688E + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("B550 AORUS PRO AC", it87_sio_force, NULL),
/* IT8688E + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("X570 AORUS MASTER", it87_sio_force, NULL),
/* IT8688E + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("X570 AORUS PRO", it87_sio_force, NULL),
/* IT8688E + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("X570 AORUS PRO WIFI", it87_sio_force, NULL),
/* IT8688E + IT8792E/IT8795E */
IT87_DMI_MATCH_GBT("X570S AERO G", it87_sio_force, NULL),
/* IT8689E + IT87952E */
IT87_DMI_MATCH_GBT("Z690 AORUS PRO DDR4", it87_sio_force, NULL),
/* IT8689E + IT87952E */
IT87_DMI_MATCH_GBT("Z690 AORUS PRO", it87_sio_force, NULL),
/* IT8689E + IT87952E */
IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
{ }

View File

@ -609,7 +609,7 @@ static const struct dev_pm_ops jc42_dev_pm_ops = {
#endif /* CONFIG_PM */
static const struct i2c_device_id jc42_id[] = {
{ "jc42", 0 },
{ "jc42" },
{ }
};
MODULE_DEVICE_TABLE(i2c, jc42_id);
@ -623,7 +623,7 @@ MODULE_DEVICE_TABLE(of, jc42_of_ids);
#endif
static struct i2c_driver jc42_driver = {
.class = I2C_CLASS_SPD | I2C_CLASS_HWMON,
.class = I2C_CLASS_HWMON,
.driver = {
.name = "jc42",
.pm = JC42_DEV_PM_OPS,

View File

@ -0,0 +1,602 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* HWMON driver for Lenovo ThinkStation based workstations
* via the embedded controller registers
*
* Copyright (C) 2024 David Ober (Lenovo) <dober@lenovo.com>
*
* EC provides:
* - CPU temperature
* - DIMM temperature
* - Chassis zone temperatures
* - CPU fan RPM
* - DIMM fan RPM
* - Chassis fans RPM
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/units.h>
#define MCHP_SING_IDX 0x0000
#define MCHP_EMI0_APPLICATION_ID 0x090C
#define MCHP_EMI0_EC_ADDRESS 0x0902
#define MCHP_EMI0_EC_DATA_BYTE0 0x0904
#define MCHP_EMI0_EC_DATA_BYTE1 0x0905
#define MCHP_EMI0_EC_DATA_BYTE2 0x0906
#define MCHP_EMI0_EC_DATA_BYTE3 0x0907
#define IO_REGION_START 0x0900
#define IO_REGION_LENGTH 0xD
static inline u8
get_ec_reg(unsigned char page, unsigned char index)
{
u8 onebyte;
unsigned short m_index;
unsigned short phy_index = page * 256 + index;
outb_p(0x01, MCHP_EMI0_APPLICATION_ID);
m_index = phy_index & GENMASK(14, 2);
outw_p(m_index, MCHP_EMI0_EC_ADDRESS);
onebyte = inb_p(MCHP_EMI0_EC_DATA_BYTE0 + (phy_index & GENMASK(1, 0)));
outb_p(0x01, MCHP_EMI0_APPLICATION_ID); /* write 0x01 again to clean */
return onebyte;
}
enum systems {
LENOVO_PX,
LENOVO_P7,
LENOVO_P5,
LENOVO_P8,
};
static int px_temp_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
static const char * const lenovo_px_ec_temp_label[] = {
"CPU1",
"CPU2",
"R_DIMM1",
"L_DIMM1",
"R_DIMM2",
"L_DIMM2",
"PCH",
"M2_R",
"M2_Z1R",
"M2_Z2R",
"PCI_Z1",
"PCI_Z2",
"PCI_Z3",
"PCI_Z4",
"AMB",
};
static int gen_temp_map[] = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
static const char * const lenovo_gen_ec_temp_label[] = {
"CPU1",
"R_DIMM",
"L_DIMM",
"PCH",
"M2_R",
"M2_Z1R",
"M2_Z2R",
"PCI_Z1",
"PCI_Z2",
"PCI_Z3",
"PCI_Z4",
"AMB",
};
static int px_fan_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
static const char * const px_ec_fan_label[] = {
"CPU1_Fan",
"CPU2_Fan",
"Front_Fan1-1",
"Front_Fan1-2",
"Front_Fan2",
"Front_Fan3",
"MEM_Fan1",
"MEM_Fan2",
"Rear_Fan1",
"Rear_Fan2",
"Flex_Bay_Fan1",
"Flex_Bay_Fan2",
"Flex_Bay_Fan2",
"PSU_HDD_Fan",
"PSU1_Fan",
"PSU2_Fan",
};
static int p7_fan_map[] = {0, 2, 3, 4, 5, 6, 7, 8, 10, 11, 14};
static const char * const p7_ec_fan_label[] = {
"CPU1_Fan",
"HP_CPU_Fan1",
"HP_CPU_Fan2",
"PCIE1_4_Fan",
"PCIE5_7_Fan",
"MEM_Fan1",
"MEM_Fan2",
"Rear_Fan1",
"BCB_Fan",
"Flex_Bay_Fan",
"PSU_Fan",
};
static int p5_fan_map[] = {0, 5, 6, 7, 8, 10, 11, 14};
static const char * const p5_ec_fan_label[] = {
"CPU_Fan",
"HDD_Fan",
"Duct_Fan1",
"MEM_Fan",
"Rear_Fan",
"Front_Fan",
"Flex_Bay_Fan",
"PSU_Fan",
};
static int p8_fan_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14};
static const char * const p8_ec_fan_label[] = {
"CPU1_Fan",
"CPU2_Fan",
"HP_CPU_Fan1",
"HP_CPU_Fan2",
"PCIE1_4_Fan",
"PCIE5_7_Fan",
"DIMM1_Fan1",
"DIMM1_Fan2",
"DIMM2_Fan1",
"DIMM2_Fan2",
"Rear_Fan",
"HDD_Bay_Fan",
"Flex_Bay_Fan",
"PSU_Fan",
};
struct ec_sensors_data {
struct mutex mec_mutex; /* lock for sensor data access */
const char *const *fan_labels;
const char *const *temp_labels;
const int *fan_map;
const int *temp_map;
};
static int
lenovo_ec_do_read_temp(struct ec_sensors_data *data, u32 attr, int channel, long *val)
{
u8 lsb;
switch (attr) {
case hwmon_temp_input:
mutex_lock(&data->mec_mutex);
lsb = get_ec_reg(2, 0x81 + channel);
mutex_unlock(&data->mec_mutex);
if (lsb <= 0x40)
return -ENODATA;
*val = (lsb - 0x40) * 1000;
return 0;
default:
return -EOPNOTSUPP;
}
}
static int
lenovo_ec_do_read_fan(struct ec_sensors_data *data, u32 attr, int channel, long *val)
{
u8 lsb, msb;
channel *= 2;
switch (attr) {
case hwmon_fan_input:
mutex_lock(&data->mec_mutex);
lsb = get_ec_reg(4, 0x20 + channel);
msb = get_ec_reg(4, 0x21 + channel);
mutex_unlock(&data->mec_mutex);
*val = (msb << 8) + lsb;
return 0;
case hwmon_fan_max:
mutex_lock(&data->mec_mutex);
lsb = get_ec_reg(4, 0x40 + channel);
msb = get_ec_reg(4, 0x41 + channel);
mutex_unlock(&data->mec_mutex);
*val = (msb << 8) + lsb;
return 0;
default:
return -EOPNOTSUPP;
}
}
static int
lenovo_ec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
struct ec_sensors_data *state = dev_get_drvdata(dev);
switch (type) {
case hwmon_temp:
*str = state->temp_labels[channel];
return 0;
case hwmon_fan:
*str = state->fan_labels[channel];
return 0;
default:
return -EOPNOTSUPP;
}
}
static int
lenovo_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct ec_sensors_data *data = dev_get_drvdata(dev);
switch (type) {
case hwmon_temp:
return lenovo_ec_do_read_temp(data, attr, data->temp_map[channel], val);
case hwmon_fan:
return lenovo_ec_do_read_fan(data, attr, data->fan_map[channel], val);
default:
return -EOPNOTSUPP;
}
}
static umode_t
lenovo_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
switch (type) {
case hwmon_temp:
if (attr == hwmon_temp_input || attr == hwmon_temp_label)
return 0444;
return 0;
case hwmon_fan:
if (attr == hwmon_fan_input || attr == hwmon_fan_max || attr == hwmon_fan_label)
return 0444;
return 0;
default:
return 0;
}
}
static const struct hwmon_channel_info *lenovo_ec_hwmon_info_px[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
NULL
};
static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p8[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
NULL
};
static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p7[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
NULL
};
static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p5[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
NULL
};
static const struct hwmon_ops lenovo_ec_hwmon_ops = {
.is_visible = lenovo_ec_hwmon_is_visible,
.read = lenovo_ec_hwmon_read,
.read_string = lenovo_ec_hwmon_read_string,
};
static struct hwmon_chip_info lenovo_ec_chip_info = {
.ops = &lenovo_ec_hwmon_ops,
};
static const struct dmi_system_id thinkstation_dmi_table[] = {
{
.ident = "LENOVO_PX",
.driver_data = (void *)(long)LENOVO_PX,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30EU"),
},
},
{
.ident = "LENOVO_PX",
.driver_data = (void *)(long)LENOVO_PX,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30EV"),
},
},
{
.ident = "LENOVO_P7",
.driver_data = (void *)(long)LENOVO_P7,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30F2"),
},
},
{
.ident = "LENOVO_P7",
.driver_data = (void *)(long)LENOVO_P7,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30F3"),
},
},
{
.ident = "LENOVO_P5",
.driver_data = (void *)(long)LENOVO_P5,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30G9"),
},
},
{
.ident = "LENOVO_P5",
.driver_data = (void *)(long)LENOVO_P5,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30GA"),
},
},
{
.ident = "LENOVO_P8",
.driver_data = (void *)(long)LENOVO_P8,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30HH"),
},
},
{
.ident = "LENOVO_P8",
.driver_data = (void *)(long)LENOVO_P8,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "30HJ"),
},
},
{}
};
MODULE_DEVICE_TABLE(dmi, thinkstation_dmi_table);
static int lenovo_ec_probe(struct platform_device *pdev)
{
struct device *hwdev;
struct ec_sensors_data *ec_data;
const struct hwmon_chip_info *chip_info;
struct device *dev = &pdev->dev;
const struct dmi_system_id *dmi_id;
int app_id;
ec_data = devm_kzalloc(dev, sizeof(struct ec_sensors_data), GFP_KERNEL);
if (!ec_data)
return -ENOMEM;
if (!request_region(IO_REGION_START, IO_REGION_LENGTH, "LNV-WKS")) {
pr_err(":request fail\n");
return -EIO;
}
dev_set_drvdata(dev, ec_data);
chip_info = &lenovo_ec_chip_info;
mutex_init(&ec_data->mec_mutex);
mutex_lock(&ec_data->mec_mutex);
app_id = inb_p(MCHP_EMI0_APPLICATION_ID);
if (app_id) /* check EMI Application ID Value */
outb_p(app_id, MCHP_EMI0_APPLICATION_ID); /* set EMI Application ID to 0 */
outw_p(MCHP_SING_IDX, MCHP_EMI0_EC_ADDRESS);
mutex_unlock(&ec_data->mec_mutex);
if ((inb_p(MCHP_EMI0_EC_DATA_BYTE0) != 'M') &&
(inb_p(MCHP_EMI0_EC_DATA_BYTE1) != 'C') &&
(inb_p(MCHP_EMI0_EC_DATA_BYTE2) != 'H') &&
(inb_p(MCHP_EMI0_EC_DATA_BYTE3) != 'P')) {
release_region(IO_REGION_START, IO_REGION_LENGTH);
return -ENODEV;
}
dmi_id = dmi_first_match(thinkstation_dmi_table);
switch ((long)dmi_id->driver_data) {
case 0:
ec_data->fan_labels = px_ec_fan_label;
ec_data->temp_labels = lenovo_px_ec_temp_label;
ec_data->fan_map = px_fan_map;
ec_data->temp_map = px_temp_map;
lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_px;
break;
case 1:
ec_data->fan_labels = p7_ec_fan_label;
ec_data->temp_labels = lenovo_gen_ec_temp_label;
ec_data->fan_map = p7_fan_map;
ec_data->temp_map = gen_temp_map;
lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p7;
break;
case 2:
ec_data->fan_labels = p5_ec_fan_label;
ec_data->temp_labels = lenovo_gen_ec_temp_label;
ec_data->fan_map = p5_fan_map;
ec_data->temp_map = gen_temp_map;
lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p5;
break;
case 3:
ec_data->fan_labels = p8_ec_fan_label;
ec_data->temp_labels = lenovo_gen_ec_temp_label;
ec_data->fan_map = p8_fan_map;
ec_data->temp_map = gen_temp_map;
lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p8;
break;
default:
release_region(IO_REGION_START, IO_REGION_LENGTH);
return -ENODEV;
}
hwdev = devm_hwmon_device_register_with_info(dev, "lenovo_ec",
ec_data,
chip_info, NULL);
return PTR_ERR_OR_ZERO(hwdev);
}
static struct platform_driver lenovo_ec_sensors_platform_driver = {
.driver = {
.name = "lenovo-ec-sensors",
},
.probe = lenovo_ec_probe,
};
static struct platform_device *lenovo_ec_sensors_platform_device;
static int __init lenovo_ec_init(void)
{
if (!dmi_check_system(thinkstation_dmi_table))
return -ENODEV;
lenovo_ec_sensors_platform_device =
platform_create_bundle(&lenovo_ec_sensors_platform_driver,
lenovo_ec_probe, NULL, 0, NULL, 0);
if (IS_ERR(lenovo_ec_sensors_platform_device)) {
release_region(IO_REGION_START, IO_REGION_LENGTH);
return PTR_ERR(lenovo_ec_sensors_platform_device);
}
return 0;
}
module_init(lenovo_ec_init);
static void __exit lenovo_ec_exit(void)
{
release_region(IO_REGION_START, IO_REGION_LENGTH);
platform_device_unregister(lenovo_ec_sensors_platform_device);
platform_driver_unregister(&lenovo_ec_sensors_platform_driver);
}
module_exit(lenovo_ec_exit);
MODULE_AUTHOR("David Ober <dober@lenovo.com>");
MODULE_DESCRIPTION("HWMON driver for sensors accessible via EC in LENOVO motherboards");
MODULE_LICENSE("GPL");

View File

@ -502,7 +502,7 @@ static int pem_probe(struct i2c_client *client)
}
static const struct i2c_device_id pem_id[] = {
{"lineage_pem", 0},
{"lineage_pem"},
{}
};
MODULE_DEVICE_TABLE(i2c, pem_id);

View File

@ -6,9 +6,9 @@
* Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
*
* The LM70 communicates with a host processor via an SPI/Microwire Bus
* interface. The complete datasheet is available at National's website
* interface. The complete datasheet is available at TI's website
* here:
* http://www.national.com/pf/LM/LM70.html
* https://www.ti.com/product/LM70
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

View File

@ -220,7 +220,7 @@ lm73_probe(struct i2c_client *client)
}
static const struct i2c_device_id lm73_ids[] = {
{ "lm73", 0 },
{ "lm73" },
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, lm73_ids);

View File

@ -337,7 +337,7 @@ static int lm77_probe(struct i2c_client *client)
}
static const struct i2c_device_id lm77_id[] = {
{ "lm77", 0 },
{ "lm77" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm77_id);

View File

@ -975,8 +975,8 @@ static int lm87_probe(struct i2c_client *client)
*/
static const struct i2c_device_id lm87_id[] = {
{ "lm87", 0 },
{ "adm1024", 0 },
{ "lm87" },
{ "adm1024" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm87_id);

View File

@ -2624,8 +2624,8 @@ static int lm93_probe(struct i2c_client *client)
}
static const struct i2c_device_id lm93_id[] = {
{ "lm93", 0 },
{ "lm94", 0 },
{ "lm93" },
{ "lm94" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm93_id);

View File

@ -457,8 +457,8 @@ static int lm95241_probe(struct i2c_client *client)
/* Driver data (common to all clients) */
static const struct i2c_device_id lm95241_id[] = {
{ "lm95231", 0 },
{ "lm95241", 0 },
{ "lm95231" },
{ "lm95241" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm95241_id);

View File

@ -578,8 +578,8 @@ static int lm95245_probe(struct i2c_client *client)
/* Driver data (common to all clients) */
static const struct i2c_device_id lm95245_id[] = {
{ "lm95235", 0 },
{ "lm95245", 0 },
{ "lm95235" },
{ "lm95245" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm95245_id);

View File

@ -508,7 +508,7 @@ static int ltc2945_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc2945_id[] = {
{"ltc2945", 0},
{"ltc2945"},
{ }
};

View File

@ -27,7 +27,7 @@ static int ltc2947_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ltc2947_id[] = {
{"ltc2947", 0},
{"ltc2947"},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2947_id);

View File

@ -259,7 +259,7 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id ltc2990_i2c_id[] = {
{ "ltc2990", 0 },
{ "ltc2990" },
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2990_i2c_id);

View File

@ -414,7 +414,7 @@ static const struct of_device_id ltc2991_of_match[] = {
MODULE_DEVICE_TABLE(of, ltc2991_of_match);
static const struct i2c_device_id ltc2991_i2c_id[] = {
{ "ltc2991", 0 },
{ "ltc2991" },
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2991_i2c_id);

View File

@ -922,7 +922,7 @@ static const struct of_device_id ltc2992_of_match[] = {
MODULE_DEVICE_TABLE(of, ltc2992_of_match);
static const struct i2c_device_id ltc2992_i2c_id[] = {
{"ltc2992", 0},
{"ltc2992"},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2992_i2c_id);

View File

@ -188,7 +188,7 @@ static int ltc4151_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc4151_id[] = {
{ "ltc4151", 0 },
{ "ltc4151" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc4151_id);

View File

@ -245,7 +245,7 @@ static int ltc4215_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc4215_id[] = {
{ "ltc4215", 0 },
{ "ltc4215" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc4215_id);

View File

@ -200,7 +200,7 @@ static int ltc4222_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc4222_id[] = {
{"ltc4222", 0},
{"ltc4222"},
{ }
};

View File

@ -469,7 +469,7 @@ static int ltc4245_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc4245_id[] = {
{ "ltc4245", 0 },
{ "ltc4245" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc4245_id);

View File

@ -163,7 +163,7 @@ static int ltc4260_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc4260_id[] = {
{"ltc4260", 0},
{"ltc4260"},
{ }
};

View File

@ -222,7 +222,7 @@ static int ltc4261_probe(struct i2c_client *client)
}
static const struct i2c_device_id ltc4261_id[] = {
{"ltc4261", 0},
{"ltc4261"},
{}
};

View File

@ -329,7 +329,7 @@ static int max127_probe(struct i2c_client *client)
}
static const struct i2c_device_id max127_id[] = {
{ "max127", 0 },
{ "max127" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max127_id);

View File

@ -285,7 +285,7 @@ static int max1619_probe(struct i2c_client *new_client)
}
static const struct i2c_device_id max1619_id[] = {
{ "max1619", 0 },
{ "max1619" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max1619_id);

View File

@ -345,7 +345,7 @@ max31730_probe(struct i2c_client *client)
}
static const struct i2c_device_id max31730_ids[] = {
{ "max31730", 0, },
{ "max31730" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max31730_ids);

View File

@ -49,6 +49,9 @@
#define NR_CHANNEL 6
#define PWM_INPUT_SCALE 255
#define MAX31790_REG_PWMOUT_SCALE 511
/*
* Client data (each client gets its own)
*/
@ -343,10 +346,13 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
err = -EINVAL;
break;
}
val = DIV_ROUND_CLOSEST(val * MAX31790_REG_PWMOUT_SCALE,
PWM_INPUT_SCALE);
data->valid = false;
err = i2c_smbus_write_word_swapped(client,
MAX31790_REG_PWMOUT(channel),
val << 8);
val << 7);
break;
case hwmon_pwm_enable:
fan_config = data->fan_config[channel];
@ -537,7 +543,7 @@ static int max31790_probe(struct i2c_client *client)
}
static const struct i2c_device_id max31790_id[] = {
{ "max31790", 0 },
{ "max31790" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max31790_id);

View File

@ -493,7 +493,7 @@ static int max6620_probe(struct i2c_client *client)
}
static const struct i2c_device_id max6620_id[] = {
{ "max6620", 0 },
{ "max6620" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6620_id);

View File

@ -537,7 +537,7 @@ static int max6621_probe(struct i2c_client *client)
}
static const struct i2c_device_id max6621_id[] = {
{ MAX6621_DRV_NAME, 0 },
{ MAX6621_DRV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6621_id);

View File

@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/platform_data/max6639.h>
#include <linux/regmap.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
@ -57,6 +58,8 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
#define MAX6639_FAN_CONFIG3_THERM_FULL_SPEED 0x40
#define MAX6639_NUM_CHANNELS 2
static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
#define FAN_FROM_REG(val, rpm_range) ((val) == 0 || (val) == 255 ? \
@ -67,22 +70,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
* Client data (each client gets its own)
*/
struct max6639_data {
struct i2c_client *client;
struct mutex update_lock;
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
/* Register values sampled regularly */
u16 temp[2]; /* Temperature, in 1/8 C, 0..255 C */
bool temp_fault[2]; /* Detected temperature diode failure */
u8 fan[2]; /* Register value: TACH count for fans >=30 */
u8 status; /* Detected channel alarms and fan failures */
/* Register values only written to */
u8 pwm[2]; /* Register value: Duty cycle 0..120 */
u8 temp_therm[2]; /* THERM Temperature, 0..255 C (->_max) */
u8 temp_alert[2]; /* ALERT Temperature, 0..255 C (->_crit) */
u8 temp_ot[2]; /* OT Temperature, 0..255 C (->_emergency) */
struct regmap *regmap;
/* Register values initialized only once */
u8 ppr; /* Pulses per rotation 0..3 for 1..4 ppr */
@ -92,90 +80,47 @@ struct max6639_data {
struct regulator *reg;
};
static struct max6639_data *max6639_update_device(struct device *dev)
{
struct max6639_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
struct max6639_data *ret = data;
int i;
int status_reg;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
int res;
dev_dbg(&client->dev, "Starting max6639 update\n");
status_reg = i2c_smbus_read_byte_data(client,
MAX6639_REG_STATUS);
if (status_reg < 0) {
ret = ERR_PTR(status_reg);
goto abort;
}
data->status = status_reg;
for (i = 0; i < 2; i++) {
res = i2c_smbus_read_byte_data(client,
MAX6639_REG_FAN_CNT(i));
if (res < 0) {
ret = ERR_PTR(res);
goto abort;
}
data->fan[i] = res;
res = i2c_smbus_read_byte_data(client,
MAX6639_REG_TEMP_EXT(i));
if (res < 0) {
ret = ERR_PTR(res);
goto abort;
}
data->temp[i] = res >> 5;
data->temp_fault[i] = res & 0x01;
res = i2c_smbus_read_byte_data(client,
MAX6639_REG_TEMP(i));
if (res < 0) {
ret = ERR_PTR(res);
goto abort;
}
data->temp[i] |= res << 3;
}
data->last_updated = jiffies;
data->valid = true;
}
abort:
mutex_unlock(&data->update_lock);
return ret;
}
static ssize_t temp_input_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
long temp;
struct max6639_data *data = max6639_update_device(dev);
struct max6639_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
unsigned int val;
int res;
if (IS_ERR(data))
return PTR_ERR(data);
/*
* Lock isn't needed as MAX6639_REG_TEMP wpnt change for at least 250ms after reading
* MAX6639_REG_TEMP_EXT
*/
res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(attr->index), &val);
if (res < 0)
return res;
temp = val >> 5;
res = regmap_read(data->regmap, MAX6639_REG_TEMP(attr->index), &val);
if (res < 0)
return res;
temp |= val << 3;
temp *= 125;
temp = data->temp[attr->index] * 125;
return sprintf(buf, "%ld\n", temp);
}
static ssize_t temp_fault_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct max6639_data *data = max6639_update_device(dev);
struct max6639_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
unsigned int val;
int res;
if (IS_ERR(data))
return PTR_ERR(data);
res = regmap_read(data->regmap, MAX6639_REG_TEMP_EXT(attr->index), &val);
if (res < 0)
return res;
return sprintf(buf, "%d\n", data->temp_fault[attr->index]);
return sprintf(buf, "%d\n", val & 1);
}
static ssize_t temp_max_show(struct device *dev,
@ -183,8 +128,14 @@ static ssize_t temp_max_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
unsigned int val;
int res;
return sprintf(buf, "%d\n", (data->temp_therm[attr->index] * 1000));
res = regmap_read(data->regmap, MAX6639_REG_THERM_LIMIT(attr->index), &val);
if (res < 0)
return res;
return sprintf(buf, "%d\n", (val * 1000));
}
static ssize_t temp_max_store(struct device *dev,
@ -193,7 +144,6 @@ static ssize_t temp_max_store(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long val;
int res;
@ -201,12 +151,8 @@ static ssize_t temp_max_store(struct device *dev,
if (res)
return res;
mutex_lock(&data->update_lock);
data->temp_therm[attr->index] = TEMP_LIMIT_TO_REG(val);
i2c_smbus_write_byte_data(client,
MAX6639_REG_THERM_LIMIT(attr->index),
data->temp_therm[attr->index]);
mutex_unlock(&data->update_lock);
regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(attr->index),
TEMP_LIMIT_TO_REG(val));
return count;
}
@ -215,8 +161,14 @@ static ssize_t temp_crit_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
unsigned int val;
int res;
return sprintf(buf, "%d\n", (data->temp_alert[attr->index] * 1000));
res = regmap_read(data->regmap, MAX6639_REG_ALERT_LIMIT(attr->index), &val);
if (res < 0)
return res;
return sprintf(buf, "%d\n", (val * 1000));
}
static ssize_t temp_crit_store(struct device *dev,
@ -225,7 +177,6 @@ static ssize_t temp_crit_store(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long val;
int res;
@ -233,12 +184,8 @@ static ssize_t temp_crit_store(struct device *dev,
if (res)
return res;
mutex_lock(&data->update_lock);
data->temp_alert[attr->index] = TEMP_LIMIT_TO_REG(val);
i2c_smbus_write_byte_data(client,
MAX6639_REG_ALERT_LIMIT(attr->index),
data->temp_alert[attr->index]);
mutex_unlock(&data->update_lock);
regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(attr->index),
TEMP_LIMIT_TO_REG(val));
return count;
}
@ -248,8 +195,14 @@ static ssize_t temp_emergency_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
unsigned int val;
int res;
return sprintf(buf, "%d\n", (data->temp_ot[attr->index] * 1000));
res = regmap_read(data->regmap, MAX6639_REG_OT_LIMIT(attr->index), &val);
if (res < 0)
return res;
return sprintf(buf, "%d\n", (val * 1000));
}
static ssize_t temp_emergency_store(struct device *dev,
@ -258,7 +211,6 @@ static ssize_t temp_emergency_store(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long val;
int res;
@ -266,12 +218,8 @@ static ssize_t temp_emergency_store(struct device *dev,
if (res)
return res;
mutex_lock(&data->update_lock);
data->temp_ot[attr->index] = TEMP_LIMIT_TO_REG(val);
i2c_smbus_write_byte_data(client,
MAX6639_REG_OT_LIMIT(attr->index),
data->temp_ot[attr->index]);
mutex_unlock(&data->update_lock);
regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(attr->index), TEMP_LIMIT_TO_REG(val));
return count;
}
@ -280,8 +228,14 @@ static ssize_t pwm_show(struct device *dev, struct device_attribute *dev_attr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
unsigned int val;
int res;
return sprintf(buf, "%d\n", data->pwm[attr->index] * 255 / 120);
res = regmap_read(data->regmap, MAX6639_REG_TARGTDUTY(attr->index), &val);
if (res < 0)
return res;
return sprintf(buf, "%d\n", val * 255 / 120);
}
static ssize_t pwm_store(struct device *dev,
@ -290,7 +244,6 @@ static ssize_t pwm_store(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
struct max6639_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long val;
int res;
@ -300,38 +253,39 @@ static ssize_t pwm_store(struct device *dev,
val = clamp_val(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm[attr->index] = (u8)(val * 120 / 255);
i2c_smbus_write_byte_data(client,
MAX6639_REG_TARGTDUTY(attr->index),
data->pwm[attr->index]);
mutex_unlock(&data->update_lock);
regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(attr->index), val * 120 / 255);
return count;
}
static ssize_t fan_input_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct max6639_data *data = max6639_update_device(dev);
struct max6639_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
unsigned int val;
int res;
if (IS_ERR(data))
return PTR_ERR(data);
res = regmap_read(data->regmap, MAX6639_REG_FAN_CNT(attr->index), &val);
if (res < 0)
return res;
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
data->rpm_range));
return sprintf(buf, "%d\n", FAN_FROM_REG(val, data->rpm_range));
}
static ssize_t alarm_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct max6639_data *data = max6639_update_device(dev);
struct max6639_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
unsigned int val;
int res;
if (IS_ERR(data))
return PTR_ERR(data);
res = regmap_read(data->regmap, MAX6639_REG_STATUS, &val);
if (res < 0)
return res;
return sprintf(buf, "%d\n", !!(data->status & (1 << attr->index)));
return sprintf(buf, "%d\n", !!(val & (1 << attr->index)));
}
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_input, 0);
@ -401,6 +355,11 @@ static int rpm_range_to_reg(int range)
return 1; /* default: 4000 RPM */
}
static int max6639_set_ppr(struct max6639_data *data, u8 channel, u8 ppr)
{
return regmap_write(data->regmap, MAX6639_REG_FAN_PPR(channel), ppr << 6);
}
static int max6639_init_client(struct i2c_client *client,
struct max6639_data *data)
{
@ -408,94 +367,76 @@ static int max6639_init_client(struct i2c_client *client,
dev_get_platdata(&client->dev);
int i;
int rpm_range = 1; /* default: 4000 RPM */
int err;
int err, ppr;
/* Reset chip to default values, see below for GCONFIG setup */
err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
MAX6639_GCONFIG_POR);
err = regmap_write(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_POR);
if (err)
goto exit;
return err;
/* Fans pulse per revolution is 2 by default */
if (max6639_info && max6639_info->ppr > 0 &&
max6639_info->ppr < 5)
data->ppr = max6639_info->ppr;
ppr = max6639_info->ppr;
else
data->ppr = 2;
data->ppr -= 1;
ppr = 2;
ppr -= 1;
if (max6639_info)
rpm_range = rpm_range_to_reg(max6639_info->rpm_range);
data->rpm_range = rpm_range;
for (i = 0; i < 2; i++) {
for (i = 0; i < MAX6639_NUM_CHANNELS; i++) {
/* Set Fan pulse per revolution */
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_FAN_PPR(i),
data->ppr << 6);
err = max6639_set_ppr(data, i, ppr);
if (err)
goto exit;
return err;
/* Fans config PWM, RPM */
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_FAN_CONFIG1(i),
MAX6639_FAN_CONFIG1_PWM | rpm_range);
err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG1(i),
MAX6639_FAN_CONFIG1_PWM | rpm_range);
if (err)
goto exit;
return err;
/* Fans PWM polarity high by default */
if (max6639_info && max6639_info->pwm_polarity == 0)
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_FAN_CONFIG2a(i), 0x00);
err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00);
else
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_FAN_CONFIG2a(i), 0x02);
err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02);
if (err)
goto exit;
return err;
/*
* /THERM full speed enable,
* PWM frequency 25kHz, see also GCONFIG below
*/
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_FAN_CONFIG3(i),
MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG3(i),
MAX6639_FAN_CONFIG3_THERM_FULL_SPEED | 0x03);
if (err)
goto exit;
return err;
/* Max. temp. 80C/90C/100C */
data->temp_therm[i] = 80;
data->temp_alert[i] = 90;
data->temp_ot[i] = 100;
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_THERM_LIMIT(i),
data->temp_therm[i]);
err = regmap_write(data->regmap, MAX6639_REG_THERM_LIMIT(i), 80);
if (err)
goto exit;
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_ALERT_LIMIT(i),
data->temp_alert[i]);
return err;
err = regmap_write(data->regmap, MAX6639_REG_ALERT_LIMIT(i), 90);
if (err)
goto exit;
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_OT_LIMIT(i), data->temp_ot[i]);
return err;
err = regmap_write(data->regmap, MAX6639_REG_OT_LIMIT(i), 100);
if (err)
goto exit;
return err;
/* PWM 120/120 (i.e. 100%) */
data->pwm[i] = 120;
err = i2c_smbus_write_byte_data(client,
MAX6639_REG_TARGTDUTY(i), data->pwm[i]);
err = regmap_write(data->regmap, MAX6639_REG_TARGTDUTY(i), 120);
if (err)
goto exit;
return err;
}
/* Start monitoring */
err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG,
MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
MAX6639_GCONFIG_PWM_FREQ_HI);
exit:
return err;
return regmap_write(data->regmap, MAX6639_REG_GCONFIG,
MAX6639_GCONFIG_DISABLE_TIMEOUT | MAX6639_GCONFIG_CH2_LOCAL |
MAX6639_GCONFIG_PWM_FREQ_HI);
}
/* Return 0 if detection is successful, -ENODEV otherwise */
@ -524,6 +465,32 @@ static void max6639_regulator_disable(void *data)
regulator_disable(data);
}
static bool max6639_regmap_is_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX6639_REG_TEMP(0):
case MAX6639_REG_TEMP_EXT(0):
case MAX6639_REG_TEMP(1):
case MAX6639_REG_TEMP_EXT(1):
case MAX6639_REG_STATUS:
case MAX6639_REG_FAN_CNT(0):
case MAX6639_REG_FAN_CNT(1):
case MAX6639_REG_TARGTDUTY(0):
case MAX6639_REG_TARGTDUTY(1):
return true;
default:
return false;
}
}
static const struct regmap_config max6639_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX6639_REG_DEVREV,
.cache_type = REGCACHE_MAPLE,
.volatile_reg = max6639_regmap_is_volatile,
};
static int max6639_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@ -535,7 +502,11 @@ static int max6639_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
data->client = client;
data->regmap = devm_regmap_init_i2c(client, &max6639_regmap_config);
if (IS_ERR(data->regmap))
return dev_err_probe(dev,
PTR_ERR(data->regmap),
"regmap initialization failed\n");
data->reg = devm_regulator_get_optional(dev, "fan");
if (IS_ERR(data->reg)) {
@ -558,8 +529,6 @@ static int max6639_probe(struct i2c_client *client)
}
}
mutex_init(&data->update_lock);
/* Initialize the max6639 chip */
err = max6639_init_client(client, data);
if (err < 0)
@ -573,23 +542,17 @@ static int max6639_probe(struct i2c_client *client)
static int max6639_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct max6639_data *data = dev_get_drvdata(dev);
int ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
if (ret < 0)
return ret;
if (data->reg)
regulator_disable(data->reg);
return i2c_smbus_write_byte_data(client,
MAX6639_REG_GCONFIG, ret | MAX6639_GCONFIG_STANDBY);
return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
MAX6639_GCONFIG_STANDBY);
}
static int max6639_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct max6639_data *data = dev_get_drvdata(dev);
int ret;
@ -601,16 +564,12 @@ static int max6639_resume(struct device *dev)
}
}
ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
if (ret < 0)
return ret;
return i2c_smbus_write_byte_data(client,
MAX6639_REG_GCONFIG, ret & ~MAX6639_GCONFIG_STANDBY);
return regmap_write_bits(data->regmap, MAX6639_REG_GCONFIG, MAX6639_GCONFIG_STANDBY,
~MAX6639_GCONFIG_STANDBY);
}
static const struct i2c_device_id max6639_id[] = {
{"max6639", 0},
{"max6639"},
{ }
};

View File

@ -291,7 +291,7 @@ static int max6642_probe(struct i2c_client *client)
*/
static const struct i2c_device_id max6642_id[] = {
{ "max6642", 0 },
{ "max6642" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6642_id);

View File

@ -235,7 +235,7 @@ static int mc34vr500_probe(struct i2c_client *client)
}
static const struct i2c_device_id mc34vr500_id[] = {
{ "mc34vr500", 0 },
{ "mc34vr500" },
{ },
};
MODULE_DEVICE_TABLE(i2c, mc34vr500_id);

View File

@ -1212,7 +1212,7 @@ static const unsigned short nct7802_address_list[] = {
};
static const struct i2c_device_id nct7802_idtable[] = {
{ "nct7802", 0 },
{ "nct7802" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nct7802_idtable);

View File

@ -1161,7 +1161,7 @@ static int nct7904_probe(struct i2c_client *client)
}
static const struct i2c_device_id nct7904_id[] = {
{"nct7904", 0},
{"nct7904"},
{}
};
MODULE_DEVICE_TABLE(i2c, nct7904_id);

View File

@ -196,8 +196,6 @@ struct npcm7xx_pwm_fan_data {
void __iomem *pwm_base;
void __iomem *fan_base;
int pwm_modules;
unsigned long pwm_clk_freq;
unsigned long fan_clk_freq;
struct clk *pwm_clk;
struct clk *fan_clk;
struct mutex pwm_lock[NPCM7XX_PWM_MAX_MODULES];
@ -692,11 +690,12 @@ static u32 npcm7xx_pwm_init(struct npcm7xx_pwm_fan_data *data)
{
int m, ch;
u32 prescale_val, output_freq;
unsigned long pwm_clk_freq;
data->pwm_clk_freq = clk_get_rate(data->pwm_clk);
pwm_clk_freq = clk_get_rate(data->pwm_clk);
/* Adjust NPCM7xx PWMs output frequency to ~25Khz */
output_freq = data->pwm_clk_freq / PWN_CNT_DEFAULT;
output_freq = pwm_clk_freq / PWN_CNT_DEFAULT;
prescale_val = DIV_ROUND_CLOSEST(output_freq, PWM_OUTPUT_FREQ_25KHZ);
/* If prescale_val = 0, then the prescale output clock is stopped */

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* hwmon driver for NZXT Kraken X53/X63/X73 and Z53/Z63/Z73 all in one coolers.
* X53 and Z53 in code refer to all models in their respective series (shortened
* for brevity).
* hwmon driver for NZXT Kraken X53/X63/X73, Z53/Z63/Z73 and 2023/2023 Elite all in one coolers.
* X53 and Z53 in code refer to all models in their respective series (shortened for brevity).
* 2023 models use the Z53 code paths.
*
* Copyright 2021 Jonas Malaco <jonas@protocubo.io>
* Copyright 2022 Aleksa Savic <savicaleksa83@gmail.com>
@ -23,15 +23,12 @@
#define USB_PRODUCT_ID_X53 0x2007
#define USB_PRODUCT_ID_X53_SECOND 0x2014
#define USB_PRODUCT_ID_Z53 0x3008
#define USB_PRODUCT_ID_KRAKEN2023 0x300E
#define USB_PRODUCT_ID_KRAKEN2023_ELITE 0x300C
enum kinds { X53, Z53 } __packed;
enum kinds { X53, Z53, KRAKEN2023 } __packed;
enum pwm_enable { off, manual, curve } __packed;
static const char *const kraken3_device_names[] = {
[X53] = "x53",
[Z53] = "z53",
};
#define DRIVER_NAME "nzxt_kraken3"
#define STATUS_REPORT_ID 0x75
#define FIRMWARE_REPORT_ID 0x11
@ -141,6 +138,7 @@ static umode_t kraken3_is_visible(const void *data, enum hwmon_sensor_types type
return 0444;
break;
case Z53:
case KRAKEN2023:
/* Pump and fan */
if (channel < 2)
return 0444;
@ -160,6 +158,7 @@ static umode_t kraken3_is_visible(const void *data, enum hwmon_sensor_types type
return 0644;
break;
case Z53:
case KRAKEN2023:
/* Pump and fan */
if (channel < 2)
return 0644;
@ -247,6 +246,7 @@ static int kraken3_read_x53(struct kraken3_data *priv)
return 0;
}
/* Covers Z53 and KRAKEN2023 device kinds */
static int kraken3_read_z53(struct kraken3_data *priv)
{
int ret = mutex_lock_interruptible(&priv->z53_status_request_lock);
@ -360,6 +360,13 @@ static int kraken3_write_curve(struct kraken3_data *priv, u8 *curve_array, int c
/* Set the correct ID for writing pump/fan duty (0x01 or 0x02, respectively) */
fixed_duty_cmd[SET_DUTY_ID_OFFSET] = channel + 1;
if (priv->kind == KRAKEN2023) {
/* These require 1s in the next one or two slots after SET_DUTY_ID_OFFSET */
fixed_duty_cmd[SET_DUTY_ID_OFFSET + 1] = 1;
if (channel == 1) /* Fan */
fixed_duty_cmd[SET_DUTY_ID_OFFSET + 2] = 1;
}
/* Copy curve to command */
memcpy(fixed_duty_cmd + SET_CURVE_DUTY_CMD_HEADER_LENGTH, curve_array, CUSTOM_CURVE_POINTS);
@ -507,8 +514,8 @@ static umode_t kraken3_curve_props_are_visible(struct kobject *kobj, struct attr
struct device *dev = kobj_to_dev(kobj);
struct kraken3_data *priv = dev_get_drvdata(dev);
/* Only Z53 has the fan curve */
if (index >= CUSTOM_CURVE_POINTS && priv->kind != Z53)
/* X53 does not have a fan */
if (index >= CUSTOM_CURVE_POINTS && priv->kind == X53)
return 0;
return attr->mode;
@ -774,8 +781,8 @@ static int kraken3_raw_event(struct hid_device *hdev, struct hid_report *report,
if (priv->kind == X53 && !completion_done(&priv->status_report_processed)) {
/* Mark first X-series device report as received */
complete_all(&priv->status_report_processed);
} else if (priv->kind == Z53) {
/* Additional readings for Z53 */
} else if (priv->kind == Z53 || priv->kind == KRAKEN2023) {
/* Additional readings for Z53 and KRAKEN2023 */
priv->fan_input[1] = get_unaligned_le16(data + Z53_FAN_SPEED_OFFSET);
priv->channel_info[1].reported_duty =
kraken3_percent_to_pwm(data[Z53_FAN_DUTY_OFFSET]);
@ -849,14 +856,14 @@ static int firmware_version_show(struct seq_file *seqf, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(firmware_version);
static void kraken3_debugfs_init(struct kraken3_data *priv)
static void kraken3_debugfs_init(struct kraken3_data *priv, const char *device_name)
{
char name[64];
if (!priv->firmware_version[0])
return; /* Nothing to display in debugfs */
scnprintf(name, sizeof(name), "%s_%s-%s", DRIVER_NAME, kraken3_device_names[priv->kind],
scnprintf(name, sizeof(name), "%s_%s-%s", DRIVER_NAME, device_name,
dev_name(&priv->hdev->dev));
priv->debugfs = debugfs_create_dir(name, NULL);
@ -866,6 +873,7 @@ static void kraken3_debugfs_init(struct kraken3_data *priv)
static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct kraken3_data *priv;
const char *device_name;
int ret;
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
@ -905,12 +913,23 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
case USB_PRODUCT_ID_X53:
case USB_PRODUCT_ID_X53_SECOND:
priv->kind = X53;
device_name = "x53";
break;
case USB_PRODUCT_ID_Z53:
priv->kind = Z53;
device_name = "z53";
break;
case USB_PRODUCT_ID_KRAKEN2023:
priv->kind = KRAKEN2023;
device_name = "kraken2023";
break;
case USB_PRODUCT_ID_KRAKEN2023_ELITE:
priv->kind = KRAKEN2023;
device_name = "kraken2023elite";
break;
default:
break;
ret = -ENODEV;
goto fail_and_close;
}
priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL);
@ -936,8 +955,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
if (ret < 0)
hid_warn(hdev, "fw version request failed with %d\n", ret);
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev,
kraken3_device_names[priv->kind], priv,
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, device_name, priv,
&kraken3_chip_info, kraken3_groups);
if (IS_ERR(priv->hwmon_dev)) {
ret = PTR_ERR(priv->hwmon_dev);
@ -945,7 +963,7 @@ static int kraken3_probe(struct hid_device *hdev, const struct hid_device_id *id
goto fail_and_close;
}
kraken3_debugfs_init(priv);
kraken3_debugfs_init(priv, device_name);
return 0;
@ -972,6 +990,8 @@ static const struct hid_device_id kraken3_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_X53) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_X53_SECOND) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_Z53) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_KRAKEN2023) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NZXT, USB_PRODUCT_ID_KRAKEN2023_ELITE) },
{ }
};

View File

@ -285,7 +285,7 @@ static int pcf8591_read_channel(struct device *dev, int channel)
}
static const struct i2c_device_id pcf8591_id[] = {
{ "pcf8591", 0 },
{ "pcf8591" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8591_id);

View File

@ -51,12 +51,22 @@ config SENSORS_ADM1275
tristate "Analog Devices ADM1275 and compatibles"
help
If you say yes here you get hardware monitoring support for Analog
Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293,
and ADM1294 Hot-Swap Controller and Digital Power Monitors.
Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1281,
ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors.
This driver can also be built as a module. If so, the module will
be called adm1275.
config SENSORS_ADP1050
tristate "Analog Devices ADP1050 digital controller for Power Supplies"
help
If you say yes here you get hardware monitoring support for Analog
Devices ADP1050 digital controller for isolated power supply with
PMBus interface.
This driver can also be built as a module. If so, the module will
be called adp1050.
config SENSORS_BEL_PFE
tristate "Bel PFE Compatible Power Supplies"
help
@ -511,6 +521,15 @@ config SENSORS_UCD9200
This driver can also be built as a module. If so, the module will
be called ucd9200.
config SENSORS_XDP710
tristate "Infineon XDP710 family"
help
If you say yes here you get hardware monitoring support for Infineon
XDP710.
This driver can also be built as a module. If so, the module will
be called xdp710.
config SENSORS_XDPE152
tristate "Infineon XDPE152 family"
help

View File

@ -8,6 +8,7 @@ obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ACBEL_FSG032) += acbel-fsg032.o
obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_ADP1050) += adp1050.o
obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
obj-$(CONFIG_SENSORS_BPA_RS600) += bpa-rs600.o
obj-$(CONFIG_SENSORS_DELTA_AHE50DC_FAN) += delta-ahe50dc-fan.o
@ -51,6 +52,7 @@ obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
obj-$(CONFIG_SENSORS_XDP710) += xdp710.o
obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o
obj-$(CONFIG_SENSORS_XDPE152) += xdpe152c4.o
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o

View File

@ -490,7 +490,7 @@ static const struct of_device_id adm1266_of_match[] = {
MODULE_DEVICE_TABLE(of, adm1266_of_match);
static const struct i2c_device_id adm1266_id[] = {
{ "adm1266", 0 },
{ "adm1266" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adm1266_id);

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