Merge b109bc7229 ("Merge tag 'thermal-v5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux") into android-mainline

Steps on the way to 5.11-rc1.

Change-Id: I292f4c045f63dc2fb936d383de8b61212ba25284
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2020-12-18 15:24:25 +01:00
289 changed files with 14760 additions and 3776 deletions

View File

@@ -0,0 +1,258 @@
What: /sys/class/firmware-attributes/*/attributes/*/
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
A sysfs interface for systems management software to enable
configuration capability on supported systems. This directory
exposes interfaces for interacting with configuration options.
Unless otherwise specified in an attribute description all attributes are optional
and will accept UTF-8 input.
type:
A file that can be read to obtain the type of attribute.
This attribute is mandatory.
The following are known types:
- enumeration: a set of pre-defined valid values
- integer: a range of numerical values
- string
All attribute types support the following values:
current_value:
A file that can be read to obtain the current
value of the <attr>.
This file can also be written to in order to update the value of a
<attr>
This attribute is mandatory.
default_value:
A file that can be read to obtain the default
value of the <attr>
display_name:
A file that can be read to obtain a user friendly
description of the at <attr>
display_name_language_code:
A file that can be read to obtain
the IETF language tag corresponding to the
"display_name" of the <attr>
"enumeration"-type specific properties:
possible_values:
A file that can be read to obtain the possible
values of the <attr>. Values are separated using
semi-colon (``;``).
"integer"-type specific properties:
min_value:
A file that can be read to obtain the lower
bound value of the <attr>
max_value:
A file that can be read to obtain the upper
bound value of the <attr>
scalar_increment:
A file that can be read to obtain the scalar value used for
increments of current_value this attribute accepts.
"string"-type specific properties:
max_length:
A file that can be read to obtain the maximum
length value of the <attr>
min_length:
A file that can be read to obtain the minimum
length value of the <attr>
Dell specific class extensions
------------------------------
On Dell systems the following additional attributes are available:
dell_modifier:
A file that can be read to obtain attribute-level
dependency rule. It says an attribute X will become read-only or
suppressed, if/if-not attribute Y is configured.
modifier rules can be in following format::
[ReadOnlyIf:<attribute>=<value>]
[ReadOnlyIfNot:<attribute>=<value>]
[SuppressIf:<attribute>=<value>]
[SuppressIfNot:<attribute>=<value>]
For example::
AutoOnFri/dell_modifier has value,
[SuppressIfNot:AutoOn=SelectDays]
This means AutoOnFri will be suppressed in BIOS setup if AutoOn
attribute is not "SelectDays" and its value will not be effective
through sysfs until this rule is met.
Enumeration attributes also support the following:
dell_value_modifier:
A file that can be read to obtain value-level dependency.
This file is similar to dell_modifier but here, an
attribute's current value will be forcefully changed based
dependent attributes value.
dell_value_modifier rules can be in following format::
<value>[ForceIf:<attribute>=<value>]
<value>[ForceIfNot:<attribute>=<value>]
For example:
LegacyOrom/dell_value_modifier has value:
Disabled[ForceIf:SecureBoot=Enabled]
This means LegacyOrom's current value will be forced to
"Disabled" in BIOS setup if SecureBoot is Enabled and its
value will not be effective through sysfs until this rule is
met.
What: /sys/class/firmware-attributes/*/authentication/
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
Devices support various authentication mechanisms which can be exposed
as a separate configuration object.
For example a "BIOS Admin" password and "System" Password can be set,
reset or cleared using these attributes.
- An "Admin" password is used for preventing modification to the BIOS
settings.
- A "System" password is required to boot a machine.
Change in any of these two authentication methods will also generate an
uevent KOBJ_CHANGE.
is_enabled:
A file that can be read to obtain a 0/1 flag to see if
<attr> authentication is enabled.
This attribute is mandatory.
role:
The type of authentication used.
This attribute is mandatory.
Known types:
bios-admin:
Representing BIOS administrator password
power-on:
Representing a password required to use
the system
mechanism:
The means of authentication. This attribute is mandatory.
Only supported type currently is "password".
max_password_length:
A file that can be read to obtain the
maximum length of the Password
min_password_length:
A file that can be read to obtain the
minimum length of the Password
current_password:
A write only value used for privileged access such as
setting attributes when a system or admin password is set
or resetting to a new password
This attribute is mandatory when mechanism == "password".
new_password:
A write only value that when used in tandem with
current_password will reset a system or admin password.
Note, password management is session specific. If Admin password is set,
same password must be written into current_password file (required for
password-validation) and must be cleared once the session is over.
For example::
echo "password" > current_password
echo "disabled" > TouchScreen/current_value
echo "" > current_password
Drivers may emit a CHANGE uevent when a password is set or unset
userspace may check it again.
On Dell systems, if Admin password is set, then all BIOS attributes
require password validation.
What: /sys/class/firmware-attributes/*/attributes/pending_reboot
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
A read-only attribute reads 1 if a reboot is necessary to apply
pending BIOS attribute changes. Also, an uevent_KOBJ_CHANGE is
generated when it changes to 1.
== =========================================
0 All BIOS attributes setting are current
1 A reboot is necessary to get pending BIOS
attribute changes applied
== =========================================
Note, userspace applications need to follow below steps for efficient
BIOS management,
1. Check if admin password is set. If yes, follow session method for
password management as briefed under authentication section above.
2. Before setting any attribute, check if it has any modifiers
or value_modifiers. If yes, incorporate them and then modify
attribute.
Drivers may emit a CHANGE uevent when this value changes and userspace
may check it again.
What: /sys/class/firmware-attributes/*/attributes/reset_bios
Date: February 2021
KernelVersion: 5.11
Contact: Divya Bharathi <Divya.Bharathi@Dell.com>,
Mario Limonciello <mario.limonciello@dell.com>,
Prasanth KSR <prasanth.ksr@dell.com>
Description:
This attribute can be used to reset the BIOS Configuration.
Specifically, it tells which type of reset BIOS configuration is being
requested on the host.
Reading from it returns a list of supported options encoded as:
- 'builtinsafe' (Built in safe configuration profile)
- 'lastknowngood' (Last known good saved configuration profile)
- 'factory' (Default factory settings configuration profile)
- 'custom' (Custom saved configuration profile)
The currently selected option is printed in square brackets as
shown below::
# echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
# cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
# builtinsafe lastknowngood [factory] custom
Note that any changes to this attribute requires a reboot
for changes to take effect.

View File

@@ -0,0 +1,119 @@
What: /sys/class/intel_pmt/
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
The intel_pmt/ class directory contains information for
devices that expose hardware telemetry using Intel Platform
Monitoring Technology (PMT)
What: /sys/class/intel_pmt/telem<x>
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
The telem<x> directory contains files describing an instance of
a PMT telemetry device that exposes hardware telemetry. Each
telem<x> directory has an associated telem file. This file
may be opened and mapped or read to access the telemetry space
of the device. The register layout of the telemetry space is
determined from an XML file that matches the PCI device id and
GUID for the device.
What: /sys/class/intel_pmt/telem<x>/telem
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The telemetry data for this telemetry device. This file
may be mapped or read to obtain the data.
What: /sys/class/intel_pmt/telem<x>/guid
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The GUID for this telemetry device. The GUID identifies
the version of the XML file for the parent device that is to
be used to get the register layout.
What: /sys/class/intel_pmt/telem<x>/size
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The size of telemetry region in bytes that corresponds to
the mapping size for the telem file.
What: /sys/class/intel_pmt/telem<x>/offset
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The offset of telemetry region in bytes that corresponds to
the mapping for the telem file.
What: /sys/class/intel_pmt/crashlog<x>
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
The crashlog<x> directory contains files for configuring an
instance of a PMT crashlog device that can perform crash data
recording. Each crashlog<x> device has an associated crashlog
file. This file can be opened and mapped or read to access the
resulting crashlog buffer. The register layout for the buffer
can be determined from an XML file of specified GUID for the
parent device.
What: /sys/class/intel_pmt/crashlog<x>/crashlog
Date: October 2020
KernelVersion: 5.10
Contact: David Box <david.e.box@linux.intel.com>
Description:
(RO) The crashlog buffer for this crashlog device. This file
may be mapped or read to obtain the data.
What: /sys/class/intel_pmt/crashlog<x>/guid
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RO) The GUID for this crashlog device. The GUID identifies the
version of the XML file for the parent device that should be
used to determine the register layout.
What: /sys/class/intel_pmt/crashlog<x>/size
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RO) The length of the result buffer in bytes that corresponds
to the size for the crashlog buffer.
What: /sys/class/intel_pmt/crashlog<x>/offset
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RO) The offset of the buffer in bytes that corresponds
to the mapping for the crashlog device.
What: /sys/class/intel_pmt/crashlog<x>/enable
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RW) Boolean value controlling if the crashlog functionality
is enabled for the crashlog device.
What: /sys/class/intel_pmt/crashlog<x>/trigger
Date: October 2020
KernelVersion: 5.10
Contact: Alexander Duyck <alexander.h.duyck@linux.intel.com>
Description:
(RW) Boolean value controlling the triggering of the crashlog
device node. When read it provides data on if the crashlog has
been triggered. When written to it can be used to either clear
the current trigger by writing false, or to trigger a new
event if the trigger is not currently set.

View File

@@ -1,13 +1,13 @@
Device-tree bindings for FSI-attached POWER9 On-Chip Controller (OCC)
---------------------------------------------------------------------
Device-tree bindings for FSI-attached POWER9/POWER10 On-Chip Controller (OCC)
-----------------------------------------------------------------------------
This is the binding for the P9 On-Chip Controller accessed over FSI from a
service processor. See fsi.txt for details on bindings for FSI slave and CFAM
This is the binding for the P9 or P10 On-Chip Controller accessed over FSI from
a service processor. See fsi.txt for details on bindings for FSI slave and CFAM
nodes. The OCC is not an FSI slave device itself, rather it is accessed
through the SBE fifo.
through the SBE FIFO.
Required properties:
- compatible = "ibm,p9-occ"
- compatible = "ibm,p9-occ" or "ibm,p10-occ"
Examples:

View File

@@ -1,15 +0,0 @@
* AD7416/AD7417/AD7418 Temperature Sensor Device Tree Bindings
Required properties:
- compatible: one of
"adi,ad7416"
"adi,ad7417"
"adi,ad7418"
- reg: I2C address
Example:
hwmon@28 {
compatible = "adi,ad7418";
reg = <0x28>;
};

View File

@@ -0,0 +1,39 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/adi,ad741x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7416/AD7417/AD7418 temperature sensors
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
properties:
compatible:
enum:
- adi,ad7416
- adi,ad7417
- adi,ad7418
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
temperature-sensor@28 {
compatible = "adi,ad7418";
reg = <0x28>;
};
};

View File

@@ -0,0 +1,57 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$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
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
description: |
The ADM1293 and ADM1294 are high accuracy integrated digital power monitors
that offer digital current, voltage, and power monitoring using an on-chip,
12-bit analog-to-digital converter (ADC), communicated through a PMBus
compliant I2C interface.
Datasheets:
https://www.analog.com/en/products/adm1294.html
properties:
compatible:
enum:
- adi,adm1075
- adi,adm1272
- adi,adm1275
- adi,adm1276
- adi,adm1278
- adi,adm1293
- adi,adm1294
reg:
maxItems: 1
shunt-resistor-micro-ohms:
description:
Shunt resistor value in micro-Ohm.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
power-sensor@10 {
compatible = "adi,adm1272";
reg = <0x10>;
shunt-resistor-micro-ohms = <500>;
};
};

View File

@@ -0,0 +1,80 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/adi,ltc2992.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Linear Technology 2992 Power Monitor
maintainers:
- Alexandru Tachici <alexandru.tachici@analog.com>
description: |
Linear Technology 2992 Dual Wide Range Power Monitor
https://www.analog.com/media/en/technical-documentation/data-sheets/ltc2992.pdf
properties:
compatible:
enum:
- adi,ltc2992
reg:
maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
avcc-supply: true
patternProperties:
"^channel@([0-1])$":
type: object
description: |
Represents the two supplies to be monitored.
properties:
reg:
description: |
The channel number. LTC2992 can monitor two supplies.
items:
minimum: 0
maximum: 1
shunt-resistor-micro-ohms:
description:
The value of curent sense resistor in microohms.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c1 {
#address-cells = <1>;
#size-cells = <0>;
ltc2992@6F {
#address-cells = <1>;
#size-cells = <0>;
compatible = "adi,ltc2992";
reg = <0x6F>;
channel@0 {
reg = <0x0>;
shunt-resistor-micro-ohms = <10000>;
};
channel@1 {
reg = <0x1>;
shunt-resistor-micro-ohms = <10000>;
};
};
};
...

View File

@@ -1,25 +0,0 @@
adm1275 properties
Required properties:
- compatible: Must be one of the supported compatible strings:
- "adi,adm1075" for adm1075
- "adi,adm1272" for adm1272
- "adi,adm1275" for adm1275
- "adi,adm1276" for adm1276
- "adi,adm1278" for adm1278
- "adi,adm1293" for adm1293
- "adi,adm1294" for adm1294
- reg: I2C address
Optional properties:
- shunt-resistor-micro-ohms
Shunt resistor value in micro-Ohm
Example:
adm1272@10 {
compatible = "adi,adm1272";
reg = <0x10>;
shunt-resistor-micro-ohms = <500>;
};

View File

@@ -1,25 +0,0 @@
ads7828 properties
Required properties:
- compatible: Should be one of
ti,ads7828
ti,ads7830
- reg: I2C address
Optional properties:
- ti,differential-input
Set to use the device in differential mode.
- vref-supply
The external reference on the device is set to this regulators output. If it
does not exists the internal reference will be used and output by the ads78xx
on the "external vref" pin.
Example ADS7828 node:
ads7828: ads@48 {
comatible = "ti,ads7828";
reg = <0x48>;
vref-supply = <&vref>;
ti,differential-input;
};

View File

@@ -0,0 +1,54 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/amd,sbtsi.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: >
Sideband interface Temperature Sensor Interface (SB-TSI) compliant
AMD SoC temperature device
maintainers:
- Kun Yi <kunyi@google.com>
- Supreeth Venkatesh <supreeth.venkatesh@amd.com>
description: |
SB Temperature Sensor Interface (SB-TSI) is an SMBus compatible
interface that reports AMD SoC's Ttcl (normalized temperature),
and resembles a typical 8-pin remote temperature sensor's I2C interface
to BMC. The emulated thermal sensor can report temperatures in increments
of 0.125 degrees, ranging from 0 to 255.875.
properties:
compatible:
enum:
- amd,sbtsi
reg:
maxItems: 1
description: |
I2C bus address of the device as specified in Section 6.3.1 of the
SoC register reference. The SB-TSI address is normally 98h for socket
0 and 90h for socket 1, but it could vary based on hardware address
select pins.
\[open source SoC register reference\]
https://www.amd.com/system/files/TechDocs/56255_OSRR.pdf
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
sbtsi@4c {
compatible = "amd,sbtsi";
reg = <0x4c>;
};
};
...

View File

@@ -1,24 +0,0 @@
ina2xx properties
Required properties:
- compatible: Must be one of the following:
- "ti,ina209" for ina209
- "ti,ina219" for ina219
- "ti,ina220" for ina220
- "ti,ina226" for ina226
- "ti,ina230" for ina230
- "ti,ina231" for ina231
- reg: I2C address
Optional properties:
- shunt-resistor
Shunt resistor value in micro-Ohm
Example:
ina220@44 {
compatible = "ti,ina220";
reg = <0x44>;
shunt-resistor = <1000>;
};

View File

@@ -8,15 +8,16 @@ Required properties:
Optional properties:
- fan-supply : phandle to the regulator that provides power to the fan
- interrupts : This contains a single interrupt specifier which
describes the tachometer output of the fan as an
interrupt source. The output signal must generate a
defined number of interrupts per fan revolution, which
require that it must be self resetting edge interrupts.
See interrupt-controller/interrupts.txt for the format.
- pulses-per-revolution : define the tachometer pulses per fan revolution as
an integer (default is 2 interrupts per revolution).
The value must be greater than zero.
- interrupts : This contains an interrupt specifier for each fan
tachometer output connected to an interrupt source.
The output signal must generate a defined number of
interrupts per fan revolution, which require that
it must be self resetting edge interrupts. See
interrupt-controller/interrupts.txt for the format.
- pulses-per-revolution : define the number of pulses per fan revolution for
each tachometer input as an integer (default is 2
interrupts per revolution). The value must be
greater than zero.
Example:
fan0: pwm-fan {
@@ -55,3 +56,12 @@ Example 2:
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
pulses-per-revolution = <2>;
};
Example 3:
fan0: pwm-fan {
compatible = "pwm-fan";
pwms = <&pwm1 0 25000 0>;
interrupts-extended = <&gpio1 1 IRQ_TYPE_EDGE_FALLING>,
<&gpio2 5 IRQ_TYPE_EDGE_FALLING>;
pulses-per-revolution = <2>, <1>;
};

View File

@@ -0,0 +1,57 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,ads7828.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments ADS7828/ADS7830 Analog to Digital Converter (ADC)
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
description: |
The ADS7828 is 12-Bit, 8-Channel Sampling Analog to Digital Converter (ADC)
with an I2C interface.
Datasheets:
https://www.ti.com/product/ADS7828
properties:
compatible:
enum:
- ti,ads7828
- ti,ads7830
reg:
maxItems: 1
ti,differential-input:
description:
Set to use the device in differential mode.
type: boolean
vref-supply:
description:
The regulator to use as an external reference. If it does not exists the
internal reference will be used.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@48 {
comatible = "ti,ads7828";
reg = <0x48>;
vref-supply = <&vref>;
ti,differential-input;
};
};

View File

@@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,ina2xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments INA209 family of power/voltage monitors
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
description: |
The INA209 is a high-side current shunt and power monitor with
an I2C interface.
Datasheets:
https://www.ti.com/product/INA209
properties:
compatible:
enum:
- ti,ina209
- ti,ina219
- ti,ina220
- ti,ina226
- ti,ina230
- ti,ina231
reg:
maxItems: 1
shunt-resistor:
description:
Shunt resistor value in micro-Ohm.
$ref: /schemas/types.yaml#/definitions/uint32
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
power-sensor@44 {
compatible = "ti,ina220";
reg = <0x44>;
shunt-resistor = <1000>;
};
};

View File

@@ -0,0 +1,57 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/ariel-pwrbutton.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Dell Wyse 3020 a.k.a. "Ariel" Power Button
maintainers:
- Lubomir Rintel <lkundrak@v3.sk>
description: |
The ENE Embedded Controller on the Ariel board has an interface to the
SPI bus that is capable of sending keyboard and mouse data. A single
power button is attached to it. This binding describes this
configuration.
allOf:
- $ref: input.yaml#
properties:
compatible:
items:
- const: dell,wyse-ariel-ec-input
- const: ene,kb3930-input
reg:
maxItems: 1
interrupts:
maxItems: 1
spi-max-frequency: true
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
power-button@0 {
compatible = "dell,wyse-ariel-ec-input", "ene,kb3930-input";
reg = <0>;
interrupt-parent = <&gpio>;
interrupts = <60 IRQ_TYPE_EDGE_RISING>;
spi-max-frequency = <33000000>;
};
};

View File

@@ -1,41 +0,0 @@
Atmel maXTouch touchscreen/touchpad
Required properties:
- compatible:
atmel,maxtouch
The following compatibles have been used in various products but are
deprecated:
atmel,qt602240_ts
atmel,atmel_mxt_ts
atmel,atmel_mxt_tp
atmel,mXT224
- reg: The I2C address of the device
- interrupts: The sink for the touchpad's IRQ output
See ../interrupt-controller/interrupts.txt
Optional properties for main touchpad device:
- linux,gpio-keymap: When enabled, the SPT_GPIOPWN_T19 object sends messages
on GPIO bit changes. An array of up to 8 entries can be provided
indicating the Linux keycode mapped to each bit of the status byte,
starting at the LSB. Linux keycodes are defined in
<dt-bindings/input/input.h>.
Note: the numbering of the GPIOs and the bit they start at varies between
maXTouch devices. You must either refer to the documentation, or
experiment to determine which bit corresponds to which input. Use
KEY_RESERVED for unused padding values.
- reset-gpios: GPIO specifier for the touchscreen's reset pin (active low)
Example:
touch@4b {
compatible = "atmel,maxtouch";
reg = <0x4b>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(W, 3) IRQ_TYPE_LEVEL_LOW>;
};

View File

@@ -0,0 +1,81 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/atmel,maxtouch.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel maXTouch touchscreen/touchpad
maintainers:
- Nick Dyer <nick@shmanahar.org>
- Linus Walleij <linus.walleij@linaro.org>
description: |
Atmel maXTouch touchscreen or touchpads such as the mXT244
and similar devices.
properties:
compatible:
const: atmel,maxtouch
reg:
maxItems: 1
interrupts:
maxItems: 1
vdda-supply:
description:
Optional regulator for the AVDD analog voltage.
vdd-supply:
description:
Optional regulator for the VDD digital voltage.
reset-gpios:
maxItems: 1
description:
Optional GPIO specifier for the touchscreen's reset pin
(active low). The line must be flagged with
GPIO_ACTIVE_LOW.
linux,gpio-keymap:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: |
When enabled, the SPT_GPIOPWN_T19 object sends messages
on GPIO bit changes. An array of up to 8 entries can be provided
indicating the Linux keycode mapped to each bit of the status byte,
starting at the LSB. Linux keycodes are defined in
<dt-bindings/input/input.h>.
Note: the numbering of the GPIOs and the bit they start at varies
between maXTouch devices. You must either refer to the documentation,
or experiment to determine which bit corresponds to which input. Use
KEY_RESERVED for unused padding values.
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touchscreen@4a {
compatible = "atmel,maxtouch";
reg = <0x4a>;
interrupt-parent = <&gpio>;
interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>;
vdda-supply = <&ab8500_ldo_aux2_reg>;
vdd-supply = <&ab8500_ldo_aux5_reg>;
};
};
...

View File

@@ -1,33 +0,0 @@
Samsung tm2-touchkey
Required properties:
- compatible:
* "cypress,tm2-touchkey" - for the touchkey found on the tm2 board
* "cypress,midas-touchkey" - for the touchkey found on midas boards
* "cypress,aries-touchkey" - for the touchkey found on aries boards
* "coreriver,tc360-touchkey" - for the Coreriver TouchCore 360 touchkey
- reg: I2C address of the chip.
- interrupts: interrupt to which the chip is connected (see interrupt
binding[0]).
- vcc-supply : internal regulator output. 1.8V
- vdd-supply : power supply for IC 3.3V
Optional properties:
- linux,keycodes: array of keycodes (max 4), default KEY_PHONE and KEY_BACK
[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Example:
&i2c0 {
/* ... */
touchkey@20 {
compatible = "cypress,tm2-touchkey";
reg = <0x20>;
interrupt-parent = <&gpa3>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
vcc-supply=<&ldo32_reg>;
vdd-supply=<&ldo33_reg>;
linux,keycodes = <KEY_PHONE KEY_BACK>;
};
};

