mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
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:
258
Documentation/ABI/testing/sysfs-class-firmware-attributes
Normal file
258
Documentation/ABI/testing/sysfs-class-firmware-attributes
Normal 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.
|
||||
119
Documentation/ABI/testing/sysfs-class-intel_pmt
Normal file
119
Documentation/ABI/testing/sysfs-class-intel_pmt
Normal 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.
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
39
Documentation/devicetree/bindings/hwmon/adi,ad741x.yaml
Normal file
39
Documentation/devicetree/bindings/hwmon/adi,ad741x.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
57
Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml
Normal file
57
Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
80
Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml
Normal file
80
Documentation/devicetree/bindings/hwmon/adi,ltc2992.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
54
Documentation/devicetree/bindings/hwmon/amd,sbtsi.yaml
Normal file
54
Documentation/devicetree/bindings/hwmon/amd,sbtsi.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
|
||||
57
Documentation/devicetree/bindings/hwmon/ti,ads7828.yaml
Normal file
57
Documentation/devicetree/bindings/hwmon/ti,ads7828.yaml
Normal 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;
|
||||
};
|
||||
};
|
||||
55
Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
Normal file
55
Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
57
Documentation/devicetree/bindings/input/ariel-pwrbutton.yaml
Normal file
57
Documentation/devicetree/bindings/input/ariel-pwrbutton.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
81
Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
Normal file
81
Documentation/devicetree/bindings/input/atmel,maxtouch.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
108
Documentation/devicetree/bindings/input/dlg,da7280.txt
Normal file
108
Documentation/devicetree/bindings/input/dlg,da7280.txt
Normal 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
|
||||
>;
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
82
Documentation/hwmon/corsair-psu.rst
Normal file
82
Documentation/hwmon/corsair-psu.rst
Normal 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
|
||||
======================= ========================================================
|
||||
@@ -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
|
||||
|
||||
56
Documentation/hwmon/ltc2992.rst
Normal file
56
Documentation/hwmon/ltc2992.rst
Normal 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 supply’s 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.
|
||||
45
Documentation/hwmon/max127.rst
Normal file
45
Documentation/hwmon/max127.rst
Normal 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
|
||||
============== ==============================================================
|
||||
@@ -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
|
||||
=============== ===============================================
|
||||
|
||||
32
Documentation/hwmon/pm6764tr.rst
Normal file
32
Documentation/hwmon/pm6764tr.rst
Normal 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 Intel’s 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.
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
54
Documentation/hwmon/q54sj108a2.rst
Normal file
54
Documentation/hwmon/q54sj108a2.rst
Normal 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
|
||||
===================== ===== ==================================================
|
||||
42
Documentation/hwmon/sbtsi_temp.rst
Normal file
42
Documentation/hwmon/sbtsi_temp.rst
Normal 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.
|
||||
@@ -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
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
60
MAINTAINERS
60
MAINTAINERS
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
600
drivers/hwmon/corsair-psu.c
Normal 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");
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
971
drivers/hwmon/ltc2992.c
Normal 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[] = {
|
||||
<c2992_chip,
|
||||
<c2992_in,
|
||||
<c2992_curr,
|
||||
<c2992_power,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info ltc2992_chip_info = {
|
||||
.ops = <c2992_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, <c2992_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,
|
||||
<c2992_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
352
drivers/hwmon/max127.c
Normal 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 two’s 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");
|
||||
@@ -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);
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -797,7 +797,6 @@ static struct i2c_driver adm1275_driver = {
|
||||
.name = "adm1275",
|
||||
},
|
||||
.probe_new = adm1275_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = adm1275_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -137,7 +137,6 @@ static struct i2c_driver ir35221_driver = {
|
||||
.name = "ir35221",
|
||||
},
|
||||
.probe_new = ir35221_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = ir35221_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ static struct i2c_driver ir38064_driver = {
|
||||
.name = "ir38064",
|
||||
},
|
||||
.probe_new = ir38064_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = ir38064_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ static struct i2c_driver irps5401_driver = {
|
||||
.name = "irps5401",
|
||||
},
|
||||
.probe_new = irps5401_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = irps5401_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -508,7 +508,6 @@ static struct i2c_driver lm25066_driver = {
|
||||
.name = "lm25066",
|
||||
},
|
||||
.probe_new = lm25066_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = lm25066_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -200,7 +200,6 @@ static struct i2c_driver ltc3815_driver = {
|
||||
.name = "ltc3815",
|
||||
},
|
||||
.probe_new = ltc3815_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = ltc3815_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -103,7 +103,6 @@ static struct i2c_driver max16064_driver = {
|
||||
.name = "max16064",
|
||||
},
|
||||
.probe_new = max16064_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max16064_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -302,7 +302,6 @@ static struct i2c_driver max16601_driver = {
|
||||
.name = "max16601",
|
||||
},
|
||||
.probe_new = max16601_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max16601_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ static struct i2c_driver max20751_driver = {
|
||||
.name = "max20751",
|
||||
},
|
||||
.probe_new = max20751_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max20751_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -521,7 +521,6 @@ static struct i2c_driver max34440_driver = {
|
||||
.name = "max34440",
|
||||
},
|
||||
.probe_new = max34440_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max34440_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -183,7 +183,6 @@ static struct i2c_driver max8688_driver = {
|
||||
.name = "max8688",
|
||||
},
|
||||
.probe_new = max8688_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = max8688_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
75
drivers/hwmon/pmbus/pm6764tr.c
Normal file
75
drivers/hwmon/pmbus/pm6764tr.c
Normal 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");
|
||||
@@ -238,7 +238,6 @@ static struct i2c_driver pmbus_driver = {
|
||||
.name = "pmbus",
|
||||
},
|
||||
.probe_new = pmbus_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = pmbus_id,
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user