diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2024-04-29 09:14:30 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2024-04-29 09:14:30 +1000 |
commit | 58d39140fb13c8a2fda3065d4b857b644be03a9d (patch) | |
tree | 7ef57e23f09359ff05543ec14271c4baf6113db7 | |
parent | a0f4c53dbc078ba03380337ee7a664e1792dadb5 (diff) | |
parent | 2ba3ec0d5d4a6b380a10a295d4c83e4a9bcfc51a (diff) | |
download | linux-next-58d39140fb13c8a2fda3065d4b857b644be03a9d.tar.gz |
Merge branch 'hwmon-next' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
Notice: this object is not reachable from any branch.
Notice: this object is not reachable from any branch.
46 files changed, 1734 insertions, 352 deletions
diff --git a/Documentation/devicetree/bindings/hwmon/adc128d818.txt b/Documentation/devicetree/bindings/hwmon/adc128d818.txt deleted file mode 100644 index d0ae46d7bac370..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/adc128d818.txt +++ /dev/null @@ -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>; - }; diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml index b680612949642f..5b076d677395f9 100644 --- a/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml +++ b/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml @@ -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: diff --git a/Documentation/devicetree/bindings/hwmon/as370.txt b/Documentation/devicetree/bindings/hwmon/as370.txt deleted file mode 100644 index d102fe7651249e..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/as370.txt +++ /dev/null @@ -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>; - }; diff --git a/Documentation/devicetree/bindings/hwmon/ibm,opal-sensor.yaml b/Documentation/devicetree/bindings/hwmon/ibm,opal-sensor.yaml new file mode 100644 index 00000000000000..376ee7f1cdb733 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ibm,opal-sensor.yaml @@ -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>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ibm,p8-occ-hwmon.txt b/Documentation/devicetree/bindings/hwmon/ibm,p8-occ-hwmon.txt deleted file mode 100644 index 5dc5d2e2573db4..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/ibm,p8-occ-hwmon.txt +++ /dev/null @@ -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>; - }; - }; diff --git a/Documentation/devicetree/bindings/hwmon/ibmpowernv.txt b/Documentation/devicetree/bindings/hwmon/ibmpowernv.txt deleted file mode 100644 index f93242be60a145..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/ibmpowernv.txt +++ /dev/null @@ -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"; -}; diff --git a/Documentation/devicetree/bindings/hwmon/lm87.txt b/Documentation/devicetree/bindings/hwmon/lm87.txt deleted file mode 100644 index 758ff398b67b5c..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/lm87.txt +++ /dev/null @@ -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 = <®_5v0>; -}; diff --git a/Documentation/devicetree/bindings/hwmon/max6650.txt b/Documentation/devicetree/bindings/hwmon/max6650.txt deleted file mode 100644 index f6bd87d8e28456..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/max6650.txt +++ /dev/null @@ -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>; - }; diff --git a/Documentation/devicetree/bindings/hwmon/maxim,max6650.yaml b/Documentation/devicetree/bindings/hwmon/maxim,max6650.yaml new file mode 100644 index 00000000000000..2c26104a5e1690 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/maxim,max6650.yaml @@ -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>; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml new file mode 100644 index 00000000000000..10c2204bc3df3e --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/adi,adp1050.yaml @@ -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>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt deleted file mode 100644 index 48886f0ce415f3..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt +++ /dev/null @@ -1 +0,0 @@ -This file has moved to pwm-fan.yaml. diff --git a/Documentation/devicetree/bindings/hwmon/st,stts751.yaml b/Documentation/devicetree/bindings/hwmon/st,stts751.yaml new file mode 100644 index 00000000000000..9c825adbed58ff --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/st,stts751.yaml @@ -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; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/stts751.txt b/Documentation/devicetree/bindings/hwmon/stts751.txt deleted file mode 100644 index 3ee1dc30e72f86..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/stts751.txt +++ /dev/null @@ -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>; -} diff --git a/Documentation/devicetree/bindings/hwmon/syna,as370.yaml b/Documentation/devicetree/bindings/hwmon/syna,as370.yaml new file mode 100644 index 00000000000000..1f7005f552475c --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/syna,as370.yaml @@ -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>; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,adc128d818.yaml b/Documentation/devicetree/bindings/hwmon/ti,adc128d818.yaml new file mode 100644 index 00000000000000..a32035409cee7e --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ti,adc128d818.yaml @@ -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>; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/ti,lm87.yaml b/Documentation/devicetree/bindings/hwmon/ti,lm87.yaml new file mode 100644 index 00000000000000..f553235a73216a --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/ti,lm87.yaml @@ -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 = <®_5v0>; + }; + }; diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index e07be7bf8395f7..025d50454f8816 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -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 diff --git a/Documentation/hwmon/adm1275.rst b/Documentation/hwmon/adm1275.rst index 804590eeabdc86..467daf8ce3c5b0 100644 --- a/Documentation/hwmon/adm1275.rst +++ b/Documentation/hwmon/adm1275.rst @@ -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. ======================= ======================================================= diff --git a/Documentation/hwmon/adp1050.rst b/Documentation/hwmon/adp1050.rst new file mode 100644 index 00000000000000..8fa937064886ab --- /dev/null +++ b/Documentation/hwmon/adp1050.rst @@ -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 +================= ======================================== diff --git a/Documentation/hwmon/aquacomputer_d5next.rst b/Documentation/hwmon/aquacomputer_d5next.rst index cb073c79479c34..49163f387b9097 100644 --- a/Documentation/hwmon/aquacomputer_d5next.rst +++ b/Documentation/hwmon/aquacomputer_d5next.rst @@ -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) diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 1ca7a4fe1f8f57..03d313af469a18 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -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 diff --git a/Documentation/hwmon/lm70.rst b/Documentation/hwmon/lm70.rst index 11303a7e16a806..02ed60dddffb67 100644 --- a/Documentation/hwmon/lm70.rst +++ b/Documentation/hwmon/lm70.rst @@ -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 diff --git a/Documentation/hwmon/nzxt-kraken3.rst b/Documentation/hwmon/nzxt-kraken3.rst index 90fd9dec15ff22..57fe99d233011a 100644 --- a/Documentation/hwmon/nzxt-kraken3.rst +++ b/Documentation/hwmon/nzxt-kraken3.rst @@ -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 diff --git a/Documentation/hwmon/xdp710.rst b/Documentation/hwmon/xdp710.rst new file mode 100644 index 00000000000000..083891f27818c2 --- /dev/null +++ b/Documentation/hwmon/xdp710.rst @@ -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** diff --git a/MAINTAINERS b/MAINTAINERS index f66a480806faaa..2df4bd264e021f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c index 0555f68c2dfd68..5fba4dab5d0886 100644 --- a/drivers/acpi/acpi_ipmi.c +++ b/drivers/acpi/acpi_ipmi.c @@ -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, diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 83945397b6eb1b..bafc0058c728f5 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -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 @@ -1561,6 +1574,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 +1589,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 +1621,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 +1643,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 +1795,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 +1900,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 +1920,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 +1977,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 +2012,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 +2027,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 +2041,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 +2294,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 +2304,7 @@ config SENSORS_VIA686A config SENSORS_VT1211 tristate "VIA VT1211" + depends on HAS_IOPORT depends on !PPC select HWMON_VID help @@ -2293,7 +2316,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 +2424,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 +2437,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 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 5c31808f6378d9..e3f25475d1f043 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -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 diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 703666b95bf49b..6c8a9c863528ed 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -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; diff --git a/drivers/hwmon/aquacomputer_d5next.c b/drivers/hwmon/aquacomputer_d5next.c index 2efe97f8d003c8..8e55cd2f46f53e 100644 --- a/drivers/hwmon/aquacomputer_d5next.c +++ b/drivers/hwmon/aquacomputer_d5next.c @@ -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; diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c index 597b3b019d49a9..262d46fed3aa5b 100644 --- a/drivers/hwmon/aspeed-g6-pwm-tach.c +++ b/drivers/hwmon/aspeed-g6-pwm-tach.c @@ -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, diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 616bd1a5b86419..1b9203b20d7099 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -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; } diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index efcf78673e7477..48a81c64f00d25 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -1215,6 +1215,13 @@ static const struct dmi_system_id i8k_dmi_table[] __initconst = { }, }, { + .ident = "Dell G5 5505", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G5 5505"), + }, + }, + { .ident = "Dell Inspiron", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), @@ -1507,6 +1514,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 = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index fbe86cec605538..e233aafa8856c9 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -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) @@ -3641,27 +3684,6 @@ static int it87_dmi_cb(const struct dmi_system_id *dmi_entry) } /* - * 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 * has reported instant system power-off when changing @@ -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), { } diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 75dc25df0f8bbe..a00168fe569d3b 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -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, diff --git a/drivers/hwmon/lenovo-ec-sensors.c b/drivers/hwmon/lenovo-ec-sensors.c new file mode 100644 index 00000000000000..50adeb82468b04 --- /dev/null +++ b/drivers/hwmon/lenovo-ec-sensors.c @@ -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 accesssible via EC in LENOVO motherboards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index c20a749fc7f21a..481e4e1f8f4f68 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -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 diff --git a/drivers/hwmon/nzxt-kraken3.c b/drivers/hwmon/nzxt-kraken3.c index 5806a3f32bcb43..0b3f04c740b0d5 100644 --- a/drivers/hwmon/nzxt-kraken3.c +++ b/drivers/hwmon/nzxt-kraken3.c @@ -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,9 +913,19 @@ 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; @@ -936,8 +954,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 +962,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 +989,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) }, { } }; diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 557ae0c414b09e..08e82c45735667 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -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 diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index f14ecf03ad7790..2279b3327bbfc6 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -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 diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index e2c61d6fa521b1..59ffc08289bdf7 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -18,7 +18,7 @@ #include <linux/log2.h> #include "pmbus.h" -enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 }; +enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1281, adm1293, adm1294 }; #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) @@ -482,6 +482,7 @@ static const struct i2c_device_id adm1275_id[] = { { "adm1275", adm1275 }, { "adm1276", adm1276 }, { "adm1278", adm1278 }, + { "adm1281", adm1281 }, { "adm1293", adm1293 }, { "adm1294", adm1294 }, { } @@ -555,7 +556,8 @@ static int adm1275_probe(struct i2c_client *client) client->name, mid->name); if (mid->driver_data == adm1272 || mid->driver_data == adm1278 || - mid->driver_data == adm1293 || mid->driver_data == adm1294) + mid->driver_data == adm1281 || mid->driver_data == adm1293 || + mid->driver_data == adm1294) config_read_fn = i2c_smbus_read_word_data; else config_read_fn = i2c_smbus_read_byte_data; @@ -703,6 +705,7 @@ static int adm1275_probe(struct i2c_client *client) PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; break; case adm1278: + case adm1281: data->have_vout = true; data->have_pin_max = true; data->have_temp_max = true; diff --git a/drivers/hwmon/pmbus/adp1050.c b/drivers/hwmon/pmbus/adp1050.c new file mode 100644 index 00000000000000..ea08554662d57e --- /dev/null +++ b/drivers/hwmon/pmbus/adp1050.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hardware monitoring driver for Analog Devices ADP1050 + * + * Copyright (C) 2024 Analog Devices, Inc. + */ +#include <linux/bits.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> + +#include "pmbus.h" + +static struct pmbus_driver_info adp1050_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = linear, + .format[PSC_VOLTAGE_OUT] = linear, + .format[PSC_CURRENT_IN] = linear, + .format[PSC_TEMPERATURE] = linear, + .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_IIN | PMBUS_HAVE_TEMP + | PMBUS_HAVE_STATUS_TEMP, +}; + +static int adp1050_probe(struct i2c_client *client) +{ + return pmbus_do_probe(client, &adp1050_info); +} + +static const struct i2c_device_id adp1050_id[] = { + {"adp1050", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, adp1050_id); + +static const struct of_device_id adp1050_of_match[] = { + { .compatible = "adi,adp1050"}, + {} +}; +MODULE_DEVICE_TABLE(of, adp1050_of_match); + +static struct i2c_driver adp1050_driver = { + .driver = { + .name = "adp1050", + .of_match_table = adp1050_of_match, + }, + .probe = adp1050_probe, + .id_table = adp1050_id, +}; +module_i2c_driver(adp1050_driver); + +MODULE_AUTHOR("Radu Sabau <radu.sabau@analog.com>"); +MODULE_DESCRIPTION("Analog Devices ADP1050 HWMON PMBus Driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c index e5fa10b3b8bc71..280bb12f762c3d 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -5,12 +5,14 @@ * Copyright (C) 2020 Nvidia Technologies Ltd. */ +#include <linux/bitops.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of_device.h> + #include "pmbus.h" /* Vendor specific registers. */ @@ -97,6 +99,11 @@ static const int mp2975_max_phases[][MP2975_PAGE_NUM] = { [mp2971] = { MP2971_MAX_PHASE_RAIL1, MP2971_MAX_PHASE_RAIL2 }, }; +struct mp2975_driver_info { + const struct pmbus_driver_info *info; + enum chips chip_id; +}; + struct mp2975_data { struct pmbus_driver_info info; enum chips chip_id; @@ -110,15 +117,6 @@ struct mp2975_data { int curr_sense_gain[MP2975_PAGE_NUM]; }; -static const struct i2c_device_id mp2975_id[] = { - {"mp2971", mp2971}, - {"mp2973", mp2973}, - {"mp2975", mp2975}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, mp2975_id); - static const struct regulator_desc __maybe_unused mp2975_reg_desc[] = { PMBUS_REGULATOR("vout", 0), PMBUS_REGULATOR("vout", 1), @@ -392,6 +390,80 @@ static int mp2973_read_word_data(struct i2c_client *client, int page, return ret; } +static int mp2973_write_word_data(struct i2c_client *client, int page, + int reg, u16 word) +{ + u8 target, mask; + long ret; + + if (reg != PMBUS_SMBALERT_MASK) + return -ENODATA; + + /* + * Vendor-specific SMBALERT_MASK register with 16 maskable bits. + */ + ret = pmbus_read_word_data(client, 0, 0, PMBUS_SMBALERT_MASK); + if (ret < 0) + return ret; + + target = word & 0xff; + mask = word >> 8; + +/* + * Set/Clear 'bit' in 'ret' based on condition followed by define for each bit in SMBALERT_MASK. + * Also bit 2 & 15 are reserved. + */ + +#define MP2973_TEMP_OT 0 +#define MP2973_VIN_UVLO 1 +#define MP2973_VIN_OVP 3 +#define MP2973_MTP_FAULT 4 +#define MP2973_OTHER_COMM 5 +#define MP2973_MTP_BLK_TRIG 6 +#define MP2973_PACKET_ERROR 7 +#define MP2973_INVALID_DATA 8 +#define MP2973_INVALID_COMMAND 9 +#define MP2973_IOUT_OC_LV 10 +#define MP2973_IOUT_OC 11 +#define MP2973_VOUT_MAX_MIN_WARNING 12 +#define MP2973_VOLTAGE_UV 13 +#define MP2973_VOLTAGE_OV 14 + + switch (target) { + case PMBUS_STATUS_CML: + __assign_bit(MP2973_INVALID_DATA, &ret, !(mask & PB_CML_FAULT_INVALID_DATA)); + __assign_bit(MP2973_INVALID_COMMAND, &ret, !(mask & PB_CML_FAULT_INVALID_COMMAND)); + __assign_bit(MP2973_OTHER_COMM, &ret, !(mask & PB_CML_FAULT_OTHER_COMM)); + __assign_bit(MP2973_PACKET_ERROR, &ret, !(mask & PB_CML_FAULT_PACKET_ERROR)); + break; + case PMBUS_STATUS_VOUT: + __assign_bit(MP2973_VOLTAGE_UV, &ret, !(mask & PB_VOLTAGE_UV_FAULT)); + __assign_bit(MP2973_VOLTAGE_OV, &ret, !(mask & PB_VOLTAGE_OV_FAULT)); + break; + case PMBUS_STATUS_IOUT: + __assign_bit(MP2973_IOUT_OC, &ret, !(mask & PB_IOUT_OC_FAULT)); + __assign_bit(MP2973_IOUT_OC_LV, &ret, !(mask & PB_IOUT_OC_LV_FAULT)); + break; + case PMBUS_STATUS_TEMPERATURE: + __assign_bit(MP2973_TEMP_OT, &ret, !(mask & PB_TEMP_OT_FAULT)); + break; + /* + * Map remaining bits to MFR specific to let the PMBUS core mask + * those bits by default. + */ + case PMBUS_STATUS_MFR_SPECIFIC: + __assign_bit(MP2973_VIN_UVLO, &ret, !(mask & BIT(1))); + __assign_bit(MP2973_VIN_OVP, &ret, !(mask & BIT(3))); + __assign_bit(MP2973_MTP_FAULT, &ret, !(mask & BIT(4))); + __assign_bit(MP2973_MTP_BLK_TRIG, &ret, !(mask & BIT(6))); + break; + default: + return 0; + } + + return pmbus_write_word_data(client, 0, PMBUS_SMBALERT_MASK, ret); +} + static int mp2975_read_word_data(struct i2c_client *client, int page, int phase, int reg) { @@ -867,7 +939,7 @@ mp2975_vout_per_rail_config_get(struct i2c_client *client, return 0; } -static struct pmbus_driver_info mp2975_info = { +static const struct pmbus_driver_info mp2975_info = { .pages = 1, .format[PSC_VOLTAGE_IN] = linear, .format[PSC_VOLTAGE_OUT] = direct, @@ -892,7 +964,7 @@ static struct pmbus_driver_info mp2975_info = { #endif }; -static struct pmbus_driver_info mp2973_info = { +static const struct pmbus_driver_info mp2973_info = { .pages = 1, .format[PSC_VOLTAGE_IN] = linear, .format[PSC_VOLTAGE_OUT] = direct, @@ -907,35 +979,41 @@ static struct pmbus_driver_info mp2973_info = { PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT, .read_word_data = mp2973_read_word_data, + .write_word_data = mp2973_write_word_data, #if IS_ENABLED(CONFIG_SENSORS_MP2975_REGULATOR) .num_regulators = 1, .reg_desc = mp2975_reg_desc, #endif }; +static const struct mp2975_driver_info mp2975_ddinfo[] = { + [mp2975] = { .info = &mp2975_info, .chip_id = mp2975 }, + [mp2973] = { .info = &mp2973_info, .chip_id = mp2973 }, + [mp2971] = { .info = &mp2973_info, .chip_id = mp2971 }, +}; + static int mp2975_probe(struct i2c_client *client) { + const struct mp2975_driver_info *ddinfo; struct pmbus_driver_info *info; struct mp2975_data *data; int ret; + ddinfo = i2c_get_match_data(client); + if (!ddinfo) + return -ENODEV; + data = devm_kzalloc(&client->dev, sizeof(struct mp2975_data), GFP_KERNEL); if (!data) return -ENOMEM; - if (client->dev.of_node) - data->chip_id = (enum chips)(unsigned long)of_device_get_match_data(&client->dev); - else - data->chip_id = i2c_match_id(mp2975_id, client)->driver_data; + data->chip_id = ddinfo->chip_id; memcpy(data->max_phases, mp2975_max_phases[data->chip_id], sizeof(data->max_phases)); - if (data->chip_id == mp2975) - memcpy(&data->info, &mp2975_info, sizeof(*info)); - else - memcpy(&data->info, &mp2973_info, sizeof(*info)); + memcpy(&data->info, ddinfo->info, sizeof(data->info)); info = &data->info; @@ -993,18 +1071,26 @@ static int mp2975_probe(struct i2c_client *client) return pmbus_do_probe(client, info); } -static const struct of_device_id __maybe_unused mp2975_of_match[] = { - {.compatible = "mps,mp2971", .data = (void *)mp2971}, - {.compatible = "mps,mp2973", .data = (void *)mp2973}, - {.compatible = "mps,mp2975", .data = (void *)mp2975}, +static const struct of_device_id mp2975_of_match[] = { + {.compatible = "mps,mp2971", .data = &mp2975_ddinfo[mp2971]}, + {.compatible = "mps,mp2973", .data = &mp2975_ddinfo[mp2973]}, + {.compatible = "mps,mp2975", .data = &mp2975_ddinfo[mp2975]}, {} }; MODULE_DEVICE_TABLE(of, mp2975_of_match); +static const struct i2c_device_id mp2975_id[] = { + {"mp2971", (kernel_ulong_t)&mp2975_ddinfo[mp2971]}, + {"mp2973", (kernel_ulong_t)&mp2975_ddinfo[mp2973]}, + {"mp2975", (kernel_ulong_t)&mp2975_ddinfo[mp2975]}, + {} +}; +MODULE_DEVICE_TABLE(i2c, mp2975_id); + static struct i2c_driver mp2975_driver = { .driver = { .name = "mp2975", - .of_match_table = of_match_ptr(mp2975_of_match), + .of_match_table = mp2975_of_match, }, .probe = mp2975_probe, .id_table = mp2975_id, diff --git a/drivers/hwmon/pmbus/xdp710.c b/drivers/hwmon/pmbus/xdp710.c new file mode 100644 index 00000000000000..11971a0e0d26b9 --- /dev/null +++ b/drivers/hwmon/pmbus/xdp710.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Infineon XDP710 Hot-Swap Controller + */ + +#include <linux/bitops.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include "pmbus.h" + +#define XDP710_REG_CFG 0xD3 +#define XDP710_V_SNS_CFG 0xD4 +#define XDP710_CS_RNG 0xD5 + +/* + * The table to map configuration register values + * to sense resistor values + */ +const int micro_ohm_rsense[] = { + 200, 250, 300, 330, 400, 470, 500, 600, + 670, 700, 750, 800, 900, 1000, 1100, 1200, + 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, + 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, + 2800, 3000, 3100, 3200, 3300, 3400, 3500, 3600, + 3700, 3800, 3900, 4000, 4100, 4200, 4300, 4400, + 4500, 4600, 4700, 4800, 4900, 5000, 5500, 6000, + 6500, 7000, 7500, 8000, 8500, 9000, 9500, 10000 +}; + +static struct pmbus_driver_info xdp710_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = direct, + .format[PSC_VOLTAGE_OUT] = direct, + .format[PSC_CURRENT_OUT] = direct, + .format[PSC_POWER] = direct, + .format[PSC_TEMPERATURE] = direct, + .m[PSC_VOLTAGE_IN] = 4653, + .b[PSC_VOLTAGE_IN] = 0, + .R[PSC_VOLTAGE_IN] = -2, + .m[PSC_VOLTAGE_OUT] = 4653, + .b[PSC_VOLTAGE_OUT] = 0, + .R[PSC_VOLTAGE_OUT] = -2, + .m[PSC_CURRENT_OUT] = 23165, + .b[PSC_CURRENT_OUT] = 0, + .R[PSC_CURRENT_OUT] = -2, + .m[PSC_POWER] = 4211, + .b[PSC_POWER] = 0, + .R[PSC_POWER] = -2, + .m[PSC_TEMPERATURE] = 52, + .b[PSC_TEMPERATURE] = 14321, + .R[PSC_TEMPERATURE] = -1, + .func[0] = + PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_PIN | + PMBUS_HAVE_TEMP | PMBUS_HAVE_IOUT | + PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP, +}; + +static int xdp710_probe(struct i2c_client *client) +{ + struct pmbus_driver_info *info; + u8 cs_rng; + u8 vtlm_rng; + int rsense; + int ret; + int m = 0; + + info = devm_kmemdup(&client->dev, &xdp710_info, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = i2c_smbus_read_word_data(client, XDP710_CS_RNG); + if (ret < 0) { + dev_err(&client->dev, "Can't get CS_RNG"); + return ret; + } + cs_rng = (ret >> 6) & GENMASK(1, 0); + + ret = i2c_smbus_read_word_data(client, XDP710_V_SNS_CFG); + if (ret < 0) { + dev_err(&client->dev, "Can't get V_SNS_CFG"); + return ret; + } + vtlm_rng = ret & GENMASK(1, 0); + + ret = i2c_smbus_read_word_data(client, XDP710_REG_CFG); + if (ret < 0) { + dev_err(&client->dev, "Can't get REG_CFG"); + return ret; + } + ret &= GENMASK(5, 0); + rsense = micro_ohm_rsense[ret]; + + info->m[PSC_VOLTAGE_IN] <<= vtlm_rng; + info->m[PSC_VOLTAGE_OUT] <<= vtlm_rng; + + m = info->m[PSC_CURRENT_OUT]; + info->m[PSC_CURRENT_OUT] = DIV_ROUND_CLOSEST(m * rsense >> cs_rng, 1000); + + m = info->m[PSC_POWER]; + info->m[PSC_POWER] = DIV_ROUND_CLOSEST(m * rsense >> cs_rng, 1000); + + return pmbus_do_probe(client, info); +} + +static const struct of_device_id xdp710_of_match[] = { + { .compatible = "infineon,xdp710" }, + {} +}; + +static const struct i2c_device_id xdp710_id[] = { + {"xdp710", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, xdp710_id); + +static struct i2c_driver xdp710_driver = { + .driver = { + .name = "xdp710", + .of_match_table = xdp710_of_match, + }, + .probe = xdp710_probe, + .id_table = xdp710_id, +}; +module_i2c_driver(xdp710_driver); + +MODULE_AUTHOR("Peter Yin <peter.yin@quantatw.com>"); +MODULE_DESCRIPTION("PMBus driver for XDP710 HSC"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(PMBUS); diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index b67bc9e833c01e..a1712649b07e3f 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -9,10 +9,11 @@ #include <linux/hwmon.h> #include <linux/interrupt.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> -#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/pwm.h> #include <linux/regulator/consumer.h> #include <linux/sysfs.h> @@ -25,7 +26,6 @@ struct pwm_fan_tach { int irq; atomic_t pulses; unsigned int rpm; - u8 pulses_per_revolution; }; enum pwm_fan_enable_mode { @@ -48,6 +48,7 @@ struct pwm_fan_ctx { int tach_count; struct pwm_fan_tach *tachs; + u32 *pulses_per_revolution; ktime_t sample_start; struct timer_list rpm_timer; @@ -85,7 +86,7 @@ static void sample_timer(struct timer_list *t) pulses = atomic_read(&tach->pulses); atomic_sub(pulses, &tach->pulses); tach->rpm = (unsigned int)(pulses * 1000 * 60) / - (tach->pulses_per_revolution * delta); + (ctx->pulses_per_revolution[i] * delta); } ctx->sample_start = ktime_get(); @@ -421,16 +422,14 @@ static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = { .set_cur_state = pwm_fan_set_cur_state, }; -static int pwm_fan_of_get_cooling_data(struct device *dev, - struct pwm_fan_ctx *ctx) +static int pwm_fan_get_cooling_data(struct device *dev, struct pwm_fan_ctx *ctx) { - struct device_node *np = dev->of_node; int num, i, ret; - if (!of_property_present(np, "cooling-levels")) + if (!device_property_present(dev, "cooling-levels")) return 0; - ret = of_property_count_u32_elems(np, "cooling-levels"); + ret = device_property_count_u32(dev, "cooling-levels"); if (ret <= 0) { dev_err(dev, "Wrong data!\n"); return ret ? : -EINVAL; @@ -442,8 +441,8 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, if (!ctx->pwm_fan_cooling_levels) return -ENOMEM; - ret = of_property_read_u32_array(np, "cooling-levels", - ctx->pwm_fan_cooling_levels, num); + ret = device_property_read_u32_array(dev, "cooling-levels", + ctx->pwm_fan_cooling_levels, num); if (ret) { dev_err(dev, "Property 'cooling-levels' cannot be read!\n"); return ret; @@ -562,6 +561,20 @@ static int pwm_fan_probe(struct platform_device *pdev) if (!fan_channel_config) return -ENOMEM; ctx->fan_channel.config = fan_channel_config; + + ctx->pulses_per_revolution = devm_kmalloc_array(dev, + ctx->tach_count, + sizeof(*ctx->pulses_per_revolution), + GFP_KERNEL); + if (!ctx->pulses_per_revolution) + return -ENOMEM; + + /* Setup default pulses per revolution */ + for (i = 0; i < ctx->tach_count; i++) + ctx->pulses_per_revolution[i] = 2; + + device_property_read_u32_array(dev, "pulses-per-revolution", + ctx->pulses_per_revolution, ctx->tach_count); } channels = devm_kcalloc(dev, channel_count + 1, @@ -573,7 +586,6 @@ static int pwm_fan_probe(struct platform_device *pdev) for (i = 0; i < ctx->tach_count; i++) { struct pwm_fan_tach *tach = &ctx->tachs[i]; - u32 ppr = 2; tach->irq = platform_get_irq(pdev, i); if (tach->irq == -EPROBE_DEFER) @@ -589,12 +601,7 @@ static int pwm_fan_probe(struct platform_device *pdev) } } - of_property_read_u32_index(dev->of_node, - "pulses-per-revolution", - i, - &ppr); - tach->pulses_per_revolution = ppr; - if (!tach->pulses_per_revolution) { + if (!ctx->pulses_per_revolution[i]) { dev_err(dev, "pulses-per-revolution can't be zero.\n"); return -EINVAL; } @@ -602,7 +609,7 @@ static int pwm_fan_probe(struct platform_device *pdev) fan_channel_config[i] = HWMON_F_INPUT; dev_dbg(dev, "tach%d: irq=%d, pulses_per_revolution=%d\n", - i, tach->irq, tach->pulses_per_revolution); + i, tach->irq, ctx->pulses_per_revolution[i]); } if (ctx->tach_count > 0) { @@ -622,7 +629,7 @@ static int pwm_fan_probe(struct platform_device *pdev) return PTR_ERR(hwmon); } - ret = pwm_fan_of_get_cooling_data(dev, ctx); + ret = pwm_fan_get_cooling_data(dev, ctx); if (ret) return ret; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e7796f373d0dac..1e0ee6cebf2eae 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -978,11 +978,16 @@ static inline void acpi_put_acpi_dev(struct acpi_device *adev) { acpi_dev_put(adev); } + +int acpi_wait_for_acpi_ipmi(void); + #else /* CONFIG_ACPI */ static inline int register_acpi_bus_type(void *bus) { return 0; } static inline int unregister_acpi_bus_type(void *bus) { return 0; } +static inline int acpi_wait_for_acpi_ipmi(void) { return 0; } + #endif /* CONFIG_ACPI */ #endif /*__ACPI_BUS_H__*/ |