View File

@@ -0,0 +1,73 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/cypress,tm2-touchkey.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung TM2 touch key controller
maintainers:
- Stephan Gerhold <stephan@gerhold.net>
description: |
Touch key controllers similar to the TM2 can be found in a wide range of
Samsung devices. They are implemented using many different MCUs, but use
a similar I2C protocol.
allOf:
- $ref: input.yaml#
properties:
compatible:
enum:
- cypress,tm2-touchkey
- cypress,midas-touchkey
- cypress,aries-touchkey
- coreriver,tc360-touchkey
reg:
maxItems: 1
interrupts:
maxItems: 1
vdd-supply:
description: Optional regulator for LED voltage, 3.3V.
vcc-supply:
description: Optional regulator for MCU, 1.8V-3.3V (depending on MCU).
vddio-supply:
description: |
Optional regulator that provides digital I/O voltage,
e.g. for pulling up the interrupt line or the I2C pins.
linux,keycodes:
minItems: 1
maxItems: 4
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touchkey@20 {
compatible = "cypress,tm2-touchkey";
reg = <0x20>;
interrupt-parent = <&gpa3>;
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
vcc-supply = <&ldo32_reg>;
vdd-supply = <&ldo33_reg>;
linux,keycodes = <KEY_MENU KEY_BACK>;
};
};

View File

@@ -0,0 +1,108 @@
Dialog Semiconductor DA7280 Haptics bindings
Required properties:
- compatible: Should be "dlg,da7280".
- reg: Specifies the I2C slave address.
- interrupt-parent : Specifies the phandle of the interrupt controller to
which the IRQs from DA7280 are delivered to.
- dlg,actuator-type: Set Actuator type. it should be one of:
"LRA" - Linear Resonance Actuator type.
"ERM-bar" - Bar type Eccentric Rotating Mass.
"ERM-coin" - Coin type Eccentric Rotating Mass.
- dlg,const-op-mode: Haptic operation mode for FF_CONSTANT.
Possible values:
1 - Direct register override(DRO) mode triggered by i2c(default),
2 - PWM data source mode controlled by PWM duty,
- dlg,periodic-op-mode: Haptic operation mode for FF_PERIODIC.
Possible values:
1 - Register triggered waveform memory(RTWM) mode, the pattern
assigned to the PS_SEQ_ID played as much times as PS_SEQ_LOOP,
2 - Edge triggered waveform memory(ETWM) mode, external GPI(N)
control are required to enable/disable and it needs to keep
device enabled by sending magnitude (X > 0),
the pattern is assigned to the GPI(N)_SEQUENCE_ID below.
The default value is 1 for both of the operation modes.
For more details, please see the datasheet.
- dlg,nom-microvolt: Nominal actuator voltage rating.
Valid values: 0 - 6000000.
- dlg,abs-max-microvolt: Absolute actuator maximum voltage rating.
Valid values: 0 - 6000000.
- dlg,imax-microamp: Actuator max current rating.
Valid values: 0 - 252000.
Default: 130000.
- dlg,impd-micro-ohms: the impedance of the actuator in micro ohms.
Valid values: 0 - 1500000000.
Optional properties:
- pwms : phandle to the physical PWM(Pulse Width Modulation) device.
PWM properties should be named "pwms". And number of cell is different
for each pwm device.
(See Documentation/devicetree/bindings/pwm/pwm.txt
for further information relating to pwm properties)
- dlg,ps-seq-id: the PS_SEQ_ID(pattern ID in waveform memory inside chip)
to play back when RTWM-MODE is enabled.
Valid range: 0 - 15.
- dlg,ps-seq-loop: the PS_SEQ_LOOP, Number of times the pre-stored sequence
pointed to by PS_SEQ_ID or GPI(N)_SEQUENCE_ID is repeated.
Valid range: 0 - 15.
- dlg,gpiN-seq-id: the GPI(N)_SEQUENCE_ID, pattern to play
when gpi0 is triggered, 'N' must be 0 - 2.
Valid range: 0 - 15.
- dlg,gpiN-mode: the pattern mode which can select either
"Single-pattern" or "Multi-pattern", 'N' must be 0 - 2.
- dlg,gpiN-polarity: gpiN polarity which can be chosen among
"Rising-edge", "Falling-edge" and "Both-edge",
'N' must be 0 - 2
Haptic will work by this edge option in case of ETWM mode.
- dlg,resonant-freq-hz: use in case of LRA.
the frequency range: 50 - 300.
Default: 205.
- dlg,bemf-sens-enable: Enable for internal loop computations.
- dlg,freq-track-enable: Enable for resonant frequency tracking.
- dlg,acc-enable: Enable for active acceleration.
- dlg,rapid-stop-enable: Enable for rapid stop.
- dlg,amp-pid-enable: Enable for the amplitude PID.
- dlg,mem-array: Customized waveform memory(patterns) data downloaded to
the device during initialization. This is an array of 100 values(u8).
For further information, see device datasheet.
======
Example:
haptics: da7280-haptics@4a {
compatible = "dlg,da7280";
reg = <0x4a>;
interrupt-parent = <&gpio6>;
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
dlg,actuator-type = "LRA";
dlg,dlg,const-op-mode = <1>;
dlg,dlg,periodic-op-mode = <1>;
dlg,nom-microvolt = <2000000>;
dlg,abs-max-microvolt = <2000000>;
dlg,imax-microamp = <170000>;
dlg,resonant-freq-hz = <180>;
dlg,impd-micro-ohms = <10500000>;
dlg,freq-track-enable;
dlg,rapid-stop-enable;
dlg,mem-array = <
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
>;
};

View File

@@ -1,23 +0,0 @@
Spreadtrum SC27xx PMIC Vibrator
Required properties:
- compatible: should be "sprd,sc2731-vibrator".
- reg: address of vibrator control register.
Example :
sc2731_pmic: pmic@0 {
compatible = "sprd,sc2731";
reg = <0>;
spi-max-frequency = <26000000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <0>;
vibrator@eb4 {
compatible = "sprd,sc2731-vibrator";
reg = <0xeb4>;
};
};

View File

@@ -0,0 +1,48 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright 2020 Unisoc Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/sprd,sc27xx-vibrator.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Spreadtrum SC27xx PMIC Vibrator Device Tree Bindings
maintainers:
- Orson Zhai <orsonzhai@gmail.com>
- Baolin Wang <baolin.wang7@gmail.com>
- Chunyan Zhang <zhang.lyra@gmail.com>
properties:
compatible:
enum:
- sprd,sc2721-vibrator
- sprd,sc2730-vibrator
- sprd,sc2731-vibrator
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
sc2731_pmic: pmic@0 {
compatible = "sprd,sc2731";
reg = <0 0>;
spi-max-frequency = <26000000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <0>;
vibrator@eb4 {
compatible = "sprd,sc2731-vibrator";
reg = <0xeb4>;
};
};

View File

@@ -1,7 +1,7 @@
* Elan eKTF2127 I2C touchscreen controller
Required properties:
- compatible : "elan,ektf2127"
- compatible : "elan,ektf2127" or "elan,ektf2132"
- reg : I2C slave address of the chip (0x40)
- interrupts : interrupt specification for the ektf2127 interrupt
- power-gpios : GPIO specification for the pin connected to the

View File

@@ -14,18 +14,19 @@ Required properties:
- "mediatek,mt2712-thermal" : For MT2712 family of SoCs
- "mediatek,mt7622-thermal" : For MT7622 SoC
- "mediatek,mt8183-thermal" : For MT8183 family of SoCs
- "mediatek,mt8516-thermal", "mediatek,mt2701-thermal : For MT8516 family of SoCs
- reg: Address range of the thermal controller
- interrupts: IRQ for the thermal controller
- clocks, clock-names: Clocks needed for the thermal controller. required
clocks are:
"therm": Main clock needed for register access
"auxadc": The AUXADC clock
- resets: Reference to the reset controller controlling the thermal controller.
- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses
- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller.
- #thermal-sensor-cells : Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description.
Optional properties:
- resets: Reference to the reset controller controlling the thermal controller.
- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If
unspecified default values shall be used.
- nvmem-cell-names: Should be "calibration-data"

View File

@@ -26,13 +26,16 @@ properties:
- renesas,r8a77961-thermal # R-Car M3-W+
- renesas,r8a77965-thermal # R-Car M3-N
- renesas,r8a77980-thermal # R-Car V3H
- renesas,r8a779a0-thermal # R-Car V3U
reg:
minItems: 2
maxItems: 3
maxItems: 4
items:
- description: TSC1 registers
- description: TSC2 registers
- description: TSC3 registers
- description: TSC4 registers
interrupts:
items:
@@ -55,12 +58,22 @@ properties:
required:
- compatible
- reg
- interrupts
- clocks
- power-domains
- resets
- "#thermal-sensor-cells"
if:
not:
properties:
compatible:
contains:
enum:
- renesas,r8a779a0-thermal
then:
required:
- interrupts
additionalProperties: false
examples:

View File

@@ -62,25 +62,35 @@ properties:
"#thermal-sensor-cells":
const: 0
if:
properties:
compatible:
contains:
enum:
- renesas,thermal-r8a73a4 # R-Mobile APE6
- renesas,thermal-r8a7779 # R-Car H1
then:
required:
- compatible
- reg
else:
required:
- compatible
- reg
- interrupts
- clocks
- power-domains
- resets
required:
- compatible
- reg
allOf:
- if:
not:
properties:
compatible:
contains:
enum:
- renesas,thermal-r8a73a4 # R-Mobile APE6
- renesas,thermal-r8a7779 # R-Car H1
then:
required:
- resets
- '#thermal-sensor-cells'
- if:
not:
properties:
compatible:
contains:
const: renesas,thermal-r8a7779 # R-Car H1
then:
required:
- interrupts
- clocks
- power-domains
additionalProperties: false

View File

@@ -254,10 +254,6 @@ properties:
- st,24c256
# Ambient Light Sensor with SMBUS/Two Wire Serial Interface
- taos,tsl2550
# 8-Channels, 12-bit ADC
- ti,ads7828
# 8-Channels, 8-bit ADC
- ti,ads7830
# Temperature Monitoring and Fan Control
- ti,amc6821
# Temperature and humidity sensor with i2c interface

View File

@@ -25,15 +25,6 @@ Multitouch Library
.. kernel-doc:: drivers/input/input-mt.c
:export:
Polled input devices
--------------------
.. kernel-doc:: include/linux/input-polldev.h
:internal:
.. kernel-doc:: drivers/input/input-polldev.c
:export:
Matrix keyboards/keypads
------------------------

View File

@@ -654,8 +654,7 @@ stats/time_in_state_ms:
The amount of time spent by the cooling device in various cooling
states. The output will have "<state> <time>" pair in each line, which
will mean this cooling device spent <time> msec of time at <state>.
Output will have one line for each of the supported states. usertime
units here is 10mS (similar to other time exported in /proc).
Output will have one line for each of the supported states.
RO, Required

View File

@@ -83,7 +83,7 @@ or current scaling. Reported voltages, currents, and power are raw measurements,
and will typically have to be scaled.
The shunt value in micro-ohms can be set via device tree at compile-time. Please
refer to the Documentation/devicetree/bindings/hwmon/adm1275.txt for bindings
refer to the Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml for bindings
if the device tree is used.
Platform data support

View File

@@ -5,7 +5,9 @@ Kernel driver amd_energy
Supported chips:
* AMD Family 17h Processors
* AMD Family 17h Processors: Model 30h
* AMD Family 19h Processors: Model 01h
Prefix: 'amd_energy'
@@ -112,3 +114,6 @@ energy[N]_input EcoreX Core Energy X = [0] to [nr_cpus - 1]
energy[N]_input EsocketX Socket Energy X = [0] to [nr_socks -1]
Measured input socket energy
=============== ======== ======================================
Note: To address CVE-2020-12912, the visibility of the energy[N]_input
attributes is restricted to owner and groups only.

View File

@@ -0,0 +1,82 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver corsair-psu
=========================
Supported devices:
* Corsair Power Supplies
Corsair HX550i
Corsair HX650i
Corsair HX750i
Corsair HX850i
Corsair HX1000i
Corsair HX1200i
Corsair RM550i
Corsair RM650i
Corsair RM750i
Corsair RM850i
Corsair RM1000i
Author: Wilken Gottwalt
Description
-----------
This driver implements the sysfs interface for the Corsair PSUs with a HID protocol
interface of the HXi and RMi series.
These power supplies provide access to a micro-controller with 2 attached
temperature sensors, 1 fan rpm sensor, 4 sensors for volt levels, 4 sensors for
power usage and 4 sensors for current levels and addtional non-sensor information
like uptimes.
Sysfs entries
-------------
======================= ========================================================
curr1_input Total current usage
curr2_input Current on the 12v psu rail
curr3_input Current on the 5v psu rail
curr4_input Current on the 3.3v psu rail
fan1_input RPM of psu fan
in0_input Voltage of the psu ac input
in1_input Voltage of the 12v psu rail
in2_input Voltage of the 5v psu rail
in3_input Voltage of the 3.3 psu rail
power1_input Total power usage
power2_input Power usage of the 12v psu rail
power3_input Power usage of the 5v psu rail
power4_input Power usage of the 3.3v psu rail
temp1_input Temperature of the psu vrm component
temp2_input Temperature of the psu case
======================= ========================================================
Usage Notes
-----------
It is an USB HID device, so it is auto-detected and supports hot-swapping.
Flickering values in the rail voltage levels can be an indicator for a failing
PSU. The driver also provides some additional useful values via debugfs, which
do not fit into the hwmon class.
Debugfs entries
---------------
======================= ========================================================
uptime Current uptime of the psu
uptime_total Total uptime of the psu
vendor Vendor name of the psu
product Product name of the psu
======================= ========================================================

View File

@@ -49,6 +49,7 @@ Hardware Monitoring Kernel Drivers
bt1-pvt
coretemp
corsair-cpro
corsair-psu
da9052
da9055
dell-smm-hwmon
@@ -100,6 +101,7 @@ Hardware Monitoring Kernel Drivers
lm95234
lm95245
lochnagar
ltc2992
ltc2945
ltc2947
ltc2978
@@ -110,6 +112,7 @@ Hardware Monitoring Kernel Drivers
ltc4245
ltc4260
ltc4261
max127
max16064
max16065
max1619
@@ -144,11 +147,14 @@ Hardware Monitoring Kernel Drivers
pc87360
pc87427
pcf8591
pm6764tr
pmbus
powr1220
pxe1610
pwm-fan
q54sj108a2
raspberrypi-hwmon
sbtsi_temp
sch5627
sch5636
scpi-hwmon

View File

@@ -0,0 +1,56 @@
.. SPDX-License-Identifier: GPL-2.0
Kernel driver ltc2992
=====================
Supported chips:
* Linear Technology LTC2992
Prefix: 'ltc2992'
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ltc2992.pdf
Author: Alexandru Tachici <alexandru.tachici@analog.com>
Description
-----------
This driver supports hardware monitoring for Linear Technology LTC2992 power monitor.
LTC2992 is a rail-to-rail system monitor that measures current,
voltage, and power of two supplies.
Two ADCs simultaneously measure each supplys current. A third ADC monitors
the input voltages and four auxiliary external voltages.
Sysfs entries
-------------
The following attributes are supported. Limits are read-write,
all other attributes are read-only.
in_reset_history Reset all highest/lowest values.
inX_input Measured voltage.
inX_lowest Minimum measured voltage.
inX_highest Maximum measured voltage.
inX_min Minimum voltage allowed.
inX_max Maximum voltage allowed.
inX_min_alarm An undervoltage occurred. Cleared on read.
inX_max_alarm An overvoltage occurred. Cleared on read.
currX_input Measured current.
currX_lowest Minimum measured current.
currX_highest Maximum measured current.
currX_min Minimum current allowed.
currX_max Maximum current allowed.
currX_min_alarm An undercurrent occurred. Cleared on read.
currX_max_alarm An overcurrent occurred. Cleared on read.
powerX_input Measured power.
powerX_input_lowest Minimum measured voltage.
powerX_input_highest Maximum measured voltage.
powerX_min Minimum power.
powerX_max Maximum power.
powerX_min_alarm An underpower occurred. Cleared on read.
powerX_max_alarm An overpower occurred. Cleared on read.

View File

@@ -0,0 +1,45 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver max127
====================
Author:
* Tao Ren <rentao.bupt@gmail.com>
Supported chips:
* Maxim MAX127
Prefix: 'max127'
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX127-MAX128.pdf
Description
-----------
The MAX127 is a multirange, 12-bit data acquisition system (DAS) providing
8 analog input channels that are independently software programmable for
a variety of ranges. The available ranges are {0,5V}, {0,10V}, {-5,5V}
and {-10,10V}.
The MAX127 features a 2-wire, I2C-compatible serial interface that allows
communication among multiple devices using SDA and SCL lines.
Sysfs interface
---------------
============== ==============================================================
in[0-7]_input The input voltage (in mV) of the corresponding channel.
RO
in[0-7]_min The lower input limit (in mV) for the corresponding channel.
ADC range and LSB will be updated when the limit is changed.
For the MAX127, it will be adjusted to -10000, -5000, or 0.
RW
in[0-7]_max The higher input limit (in mV) for the corresponding channel.
ADC range and LSB will be updated when the limit is changed.
For the MAX127, it will be adjusted to 0, 5000, or 10000.
RW
============== ==============================================================

View File

@@ -3,7 +3,7 @@ Kernel driver nct6683
Supported chips:
* Nuvoton NCT6683D
* Nuvoton NCT6683D/NCT6687D
Prefix: 'nct6683'
@@ -61,4 +61,5 @@ Board Firmware version
Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13
Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13
Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13
MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20
=============== ===============================================

View File

@@ -0,0 +1,32 @@
.. SPDX-License-Identifier: GPL-2.0-only
Kernel driver pm6764tr
======================
Supported chips:
* ST PM6764TR
Prefix: 'pm6764tr'
Addresses scanned: -
Datasheet: http://www.st.com/resource/en/data_brief/pm6764.pdf
Authors:
<hsu.yungteng@gmail.com>
Description:
------------
This driver supports the STMicroelectronics PM6764TR chip. The PM6764TR is a high
performance digital controller designed to power Intels VR12.5 processors and memories.
The device utilizes digital technology to implement all control and power management
functions to provide maximum flexibility and performance. The NVM is embedded to store
custom configurations. The PM6764TR device features up to 4-phase programmable operation.
The PM6764TR supports power state transitions featuring VFDE, and programmable DPM
maintaining the best efficiency over all loading conditions without compromising transient
response. The device assures fast and independent protection against load overcurrent,
under/overvoltage and feedback disconnections.

View File

@@ -277,12 +277,6 @@ with the pointer to struct pmbus_driver_info as additional argument. Calls
identify function if supported. Must only be called from device probe
function.
::
void pmbus_do_remove(struct i2c_client *client);
Execute driver remove function. Similar to standard driver remove function.
::
const struct pmbus_driver_info

View File

@@ -148,11 +148,6 @@ Emerson DS1200 power modules might look as follows::
return pmbus_do_probe(client, &ds1200_info);
}
static int ds1200_remove(struct i2c_client *client)
{
return pmbus_do_remove(client);
}
static const struct i2c_device_id ds1200_id[] = {
{"ds1200", 0},
{}
@@ -166,7 +161,6 @@ Emerson DS1200 power modules might look as follows::
.name = "ds1200",
},
.probe_new = ds1200_probe,
.remove = ds1200_remove,
.id_table = ds1200_id,
};

View File

@@ -0,0 +1,54 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver q54sj108a2
========================
Supported chips:
* DELTA Q54SJ108A2NCAH, Q54SJ108A2NCDH, Q54SJ108A2NCPG, Q54SJ108A2NCPH
Prefix: 'q54sj108a2'
Addresses scanned: -
Datasheet: https://filecenter.delta-china.com.cn/products/download/01/0102/datasheet/DS_Q54SJ108A2.pdf
Authors:
Xiao.ma <xiao.mx.ma@deltaww.com>
Description
-----------
This driver implements support for DELTA Q54SJ108A2NCAH, Q54SJ108A2NCDH,
Q54SJ108A2NCPG, and Q54SJ108A2NCPH 1/4 Brick DC/DC Regulated Power Module
with PMBus support.
The driver is a client driver to the core PMBus driver.
Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
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.
Sysfs entries
-------------
===================== ===== ==================================================
curr1_alarm RO Output current alarm
curr1_input RO Output current
curr1_label RO 'iout1'
in1_alarm RO Input voltage alarm
in1_input RO Input voltage
in1_label RO 'vin'
in2_alarm RO Output voltage alarm
in2_input RO Output voltage
in2_label RO 'vout1'
temp1_alarm RO Temperature alarm
temp1_input RO Chip temperature
===================== ===== ==================================================

View File

@@ -0,0 +1,42 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver sbtsi_temp
==================
Supported hardware:
* Sideband interface (SBI) Temperature Sensor Interface (SB-TSI)
compliant AMD SoC temperature device.
Prefix: 'sbtsi_temp'
Addresses scanned: This driver doesn't support address scanning.
To instantiate this driver on an AMD CPU with SB-TSI
support, the i2c bus number would be the bus connected from the board
management controller (BMC) to the CPU. The i2c address is specified in
Section 6.3.1 of the SoC register reference: The SB-TSI address is normally
98h for socket 0 and 90h for socket 1, but it could vary based on hardware
address select pins.
Datasheet: The SB-TSI interface and protocol is available as part of
the open source SoC register reference at:
https://www.amd.com/system/files/TechDocs/56255_OSRR.pdf
The Advanced Platform Management Link (APML) Specification is
available at:
http://developer.amd.com/wordpress/media/2012/10/41918.pdf
Author: Kun Yi <kunyi@google.com>
Description
-----------
The SBI temperature sensor interface (SB-TSI) is an emulation of the software
and physical interface of a typical 8-pin remote temperature sensor (RTS) on
AMD SoCs. It implements one temperature sensor with readings and limit
registers encode the temperature in increments of 0.125 from 0 to 255.875.
Limits can be set through the writable thresholds, and if reached will trigger
corresponding alert signals.

View File

@@ -164,6 +164,52 @@ disconnects. Calls to both callbacks are serialized.
The open() callback should return a 0 in case of success or any nonzero value
in case of failure. The close() callback (which is void) must always succeed.
Inhibiting input devices
~~~~~~~~~~~~~~~~~~~~~~~~
Inhibiting a device means ignoring input events from it. As such it is about
maintaining relationships with input handlers - either already existing
relationships, or relationships to be established while the device is in
inhibited state.
If a device is inhibited, no input handler will receive events from it.
The fact that nobody wants events from the device is exploited further, by
calling device's close() (if there are users) and open() (if there are users) on
inhibit and uninhibit operations, respectively. Indeed, the meaning of close()
is to stop providing events to the input core and that of open() is to start
providing events to the input core.
Calling the device's close() method on inhibit (if there are users) allows the
driver to save power. Either by directly powering down the device or by
releasing the runtime-pm reference it got in open() when the driver is using
runtime-pm.
Inhibiting and uninhibiting are orthogonal to opening and closing the device by
input handlers. Userspace might want to inhibit a device in anticipation before
any handler is positively matched against it.
Inhibiting and uninhibiting are orthogonal to device's being a wakeup source,
too. Being a wakeup source plays a role when the system is sleeping, not when
the system is operating. How drivers should program their interaction between
inhibiting, sleeping and being a wakeup source is driver-specific.
Taking the analogy with the network devices - bringing a network interface down
doesn't mean that it should be impossible be wake the system up on LAN through
this interface. So, there may be input drivers which should be considered wakeup
sources even when inhibited. Actually, in many I2C input devices their interrupt
is declared a wakeup interrupt and its handling happens in driver's core, which
is not aware of input-specific inhibit (nor should it be). Composite devices
containing several interfaces can be inhibited on a per-interface basis and e.g.
inhibiting one interface shouldn't affect the device's capability of being a
wakeup source.
If a device is to be considered a wakeup source while inhibited, special care
must be taken when programming its suspend(), as it might need to call device's
open(). Depending on what close() means for the device in question, not
opening() it before going to sleep might make it impossible to provide any
wakeup events. The device is going to sleep anyway.
Basic event types
~~~~~~~~~~~~~~~~~

View File

@@ -929,6 +929,12 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-amd-mp2*
AMD PMC DRIVER
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/amd-pmc.*
AMD POWERPLAY
M: Evan Quan <evan.quan@amd.com>
L: amd-gfx@lists.freedesktop.org
@@ -2960,7 +2966,7 @@ ATMEL MAXTOUCH DRIVER
M: Nick Dyer <nick@shmanahar.org>
S: Maintained
T: git git://github.com/ndyer/linux.git
F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt
F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
F: drivers/input/touchscreen/atmel_mxt_ts.c
ATMEL WIRELESS DRIVER
@@ -4513,6 +4519,13 @@ L: linux-hwmon@vger.kernel.org
S: Maintained
F: drivers/hwmon/corsair-cpro.c
CORSAIR-PSU HARDWARE MONITOR DRIVER
M: Wilken Gottwalt <wilken.gottwalt@posteo.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/corsair-psu.rst
F: drivers/hwmon/corsair-psu.c
COSA/SRP SYNC SERIAL DRIVER
M: Jan "Yenya" Kasprzak <kas@fi.muni.cz>
S: Maintained
@@ -5008,6 +5021,15 @@ M: Mario Limonciello <mario.limonciello@dell.com>
S: Maintained
F: drivers/platform/x86/dell-wmi-descriptor.c
DELL WMI SYSMAN DRIVER
M: Divya Bharathi <divya.bharathi@dell.com>
M: Mario Limonciello <mario.limonciello@dell.com>
M: Prasanth Ksr <prasanth.ksr@dell.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-class-firmware-attributes
F: drivers/platform/x86/dell-wmi-sysman/
DELL WMI NOTIFICATIONS DRIVER
M: Matthew Garrett <mjg59@srcf.ucam.org>
M: Pali Rohár <pali@kernel.org>
@@ -5137,6 +5159,7 @@ M: Support Opensource <support.opensource@diasemi.com>
S: Supported
W: http://www.dialog-semiconductor.com/products
F: Documentation/devicetree/bindings/input/da90??-onkey.txt
F: Documentation/devicetree/bindings/input/dlg,da72??.txt
F: Documentation/devicetree/bindings/mfd/da90*.txt
F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml
F: Documentation/devicetree/bindings/regulator/da92*.txt
@@ -5148,6 +5171,7 @@ F: Documentation/hwmon/da90??.rst
F: drivers/gpio/gpio-da90??.c
F: drivers/hwmon/da90??-hwmon.c
F: drivers/iio/adc/da91??-*.c
F: drivers/input/misc/da72??.[ch]
F: drivers/input/misc/da90??_onkey.c
F: drivers/input/touchscreen/da9052_tsi.c
F: drivers/leds/leds-da90??.c
@@ -8675,7 +8699,7 @@ INA209 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/hwmon/ina2xx.txt
F: Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
F: Documentation/hwmon/ina209.rst
F: drivers/hwmon/ina209.c
@@ -9077,6 +9101,12 @@ F: drivers/mfd/intel_soc_pmic*
F: include/linux/mfd/intel_msic.h
F: include/linux/mfd/intel_soc_pmic*
INTEL PMT DRIVER
M: "David E. Box" <david.e.box@linux.intel.com>
S: Maintained
F: drivers/mfd/intel_pmt.c
F: drivers/platform/x86/intel_pmt_*
INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
M: Stanislav Yakovlev <stas.yakovlev@gmail.com>
L: linux-wireless@vger.kernel.org
@@ -11735,11 +11765,26 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch]
F: include/linux/cciss*.h
F: include/uapi/linux/cciss*.h
MICROSOFT SURFACE GPE LID SUPPORT DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/surface/surface_gpe.c
MICROSOFT SURFACE HARDWARE PLATFORM SUPPORT
M: Hans de Goede <hdegoede@redhat.com>
M: Mark Gross <mgross@linux.intel.com>
M: Maximilian Luz <luzmaximilian@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
F: drivers/platform/surface/
MICROSOFT SURFACE PRO 3 BUTTON DRIVER
M: Chen Yu <yu.c.chen@intel.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
F: drivers/platform/x86/surfacepro3_button.c
F: drivers/platform/surface/surfacepro3_button.c
MICROTEK X6 SCANNER
M: Oliver Neukum <oliver@neukum.org>
@@ -13326,7 +13371,7 @@ F: include/trace/events/page_pool.h
F: net/core/page_pool.c
PANASONIC LAPTOP ACPI EXTRAS DRIVER
M: Harald Welte <laforge@gnumonks.org>
M: Kenneth Chan <kenneth.t.chan@gmail.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/panasonic-laptop.c
@@ -14048,6 +14093,13 @@ M: Logan Gunthorpe <logang@deltatee.com>
S: Maintained
F: drivers/dma/plx_dma.c
PM6764TR DRIVER
M: Charles Hsu <hsu.yungteng@gmail.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/pm6764tr.rst
F: drivers/hwmon/pmbus/pm6764tr.c
PM-GRAPH UTILITY
M: "Todd E Brandt" <todd.e.brandt@linux.intel.com>
L: linux-pm@vger.kernel.org

View File

@@ -589,7 +589,7 @@
touchscreen@4b {
compatible = "atmel,maxtouch";
reset-gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;
reset-gpio = <&gpio5 19 GPIO_ACTIVE_LOW>;
reg = <0x4b>;
interrupt-parent = <&gpio5>;
interrupts = <4 IRQ_TYPE_LEVEL_LOW>;

View File

@@ -143,7 +143,7 @@
reg = <0x4a>;
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* SODIMM 28 */
reset-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; /* SODIMM 30 */
reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; /* SODIMM 30 */
status = "disabled";
};

View File

@@ -140,7 +140,7 @@
reg = <0x4a>;
interrupt-parent = <&gpio6>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */
reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */
status = "disabled";
};

View File

@@ -145,7 +145,7 @@
reg = <0x4a>;
interrupt-parent = <&gpio6>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */
reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */
status = "disabled";
};

View File

@@ -144,7 +144,7 @@
reg = <0x4a>;
interrupt-parent = <&gpio6>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
reset-gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>; /* SODIMM 13 */
reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; /* SODIMM 13 */
status = "disabled";
};

View File

@@ -99,7 +99,7 @@
reg = <0x4a>;
interrupt-parent = <&gpio2>;
interrupts = <15 IRQ_TYPE_EDGE_FALLING>; /* SODIMM 107 */
reset-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* SODIMM 106 */
reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* SODIMM 106 */
};
/* M41T0M6 real time clock on carrier board */

View File

@@ -124,7 +124,7 @@
reg = <0x4a>;
interrupt-parent = <&gpio1>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>; /* SODIMM 28 */
reset-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; /* SODIMM 30 */
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* SODIMM 30 */
status = "disabled";
};

View File

@@ -430,7 +430,7 @@
pinctrl-names = "default";
pinctrl-0 = <&touchscreen_pins>;
reset-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; /* gpio173 */
reset-gpios = <&gpio6 13 GPIO_ACTIVE_LOW>; /* gpio173 */
/* gpio_183 with sys_nirq2 pad as wakeup */
interrupts-extended = <&gpio6 23 IRQ_TYPE_LEVEL_LOW>,

View File

@@ -632,7 +632,7 @@
interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
pinctrl-names = "default";
pinctrl-0 = <&ts_irq>;
reset-gpios = <&gpj1 3 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpj1 3 GPIO_ACTIVE_LOW>;
};
};

View File

@@ -446,7 +446,7 @@
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(V, 6) IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio TEGRA_GPIO(Q, 7) GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio TEGRA_GPIO(Q, 7) GPIO_ACTIVE_LOW>;
avdd-supply = <&vdd_3v3_sys>;
vdd-supply = <&vdd_3v3_sys>;

View File

@@ -579,7 +579,6 @@ CONFIG_JOYSTICK_XPAD_LEDS=y
CONFIG_INPUT_TABLET=y
CONFIG_TABLET_USB_ACECAD=m
CONFIG_TABLET_USB_AIPTEK=m
CONFIG_TABLET_USB_GTCO=m
CONFIG_TABLET_USB_KBTAB=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_PCSPKR=m

View File

@@ -14,6 +14,7 @@
#include <linux/mutex.h>
#include <linux/fsi-occ.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -24,8 +25,13 @@
#define OCC_CMD_DATA_BYTES 4090
#define OCC_RESP_DATA_BYTES 4089
#define OCC_SRAM_CMD_ADDR 0xFFFBE000
#define OCC_SRAM_RSP_ADDR 0xFFFBF000
#define OCC_P9_SRAM_CMD_ADDR 0xFFFBE000
#define OCC_P9_SRAM_RSP_ADDR 0xFFFBF000
#define OCC_P10_SRAM_CMD_ADDR 0xFFFFD000
#define OCC_P10_SRAM_RSP_ADDR 0xFFFFE000
#define OCC_P10_SRAM_MODE 0x58 /* Normal mode, OCB channel 2 */
/*
* Assume we don't have much FFDC, if we do we'll overflow and
@@ -37,11 +43,14 @@
#define OCC_TIMEOUT_MS 1000
#define OCC_CMD_IN_PRG_WAIT_MS 50
enum versions { occ_p9, occ_p10 };
struct occ {
struct device *dev;
struct device *sbefifo;
char name[32];
int idx;
enum versions version;
struct miscdevice mdev;
struct mutex occ_lock;
};
@@ -235,29 +244,43 @@ static int occ_verify_checksum(struct occ_response *resp, u16 data_length)
return 0;
}
static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)
{
u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */
size_t resp_len, resp_data_len;
__be32 *resp, cmd[5];
int rc;
size_t cmd_len, resp_len, resp_data_len;
__be32 *resp, cmd[6];
int idx = 0, rc;
/*
* Magic sequence to do SBE getsram command. SBE will fetch data from
* specified SRAM address.
*/
cmd[0] = cpu_to_be32(0x5);
switch (occ->version) {
default:
case occ_p9:
cmd_len = 5;
cmd[2] = cpu_to_be32(1); /* Normal mode */
cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);
break;
case occ_p10:
idx = 1;
cmd_len = 6;
cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
cmd[3] = 0;
cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);
break;
}
cmd[0] = cpu_to_be32(cmd_len);
cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);
cmd[2] = cpu_to_be32(1);
cmd[3] = cpu_to_be32(address);
cmd[4] = cpu_to_be32(data_len);
cmd[4 + idx] = cpu_to_be32(data_len);
resp_len = (data_len >> 2) + OCC_SBE_STATUS_WORDS;
resp = kzalloc(resp_len << 2, GFP_KERNEL);
if (!resp)
return -ENOMEM;
rc = sbefifo_submit(occ->sbefifo, cmd, 5, resp, &resp_len);
rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);
if (rc)
goto free;
@@ -287,20 +310,21 @@ free:
return rc;
}
static int occ_putsram(struct occ *occ, u32 address, const void *data,
ssize_t len)
static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
{
size_t cmd_len, buf_len, resp_len, resp_data_len;
u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */
__be32 *buf;
int rc;
int idx = 0, rc;
cmd_len = (occ->version == occ_p10) ? 6 : 5;
/*
* We use the same buffer for command and response, make
* sure it's big enough
*/
resp_len = OCC_SBE_STATUS_WORDS;
cmd_len = (data_len >> 2) + 5;
cmd_len += data_len >> 2;
buf_len = max(cmd_len, resp_len);
buf = kzalloc(buf_len << 2, GFP_KERNEL);
if (!buf)
@@ -312,11 +336,23 @@ static int occ_putsram(struct occ *occ, u32 address, const void *data,
*/
buf[0] = cpu_to_be32(cmd_len);
buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
buf[2] = cpu_to_be32(1);
buf[3] = cpu_to_be32(address);
buf[4] = cpu_to_be32(data_len);
memcpy(&buf[5], data, len);
switch (occ->version) {
default:
case occ_p9:
buf[2] = cpu_to_be32(1); /* Normal mode */
buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);
break;
case occ_p10:
idx = 1;
buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
buf[3] = 0;
buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);
break;
}
buf[4 + idx] = cpu_to_be32(data_len);
memcpy(&buf[5 + idx], data, len);
rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
if (rc)
@@ -356,21 +392,35 @@ free:
static int occ_trigger_attn(struct occ *occ)
{
__be32 buf[OCC_SBE_STATUS_WORDS];
size_t resp_len, resp_data_len;
int rc;
size_t cmd_len, resp_len, resp_data_len;
int idx = 0, rc;
BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 7);
BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 8);
resp_len = OCC_SBE_STATUS_WORDS;
buf[0] = cpu_to_be32(0x5 + 0x2); /* Chip-op length in words */
buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
buf[2] = cpu_to_be32(0x3); /* Mode: Circular */
buf[3] = cpu_to_be32(0x0); /* Address: ignore in mode 3 */
buf[4] = cpu_to_be32(0x8); /* Data length in bytes */
buf[5] = cpu_to_be32(0x20010000); /* Trigger OCC attention */
buf[6] = 0;
switch (occ->version) {
default:
case occ_p9:
cmd_len = 7;
buf[2] = cpu_to_be32(3); /* Circular mode */
buf[3] = 0;
break;
case occ_p10:
idx = 1;
cmd_len = 8;
buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */
buf[3] = 0;
buf[4] = 0;
break;
}
rc = sbefifo_submit(occ->sbefifo, buf, 7, buf, &resp_len);
buf[0] = cpu_to_be32(cmd_len); /* Chip-op length in words */
buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
buf[4 + idx] = cpu_to_be32(8); /* Data length in bytes */
buf[5 + idx] = cpu_to_be32(0x20010000); /* Trigger OCC attention */
buf[6 + idx] = 0;
rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
if (rc)
goto error;
@@ -429,7 +479,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
/* Extract the seq_no from the command (first byte) */
seq_no = *(const u8 *)request;
rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
rc = occ_putsram(occ, request, req_len);
if (rc)
goto done;
@@ -440,7 +490,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
/* Read occ response header */
start = jiffies;
do {
rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR, resp, 8);
rc = occ_getsram(occ, 0, resp, 8);
if (rc)
goto done;
@@ -476,8 +526,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
/* Grab the rest */
if (resp_data_length > 1) {
/* already got 3 bytes resp, also need 2 bytes checksum */
rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR + 8,
&resp->data[3], resp_data_length - 1);
rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1);
if (rc)
goto done;
}
@@ -517,6 +566,7 @@ static int occ_probe(struct platform_device *pdev)
if (!occ)
return -ENOMEM;
occ->version = (uintptr_t)of_device_get_match_data(dev);
occ->dev = dev;
occ->sbefifo = dev->parent;
mutex_init(&occ->occ_lock);
@@ -575,7 +625,14 @@ static int occ_remove(struct platform_device *pdev)
}
static const struct of_device_id occ_match[] = {
{ .compatible = "ibm,p9-occ" },
{
.compatible = "ibm,p9-occ",
.data = (void *)occ_p9
},
{
.compatible = "ibm,p10-occ",
.data = (void *)occ_p10
},
{ },
};

View File

@@ -138,7 +138,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
}
pfdevfreq->devfreq = devfreq;
cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
cooling = devfreq_cooling_em_register(devfreq, NULL);
if (IS_ERR(cooling))
DRM_DEV_INFO(dev, "Failed to register cooling device\n");
else

View File

@@ -449,6 +449,19 @@ config SENSORS_CORSAIR_CPRO
This driver can also be built as a module. If so, the module
will be called corsair-cpro.
config SENSORS_CORSAIR_PSU
tristate "Corsair PSU HID controller"
depends on HID
help
If you say yes here you get support for Corsair PSUs with a HID
interface.
Currently this driver supports the (RM/HX)550i, (RM/HX)650i,
(RM/HX)750i, (RM/HX)850i, (RM/HX)1000i and HX1200i power supplies
by Corsair.
This driver can also be built as a module. If so, the module
will be called corsair-psu.
config SENSORS_DRIVETEMP
tristate "Hard disk drives with temperature sensors"
depends on SCSI && ATA
@@ -858,6 +871,18 @@ config SENSORS_LTC2990
This driver can also be built as a module. If so, the module will
be called ltc2990.
config SENSORS_LTC2992
tristate "Linear Technology LTC2992"
depends on I2C
depends on GPIOLIB
help
If you say yes here you get support for Linear Technology LTC2992
I2C System Monitor. The LTC2992 measures current, voltage, and
power of two supplies.
This driver can also be built as a module. If so, the module will
be called ltc2992.
config SENSORS_LTC4151
tristate "Linear Technology LTC4151"
depends on I2C
@@ -937,6 +962,15 @@ config SENSORS_MAX1111
This driver can also be built as a module. If so, the module
will be called max1111.
config SENSORS_MAX127
tristate "Maxim MAX127 12-bit 8-channel Data Acquisition System"
depends on I2C
help
Say y here to support Maxim's MAX127 DAS chips.
This driver can also be built as a module. If so, the module
will be called max127.
config SENSORS_MAX16065
tristate "Maxim MAX16065 System Manager and compatibles"
depends on I2C
@@ -1499,6 +1533,16 @@ config SENSORS_SL28CPLD
This driver can also be built as a module. If so, the module
will be called sl28cpld-hwmon.
config SENSORS_SBTSI
tristate "Emulated SB-TSI temperature sensor"
depends on I2C
help
If you say yes here you get support for emulated temperature
sensors on AMD SoCs with SB-TSI interface connected to a BMC device.
This driver can also be built as a module. If so, the module will
be called sbtsi_temp.
config SENSORS_SHT15
tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
depends on GPIOLIB || COMPILE_TEST

View File

@@ -57,6 +57,7 @@ obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o
obj-$(CONFIG_SENSORS_BT1_PVT) += bt1-pvt.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_CORSAIR_CPRO) += corsair-cpro.o
obj-$(CONFIG_SENSORS_CORSAIR_PSU) += corsair-psu.o
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o
@@ -118,6 +119,7 @@ obj-$(CONFIG_SENSORS_LTC2947) += ltc2947-core.o
obj-$(CONFIG_SENSORS_LTC2947_I2C) += ltc2947-i2c.o
obj-$(CONFIG_SENSORS_LTC2947_SPI) += ltc2947-spi.o
obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o
obj-$(CONFIG_SENSORS_LTC2992) += ltc2992.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o
@@ -126,6 +128,7 @@ obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_LTQ_CPUTEMP) += ltq-cputemp.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX127) += max127.o
obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
@@ -158,6 +161,7 @@ obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o

View File

@@ -263,7 +263,7 @@ static ssize_t max_alarm_show(struct device *dev,
static umode_t abx500_attrs_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct abx500_temp *data = dev_get_drvdata(dev);
if (data->ops.is_visible)

View File

@@ -725,8 +725,10 @@ static void free_capabilities(struct acpi_power_meter_resource *resource)
int i;
str = &resource->model_number;
for (i = 0; i < 3; i++, str++)
for (i = 0; i < 3; i++, str++) {
kfree(*str);
*str = NULL;
}
}
static int read_capabilities(struct acpi_power_meter_resource *resource)
@@ -801,9 +803,7 @@ static int read_capabilities(struct acpi_power_meter_resource *resource)
dev_info(&resource->acpi_dev->dev, "Found ACPI power meter.\n");
goto end;
error:
str = &resource->model_number;
for (i = 0; i < 3; i++, str++)
kfree(*str);
free_capabilities(resource);
end:
kfree(buffer.pointer);
return res;
@@ -874,7 +874,6 @@ static int acpi_power_meter_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_POWER_METER_CLASS);
device->driver_data = resource;
free_capabilities(resource);
res = read_capabilities(resource);
if (res)
goto exit_free;

View File

@@ -25,11 +25,11 @@
/**
* struct adm1177_state - driver instance specific data
* @client pointer to i2c client
* @reg regulator info for the the power supply of the device
* @r_sense_uohm current sense resistor value
* @alert_threshold_ua current limit for shutdown
* @vrange_high internal voltage divider
* @client: pointer to i2c client
* @reg: regulator info for the power supply of the device
* @r_sense_uohm: current sense resistor value
* @alert_threshold_ua: current limit for shutdown
* @vrange_high: internal voltage divider
*/
struct adm1177_state {
struct i2c_client *client;

View File

@@ -270,37 +270,11 @@ static int adt7470_update_thread(void *p)
return 0;
}
static struct adt7470_data *adt7470_update_device(struct device *dev)
static int adt7470_update_sensors(struct adt7470_data *data)
{
struct adt7470_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
unsigned long local_jiffies = jiffies;
u8 cfg;
int i;
int need_sensors = 1;
int need_limits = 1;
/*
* Figure out if we need to update the shadow registers.
* Lockless means that we may occasionally report out of
* date data.
*/
if (time_before(local_jiffies, data->sensors_last_updated +
SENSOR_REFRESH_INTERVAL) &&
data->sensors_valid)
need_sensors = 0;
if (time_before(local_jiffies, data->limits_last_updated +
LIMIT_REFRESH_INTERVAL) &&
data->limits_valid)
need_limits = 0;
if (!need_sensors && !need_limits)
return data;
mutex_lock(&data->lock);
if (!need_sensors)
goto no_sensor_update;
if (!data->temperatures_probed)
adt7470_read_temperatures(client, data);
@@ -352,12 +326,13 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
data->alarms_mask = adt7470_read_word_data(client,
ADT7470_REG_ALARM1_MASK);
data->sensors_last_updated = local_jiffies;
data->sensors_valid = 1;
return 0;
}
no_sensor_update:
if (!need_limits)
goto out;
static int adt7470_update_limits(struct adt7470_data *data)
{
struct i2c_client *client = data->client;
int i;
for (i = 0; i < ADT7470_TEMP_COUNT; i++) {
data->temp_min[i] = i2c_smbus_read_byte_data(client,
@@ -382,12 +357,55 @@ no_sensor_update:
ADT7470_REG_PWM_TMIN(i));
}
data->limits_last_updated = local_jiffies;
data->limits_valid = 1;
return 0;
}
static struct adt7470_data *adt7470_update_device(struct device *dev)
{
struct adt7470_data *data = dev_get_drvdata(dev);
unsigned long local_jiffies = jiffies;
int need_sensors = 1;
int need_limits = 1;
int err;
/*
* Figure out if we need to update the shadow registers.
* Lockless means that we may occasionally report out of
* date data.
*/
if (time_before(local_jiffies, data->sensors_last_updated +
SENSOR_REFRESH_INTERVAL) &&
data->sensors_valid)
need_sensors = 0;
if (time_before(local_jiffies, data->limits_last_updated +
LIMIT_REFRESH_INTERVAL) &&
data->limits_valid)
need_limits = 0;
if (!need_sensors && !need_limits)
return data;
mutex_lock(&data->lock);
if (need_sensors) {
err = adt7470_update_sensors(data);
if (err < 0)
goto out;
data->sensors_last_updated = local_jiffies;
data->sensors_valid = 1;
}
if (need_limits) {
err = adt7470_update_limits(data);
if (err < 0)
goto out;
data->limits_last_updated = local_jiffies;
data->limits_valid = 1;
}
out:
mutex_unlock(&data->lock);
return data;
return err < 0 ? ERR_PTR(err) : data;
}
static ssize_t auto_update_interval_show(struct device *dev,
@@ -395,6 +413,10 @@ static ssize_t auto_update_interval_show(struct device *dev,
char *buf)
{
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->auto_update_interval);
}
@@ -422,6 +444,10 @@ static ssize_t num_temp_sensors_show(struct device *dev,
char *buf)
{
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->num_temp_sensors);
}
@@ -451,6 +477,10 @@ static ssize_t temp_min_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
}
@@ -483,6 +513,10 @@ static ssize_t temp_max_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
}
@@ -515,6 +549,10 @@ static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
}
@@ -524,6 +562,9 @@ static ssize_t alarm_mask_show(struct device *dev,
{
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%x\n", data->alarms_mask);
}
@@ -554,6 +595,9 @@ static ssize_t fan_max_show(struct device *dev,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
if (FAN_DATA_VALID(data->fan_max[attr->index]))
return sprintf(buf, "%d\n",
FAN_PERIOD_TO_RPM(data->fan_max[attr->index]));
@@ -590,6 +634,9 @@ static ssize_t fan_min_show(struct device *dev,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
if (FAN_DATA_VALID(data->fan_min[attr->index]))
return sprintf(buf, "%d\n",
FAN_PERIOD_TO_RPM(data->fan_min[attr->index]));
@@ -626,6 +673,9 @@ static ssize_t fan_show(struct device *dev, struct device_attribute *devattr,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
if (FAN_DATA_VALID(data->fan[attr->index]))
return sprintf(buf, "%d\n",
FAN_PERIOD_TO_RPM(data->fan[attr->index]));
@@ -637,6 +687,10 @@ static ssize_t force_pwm_max_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->force_pwm_max);
}
@@ -670,6 +724,10 @@ static ssize_t pwm_show(struct device *dev, struct device_attribute *devattr,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->pwm[attr->index]);
}
@@ -763,6 +821,10 @@ static ssize_t pwm_max_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
}
@@ -794,6 +856,10 @@ static ssize_t pwm_min_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
}
@@ -825,6 +891,10 @@ static ssize_t pwm_tmax_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
/* the datasheet says that tmax = tmin + 20C */
return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
}
@@ -834,6 +904,10 @@ static ssize_t pwm_tmin_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
}
@@ -866,6 +940,10 @@ static ssize_t pwm_auto_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
}
@@ -911,8 +989,12 @@ static ssize_t pwm_auto_temp_show(struct device *dev,
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7470_data *data = adt7470_update_device(dev);
u8 ctrl = data->pwm_auto_temp[attr->index];
u8 ctrl;
if (IS_ERR(data))
return PTR_ERR(data);
ctrl = data->pwm_auto_temp[attr->index];
if (ctrl)
return sprintf(buf, "%d\n", 1 << (ctrl - 1));
else

View File

@@ -331,6 +331,7 @@ static struct platform_device *amd_energy_platdev;
static const struct x86_cpu_id cpu_ids[] __initconst = {
X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x17, 0x31, NULL),
X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x19, 0x01, NULL),
{}
};
MODULE_DEVICE_TABLE(x86cpu, cpu_ids);

View File

@@ -1299,6 +1299,10 @@ static const struct dmi_system_id applesmc_whitelist[] __initconst = {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "iMac") },
},
{ applesmc_dmi_match, "Apple Xserve", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "Xserve") },
},
{ .ident = NULL }
};

600
drivers/hwmon/corsair-psu.c Normal file
View File

@@ -0,0 +1,600 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* corsair-psu.c - Linux driver for Corsair power supplies with HID sensors interface
* Copyright (C) 2020 Wilken Gottwalt <wilken.gottwalt@posteo.net>
*/
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/hid.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
/*
* Corsair protocol for PSUs
*
* message size = 64 bytes (request and response, little endian)
* request:
* [length][command][param0][param1][paramX]...
* reply:
* [echo of length][echo of command][data0][data1][dataX]...
*
* - commands are byte sized opcodes
* - length is the sum of all bytes of the commands/params
* - the micro-controller of most of these PSUs support concatenation in the request and reply,
* but it is better to not rely on this (it is also hard to parse)
* - the driver uses raw events to be accessible from userspace (though this is not really
* supported, it is just there for convenience, may be removed in the future)
* - a reply always start with the length and command in the same order the request used it
* - length of the reply data is specific to the command used
* - some of the commands work on a rail and can be switched to a specific rail (0 = 12v,
* 1 = 5v, 2 = 3.3v)
* - the format of the init command 0xFE is swapped length/command bytes
* - parameter bytes amount and values are specific to the command (rail setting is the only
* for now that uses non-zero values)
* - there are much more commands, especially for configuring the device, but they are not
* supported because a wrong command/length can lockup the micro-controller
* - the driver supports debugfs for values not fitting into the hwmon class
* - not every device class (HXi, RMi or AXi) supports all commands
* - it is a pure sensors reading driver (will not support configuring)
*/
#define DRIVER_NAME "corsair-psu"
#define REPLY_SIZE 16 /* max length of a reply to a single command */
#define CMD_BUFFER_SIZE 64
#define CMD_TIMEOUT_MS 250
#define SECONDS_PER_HOUR (60 * 60)
#define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
#define PSU_CMD_SELECT_RAIL 0x00 /* expects length 2 */
#define PSU_CMD_IN_VOLTS 0x88 /* the rest of the commands expect length 3 */
#define PSU_CMD_IN_AMPS 0x89
#define PSU_CMD_RAIL_OUT_VOLTS 0x8B
#define PSU_CMD_RAIL_AMPS 0x8C
#define PSU_CMD_TEMP0 0x8D
#define PSU_CMD_TEMP1 0x8E
#define PSU_CMD_FAN 0x90
#define PSU_CMD_RAIL_WATTS 0x96
#define PSU_CMD_VEND_STR 0x99
#define PSU_CMD_PROD_STR 0x9A
#define PSU_CMD_TOTAL_WATTS 0xEE
#define PSU_CMD_TOTAL_UPTIME 0xD1
#define PSU_CMD_UPTIME 0xD2
#define PSU_CMD_INIT 0xFE
#define L_IN_VOLTS "v_in"
#define L_OUT_VOLTS_12V "v_out +12v"
#define L_OUT_VOLTS_5V "v_out +5v"
#define L_OUT_VOLTS_3_3V "v_out +3.3v"
#define L_IN_AMPS "curr in"
#define L_AMPS_12V "curr +12v"
#define L_AMPS_5V "curr +5v"
#define L_AMPS_3_3V "curr +3.3v"
#define L_FAN "psu fan"
#define L_TEMP0 "vrm temp"
#define L_TEMP1 "case temp"
#define L_WATTS "power total"
#define L_WATTS_12V "power +12v"
#define L_WATTS_5V "power +5v"
#define L_WATTS_3_3V "power +3.3v"
static const char *const label_watts[] = {
L_WATTS,
L_WATTS_12V,
L_WATTS_5V,
L_WATTS_3_3V
};
static const char *const label_volts[] = {
L_IN_VOLTS,
L_OUT_VOLTS_12V,
L_OUT_VOLTS_5V,
L_OUT_VOLTS_3_3V
};
static const char *const label_amps[] = {
L_IN_AMPS,
L_AMPS_12V,
L_AMPS_5V,
L_AMPS_3_3V
};
struct corsairpsu_data {
struct hid_device *hdev;
struct device *hwmon_dev;
struct dentry *debugfs;
struct completion wait_completion;
struct mutex lock; /* for locking access to cmd_buffer */
u8 *cmd_buffer;
char vendor[REPLY_SIZE];
char product[REPLY_SIZE];
};
/* some values are SMBus LINEAR11 data which need a conversion */
static int corsairpsu_linear11_to_int(const int val)
{
int exp = (val & 0xFFFF) >> 0x0B;
int mant = val & 0x7FF;
int i;
if (exp > 0x0F)
exp -= 0x20;
if (mant > 0x3FF)
mant -= 0x800;
if ((mant & 0x01) == 1)
++mant;
if (exp < 0) {
for (i = 0; i < -exp; ++i)
mant /= 2;
} else {
for (i = 0; i < exp; ++i)
mant *= 2;
}
return mant;
}
static int corsairpsu_usb_cmd(struct corsairpsu_data *priv, u8 p0, u8 p1, u8 p2, void *data)
{
unsigned long time;
int ret;
memset(priv->cmd_buffer, 0, CMD_BUFFER_SIZE);
priv->cmd_buffer[0] = p0;
priv->cmd_buffer[1] = p1;
priv->cmd_buffer[2] = p2;
reinit_completion(&priv->wait_completion);
ret = hid_hw_output_report(priv->hdev, priv->cmd_buffer, CMD_BUFFER_SIZE);
if (ret < 0)
return ret;
time = wait_for_completion_timeout(&priv->wait_completion,
msecs_to_jiffies(CMD_TIMEOUT_MS));
if (!time)
return -ETIMEDOUT;
/*
* at the start of the reply is an echo of the send command/length in the same order it
* was send, not every command is supported on every device class, if a command is not
* supported, the length value in the reply is okay, but the command value is set to 0
*/
if (p0 != priv->cmd_buffer[0] || p1 != priv->cmd_buffer[1])
return -EOPNOTSUPP;
if (data)
memcpy(data, priv->cmd_buffer + 2, REPLY_SIZE);
return 0;
}
static int corsairpsu_init(struct corsairpsu_data *priv)
{
/*
* PSU_CMD_INIT uses swapped length/command and expects 2 parameter bytes, this command
* actually generates a reply, but we don't need it
*/
return corsairpsu_usb_cmd(priv, PSU_CMD_INIT, 3, 0, NULL);
}
static int corsairpsu_fwinfo(struct corsairpsu_data *priv)
{
int ret;
ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_VEND_STR, 0, priv->vendor);
if (ret < 0)
return ret;
ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_PROD_STR, 0, priv->product);
if (ret < 0)
return ret;
return 0;
}
static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, void *data)
{
int ret;
mutex_lock(&priv->lock);
switch (cmd) {
case PSU_CMD_RAIL_OUT_VOLTS:
case PSU_CMD_RAIL_AMPS:
case PSU_CMD_RAIL_WATTS:
ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL);
if (ret < 0)
goto cmd_fail;
break;
default:
break;
}
ret = corsairpsu_usb_cmd(priv, 3, cmd, 0, data);
cmd_fail:
mutex_unlock(&priv->lock);
return ret;
}
static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, long *val)
{
u8 data[REPLY_SIZE];
long tmp;
int ret;
ret = corsairpsu_request(priv, cmd, rail, data);
if (ret < 0)
return ret;
/*
* the biggest value here comes from the uptime command and to exceed MAXINT total uptime
* needs to be about 68 years, the rest are u16 values and the biggest value coming out of
* the LINEAR11 conversion are the watts values which are about 1200 for the strongest psu
* supported (HX1200i)
*/
tmp = ((long)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
switch (cmd) {
case PSU_CMD_IN_VOLTS:
case PSU_CMD_IN_AMPS:
case PSU_CMD_RAIL_OUT_VOLTS:
case PSU_CMD_RAIL_AMPS:
case PSU_CMD_TEMP0:
case PSU_CMD_TEMP1:
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF) * 1000;
break;
case PSU_CMD_FAN:
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF);
break;
case PSU_CMD_RAIL_WATTS:
case PSU_CMD_TOTAL_WATTS:
*val = corsairpsu_linear11_to_int(tmp & 0xFFFF) * 1000000;
break;
case PSU_CMD_TOTAL_UPTIME:
case PSU_CMD_UPTIME:
*val = tmp;
break;
default:
ret = -EOPNOTSUPP;
break;
}
return ret;
}
static umode_t corsairpsu_hwmon_ops_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
if (type == hwmon_temp && (attr == hwmon_temp_input || attr == hwmon_temp_label))
return 0444;
else if (type == hwmon_fan && (attr == hwmon_fan_input || attr == hwmon_fan_label))
return 0444;
else if (type == hwmon_power && (attr == hwmon_power_input || attr == hwmon_power_label))
return 0444;
else if (type == hwmon_in && (attr == hwmon_in_input || attr == hwmon_in_label))
return 0444;
else if (type == hwmon_curr && (attr == hwmon_curr_input || attr == hwmon_curr_label))
return 0444;
return 0;
}
static int corsairpsu_hwmon_ops_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct corsairpsu_data *priv = dev_get_drvdata(dev);
int ret;
if (type == hwmon_temp && attr == hwmon_temp_input && channel < 2) {
ret = corsairpsu_get_value(priv, channel ? PSU_CMD_TEMP1 : PSU_CMD_TEMP0, channel,
val);
} else if (type == hwmon_fan && attr == hwmon_fan_input) {
ret = corsairpsu_get_value(priv, PSU_CMD_FAN, 0, val);
} else if (type == hwmon_power && attr == hwmon_power_input) {
switch (channel) {
case 0:
ret = corsairpsu_get_value(priv, PSU_CMD_TOTAL_WATTS, 0, val);
break;
case 1 ... 3:
ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val);
break;
default:
return -EOPNOTSUPP;
}
} else if (type == hwmon_in && attr == hwmon_in_input) {
switch (channel) {
case 0:
ret = corsairpsu_get_value(priv, PSU_CMD_IN_VOLTS, 0, val);
break;
case 1 ... 3:
ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_OUT_VOLTS, channel - 1, val);
break;
default:
return -EOPNOTSUPP;
}
} else if (type == hwmon_curr && attr == hwmon_curr_input) {
switch (channel) {
case 0:
ret = corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, val);
break;
case 1 ... 3:
ret = corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val);
break;
default:
return -EOPNOTSUPP;
}
} else {
return -EOPNOTSUPP;
}
if (ret < 0)
return ret;
return 0;
}
static int corsairpsu_hwmon_ops_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
if (type == hwmon_temp && attr == hwmon_temp_label) {
*str = channel ? L_TEMP1 : L_TEMP0;
return 0;
} else if (type == hwmon_fan && attr == hwmon_fan_label) {
*str = L_FAN;
return 0;
} else if (type == hwmon_power && attr == hwmon_power_label && channel < 4) {
*str = label_watts[channel];
return 0;
} else if (type == hwmon_in && attr == hwmon_in_label && channel < 4) {
*str = label_volts[channel];
return 0;
} else if (type == hwmon_curr && attr == hwmon_curr_label && channel < 4) {
*str = label_amps[channel];
return 0;
}
return -EOPNOTSUPP;
}
static const struct hwmon_ops corsairpsu_hwmon_ops = {
.is_visible = corsairpsu_hwmon_ops_is_visible,
.read = corsairpsu_hwmon_ops_read,
.read_string = corsairpsu_hwmon_ops_read_string,
};
static const struct hwmon_channel_info *corsairpsu_info[] = {
HWMON_CHANNEL_INFO(chip,
HWMON_C_REGISTER_TZ),
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL),
HWMON_CHANNEL_INFO(power,
HWMON_P_INPUT | HWMON_P_LABEL,
HWMON_P_INPUT | HWMON_P_LABEL,
HWMON_P_INPUT | HWMON_P_LABEL,
HWMON_P_INPUT | HWMON_P_LABEL),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL),
HWMON_CHANNEL_INFO(curr,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL),
NULL
};
static const struct hwmon_chip_info corsairpsu_chip_info = {
.ops = &corsairpsu_hwmon_ops,
.info = corsairpsu_info,
};
#ifdef CONFIG_DEBUG_FS
static void print_uptime(struct seq_file *seqf, u8 cmd)
{
struct corsairpsu_data *priv = seqf->private;
long val;
int ret;
ret = corsairpsu_get_value(priv, cmd, 0, &val);
if (ret < 0) {
seq_puts(seqf, "N/A\n");
return;
}
if (val > SECONDS_PER_DAY) {
seq_printf(seqf, "%ld day(s), %02ld:%02ld:%02ld\n", val / SECONDS_PER_DAY,
val % SECONDS_PER_DAY / SECONDS_PER_HOUR, val % SECONDS_PER_HOUR / 60,
val % 60);
return;
}
seq_printf(seqf, "%02ld:%02ld:%02ld\n", val % SECONDS_PER_DAY / SECONDS_PER_HOUR,
val % SECONDS_PER_HOUR / 60, val % 60);
}
static int uptime_show(struct seq_file *seqf, void *unused)
{
print_uptime(seqf, PSU_CMD_UPTIME);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(uptime);
static int uptime_total_show(struct seq_file *seqf, void *unused)
{
print_uptime(seqf, PSU_CMD_TOTAL_UPTIME);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(uptime_total);
static int vendor_show(struct seq_file *seqf, void *unused)
{
struct corsairpsu_data *priv = seqf->private;
seq_printf(seqf, "%s\n", priv->vendor);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(vendor);
static int product_show(struct seq_file *seqf, void *unused)
{
struct corsairpsu_data *priv = seqf->private;
seq_printf(seqf, "%s\n", priv->product);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(product);
static void corsairpsu_debugfs_init(struct corsairpsu_data *priv)
{
char name[32];
scnprintf(name, sizeof(name), "%s-%s", DRIVER_NAME, dev_name(&priv->hdev->dev));
priv->debugfs = debugfs_create_dir(name, NULL);
debugfs_create_file("uptime", 0444, priv->debugfs, priv, &uptime_fops);
debugfs_create_file("uptime_total", 0444, priv->debugfs, priv, &uptime_total_fops);
debugfs_create_file("vendor", 0444, priv->debugfs, priv, &vendor_fops);
debugfs_create_file("product", 0444, priv->debugfs, priv, &product_fops);
}
#else
static void corsairpsu_debugfs_init(struct corsairpsu_data *priv)
{
}
#endif
static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct corsairpsu_data *priv;
int ret;
priv = devm_kzalloc(&hdev->dev, sizeof(struct corsairpsu_data), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->cmd_buffer = devm_kmalloc(&hdev->dev, CMD_BUFFER_SIZE, GFP_KERNEL);
if (!priv->cmd_buffer)
return -ENOMEM;
ret = hid_parse(hdev);
if (ret)
return ret;
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret)
return ret;
ret = hid_hw_open(hdev);
if (ret)
goto fail_and_stop;
priv->hdev = hdev;
hid_set_drvdata(hdev, priv);
mutex_init(&priv->lock);
init_completion(&priv->wait_completion);
hid_device_io_start(hdev);
ret = corsairpsu_init(priv);
if (ret < 0) {
dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret);
goto fail_and_stop;
}
ret = corsairpsu_fwinfo(priv);
if (ret < 0) {
dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret);
goto fail_and_stop;
}
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv,
&corsairpsu_chip_info, 0);
if (IS_ERR(priv->hwmon_dev)) {
ret = PTR_ERR(priv->hwmon_dev);
goto fail_and_close;
}
corsairpsu_debugfs_init(priv);
return 0;
fail_and_close:
hid_hw_close(hdev);
fail_and_stop:
hid_hw_stop(hdev);
return ret;
}
static void corsairpsu_remove(struct hid_device *hdev)
{
struct corsairpsu_data *priv = hid_get_drvdata(hdev);
debugfs_remove_recursive(priv->debugfs);
hwmon_device_unregister(priv->hwmon_dev);
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
static int corsairpsu_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
int size)
{
struct corsairpsu_data *priv = hid_get_drvdata(hdev);
if (completion_done(&priv->wait_completion))
return 0;
memcpy(priv->cmd_buffer, data, min(CMD_BUFFER_SIZE, size));
complete(&priv->wait_completion);
return 0;
}
static const struct hid_device_id corsairpsu_idtable[] = {
{ HID_USB_DEVICE(0x1b1c, 0x1c03) }, /* Corsair HX550i */
{ HID_USB_DEVICE(0x1b1c, 0x1c04) }, /* Corsair HX650i */
{ HID_USB_DEVICE(0x1b1c, 0x1c05) }, /* Corsair HX750i */
{ HID_USB_DEVICE(0x1b1c, 0x1c06) }, /* Corsair HX850i */
{ HID_USB_DEVICE(0x1b1c, 0x1c07) }, /* Corsair HX1000i */
{ HID_USB_DEVICE(0x1b1c, 0x1c08) }, /* Corsair HX1200i */
{ HID_USB_DEVICE(0x1b1c, 0x1c09) }, /* Corsair RM550i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0a) }, /* Corsair RM650i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0b) }, /* Corsair RM750i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0c) }, /* Corsair RM850i */
{ HID_USB_DEVICE(0x1b1c, 0x1c0d) }, /* Corsair RM1000i */
{ },
};
MODULE_DEVICE_TABLE(hid, corsairpsu_idtable);
static struct hid_driver corsairpsu_driver = {
.name = DRIVER_NAME,
.id_table = corsairpsu_idtable,
.probe = corsairpsu_probe,
.remove = corsairpsu_remove,
.raw_event = corsairpsu_raw_event,
};
module_hid_driver(corsairpsu_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wilken Gottwalt <wilken.gottwalt@posteo.net>");
MODULE_DESCRIPTION("Linux driver for Corsair power supplies with HID sensors interface");

View File

@@ -10,7 +10,7 @@
* hwmon: Driver for SCSI/ATA temperature sensors
* by Constantin Baranov <const@mimas.ru>, submitted September 2009
*
* This drive supports reporting the temperatire of SATA drives. It can be
* This drive supports reporting the temperature of SATA drives. It can be
* easily extended to report the temperature of SCSI drives.
*
* The primary means to read drive temperatures and temperature limits

View File

@@ -240,7 +240,7 @@ static int get_sensor_index_attr(const char *name, u32 *index, char *attr)
if (err)
return err;
strncpy(attr, dash_pos + 1, MAX_ATTR_LEN);
strscpy(attr, dash_pos + 1, MAX_ATTR_LEN);
return 0;
}

View File

@@ -169,7 +169,7 @@ static const struct of_device_id iio_hwmon_of_match[] = {
};
MODULE_DEVICE_TABLE(of, iio_hwmon_of_match);
static struct platform_driver __refdata iio_hwmon_driver = {
static struct platform_driver iio_hwmon_driver = {
.driver = {
.name = "iio_hwmon",
.of_match_table = iio_hwmon_of_match,

View File

@@ -139,7 +139,7 @@ static inline bool ina3221_is_enabled(struct ina3221_data *ina, int channel)
(ina->reg_config & INA3221_CONFIG_CHx_EN(channel));
}
/**
/*
* Helper function to return the resistor value for current summation.
*
* There is a condition to calculate current summation -- all the shunt
@@ -489,7 +489,7 @@ static int ina3221_write_enable(struct device *dev, int channel, bool enable)
/* For enabling routine, increase refcount and resume() at first */
if (enable) {
ret = pm_runtime_get_sync(ina->pm_dev);
ret = pm_runtime_resume_and_get(ina->pm_dev);
if (ret < 0) {
dev_err(dev, "Failed to get PM runtime\n");
return ret;

971
drivers/hwmon/ltc2992.c Normal file
View File

@@ -0,0 +1,971 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
/*
* LTC2992 - Dual Wide Range Power Monitor
*
* Copyright 2020 Analog Devices Inc.
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
#define LTC2992_CTRLB 0x01
#define LTC2992_FAULT1 0x03
#define LTC2992_POWER1 0x05
#define LTC2992_POWER1_MAX 0x08
#define LTC2992_POWER1_MIN 0x0B
#define LTC2992_POWER1_MAX_THRESH 0x0E
#define LTC2992_POWER1_MIN_THRESH 0x11
#define LTC2992_DSENSE1 0x14
#define LTC2992_DSENSE1_MAX 0x16
#define LTC2992_DSENSE1_MIN 0x18
#define LTC2992_DSENSE1_MAX_THRESH 0x1A
#define LTC2992_DSENSE1_MIN_THRESH 0x1C
#define LTC2992_SENSE1 0x1E
#define LTC2992_SENSE1_MAX 0x20
#define LTC2992_SENSE1_MIN 0x22
#define LTC2992_SENSE1_MAX_THRESH 0x24
#define LTC2992_SENSE1_MIN_THRESH 0x26
#define LTC2992_G1 0x28
#define LTC2992_G1_MAX 0x2A
#define LTC2992_G1_MIN 0x2C
#define LTC2992_G1_MAX_THRESH 0x2E
#define LTC2992_G1_MIN_THRESH 0x30
#define LTC2992_FAULT2 0x35
#define LTC2992_G2 0x5A
#define LTC2992_G2_MAX 0x5C
#define LTC2992_G2_MIN 0x5E
#define LTC2992_G2_MAX_THRESH 0x60
#define LTC2992_G2_MIN_THRESH 0x62
#define LTC2992_G3 0x64
#define LTC2992_G3_MAX 0x66
#define LTC2992_G3_MIN 0x68
#define LTC2992_G3_MAX_THRESH 0x6A
#define LTC2992_G3_MIN_THRESH 0x6C
#define LTC2992_G4 0x6E
#define LTC2992_G4_MAX 0x70
#define LTC2992_G4_MIN 0x72
#define LTC2992_G4_MAX_THRESH 0x74
#define LTC2992_G4_MIN_THRESH 0x76
#define LTC2992_FAULT3 0x92
#define LTC2992_GPIO_STATUS 0x95
#define LTC2992_GPIO_IO_CTRL 0x96
#define LTC2992_GPIO_CTRL 0x97
#define LTC2992_POWER(x) (LTC2992_POWER1 + ((x) * 0x32))
#define LTC2992_POWER_MAX(x) (LTC2992_POWER1_MAX + ((x) * 0x32))
#define LTC2992_POWER_MIN(x) (LTC2992_POWER1_MIN + ((x) * 0x32))
#define LTC2992_POWER_MAX_THRESH(x) (LTC2992_POWER1_MAX_THRESH + ((x) * 0x32))
#define LTC2992_POWER_MIN_THRESH(x) (LTC2992_POWER1_MIN_THRESH + ((x) * 0x32))
#define LTC2992_DSENSE(x) (LTC2992_DSENSE1 + ((x) * 0x32))
#define LTC2992_DSENSE_MAX(x) (LTC2992_DSENSE1_MAX + ((x) * 0x32))
#define LTC2992_DSENSE_MIN(x) (LTC2992_DSENSE1_MIN + ((x) * 0x32))
#define LTC2992_DSENSE_MAX_THRESH(x) (LTC2992_DSENSE1_MAX_THRESH + ((x) * 0x32))
#define LTC2992_DSENSE_MIN_THRESH(x) (LTC2992_DSENSE1_MIN_THRESH + ((x) * 0x32))
#define LTC2992_SENSE(x) (LTC2992_SENSE1 + ((x) * 0x32))
#define LTC2992_SENSE_MAX(x) (LTC2992_SENSE1_MAX + ((x) * 0x32))
#define LTC2992_SENSE_MIN(x) (LTC2992_SENSE1_MIN + ((x) * 0x32))
#define LTC2992_SENSE_MAX_THRESH(x) (LTC2992_SENSE1_MAX_THRESH + ((x) * 0x32))
#define LTC2992_SENSE_MIN_THRESH(x) (LTC2992_SENSE1_MIN_THRESH + ((x) * 0x32))
#define LTC2992_POWER_FAULT(x) (LTC2992_FAULT1 + ((x) * 0x32))
#define LTC2992_SENSE_FAULT(x) (LTC2992_FAULT1 + ((x) * 0x32))
#define LTC2992_DSENSE_FAULT(x) (LTC2992_FAULT1 + ((x) * 0x32))
/* CTRLB register bitfields */
#define LTC2992_RESET_HISTORY BIT(3)
/* FAULT1 FAULT2 registers common bitfields */
#define LTC2992_POWER_FAULT_MSK(x) (BIT(6) << (x))
#define LTC2992_DSENSE_FAULT_MSK(x) (BIT(4) << (x))
#define LTC2992_SENSE_FAULT_MSK(x) (BIT(2) << (x))
/* FAULT1 bitfields */
#define LTC2992_GPIO1_FAULT_MSK(x) (BIT(0) << (x))
/* FAULT2 bitfields */
#define LTC2992_GPIO2_FAULT_MSK(x) (BIT(0) << (x))
/* FAULT3 bitfields */
#define LTC2992_GPIO3_FAULT_MSK(x) (BIT(6) << (x))
#define LTC2992_GPIO4_FAULT_MSK(x) (BIT(4) << (x))
#define LTC2992_IADC_NANOV_LSB 12500
#define LTC2992_VADC_UV_LSB 25000
#define LTC2992_VADC_GPIO_UV_LSB 500
#define LTC2992_GPIO_NR 4
#define LTC2992_GPIO1_BIT 7
#define LTC2992_GPIO2_BIT 6
#define LTC2992_GPIO3_BIT 0
#define LTC2992_GPIO4_BIT 6
#define LTC2992_GPIO_BIT(x) (LTC2992_GPIO_NR - (x) - 1)
struct ltc2992_state {
struct i2c_client *client;
struct gpio_chip gc;
struct mutex gpio_mutex; /* lock for gpio access */
const char *gpio_names[LTC2992_GPIO_NR];
struct regmap *regmap;
u32 r_sense_uohm[2];
};
struct ltc2992_gpio_regs {
u8 data;
u8 max;
u8 min;
u8 max_thresh;
u8 min_thresh;
u8 alarm;
u8 min_alarm_msk;
u8 max_alarm_msk;
u8 ctrl;
u8 ctrl_bit;
};
static const struct ltc2992_gpio_regs ltc2992_gpio_addr_map[] = {
{
.data = LTC2992_G1,
.max = LTC2992_G1_MAX,
.min = LTC2992_G1_MIN,
.max_thresh = LTC2992_G1_MAX_THRESH,
.min_thresh = LTC2992_G1_MIN_THRESH,
.alarm = LTC2992_FAULT1,
.min_alarm_msk = LTC2992_GPIO1_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO1_FAULT_MSK(1),
.ctrl = LTC2992_GPIO_IO_CTRL,
.ctrl_bit = LTC2992_GPIO1_BIT,
},
{
.data = LTC2992_G2,
.max = LTC2992_G2_MAX,
.min = LTC2992_G2_MIN,
.max_thresh = LTC2992_G2_MAX_THRESH,
.min_thresh = LTC2992_G2_MIN_THRESH,
.alarm = LTC2992_FAULT2,
.min_alarm_msk = LTC2992_GPIO2_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO2_FAULT_MSK(1),
.ctrl = LTC2992_GPIO_IO_CTRL,
.ctrl_bit = LTC2992_GPIO2_BIT,
},
{
.data = LTC2992_G3,
.max = LTC2992_G3_MAX,
.min = LTC2992_G3_MIN,
.max_thresh = LTC2992_G3_MAX_THRESH,
.min_thresh = LTC2992_G3_MIN_THRESH,
.alarm = LTC2992_FAULT3,
.min_alarm_msk = LTC2992_GPIO3_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO3_FAULT_MSK(1),
.ctrl = LTC2992_GPIO_IO_CTRL,
.ctrl_bit = LTC2992_GPIO3_BIT,
},
{
.data = LTC2992_G4,
.max = LTC2992_G4_MAX,
.min = LTC2992_G4_MIN,
.max_thresh = LTC2992_G4_MAX_THRESH,
.min_thresh = LTC2992_G4_MIN_THRESH,
.alarm = LTC2992_FAULT3,
.min_alarm_msk = LTC2992_GPIO4_FAULT_MSK(0),
.max_alarm_msk = LTC2992_GPIO4_FAULT_MSK(1),
.ctrl = LTC2992_GPIO_CTRL,
.ctrl_bit = LTC2992_GPIO4_BIT,
},
};
static const char *ltc2992_gpio_names[LTC2992_GPIO_NR] = {
"GPIO1", "GPIO2", "GPIO3", "GPIO4",
};
static int ltc2992_read_reg(struct ltc2992_state *st, u8 addr, const u8 reg_len)
{
u8 regvals[4];
int val;
int ret;
int i;
ret = regmap_bulk_read(st->regmap, addr, regvals, reg_len);
if (ret < 0)
return ret;
val = 0;
for (i = 0; i < reg_len; i++)
val |= regvals[reg_len - i - 1] << (i * 8);
return val;
}
static int ltc2992_write_reg(struct ltc2992_state *st, u8 addr, const u8 reg_len, u32 val)
{
u8 regvals[4];
int i;
for (i = 0; i < reg_len; i++)
regvals[reg_len - i - 1] = (val >> (i * 8)) & 0xFF;
return regmap_bulk_write(st->regmap, addr, regvals, reg_len);
}
static int ltc2992_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct ltc2992_state *st = gpiochip_get_data(chip);
unsigned long gpio_status;
int reg;
mutex_lock(&st->gpio_mutex);
reg = ltc2992_read_reg(st, LTC2992_GPIO_STATUS, 1);
mutex_unlock(&st->gpio_mutex);
if (reg < 0)
return reg;
gpio_status = reg;
return !test_bit(LTC2992_GPIO_BIT(offset), &gpio_status);
}
static int ltc2992_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct ltc2992_state *st = gpiochip_get_data(chip);
unsigned long gpio_status;
unsigned int gpio_nr;
int reg;
mutex_lock(&st->gpio_mutex);
reg = ltc2992_read_reg(st, LTC2992_GPIO_STATUS, 1);
mutex_unlock(&st->gpio_mutex);
if (reg < 0)
return reg;
gpio_status = reg;
gpio_nr = 0;
for_each_set_bit_from(gpio_nr, mask, LTC2992_GPIO_NR) {
if (test_bit(LTC2992_GPIO_BIT(gpio_nr), &gpio_status))
set_bit(gpio_nr, bits);
}
return 0;
}
static void ltc2992_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct ltc2992_state *st = gpiochip_get_data(chip);
unsigned long gpio_ctrl;
int reg;
mutex_lock(&st->gpio_mutex);
reg = ltc2992_read_reg(st, ltc2992_gpio_addr_map[offset].ctrl, 1);
if (reg < 0) {
mutex_unlock(&st->gpio_mutex);
return;
}
gpio_ctrl = reg;
assign_bit(ltc2992_gpio_addr_map[offset].ctrl_bit, &gpio_ctrl, value);
ltc2992_write_reg(st, ltc2992_gpio_addr_map[offset].ctrl, 1, gpio_ctrl);
mutex_unlock(&st->gpio_mutex);
}
static void ltc2992_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask,
unsigned long *bits)
{
struct ltc2992_state *st = gpiochip_get_data(chip);
unsigned long gpio_ctrl_io = 0;
unsigned long gpio_ctrl = 0;
unsigned int gpio_nr;
for_each_set_bit(gpio_nr, mask, LTC2992_GPIO_NR) {
if (gpio_nr < 3)
assign_bit(ltc2992_gpio_addr_map[gpio_nr].ctrl_bit, &gpio_ctrl_io, true);
if (gpio_nr == 3)
assign_bit(ltc2992_gpio_addr_map[gpio_nr].ctrl_bit, &gpio_ctrl, true);
}
mutex_lock(&st->gpio_mutex);
ltc2992_write_reg(st, LTC2992_GPIO_IO_CTRL, 1, gpio_ctrl_io);
ltc2992_write_reg(st, LTC2992_GPIO_CTRL, 1, gpio_ctrl);
mutex_unlock(&st->gpio_mutex);
}
static int ltc2992_config_gpio(struct ltc2992_state *st)
{
const char *name = dev_name(&st->client->dev);
char *gpio_name;
int ret;
int i;
ret = ltc2992_write_reg(st, LTC2992_GPIO_IO_CTRL, 1, 0);
if (ret < 0)
return ret;
mutex_init(&st->gpio_mutex);
for (i = 0; i < ARRAY_SIZE(st->gpio_names); i++) {
gpio_name = devm_kasprintf(&st->client->dev, GFP_KERNEL, "ltc2992-%x-%s",
st->client->addr, ltc2992_gpio_names[i]);
if (!gpio_name)
return -ENOMEM;
st->gpio_names[i] = gpio_name;
}
st->gc.label = name;
st->gc.parent = &st->client->dev;
st->gc.owner = THIS_MODULE;
st->gc.base = -1;
st->gc.names = st->gpio_names;
st->gc.ngpio = ARRAY_SIZE(st->gpio_names);
st->gc.get = ltc2992_gpio_get;
st->gc.get_multiple = ltc2992_gpio_get_multiple;
st->gc.set = ltc2992_gpio_set;
st->gc.set_multiple = ltc2992_gpio_set_multiple;
ret = devm_gpiochip_add_data(&st->client->dev, &st->gc, st);
if (ret)
dev_err(&st->client->dev, "GPIO registering failed (%d)\n", ret);
return ret;
}
static umode_t ltc2992_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
int channel)
{
const struct ltc2992_state *st = data;
switch (type) {
case hwmon_chip:
switch (attr) {
case hwmon_chip_in_reset_history:
return 0200;
}
break;
case hwmon_in:
switch (attr) {
case hwmon_in_input:
case hwmon_in_lowest:
case hwmon_in_highest:
case hwmon_in_min_alarm:
case hwmon_in_max_alarm:
return 0444;
case hwmon_in_min:
case hwmon_in_max:
return 0644;
}
break;
case hwmon_curr:
switch (attr) {
case hwmon_curr_input:
case hwmon_curr_lowest:
case hwmon_curr_highest:
case hwmon_curr_min_alarm:
case hwmon_curr_max_alarm:
if (st->r_sense_uohm[channel])
return 0444;
break;
case hwmon_curr_min:
case hwmon_curr_max:
if (st->r_sense_uohm[channel])
return 0644;
break;
}
break;
case hwmon_power:
switch (attr) {
case hwmon_power_input:
case hwmon_power_input_lowest:
case hwmon_power_input_highest:
case hwmon_power_min_alarm:
case hwmon_power_max_alarm:
if (st->r_sense_uohm[channel])
return 0444;
break;
case hwmon_power_min:
case hwmon_power_max:
if (st->r_sense_uohm[channel])
return 0644;
break;
}
break;
default:
break;
}
return 0;
}
static int ltc2992_get_voltage(struct ltc2992_state *st, u32 reg, u32 scale, long *val)
{
int reg_val;
reg_val = ltc2992_read_reg(st, reg, 2);
if (reg_val < 0)
return reg_val;
reg_val = reg_val >> 4;
*val = DIV_ROUND_CLOSEST(reg_val * scale, 1000);
return 0;
}
static int ltc2992_set_voltage(struct ltc2992_state *st, u32 reg, u32 scale, long val)
{
val = DIV_ROUND_CLOSEST(val * 1000, scale);
val = val << 4;
return ltc2992_write_reg(st, reg, 2, val);
}
static int ltc2992_read_gpio_alarm(struct ltc2992_state *st, int nr_gpio, u32 attr, long *val)
{
int reg_val;
u32 mask;
if (attr == hwmon_in_max_alarm)
mask = ltc2992_gpio_addr_map[nr_gpio].max_alarm_msk;
else
mask = ltc2992_gpio_addr_map[nr_gpio].min_alarm_msk;
reg_val = ltc2992_read_reg(st, ltc2992_gpio_addr_map[nr_gpio].alarm, 1);
if (reg_val < 0)
return reg_val;
*val = !!(reg_val & mask);
reg_val &= ~mask;
return ltc2992_write_reg(st, ltc2992_gpio_addr_map[nr_gpio].alarm, 1, reg_val);
}
static int ltc2992_read_gpios_in(struct device *dev, u32 attr, int nr_gpio, long *val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
switch (attr) {
case hwmon_in_input:
reg = ltc2992_gpio_addr_map[nr_gpio].data;
break;
case hwmon_in_lowest:
reg = ltc2992_gpio_addr_map[nr_gpio].min;
break;
case hwmon_in_highest:
reg = ltc2992_gpio_addr_map[nr_gpio].max;
break;
case hwmon_in_min:
reg = ltc2992_gpio_addr_map[nr_gpio].min_thresh;
break;
case hwmon_in_max:
reg = ltc2992_gpio_addr_map[nr_gpio].max_thresh;
break;
case hwmon_in_min_alarm:
case hwmon_in_max_alarm:
return ltc2992_read_gpio_alarm(st, nr_gpio, attr, val);
default:
return -EOPNOTSUPP;
}
return ltc2992_get_voltage(st, reg, LTC2992_VADC_GPIO_UV_LSB, val);
}
static int ltc2992_read_in_alarm(struct ltc2992_state *st, int channel, long *val, u32 attr)
{
int reg_val;
u32 mask;
if (attr == hwmon_in_max_alarm)
mask = LTC2992_SENSE_FAULT_MSK(1);
else
mask = LTC2992_SENSE_FAULT_MSK(0);
reg_val = ltc2992_read_reg(st, LTC2992_SENSE_FAULT(channel), 1);
if (reg_val < 0)
return reg_val;
*val = !!(reg_val & mask);
reg_val &= ~mask;
return ltc2992_write_reg(st, LTC2992_SENSE_FAULT(channel), 1, reg_val);
}
static int ltc2992_read_in(struct device *dev, u32 attr, int channel, long *val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
if (channel > 1)
return ltc2992_read_gpios_in(dev, attr, channel - 2, val);
switch (attr) {
case hwmon_in_input:
reg = LTC2992_SENSE(channel);
break;
case hwmon_in_lowest:
reg = LTC2992_SENSE_MIN(channel);
break;
case hwmon_in_highest:
reg = LTC2992_SENSE_MAX(channel);
break;
case hwmon_in_min:
reg = LTC2992_SENSE_MIN_THRESH(channel);
break;
case hwmon_in_max:
reg = LTC2992_SENSE_MAX_THRESH(channel);
break;
case hwmon_in_min_alarm:
case hwmon_in_max_alarm:
return ltc2992_read_in_alarm(st, channel, val, attr);
default:
return -EOPNOTSUPP;
}
return ltc2992_get_voltage(st, reg, LTC2992_VADC_UV_LSB, val);
}
static int ltc2992_get_current(struct ltc2992_state *st, u32 reg, u32 channel, long *val)
{
int reg_val;
reg_val = ltc2992_read_reg(st, reg, 2);
if (reg_val < 0)
return reg_val;
reg_val = reg_val >> 4;
*val = DIV_ROUND_CLOSEST(reg_val * LTC2992_IADC_NANOV_LSB, st->r_sense_uohm[channel]);
return 0;
}
static int ltc2992_set_current(struct ltc2992_state *st, u32 reg, u32 channel, long val)
{
u32 reg_val;
reg_val = DIV_ROUND_CLOSEST(val * st->r_sense_uohm[channel], LTC2992_IADC_NANOV_LSB);
reg_val = reg_val << 4;
return ltc2992_write_reg(st, reg, 2, reg_val);
}
static int ltc2992_read_curr_alarm(struct ltc2992_state *st, int channel, long *val, u32 attr)
{
int reg_val;
u32 mask;
if (attr == hwmon_curr_max_alarm)
mask = LTC2992_DSENSE_FAULT_MSK(1);
else
mask = LTC2992_DSENSE_FAULT_MSK(0);
reg_val = ltc2992_read_reg(st, LTC2992_DSENSE_FAULT(channel), 1);
if (reg_val < 0)
return reg_val;
*val = !!(reg_val & mask);
reg_val &= ~mask;
return ltc2992_write_reg(st, LTC2992_DSENSE_FAULT(channel), 1, reg_val);
}
static int ltc2992_read_curr(struct device *dev, u32 attr, int channel, long *val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
switch (attr) {
case hwmon_curr_input:
reg = LTC2992_DSENSE(channel);
break;
case hwmon_curr_lowest:
reg = LTC2992_DSENSE_MIN(channel);
break;
case hwmon_curr_highest:
reg = LTC2992_DSENSE_MAX(channel);
break;
case hwmon_curr_min:
reg = LTC2992_DSENSE_MIN_THRESH(channel);
break;
case hwmon_curr_max:
reg = LTC2992_DSENSE_MAX_THRESH(channel);
break;
case hwmon_curr_min_alarm:
case hwmon_curr_max_alarm:
return ltc2992_read_curr_alarm(st, channel, val, attr);
default:
return -EOPNOTSUPP;
}
return ltc2992_get_current(st, reg, channel, val);
}
static int ltc2992_get_power(struct ltc2992_state *st, u32 reg, u32 channel, long *val)
{
int reg_val;
reg_val = ltc2992_read_reg(st, reg, 3);
if (reg_val < 0)
return reg_val;
*val = mul_u64_u32_div(reg_val, LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB,
st->r_sense_uohm[channel] * 1000);
return 0;
}
static int ltc2992_set_power(struct ltc2992_state *st, u32 reg, u32 channel, long val)
{
u32 reg_val;
reg_val = mul_u64_u32_div(val, st->r_sense_uohm[channel] * 1000,
LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB);
return ltc2992_write_reg(st, reg, 3, reg_val);
}
static int ltc2992_read_power_alarm(struct ltc2992_state *st, int channel, long *val, u32 attr)
{
int reg_val;
u32 mask;
if (attr == hwmon_power_max_alarm)
mask = LTC2992_POWER_FAULT_MSK(1);
else
mask = LTC2992_POWER_FAULT_MSK(0);
reg_val = ltc2992_read_reg(st, LTC2992_POWER_FAULT(channel), 1);
if (reg_val < 0)
return reg_val;
*val = !!(reg_val & mask);
reg_val &= ~mask;
return ltc2992_write_reg(st, LTC2992_POWER_FAULT(channel), 1, reg_val);
}
static int ltc2992_read_power(struct device *dev, u32 attr, int channel, long *val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
switch (attr) {
case hwmon_power_input:
reg = LTC2992_POWER(channel);
break;
case hwmon_power_input_lowest:
reg = LTC2992_POWER_MIN(channel);
break;
case hwmon_power_input_highest:
reg = LTC2992_POWER_MAX(channel);
break;
case hwmon_power_min:
reg = LTC2992_POWER_MIN_THRESH(channel);
break;
case hwmon_power_max:
reg = LTC2992_POWER_MAX_THRESH(channel);
break;
case hwmon_power_min_alarm:
case hwmon_power_max_alarm:
return ltc2992_read_power_alarm(st, channel, val, attr);
default:
return -EOPNOTSUPP;
}
return ltc2992_get_power(st, reg, channel, val);
}
static int ltc2992_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
long *val)
{
switch (type) {
case hwmon_in:
return ltc2992_read_in(dev, attr, channel, val);
case hwmon_curr:
return ltc2992_read_curr(dev, attr, channel, val);
case hwmon_power:
return ltc2992_read_power(dev, attr, channel, val);
default:
return -EOPNOTSUPP;
}
}
static int ltc2992_write_curr(struct device *dev, u32 attr, int channel, long val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
switch (attr) {
case hwmon_curr_min:
reg = LTC2992_DSENSE_MIN_THRESH(channel);
break;
case hwmon_curr_max:
reg = LTC2992_DSENSE_MAX_THRESH(channel);
break;
default:
return -EOPNOTSUPP;
}
return ltc2992_set_current(st, reg, channel, val);
}
static int ltc2992_write_gpios_in(struct device *dev, u32 attr, int nr_gpio, long val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
switch (attr) {
case hwmon_in_min:
reg = ltc2992_gpio_addr_map[nr_gpio].min_thresh;
break;
case hwmon_in_max:
reg = ltc2992_gpio_addr_map[nr_gpio].max_thresh;
break;
default:
return -EOPNOTSUPP;
}
return ltc2992_set_voltage(st, reg, LTC2992_VADC_GPIO_UV_LSB, val);
}
static int ltc2992_write_in(struct device *dev, u32 attr, int channel, long val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
if (channel > 1)
return ltc2992_write_gpios_in(dev, attr, channel - 2, val);
switch (attr) {
case hwmon_in_min:
reg = LTC2992_SENSE_MIN_THRESH(channel);
break;
case hwmon_in_max:
reg = LTC2992_SENSE_MAX_THRESH(channel);
break;
default:
return -EOPNOTSUPP;
}
return ltc2992_set_voltage(st, reg, LTC2992_VADC_UV_LSB, val);
}
static int ltc2992_write_power(struct device *dev, u32 attr, int channel, long val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
u32 reg;
switch (attr) {
case hwmon_power_min:
reg = LTC2992_POWER_MIN_THRESH(channel);
break;
case hwmon_power_max:
reg = LTC2992_POWER_MAX_THRESH(channel);
break;
default:
return -EOPNOTSUPP;
}
return ltc2992_set_power(st, reg, channel, val);
}
static int ltc2992_write_chip(struct device *dev, u32 attr, int channel, long val)
{
struct ltc2992_state *st = dev_get_drvdata(dev);
switch (attr) {
case hwmon_chip_in_reset_history:
return regmap_update_bits(st->regmap, LTC2992_CTRLB, LTC2992_RESET_HISTORY,
LTC2992_RESET_HISTORY);
default:
return -EOPNOTSUPP;
}
}
static int ltc2992_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
long val)
{
switch (type) {
case hwmon_chip:
return ltc2992_write_chip(dev, attr, channel, val);
case hwmon_in:
return ltc2992_write_in(dev, attr, channel, val);
case hwmon_curr:
return ltc2992_write_curr(dev, attr, channel, val);
case hwmon_power:
return ltc2992_write_power(dev, attr, channel, val);
default:
return -EOPNOTSUPP;
}
}
static const struct hwmon_ops ltc2992_hwmon_ops = {
.is_visible = ltc2992_is_visible,
.read = ltc2992_read,
.write = ltc2992_write,
};
static const u32 ltc2992_chip_config[] = {
HWMON_C_IN_RESET_HISTORY,
0
};
static const struct hwmon_channel_info ltc2992_chip = {
.type = hwmon_chip,
.config = ltc2992_chip_config,
};
static const u32 ltc2992_in_config[] = {
HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST | HWMON_I_MIN | HWMON_I_MAX |
HWMON_I_MIN_ALARM | HWMON_I_MAX_ALARM,
HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST | HWMON_I_MIN | HWMON_I_MAX |
HWMON_I_MIN_ALARM | HWMON_I_MAX_ALARM,
HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST | HWMON_I_MIN | HWMON_I_MAX |
HWMON_I_MIN_ALARM | HWMON_I_MAX_ALARM,
HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST | HWMON_I_MIN | HWMON_I_MAX |
HWMON_I_MIN_ALARM | HWMON_I_MAX_ALARM,
HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST | HWMON_I_MIN | HWMON_I_MAX |
HWMON_I_MIN_ALARM | HWMON_I_MAX_ALARM,
HWMON_I_INPUT | HWMON_I_LOWEST | HWMON_I_HIGHEST | HWMON_I_MIN | HWMON_I_MAX |
HWMON_I_MIN_ALARM | HWMON_I_MAX_ALARM,
0
};
static const struct hwmon_channel_info ltc2992_in = {
.type = hwmon_in,
.config = ltc2992_in_config,
};
static const u32 ltc2992_curr_config[] = {
HWMON_C_INPUT | HWMON_C_LOWEST | HWMON_C_HIGHEST | HWMON_C_MIN | HWMON_C_MAX |
HWMON_C_MIN_ALARM | HWMON_C_MAX_ALARM,
HWMON_C_INPUT | HWMON_C_LOWEST | HWMON_C_HIGHEST | HWMON_C_MIN | HWMON_C_MAX |
HWMON_C_MIN_ALARM | HWMON_C_MAX_ALARM,
0
};
static const struct hwmon_channel_info ltc2992_curr = {
.type = hwmon_curr,
.config = ltc2992_curr_config,
};
static const u32 ltc2992_power_config[] = {
HWMON_P_INPUT | HWMON_P_INPUT_LOWEST | HWMON_P_INPUT_HIGHEST | HWMON_P_MIN | HWMON_P_MAX |
HWMON_P_MIN_ALARM | HWMON_P_MAX_ALARM,
HWMON_P_INPUT | HWMON_P_INPUT_LOWEST | HWMON_P_INPUT_HIGHEST | HWMON_P_MIN | HWMON_P_MAX |
HWMON_P_MIN_ALARM | HWMON_P_MAX_ALARM,
0
};
static const struct hwmon_channel_info ltc2992_power = {
.type = hwmon_power,
.config = ltc2992_power_config,
};
static const struct hwmon_channel_info *ltc2992_info[] = {
&ltc2992_chip,
&ltc2992_in,
&ltc2992_curr,
&ltc2992_power,
NULL
};
static const struct hwmon_chip_info ltc2992_chip_info = {
.ops = &ltc2992_hwmon_ops,
.info = ltc2992_info,
};
static const struct regmap_config ltc2992_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xE8,
};
static int ltc2992_parse_dt(struct ltc2992_state *st)
{
struct fwnode_handle *fwnode;
struct fwnode_handle *child;
u32 addr;
u32 val;
int ret;
fwnode = dev_fwnode(&st->client->dev);
fwnode_for_each_available_child_node(fwnode, child) {
ret = fwnode_property_read_u32(child, "reg", &addr);
if (ret < 0)
return ret;
if (addr > 1)
return -EINVAL;
ret = fwnode_property_read_u32(child, "shunt-resistor-micro-ohms", &val);
if (!ret)
st->r_sense_uohm[addr] = val;
}
return 0;
}
static int ltc2992_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device *hwmon_dev;
struct ltc2992_state *st;
int ret;
st = devm_kzalloc(&client->dev, sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
st->client = client;
st->regmap = devm_regmap_init_i2c(client, &ltc2992_regmap_config);
if (IS_ERR(st->regmap))
return PTR_ERR(st->regmap);
ret = ltc2992_parse_dt(st);
if (ret < 0)
return ret;
ret = ltc2992_config_gpio(st);
if (ret < 0)
return ret;
hwmon_dev = devm_hwmon_device_register_with_info(&client->dev, client->name, st,
&ltc2992_chip_info, NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct of_device_id ltc2992_of_match[] = {
{ .compatible = "adi,ltc2992" },
{ }
};
MODULE_DEVICE_TABLE(of, ltc2992_of_match);
static const struct i2c_device_id ltc2992_i2c_id[] = {
{"ltc2992", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2992_i2c_id);
static struct i2c_driver ltc2992_i2c_driver = {
.driver = {
.name = "ltc2992",
.of_match_table = ltc2992_of_match,
},
.probe = ltc2992_i2c_probe,
.id_table = ltc2992_i2c_id,
};
module_i2c_driver(ltc2992_i2c_driver);
MODULE_AUTHOR("Alexandru Tachici <alexandru.tachici@analog.com>");
MODULE_DESCRIPTION("Hwmon driver for Linear Technology 2992");
MODULE_LICENSE("Dual BSD/GPL");

352
drivers/hwmon/max127.c Normal file
View File

@@ -0,0 +1,352 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for MAX127.
*
* Copyright (c) 2020 Facebook Inc.
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
/*
* MAX127 Control Byte. Refer to MAX127 datasheet, Table 1 "Control-Byte
* Format" for details.
*/
#define MAX127_CTRL_START BIT(7)
#define MAX127_CTRL_SEL_SHIFT 4
#define MAX127_CTRL_RNG BIT(3)
#define MAX127_CTRL_BIP BIT(2)
#define MAX127_CTRL_PD1 BIT(1)
#define MAX127_CTRL_PD0 BIT(0)
#define MAX127_NUM_CHANNELS 8
#define MAX127_SET_CHANNEL(ch) (((ch) & 7) << MAX127_CTRL_SEL_SHIFT)
/*
* MAX127 channel input ranges. Refer to MAX127 datasheet, Table 3 "Range
* and Polarity Selection" for details.
*/
#define MAX127_FULL_RANGE 10000 /* 10V */
#define MAX127_HALF_RANGE 5000 /* 5V */
/*
* MAX127 returns 2 bytes at read:
* - the first byte contains data[11:4].
* - the second byte contains data[3:0] (MSB) and 4 dummy 0s (LSB).
* Refer to MAX127 datasheet, "Read a Conversion (Read Cycle)" section
* for details.
*/
#define MAX127_DATA_LEN 2
#define MAX127_DATA_SHIFT 4
#define MAX127_SIGN_BIT BIT(11)
struct max127_data {
struct mutex lock;
struct i2c_client *client;
u8 ctrl_byte[MAX127_NUM_CHANNELS];
};
static int max127_select_channel(struct i2c_client *client, u8 ctrl_byte)
{
int status;
struct i2c_msg msg = {
.addr = client->addr,
.flags = 0,
.len = sizeof(ctrl_byte),
.buf = &ctrl_byte,
};
status = i2c_transfer(client->adapter, &msg, 1);
if (status < 0)
return status;
if (status != 1)
return -EIO;
return 0;
}
static int max127_read_channel(struct i2c_client *client, long *val)
{
int status;
u8 i2c_data[MAX127_DATA_LEN];
struct i2c_msg msg = {
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(i2c_data),
.buf = i2c_data,
};
status = i2c_transfer(client->adapter, &msg, 1);
if (status < 0)
return status;
if (status != 1)
return -EIO;
*val = (i2c_data[1] >> MAX127_DATA_SHIFT) |
((u16)i2c_data[0] << MAX127_DATA_SHIFT);
return 0;
}
static long max127_process_raw(u8 ctrl_byte, long raw)
{
long scale, weight;
/*
* MAX127's data coding is binary in unipolar mode with 1 LSB =
* (Full-Scale/4096) and twos complement binary in bipolar mode
* with 1 LSB = [(2 x |FS|)/4096].
* Refer to MAX127 datasheet, "Transfer Function" section for
* details.
*/
scale = (ctrl_byte & MAX127_CTRL_RNG) ? MAX127_FULL_RANGE :
MAX127_HALF_RANGE;
if (ctrl_byte & MAX127_CTRL_BIP) {
weight = (raw & MAX127_SIGN_BIT);
raw &= ~MAX127_SIGN_BIT;
raw -= weight;
raw *= 2;
}
return raw * scale / 4096;
}
static int max127_read_input(struct max127_data *data, int channel, long *val)
{
long raw;
int status;
struct i2c_client *client = data->client;
u8 ctrl_byte = data->ctrl_byte[channel];
mutex_lock(&data->lock);
status = max127_select_channel(client, ctrl_byte);
if (status)
goto exit;
status = max127_read_channel(client, &raw);
if (status)
goto exit;
*val = max127_process_raw(ctrl_byte, raw);
exit:
mutex_unlock(&data->lock);
return status;
}
static int max127_read_min(struct max127_data *data, int channel, long *val)
{
u8 rng_bip = (data->ctrl_byte[channel] >> 2) & 3;
static const int min_input_map[4] = {
0, /* RNG=0, BIP=0 */
-MAX127_HALF_RANGE, /* RNG=0, BIP=1 */
0, /* RNG=1, BIP=0 */
-MAX127_FULL_RANGE, /* RNG=1, BIP=1 */
};
*val = min_input_map[rng_bip];
return 0;
}
static int max127_read_max(struct max127_data *data, int channel, long *val)
{
u8 rng_bip = (data->ctrl_byte[channel] >> 2) & 3;
static const int max_input_map[4] = {
MAX127_HALF_RANGE, /* RNG=0, BIP=0 */
MAX127_HALF_RANGE, /* RNG=0, BIP=1 */
MAX127_FULL_RANGE, /* RNG=1, BIP=0 */
MAX127_FULL_RANGE, /* RNG=1, BIP=1 */
};
*val = max_input_map[rng_bip];
return 0;
}
static int max127_write_min(struct max127_data *data, int channel, long val)
{
u8 ctrl;
mutex_lock(&data->lock);
ctrl = data->ctrl_byte[channel];
if (val <= -MAX127_FULL_RANGE) {
ctrl |= (MAX127_CTRL_RNG | MAX127_CTRL_BIP);
} else if (val < 0) {
ctrl |= MAX127_CTRL_BIP;
ctrl &= ~MAX127_CTRL_RNG;
} else {
ctrl &= ~MAX127_CTRL_BIP;
}
data->ctrl_byte[channel] = ctrl;
mutex_unlock(&data->lock);
return 0;
}
static int max127_write_max(struct max127_data *data, int channel, long val)
{
mutex_lock(&data->lock);
if (val >= MAX127_FULL_RANGE)
data->ctrl_byte[channel] |= MAX127_CTRL_RNG;
else
data->ctrl_byte[channel] &= ~MAX127_CTRL_RNG;
mutex_unlock(&data->lock);
return 0;
}
static umode_t max127_is_visible(const void *_data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
if (type == hwmon_in) {
switch (attr) {
case hwmon_in_input:
return 0444;
case hwmon_in_min:
case hwmon_in_max:
return 0644;
default:
break;
}
}
return 0;
}
static int max127_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
int status;
struct max127_data *data = dev_get_drvdata(dev);
if (type != hwmon_in)
return -EOPNOTSUPP;
switch (attr) {
case hwmon_in_input:
status = max127_read_input(data, channel, val);
break;
case hwmon_in_min:
status = max127_read_min(data, channel, val);
break;
case hwmon_in_max:
status = max127_read_max(data, channel, val);
break;
default:
status = -EOPNOTSUPP;
break;
}
return status;
}
static int max127_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
int status;
struct max127_data *data = dev_get_drvdata(dev);
if (type != hwmon_in)
return -EOPNOTSUPP;
switch (attr) {
case hwmon_in_min:
status = max127_write_min(data, channel, val);
break;
case hwmon_in_max:
status = max127_write_max(data, channel, val);
break;
default:
status = -EOPNOTSUPP;
break;
}
return status;
}
static const struct hwmon_ops max127_hwmon_ops = {
.is_visible = max127_is_visible,
.read = max127_read,
.write = max127_write,
};
static const struct hwmon_channel_info *max127_info[] = {
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX),
NULL,
};
static const struct hwmon_chip_info max127_chip_info = {
.ops = &max127_hwmon_ops,
.info = max127_info,
};
static int max127_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int i;
struct device *hwmon_dev;
struct max127_data *data;
struct device *dev = &client->dev;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
mutex_init(&data->lock);
for (i = 0; i < ARRAY_SIZE(data->ctrl_byte); i++)
data->ctrl_byte[i] = (MAX127_CTRL_START |
MAX127_SET_CHANNEL(i));
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
data,
&max127_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max127_id[] = {
{ "max127", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max127_id);
static struct i2c_driver max127_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max127",
},
.probe = max127_probe,
.id_table = max127_id,
};
module_i2c_driver(max127_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Choi <mikechoi@fb.com>");
MODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>");
MODULE_DESCRIPTION("MAX127 Hardware Monitoring driver");

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* nct6683 - Driver for the hardware monitoring functionality of
* Nuvoton NCT6683D eSIO
* Nuvoton NCT6683D/NCT6687D eSIO
*
* Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net>
*
@@ -12,6 +12,7 @@
*
* Chip #vin #fan #pwm #temp chip ID
* nct6683d 21(1) 16 8 32(1) 0xc730
* nct6687d 21(1) 16 8 32(1) 0xd590
*
* Notes:
* (1) Total number of vin and temp inputs is 32.
@@ -32,7 +33,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
enum kinds { nct6683 };
enum kinds { nct6683, nct6687 };
static bool force;
module_param(force, bool, 0);
@@ -40,10 +41,12 @@ MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
static const char * const nct6683_device_names[] = {
"nct6683",
"nct6687",
};
static const char * const nct6683_chip_names[] = {
"NCT6683D",
"NCT6687D",
};
#define DRVNAME "nct6683"
@@ -63,6 +66,7 @@ static const char * const nct6683_chip_names[] = {
#define SIO_NCT6681_ID 0xb270 /* for later */
#define SIO_NCT6683_ID 0xc730
#define SIO_NCT6687_ID 0xd590
#define SIO_ID_MASK 0xFFF0
static inline void
@@ -164,6 +168,7 @@ superio_exit(int ioreg)
#define NCT6683_REG_CUSTOMER_ID 0x602
#define NCT6683_CUSTOMER_ID_INTEL 0x805
#define NCT6683_CUSTOMER_ID_MITAC 0xa0e
#define NCT6683_CUSTOMER_ID_MSI 0x201
#define NCT6683_REG_BUILD_YEAR 0x604
#define NCT6683_REG_BUILD_MONTH 0x605
@@ -1218,6 +1223,8 @@ static int nct6683_probe(struct platform_device *pdev)
break;
case NCT6683_CUSTOMER_ID_MITAC:
break;
case NCT6683_CUSTOMER_ID_MSI:
break;
default:
if (!force)
return -ENODEV;
@@ -1352,6 +1359,9 @@ static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
case SIO_NCT6683_ID:
sio_data->kind = nct6683;
break;
case SIO_NCT6687_ID:
sio_data->kind = nct6687;
break;
default:
if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val);

View File

@@ -41,6 +41,14 @@ struct temp_sensor_2 {
u8 value;
} __packed;
struct temp_sensor_10 {
u32 sensor_id;
u8 fru_type;
u8 value;
u8 throttle;
u8 reserved;
} __packed;
struct freq_sensor_1 {
u16 sensor_id;
u16 value;
@@ -307,6 +315,60 @@ static ssize_t occ_show_temp_2(struct device *dev,
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
}
static ssize_t occ_show_temp_10(struct device *dev,
struct device_attribute *attr, char *buf)
{
int rc;
u32 val = 0;
struct temp_sensor_10 *temp;
struct occ *occ = dev_get_drvdata(dev);
struct occ_sensors *sensors = &occ->sensors;
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
rc = occ_update_response(occ);
if (rc)
return rc;
temp = ((struct temp_sensor_10 *)sensors->temp.data) + sattr->index;
switch (sattr->nr) {
case 0:
val = get_unaligned_be32(&temp->sensor_id);
break;
case 1:
val = temp->value;
if (val == OCC_TEMP_SENSOR_FAULT)
return -EREMOTEIO;
/*
* VRM doesn't return temperature, only alarm bit. This
* attribute maps to tempX_alarm instead of tempX_input for
* VRM
*/
if (temp->fru_type != OCC_FRU_TYPE_VRM) {
/* sensor not ready */
if (val == 0)
return -EAGAIN;
val *= 1000;
}
break;
case 2:
val = temp->fru_type;
break;
case 3:
val = temp->value == OCC_TEMP_SENSOR_FAULT;
break;
case 4:
val = temp->throttle * 1000;
break;
default:
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
}
static ssize_t occ_show_freq_1(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -745,6 +807,10 @@ static int occ_setup_sensor_attrs(struct occ *occ)
num_attrs += (sensors->temp.num_sensors * 4);
show_temp = occ_show_temp_2;
break;
case 0x10:
num_attrs += (sensors->temp.num_sensors * 5);
show_temp = occ_show_temp_10;
break;
default:
sensors->temp.num_sensors = 0;
}
@@ -844,6 +910,15 @@ static int occ_setup_sensor_attrs(struct occ *occ)
attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
show_temp, NULL, 3, i);
attr++;
if (sensors->temp.version == 0x10) {
snprintf(attr->name, sizeof(attr->name),
"temp%d_max", s);
attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
show_temp, NULL,
4, i);
attr++;
}
}
}

View File

@@ -220,6 +220,15 @@ config SENSORS_MP2975
This driver can also be built as a module. If so, the module will
be called mp2975.
config SENSORS_PM6764TR
tristate "ST PM6764TR"
help
If you say yes here you get hardware monitoring support for ST
PM6764TR.
This driver can also be built as a module. If so, the module will
be called pm6764tr.
config SENSORS_PXE1610
tristate "Infineon PXE1610"
help
@@ -229,6 +238,15 @@ config SENSORS_PXE1610
This driver can also be built as a module. If so, the module will
be called pxe1610.
config SENSORS_Q54SJ108A2
tristate "Delta Power Supplies Q54SJ108A2"
help
If you say yes here you get hardware monitoring support for Delta
Q54SJ108A2 series Power Supplies.
This driver can also be built as a module. If so, the module will
be called q54sj108a2.
config SENSORS_TPS40422
tristate "TI TPS40422"
help

View File

@@ -25,7 +25,9 @@ obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o

View File

@@ -502,7 +502,6 @@ static struct i2c_driver adm1266_driver = {
.of_match_table = adm1266_of_match,
},
.probe_new = adm1266_probe,
.remove = pmbus_do_remove,
.id_table = adm1266_id,
};

View File

@@ -797,7 +797,6 @@ static struct i2c_driver adm1275_driver = {
.name = "adm1275",
},
.probe_new = adm1275_probe,
.remove = pmbus_do_remove,
.id_table = adm1275_id,
};

View File

@@ -121,7 +121,6 @@ static struct i2c_driver pfe_pmbus_driver = {
.name = "bel-pfe",
},
.probe_new = pfe_pmbus_probe,
.remove = pmbus_do_remove,
.id_table = pfe_device_id,
};

View File

@@ -617,7 +617,6 @@ static struct i2c_driver ibm_cffps_driver = {
.of_match_table = ibm_cffps_of_match,
},
.probe_new = ibm_cffps_probe,
.remove = pmbus_do_remove,
.id_table = ibm_cffps_id,
};

View File

@@ -216,7 +216,6 @@ static struct i2c_driver ipsps_driver = {
.of_match_table = of_match_ptr(ipsps_of_match),
},
.probe_new = ipsps_probe,
.remove = pmbus_do_remove,
.id_table = ipsps_id,
};

View File

@@ -137,7 +137,6 @@ static struct i2c_driver ir35221_driver = {
.name = "ir35221",
},
.probe_new = ir35221_probe,
.remove = pmbus_do_remove,
.id_table = ir35221_id,
};

View File

@@ -53,7 +53,6 @@ static struct i2c_driver ir38064_driver = {
.name = "ir38064",
},
.probe_new = ir38064_probe,
.remove = pmbus_do_remove,
.id_table = ir38064_id,
};

View File

@@ -55,7 +55,6 @@ static struct i2c_driver irps5401_driver = {
.name = "irps5401",
},
.probe_new = irps5401_probe,
.remove = pmbus_do_remove,
.id_table = irps5401_id,
};

View File

@@ -324,7 +324,6 @@ static struct i2c_driver isl68137_driver = {
.name = "isl68137",
},
.probe_new = isl68137_probe,
.remove = pmbus_do_remove,
.id_table = raa_dmpvr_id,
};

View File

@@ -508,7 +508,6 @@ static struct i2c_driver lm25066_driver = {
.name = "lm25066",
},
.probe_new = lm25066_probe,
.remove = pmbus_do_remove,
.id_table = lm25066_id,
};

View File

@@ -875,7 +875,6 @@ static struct i2c_driver ltc2978_driver = {
.of_match_table = of_match_ptr(ltc2978_of_match),
},
.probe_new = ltc2978_probe,
.remove = pmbus_do_remove,
.id_table = ltc2978_id,
};

View File

@@ -200,7 +200,6 @@ static struct i2c_driver ltc3815_driver = {
.name = "ltc3815",
},
.probe_new = ltc3815_probe,
.remove = pmbus_do_remove,
.id_table = ltc3815_id,
};

View File

@@ -103,7 +103,6 @@ static struct i2c_driver max16064_driver = {
.name = "max16064",
},
.probe_new = max16064_probe,
.remove = pmbus_do_remove,
.id_table = max16064_id,
};

View File

@@ -302,7 +302,6 @@ static struct i2c_driver max16601_driver = {
.name = "max16601",
},
.probe_new = max16601_probe,
.remove = pmbus_do_remove,
.id_table = max16601_id,
};

View File

@@ -328,8 +328,6 @@ static int max20730_init_debugfs(struct i2c_client *client,
return -ENOENT;
max20730_dir = debugfs_create_dir(client->name, debugfs);
if (!max20730_dir)
return -ENOENT;
for (i = 0; i < MAX20730_DEBUGFS_NUM_ENTRIES; ++i)
psu->debugfs_entries[i] = i;
@@ -779,7 +777,6 @@ static struct i2c_driver max20730_driver = {
.of_match_table = max20730_of_match,
},
.probe_new = max20730_probe,
.remove = pmbus_do_remove,
.id_table = max20730_id,
};

View File

@@ -43,7 +43,6 @@ static struct i2c_driver max20751_driver = {
.name = "max20751",
},
.probe_new = max20751_probe,
.remove = pmbus_do_remove,
.id_table = max20751_id,
};

View File

@@ -390,7 +390,6 @@ static struct i2c_driver max31785_driver = {
.of_match_table = max31785_of_match,
},
.probe_new = max31785_probe,
.remove = pmbus_do_remove,
.id_table = max31785_id,
};

View File

@@ -521,7 +521,6 @@ static struct i2c_driver max34440_driver = {
.name = "max34440",
},
.probe_new = max34440_probe,
.remove = pmbus_do_remove,
.id_table = max34440_id,
};

View File

@@ -183,7 +183,6 @@ static struct i2c_driver max8688_driver = {
.name = "max8688",
},
.probe_new = max8688_probe,
.remove = pmbus_do_remove,
.id_table = max8688_id,
};

View File

@@ -758,7 +758,6 @@ static struct i2c_driver mp2975_driver = {
.of_match_table = of_match_ptr(mp2975_of_match),
},
.probe_new = mp2975_probe,
.remove = pmbus_do_remove,
.id_table = mp2975_id,
};

View File

@@ -0,0 +1,75 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for STMicroelectronics digital controller PM6764TR
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pmbus.h>
#include "pmbus.h"
#define PM6764TR_PMBUS_READ_VOUT 0xD4
static int pm6764tr_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{
int ret;
switch (reg) {
case PMBUS_VIRT_READ_VMON:
ret = pmbus_read_word_data(client, page, phase, PM6764TR_PMBUS_READ_VOUT);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static struct pmbus_driver_info pm6764tr_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = vid,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT | PMBUS_HAVE_VMON |
PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.read_word_data = pm6764tr_read_word_data,
};
static int pm6764tr_probe(struct i2c_client *client)
{
return pmbus_do_probe(client, &pm6764tr_info);
}
static const struct i2c_device_id pm6764tr_id[] = {
{"pm6764tr", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, pm6764tr_id);
static const struct of_device_id __maybe_unused pm6764tr_of_match[] = {
{.compatible = "st,pm6764tr"},
{}
};
/* This is the driver that will be inserted */
static struct i2c_driver pm6764tr_driver = {
.driver = {
.name = "pm6764tr",
.of_match_table = of_match_ptr(pm6764tr_of_match),
},
.probe_new = pm6764tr_probe,
.id_table = pm6764tr_id,
};
module_i2c_driver(pm6764tr_driver);
MODULE_AUTHOR("Charles Hsu");
MODULE_DESCRIPTION("PMBus driver for ST PM6764TR");
MODULE_LICENSE("GPL");

View File

@@ -238,7 +238,6 @@ static struct i2c_driver pmbus_driver = {
.name = "pmbus",
},
.probe_new = pmbus_probe,
.remove = pmbus_do_remove,
.id_table = pmbus_id,
};

View File

@@ -490,7 +490,6 @@ void pmbus_clear_faults(struct i2c_client *client);
bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info);
int pmbus_do_remove(struct i2c_client *client);
const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
*client);
int pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id,

View File

@@ -2395,6 +2395,13 @@ static int pmbus_debugfs_set_pec(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(pmbus_debugfs_ops_pec, pmbus_debugfs_get_pec,
pmbus_debugfs_set_pec, "%llu\n");
static void pmbus_remove_debugfs(void *data)
{
struct dentry *entry = data;
debugfs_remove_recursive(entry);
}
static int pmbus_init_debugfs(struct i2c_client *client,
struct pmbus_data *data)
{
@@ -2530,7 +2537,8 @@ static int pmbus_init_debugfs(struct i2c_client *client,
}
}
return 0;
return devm_add_action_or_reset(data->dev,
pmbus_remove_debugfs, data->debugfs);
}
#else
static int pmbus_init_debugfs(struct i2c_client *client,
@@ -2617,16 +2625,6 @@ int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info)
}
EXPORT_SYMBOL_GPL(pmbus_do_probe);
int pmbus_do_remove(struct i2c_client *client)
{
struct pmbus_data *data = i2c_get_clientdata(client);
debugfs_remove_recursive(data->debugfs);
return 0;
}
EXPORT_SYMBOL_GPL(pmbus_do_remove);
struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client)
{
struct pmbus_data *data = i2c_get_clientdata(client);

View File

@@ -131,7 +131,6 @@ static struct i2c_driver pxe1610_driver = {
.name = "pxe1610",
},
.probe_new = pxe1610_probe,
.remove = pmbus_do_remove,
.id_table = pxe1610_id,
};

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