Commit 3d9e3501 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull hwmon updates from Guenter Roeck:

 - Add support for Texas Instruments TMP512/513

 - Add support for LTC2947

 - Add support for BEL PFE1100 and PFE3000

 - Various minor improvements and fixes

* tag 'hwmon-for-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  dell-smm-hwmon: Add documentation
  hwmon: (dell-smm) Add support for disabling automatic BIOS fan control
  hwmon: Add driver for Texas Instruments TMP512/513 sensor chips.
  dt-bindings: hwmon: Add TMP512/513
  docs: hwmon: Document bel-pfe pmbus driver
  hwmon: (pmbus) add driver for BEL PFE1100 and PFE3000
  dt-bindings: hwmon: Add ltc2947 documentation
  hwmon: Add support for ltc2947
  hwmon: (ina3221) Add summation feature support
  hwmon: (tmp421) Allow reading at 2Hz instead of 0.5Hz
  hwmon: (w83793d) remove redundant assignment to variable res
  hwmon: (pmbus/ibm-cffps) Add version detection capability
  dt-bindings: hwmon: Document ibm,cffps compatible string
  hwmon: abituguru: make array probe_order static, makes object smaller
  hwmon: (applesmc) switch to using input device polling mode
  hwmon: (aspeed-pwm-tacho) Use devm_platform_ioremap_resource() in aspeed_pwm_tacho_probe()
  hwmon: (pmbus/ibm-cffps) Fix LED blink behavior
  hwmon: (pmbus/ibm-cffps) Switch LEDs to blocking brightness call
parents 00074a70 4a1288f1
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/hwmon/adi,ltc2947.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices LTC2947 high precision power and energy monitor
maintainers:
- Nuno Sá <nuno.sa@analog.com>
description: |
Analog Devices LTC2947 high precision power and energy monitor over SPI or I2C.
https://www.analog.com/media/en/technical-documentation/data-sheets/LTC2947.pdf
properties:
compatible:
enum:
- adi,ltc2947
reg:
maxItems: 1
clocks:
description:
The LTC2947 uses either a trimmed internal oscillator or an external clock
as the time base for determining the integration period to represent time,
charge and energy. When an external clock is used, this property must be
set accordingly.
maxItems: 1
adi,accumulator-ctl-pol:
description:
This property controls the polarity of current that is accumulated to
calculate charge and energy so that, they can be only accumulated for
positive current for example. Since there are two sets of registers for
the accumulated values, this entry can also have two items which sets
energy1/charge1 and energy2/charger2 respectively. Check table 12 of the
datasheet for more information on the supported options.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
- minItems: 2
maxItems: 2
items:
enum: [0, 1, 2, 3]
default: 0
adi,accumulation-deadband-microamp:
description:
This property controls the Accumulation Dead band which allows to set the
level of current below which no accumulation takes place.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
maximum: 255
default: 0
adi,gpio-out-pol:
description:
This property controls the GPIO polarity. Setting it to one makes the GPIO
active high, setting it to zero makets it active low. When this property
is present, the GPIO is automatically configured as output and set to
control a fan as a function of measured temperature.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
default: 0
adi,gpio-in-accum:
description:
When set, this property sets the GPIO as input. It is then used to control
the accumulation of charge, energy and time. This function can be
enabled/configured separately for each of the two sets of accumulation
registers. Check table 13 of the datasheet for more information on the
supported options. This property cannot be used together with
adi,gpio-out-pol.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
- minItems: 2
maxItems: 2
items:
enum: [0, 1, 2]
default: 0
required:
- compatible
- reg
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ltc2947_spi: ltc2947@0 {
compatible = "adi,ltc2947";
reg = <0>;
/* accumulation takes place always for energ1/charge1. */
/* accumulation only on positive current for energy2/charge2. */
adi,accumulator-ctl-pol = <0 1>;
};
};
...
...@@ -5,6 +5,9 @@ Required properties: ...@@ -5,6 +5,9 @@ Required properties:
- compatible : Must be one of the following: - compatible : Must be one of the following:
"ibm,cffps1" "ibm,cffps1"
"ibm,cffps2" "ibm,cffps2"
or "ibm,cffps" if the system
must support any version of the
power supply
- reg = < I2C bus address >; : Address of the power supply on the - reg = < I2C bus address >; : Address of the power supply on the
I2C bus. I2C bus.
......
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,tmp513.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TMP513/512 system monitor sensor
maintainers:
- Eric Tremblay <etremblay@distech-controls.com>
description: |
The TMP512 (dual-channel) and TMP513 (triple-channel) are system monitors
that include remote sensors, a local temperature sensor, and a high-side
current shunt monitor. These system monitors have the capability of measuring
remote temperatures, on-chip temperatures, and system voltage/power/current
consumption.
Datasheets:
http://www.ti.com/lit/gpn/tmp513
http://www.ti.com/lit/gpn/tmp512
properties:
compatible:
enum:
- ti,tmp512
- ti,tmp513
reg:
maxItems: 1
shunt-resistor-micro-ohms:
description: |
If 0, the calibration process will be skiped and the current and power
measurement engine will not work. Temperature and voltage measurement
will continue to work. The shunt value also need to respect:
rshunt <= pga-gain * 40 * 1000 * 1000.
If not, it's not possible to compute a valid calibration value.
default: 1000
ti,pga-gain:
description: |
The gain value for the PGA function. This is 8, 4, 2 or 1.
The PGA gain affect the shunt voltage range.
The range will be equal to: pga-gain * 40mV
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8]
default: 8
ti,bus-range-microvolt:
description: |
This is the operating range of the bus voltage in microvolt
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
enum: [16000000, 32000000]
default: 32000000
ti,nfactor:
description: |
Array of three(TMP513) or two(TMP512) n-Factor value for each remote
temperature channel.
See datasheet Table 11 for n-Factor range list and value interpretation.
allOf:
- $ref: /schemas/types.yaml#definitions/uint32-array
- minItems: 2
maxItems: 3
items:
default: 0x00
minimum: 0x00
maximum: 0xFF
required:
- compatible
- reg
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
tmp513@5c {
compatible = "ti,tmp513";
reg = <0x5C>;
shunt-resistor-micro-ohms = <330000>;
ti,bus-range-microvolt = <32000000>;
ti,pga-gain = <8>;
ti,nfactor = <0x1 0xF3 0x00>;
};
};
Kernel driver bel-pfe
======================
Supported chips:
* BEL PFE1100
Prefixes: 'pfe1100'
Addresses scanned: -
Datasheet: https://www.belfuse.com/resources/datasheets/powersolutions/ds-bps-pfe1100-12-054xa.pdf
* BEL PFE3000
Prefixes: 'pfe3000'
Addresses scanned: -
Datasheet: https://www.belfuse.com/resources/datasheets/powersolutions/ds-bps-pfe3000-series.pdf
Author: Tao Ren <rentao.bupt@gmail.com>
Description
-----------
This driver supports hardware monitoring for below power supply devices
which support PMBus Protocol:
* BEL PFE1100
1100 Watt AC to DC power-factor-corrected (PFC) power supply.
PMBus Communication Manual is not publicly available.
* BEL PFE3000
3000 Watt AC/DC power-factor-corrected (PFC) and DC-DC power supply.
PMBus Communication Manual is not publicly available.
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.
Example: the following will load the driver for an PFE3000 at address 0x20
on I2C bus #1::
$ modprobe bel-pfe
$ echo pfe3000 0x20 > /sys/bus/i2c/devices/i2c-1/new_device
Platform data support
---------------------
The driver supports standard PMBus driver platform data.
Sysfs entries
-------------
======================= =======================================================
curr1_label "iin"
curr1_input Measured input current
curr1_max Input current max value
curr1_max_alarm Input current max alarm
curr[2-3]_label "iout[1-2]"
curr[2-3]_input Measured output current
curr[2-3]_max Output current max value
curr[2-3]_max_alarm Output current max alarm
fan[1-2]_input Fan 1 and 2 speed in RPM
fan1_target Set fan speed reference for both fans
in1_label "vin"
in1_input Measured input voltage
in1_crit Input voltage critical max value
in1_crit_alarm Input voltage critical max alarm
in1_lcrit Input voltage critical min value
in1_lcrit_alarm Input voltage critical min alarm
in1_max Input voltage max value
in1_max_alarm Input voltage max alarm
in2_label "vcap"
in2_input Hold up capacitor voltage
in[3-8]_label "vout[1-3,5-7]"
in[3-8]_input Measured output voltage
in[3-4]_alarm vout[1-2] output voltage alarm
power[1-2]_label "pin[1-2]"
power[1-2]_input Measured input power
power[1-2]_alarm Input power high alarm
power[3-4]_label "pout[1-2]"
power[3-4]_input Measured output power
temp[1-3]_input Measured temperature
temp[1-3]_alarm Temperature alarm
======================= =======================================================
.. note::
- curr3, fan2, vout[2-7], vcap, pin2, pout2 and temp3 attributes only
exist for PFE3000.
.. SPDX-License-Identifier: GPL-2.0-or-later
.. include:: <isonum.txt>
Kernel driver dell-smm-hwmon
============================
:Copyright: |copy| 2002-2005 Massimo Dal Zotto <dz@debian.org>
:Copyright: |copy| 2019 Giovanni Mascellani <gio@debian.org>
Description
-----------
On many Dell laptops the System Management Mode (SMM) BIOS can be
queried for the status of fans and temperature sensors. Userspace
utilities like ``sensors`` can be used to return the readings. The
userspace suite `i8kutils`__ can also be used to read the sensors and
automatically adjust fan speed (please notice that it currently uses
the deprecated ``/proc/i8k`` interface).
__ https://github.com/vitorafsr/i8kutils
``sysfs`` interface
-------------------
Temperature sensors and fans can be queried and set via the standard
``hwmon`` interface on ``sysfs``, under the directory
``/sys/class/hwmon/hwmonX`` for some value of ``X`` (search for the
``X`` such that ``/sys/class/hwmon/hwmonX/name`` has content
``dell_smm``). A number of other attributes can be read or written:
=============================== ======= =======================================
Name Perm Description
=============================== ======= =======================================
fan[1-3]_input RO Fan speed in RPM.
fan[1-3]_label RO Fan label.
pwm[1-3] RW Control the fan PWM duty-cycle.
pwm1_enable WO Enable or disable automatic BIOS fan
control (not supported on all laptops,
see below for details).
temp[1-10]_input RO Temperature reading in milli-degrees
Celsius.
temp[1-10]_label RO Temperature sensor label.
=============================== ======= =======================================
Disabling automatic BIOS fan control
------------------------------------
On some laptops the BIOS automatically sets fan speed every few
seconds. Therefore the fan speed set by mean of this driver is quickly
overwritten.
There is experimental support for disabling automatic BIOS fan
control, at least on laptops where the corresponding SMM command is
known, by writing the value ``1`` in the attribute ``pwm1_enable``
(writing ``2`` enables automatic BIOS control again). Even if you have
more than one fan, all of them are set to either enabled or disabled
automatic fan control at the same time and, notwithstanding the name,
``pwm1_enable`` sets automatic control for all fans.
If ``pwm1_enable`` is not available, then it means that SMM codes for
enabling and disabling automatic BIOS fan control are not whitelisted
for your hardware. It is possible that codes that work for other
laptops actually work for yours as well, or that you have to discover
new codes.
Check the list ``i8k_whitelist_fan_control`` in file
``drivers/hwmon/dell-smm-hwmon.c`` in the kernel tree: as a first
attempt you can try to add your machine and use an already-known code
pair. If, after recompiling the kernel, you see that ``pwm1_enable``
is present and works (i.e., you can manually control the fan speed),
then please submit your finding as a kernel patch, so that other users
can benefit from it. Please see
:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
for information on submitting patches.
If no known code works on your machine, you need to resort to do some
probing, because unfortunately Dell does not publish datasheets for
its SMM. You can experiment with the code in `this repository`__ to
probe the BIOS on your machine and discover the appropriate codes.
__ https://github.com/clopez/dellfan/
Again, when you find new codes, we'd be happy to have your patches!
Module parameters
-----------------
* force:bool
Force loading without checking for supported
models. (default: 0)
* ignore_dmi:bool
Continue probing hardware even if DMI data does not
match. (default: 0)
* restricted:bool
Allow fan control only to processes with the
``CAP_SYS_ADMIN`` capability set or processes run
as root when using the legacy ``/proc/i8k``
interface. In this case normal users will be able
to read temperature and fan status but not to
control the fan. If your notebook is shared with
other users and you don't trust them you may want
to use this option. (default: 1, only available
with ``CONFIG_I8K``)
* power_status:bool
Report AC status in ``/proc/i8k``. (default: 0,
only available with ``CONFIG_I8K``)
* fan_mult:uint
Factor to multiply fan speed with. (default:
autodetect)
* fan_max:uint
Maximum configurable fan speed. (default:
autodetect)
Legacy ``/proc`` interface
--------------------------
.. warning:: This interface is obsolete and deprecated and should not
used in new applications. This interface is only
available when kernel is compiled with option
``CONFIG_I8K``.
The information provided by the kernel driver can be accessed by
simply reading the ``/proc/i8k`` file. For example::
$ cat /proc/i8k
1.0 A17 2J59L02 52 2 1 8040 6420 1 2
The fields read from ``/proc/i8k`` are::
1.0 A17 2J59L02 52 2 1 8040 6420 1 2
| | | | | | | | | |
| | | | | | | | | +------- 10. buttons status
| | | | | | | | +--------- 9. AC status
| | | | | | | +-------------- 8. fan0 RPM
| | | | | | +------------------- 7. fan1 RPM
| | | | | +--------------------- 6. fan0 status
| | | | +----------------------- 5. fan1 status
| | | +-------------------------- 4. temp0 reading (Celsius)
| | +---------------------------------- 3. Dell service tag (later known as 'serial number')
| +-------------------------------------- 2. BIOS version
+------------------------------------------ 1. /proc/i8k format version
A negative value, for example -22, indicates that the BIOS doesn't
return the corresponding information. This is normal on some
models/BIOSes.
For performance reasons the ``/proc/i8k`` doesn't report by default
the AC status since this SMM call takes a long time to execute and is
not really needed. If you want to see the ac status in ``/proc/i8k``
you must explictitly enable this option by passing the
``power_status=1`` parameter to insmod. If AC status is not
available -1 is printed instead.
The driver provides also an ioctl interface which can be used to
obtain the same information and to control the fan status. The ioctl
interface can be accessed from C programs or from shell using the
i8kctl utility. See the source file of ``i8kutils`` for more
information on how to use the ioctl interface.
...@@ -41,6 +41,18 @@ curr[123]_max Warning alert current(mA) setting, activates the ...@@ -41,6 +41,18 @@ curr[123]_max Warning alert current(mA) setting, activates the
average is above this value. average is above this value.
curr[123]_max_alarm Warning alert current limit exceeded curr[123]_max_alarm Warning alert current limit exceeded
in[456]_input Shunt voltage(uV) for channels 1, 2, and 3 respectively in[456]_input Shunt voltage(uV) for channels 1, 2, and 3 respectively
in7_input Sum of shunt voltage(uV) channels
in7_label Channel label for sum of shunt voltage
curr4_input Sum of current(mA) measurement channels,
(only available when all channels use the same resistor
value for their shunt resistors)
curr4_crit Critical alert current(mA) setting for sum of current
measurements, activates the corresponding alarm
when the respective current is above this value
(only effective when all channels use the same resistor
value for their shunt resistors)
curr4_crit_alarm Critical alert current limit exceeded for sum of
current measurements.
samples Number of samples using in the averaging mode. samples Number of samples using in the averaging mode.
Supports the list of number of samples: Supports the list of number of samples:
......
...@@ -41,9 +41,11 @@ Hardware Monitoring Kernel Drivers ...@@ -41,9 +41,11 @@ Hardware Monitoring Kernel Drivers
asb100 asb100
asc7621 asc7621
aspeed-pwm-tacho aspeed-pwm-tacho
bel-pfe
coretemp coretemp
da9052 da9052
da9055 da9055
dell-smm-hwmon
dme1737 dme1737
ds1621 ds1621
ds620 ds620
...@@ -90,6 +92,7 @@ Hardware Monitoring Kernel Drivers ...@@ -90,6 +92,7 @@ Hardware Monitoring Kernel Drivers
lm95245 lm95245
lochnagar lochnagar
ltc2945 ltc2945
ltc2947
ltc2978 ltc2978
ltc2990 ltc2990
ltc3815 ltc3815
...@@ -153,6 +156,7 @@ Hardware Monitoring Kernel Drivers ...@@ -153,6 +156,7 @@ Hardware Monitoring Kernel Drivers
tmp108 tmp108
tmp401 tmp401
tmp421 tmp421
tmp513
tps40422 tps40422
twl4030-madc-hwmon twl4030-madc-hwmon
ucd9000 ucd9000
......
Kernel drivers ltc2947-i2c and ltc2947-spi
==========================================
Supported chips:
* Analog Devices LTC2947
Prefix: 'ltc2947'
Addresses scanned: -
Datasheet:
https://www.analog.com/media/en/technical-documentation/data-sheets/LTC2947.pdf
Author: Nuno Sá <nuno.sa@analog.com>
Description
___________
The LTC2947 is a high precision power and energy monitor that measures current,
voltage, power, temperature, charge and energy. The device supports both SPI
and I2C depending on the chip configuration.
The device also measures accumulated quantities as energy. It has two banks of
register's to read/set energy related values. These banks can be configured
independently to have setups like: energy1 accumulates always and enrgy2 only
accumulates if current is positive (to check battery charging efficiency for
example). The device also supports a GPIO pin that can be configured as output
to control a fan as a function of measured temperature. Then, the GPIO becomes
active as soon as a temperature reading is higher than a defined threshold. The
temp2 channel is used to control this thresholds and to read the respective
alarms.
Sysfs entries
_____________
The following attributes are supported. Limits are read-write, reset_history
is write-only and all the other attributes are read-only.
======================= ==========================================
in0_input VP-VM voltage (mV).
in0_min Undervoltage threshold
in0_max Overvoltage threshold
in0_lowest Lowest measured voltage
in0_highest Highest measured voltage
in0_reset_history Write 1 to reset in1 history
in0_min_alarm Undervoltage alarm
in0_max_alarm Overvoltage alarm
in0_label Channel label (VP-VM)
in1_input DVCC voltage (mV)
in1_min Undervoltage threshold
in1_max Overvoltage threshold
in1_lowest Lowest measured voltage
in1_highest Highest measured voltage
in1_reset_history Write 1 to reset in2 history
in1_min_alarm Undervoltage alarm
in1_max_alarm Overvoltage alarm
in1_label Channel label (DVCC)
curr1_input IP-IM Sense current (mA)
curr1_min Undercurrent threshold
curr1_max Overcurrent threshold
curr1_lowest Lowest measured current
curr1_highest Highest measured current
curr1_reset_history Write 1 to reset curr1 history
curr1_min_alarm Undercurrent alarm
curr1_max_alarm Overcurrent alarm
curr1_label Channel label (IP-IM)
power1_input Power (in uW)
power1_min Low power threshold
power1_max High power threshold
power1_input_lowest Historical minimum power use
power1_input_highest Historical maximum power use
power1_reset_history Write 1 to reset power1 history
power1_min_alarm Low power alarm
power1_max_alarm High power alarm
power1_label Channel label (Power)
temp1_input Chip Temperature (in milliC)
temp1_min Low temperature threshold
temp1_max High temperature threshold
temp1_input_lowest Historical minimum temperature use
temp1_input_highest Historical maximum temperature use
temp1_reset_history Write 1 to reset temp1 history
temp1_min_alarm Low temperature alarm
temp1_max_alarm High temperature alarm
temp1_label Channel label (Ambient)
temp2_min Low temperature threshold for fan control
temp2_max High temperature threshold for fan control
temp2_min_alarm Low temperature fan control alarm
temp2_max_alarm High temperature fan control alarm
temp2_label Channel label (TEMPFAN)
energy1_input Measured energy over time (in microJoule)
energy2_input Measured energy over time (in microJoule)
======================= ==========================================
.. SPDX-License-Identifier: GPL-2.0
Kernel driver tmp513
====================
Supported chips:
* Texas Instruments TMP512
Prefix: 'tmp512'
Datasheet: http://www.ti.com/lit/ds/symlink/tmp512.pdf
* Texas Instruments TMP513
Prefix: 'tmp513'
Datasheet: http://www.ti.com/lit/ds/symlink/tmp513.pdf
Authors:
Eric Tremblay <etremblay@distech-controls.com>
Description
-----------
This driver implements support for Texas Instruments TMP512, and TMP513.
The TMP512 (dual-channel) and TMP513 (triple-channel) are system monitors
that include remote sensors, a local temperature sensor, and a high-side current
shunt monitor. These system monitors have the capability of measuring remote
temperatures, on-chip temperatures, and system voltage/power/current
consumption.
The temperatures are measured in degrees Celsius with a range of
-40 to + 125 degrees with a resolution of 0.0625 degree C.
For hysteresis value, only the first channel is writable. Writing to it
will affect all other values since each channels are sharing the same
hysteresis value. The hysteresis is in degrees Celsius with a range of
0 to 127.5 degrees with a resolution of 0.5 degree.
The driver exports the temperature values via the following sysfs files:
**temp[1-4]_input**
**temp[1-4]_crit**
**temp[1-4]_crit_alarm**
**temp[1-4]_crit_hyst**
The driver read the shunt voltage from the chip and convert it to current.
The readable range depends on the "ti,pga-gain" property (default to 8) and the
shunt resistor value. The value resolution will be equal to 10uV/Rshunt.
The driver exports the shunt currents values via the following sysFs files:
**curr1_input**
**curr1_lcrit**
**curr1_lcrit_alarm**
**curr1_crit**
**curr1_crit_alarm**
The bus voltage range is read from the chip with a resolution of 4mV. The chip
can be configurable in two different range (32V or 16V) using the
ti,bus-range-microvolt property in the devicetree.
The driver exports the bus voltage values via the following sysFs files:
**in0_input**
**in0_lcrit**
**in0_lcrit_alarm**
**in0_crit**
**in0_crit_alarm**
The bus power and bus currents range and resolution depends on the calibration
register value. Those values are calculate by the hardware using those
formulas:
Current = (ShuntVoltage * CalibrationRegister) / 4096
Power = (Current * BusVoltage) / 5000
The driver exports the bus current and bus power values via the following
sysFs files:
**curr2_input**
**power1_input**
**power1_crit**
**power1_crit_alarm**
The calibration process follow the procedure of the datasheet (without overflow)
and depend on the shunt resistor value and the pga_gain value.
...@@ -9717,6 +9717,17 @@ S: Maintained ...@@ -9717,6 +9717,17 @@ S: Maintained
F: Documentation/hwmon/ltc4261.rst F: Documentation/hwmon/ltc4261.rst
F: drivers/hwmon/ltc4261.c F: drivers/hwmon/ltc4261.c
LTC2947 HARDWARE MONITOR DRIVER
M: Nuno Sá <nuno.sa@analog.com>
W: http://ez.analog.com/community/linux-device-drivers
L: linux-hwmon@vger.kernel.org
S: Supported
F: drivers/hwmon/ltc2947-core.c
F: drivers/hwmon/ltc2947-spi.c
F: drivers/hwmon/ltc2947-i2c.c
F: drivers/hwmon/ltc2947.h
F: Documentation/devicetree/bindings/hwmon/adi,ltc2947.yaml
LTC4306 I2C MULTIPLEXER DRIVER LTC4306 I2C MULTIPLEXER DRIVER
M: Michael Hennerich <michael.hennerich@analog.com> M: Michael Hennerich <michael.hennerich@analog.com>
W: http://ez.analog.com/community/linux-device-drivers W: http://ez.analog.com/community/linux-device-drivers
...@@ -16493,6 +16504,13 @@ S: Maintained ...@@ -16493,6 +16504,13 @@ S: Maintained
F: Documentation/hwmon/tmp401.rst F: Documentation/hwmon/tmp401.rst
F: drivers/hwmon/tmp401.c F: drivers/hwmon/tmp401.c
TMP513 HARDWARE MONITOR DRIVER
M: Eric Tremblay <etremblay@distech-controls.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/tmp513.rst
F: drivers/hwmon/tmp513.c
TMPFS (SHMEM FILESYSTEM) TMPFS (SHMEM FILESYSTEM)
M: Hugh Dickins <hughd@google.com> M: Hugh Dickins <hughd@google.com>
L: linux-mm@kvack.org L: linux-mm@kvack.org
......
...@@ -310,7 +310,6 @@ config SENSORS_APPLESMC ...@@ -310,7 +310,6 @@ config SENSORS_APPLESMC
depends on INPUT && X86 depends on INPUT && X86
select NEW_LEDS select NEW_LEDS
select LEDS_CLASS select LEDS_CLASS
select INPUT_POLLDEV
help help
This driver provides support for the Apple System Management This driver provides support for the Apple System Management
Controller, which provides an accelerometer (Apple Sudden Motion Controller, which provides an accelerometer (Apple Sudden Motion
...@@ -728,6 +727,33 @@ config SENSORS_LTC2945 ...@@ -728,6 +727,33 @@ config SENSORS_LTC2945
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called ltc2945. be called ltc2945.
config SENSORS_LTC2947
tristate
config SENSORS_LTC2947_I2C
tristate "Analog Devices LTC2947 High Precision Power and Energy Monitor over I2C"
depends on I2C
select REGMAP_I2C
select SENSORS_LTC2947
help
If you say yes here you get support for Linear Technology LTC2947
I2C High Precision Power and Energy Monitor
This driver can also be built as a module. If so, the module will
be called ltc2947-i2c.
config SENSORS_LTC2947_SPI
tristate "Analog Devices LTC2947 High Precision Power and Energy Monitor over SPI"
depends on SPI_MASTER
select REGMAP_SPI
select SENSORS_LTC2947
help
If you say yes here you get support for Linear Technology LTC2947
SPI High Precision Power and Energy Monitor
This driver can also be built as a module. If so, the module will
be called ltc2947-spi.
config SENSORS_LTC2990 config SENSORS_LTC2990
tristate "Linear Technology LTC2990" tristate "Linear Technology LTC2990"
depends on I2C depends on I2C
...@@ -1710,6 +1736,16 @@ config SENSORS_TMP421 ...@@ -1710,6 +1736,16 @@ config SENSORS_TMP421
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called tmp421. will be called tmp421.
config SENSORS_TMP513
tristate "Texas Instruments TMP513 and compatibles"
depends on I2C
help
If you say yes here you get support for Texas Instruments TMP512,
and TMP513 temperature and power supply sensor chips.
This driver can also be built as a module. If so, the module
will be called tmp513.
config SENSORS_VEXPRESS config SENSORS_VEXPRESS
tristate "Versatile Express" tristate "Versatile Express"
depends on VEXPRESS_CONFIG depends on VEXPRESS_CONFIG
......
...@@ -106,6 +106,9 @@ obj-$(CONFIG_SENSORS_LM95234) += lm95234.o ...@@ -106,6 +106,9 @@ obj-$(CONFIG_SENSORS_LM95234) += lm95234.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LM95245) += lm95245.o obj-$(CONFIG_SENSORS_LM95245) += lm95245.o
obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o
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_LTC2990) += ltc2990.o
obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
...@@ -166,6 +169,7 @@ obj-$(CONFIG_SENSORS_TMP103) += tmp103.o ...@@ -166,6 +169,7 @@ obj-$(CONFIG_SENSORS_TMP103) += tmp103.o
obj-$(CONFIG_SENSORS_TMP108) += tmp108.o obj-$(CONFIG_SENSORS_TMP108) += tmp108.o
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
obj-$(CONFIG_SENSORS_TMP513) += tmp513.o
obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
......
...@@ -1264,7 +1264,7 @@ static int abituguru_probe(struct platform_device *pdev) ...@@ -1264,7 +1264,7 @@ static int abituguru_probe(struct platform_device *pdev)
* El weirdo probe order, to keep the sysfs order identical to the * El weirdo probe order, to keep the sysfs order identical to the
* BIOS and window-appliction listing order. * BIOS and window-appliction listing order.
*/ */
const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = { static const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = {
0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02, 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C }; 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/input-polldev.h> #include <linux/input.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -140,7 +140,7 @@ static s16 rest_y; ...@@ -140,7 +140,7 @@ static s16 rest_y;
static u8 backlight_state[2]; static u8 backlight_state[2];
static struct device *hwmon_dev; static struct device *hwmon_dev;
static struct input_polled_dev *applesmc_idev; static struct input_dev *applesmc_idev;
/* /*
* Last index written to key_at_index sysfs file, and value to use for all other * Last index written to key_at_index sysfs file, and value to use for all other
...@@ -681,9 +681,8 @@ static void applesmc_calibrate(void) ...@@ -681,9 +681,8 @@ static void applesmc_calibrate(void)
rest_x = -rest_x; rest_x = -rest_x;
} }
static void applesmc_idev_poll(struct input_polled_dev *dev) static void applesmc_idev_poll(struct input_dev *idev)
{ {
struct input_dev *idev = dev->input;
s16 x, y; s16 x, y;
if (applesmc_read_s16(MOTION_SENSOR_X_KEY, &x)) if (applesmc_read_s16(MOTION_SENSOR_X_KEY, &x))
...@@ -1134,7 +1133,6 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num) ...@@ -1134,7 +1133,6 @@ static int applesmc_create_nodes(struct applesmc_node_group *groups, int num)
/* Create accelerometer resources */ /* Create accelerometer resources */
static int applesmc_create_accelerometer(void) static int applesmc_create_accelerometer(void)
{ {
struct input_dev *idev;
int ret; int ret;
if (!smcreg.has_accelerometer) if (!smcreg.has_accelerometer)
...@@ -1144,37 +1142,38 @@ static int applesmc_create_accelerometer(void) ...@@ -1144,37 +1142,38 @@ static int applesmc_create_accelerometer(void)
if (ret) if (ret)
goto out; goto out;
applesmc_idev = input_allocate_polled_device(); applesmc_idev = input_allocate_device();
if (!applesmc_idev) { if (!applesmc_idev) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_sysfs; goto out_sysfs;
} }
applesmc_idev->poll = applesmc_idev_poll;
applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL;
/* initial calibrate for the input device */ /* initial calibrate for the input device */
applesmc_calibrate(); applesmc_calibrate();
/* initialize the input device */ /* initialize the input device */
idev = applesmc_idev->input; applesmc_idev->name = "applesmc";
idev->name = "applesmc"; applesmc_idev->id.bustype = BUS_HOST;
idev->id.bustype = BUS_HOST; applesmc_idev->dev.parent = &pdev->dev;
idev->dev.parent = &pdev->dev; input_set_abs_params(applesmc_idev, ABS_X,
idev->evbit[0] = BIT_MASK(EV_ABS);
input_set_abs_params(idev, ABS_X,
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
input_set_abs_params(idev, ABS_Y, input_set_abs_params(applesmc_idev, ABS_Y,
-256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
ret = input_register_polled_device(applesmc_idev); ret = input_setup_polling(applesmc_idev, applesmc_idev_poll);
if (ret)
goto out_idev;
input_set_poll_interval(applesmc_idev, APPLESMC_POLL_INTERVAL);
ret = input_register_device(applesmc_idev);
if (ret) if (ret)
goto out_idev; goto out_idev;
return 0; return 0;
out_idev: out_idev:
input_free_polled_device(applesmc_idev); input_free_device(applesmc_idev);
out_sysfs: out_sysfs:
applesmc_destroy_nodes(accelerometer_group); applesmc_destroy_nodes(accelerometer_group);
...@@ -1189,8 +1188,7 @@ static void applesmc_release_accelerometer(void) ...@@ -1189,8 +1188,7 @@ static void applesmc_release_accelerometer(void)
{ {
if (!smcreg.has_accelerometer) if (!smcreg.has_accelerometer)
return; return;
input_unregister_polled_device(applesmc_idev); input_unregister_device(applesmc_idev);
input_free_polled_device(applesmc_idev);
applesmc_destroy_nodes(accelerometer_group); applesmc_destroy_nodes(accelerometer_group);
} }
......
...@@ -891,17 +891,12 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev) ...@@ -891,17 +891,12 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
struct device_node *np, *child; struct device_node *np, *child;
struct aspeed_pwm_tacho_data *priv; struct aspeed_pwm_tacho_data *priv;
void __iomem *regs; void __iomem *regs;
struct resource *res;
struct device *hwmon; struct device *hwmon;
struct clk *clk; struct clk *clk;
int ret; int ret;
np = dev->of_node; np = dev->of_node;
regs = devm_platform_ioremap_resource(pdev, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs)) if (IS_ERR(regs))
return PTR_ERR(regs); return PTR_ERR(regs);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
......
...@@ -68,6 +68,8 @@ static uint i8k_pwm_mult; ...@@ -68,6 +68,8 @@ static uint i8k_pwm_mult;
static uint i8k_fan_max = I8K_FAN_HIGH; static uint i8k_fan_max = I8K_FAN_HIGH;
static bool disallow_fan_type_call; static bool disallow_fan_type_call;
static bool disallow_fan_support; static bool disallow_fan_support;
static unsigned int manual_fan;
static unsigned int auto_fan;
#define I8K_HWMON_HAVE_TEMP1 (1 << 0) #define I8K_HWMON_HAVE_TEMP1 (1 << 0)
#define I8K_HWMON_HAVE_TEMP2 (1 << 1) #define I8K_HWMON_HAVE_TEMP2 (1 << 1)
...@@ -300,6 +302,20 @@ static int i8k_get_fan_nominal_speed(int fan, int speed) ...@@ -300,6 +302,20 @@ static int i8k_get_fan_nominal_speed(int fan, int speed)
return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult; return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
} }
/*
* Enable or disable automatic BIOS fan control support
*/
static int i8k_enable_fan_auto_mode(bool enable)
{
struct smm_regs regs = { };
if (disallow_fan_support)
return -EINVAL;
regs.eax = enable ? auto_fan : manual_fan;
return i8k_smm(&regs);
}
/* /*
* Set the fan speed (off, low, high). Returns the new fan status. * Set the fan speed (off, low, high). Returns the new fan status.
*/ */
...@@ -726,6 +742,35 @@ static ssize_t i8k_hwmon_pwm_store(struct device *dev, ...@@ -726,6 +742,35 @@ static ssize_t i8k_hwmon_pwm_store(struct device *dev,
return err < 0 ? -EIO : count; return err < 0 ? -EIO : count;
} }
static ssize_t i8k_hwmon_pwm_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int err;
bool enable;
unsigned long val;
if (!auto_fan)
return -ENODEV;
err = kstrtoul(buf, 10, &val);
if (err)
return err;
if (val == 1)
enable = false;
else if (val == 2)
enable = true;
else
return -EINVAL;
mutex_lock(&i8k_mutex);
err = i8k_enable_fan_auto_mode(enable);
mutex_unlock(&i8k_mutex);
return err ? err : count;
}
static SENSOR_DEVICE_ATTR_RO(temp1_input, i8k_hwmon_temp, 0); static SENSOR_DEVICE_ATTR_RO(temp1_input, i8k_hwmon_temp, 0);
static SENSOR_DEVICE_ATTR_RO(temp1_label, i8k_hwmon_temp_label, 0); static SENSOR_DEVICE_ATTR_RO(temp1_label, i8k_hwmon_temp_label, 0);
static SENSOR_DEVICE_ATTR_RO(temp2_input, i8k_hwmon_temp, 1); static SENSOR_DEVICE_ATTR_RO(temp2_input, i8k_hwmon_temp, 1);
...@@ -749,6 +794,7 @@ static SENSOR_DEVICE_ATTR_RO(temp10_label, i8k_hwmon_temp_label, 9); ...@@ -749,6 +794,7 @@ static SENSOR_DEVICE_ATTR_RO(temp10_label, i8k_hwmon_temp_label, 9);
static SENSOR_DEVICE_ATTR_RO(fan1_input, i8k_hwmon_fan, 0); static SENSOR_DEVICE_ATTR_RO(fan1_input, i8k_hwmon_fan, 0);
static SENSOR_DEVICE_ATTR_RO(fan1_label, i8k_hwmon_fan_label, 0); static SENSOR_DEVICE_ATTR_RO(fan1_label, i8k_hwmon_fan_label, 0);
static SENSOR_DEVICE_ATTR_RW(pwm1, i8k_hwmon_pwm, 0); static SENSOR_DEVICE_ATTR_RW(pwm1, i8k_hwmon_pwm, 0);
static SENSOR_DEVICE_ATTR_WO(pwm1_enable, i8k_hwmon_pwm_enable, 0);
static SENSOR_DEVICE_ATTR_RO(fan2_input, i8k_hwmon_fan, 1); static SENSOR_DEVICE_ATTR_RO(fan2_input, i8k_hwmon_fan, 1);
static SENSOR_DEVICE_ATTR_RO(fan2_label, i8k_hwmon_fan_label, 1); static SENSOR_DEVICE_ATTR_RO(fan2_label, i8k_hwmon_fan_label, 1);
static SENSOR_DEVICE_ATTR_RW(pwm2, i8k_hwmon_pwm, 1); static SENSOR_DEVICE_ATTR_RW(pwm2, i8k_hwmon_pwm, 1);
...@@ -780,12 +826,13 @@ static struct attribute *i8k_attrs[] = { ...@@ -780,12 +826,13 @@ static struct attribute *i8k_attrs[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr, /* 20 */ &sensor_dev_attr_fan1_input.dev_attr.attr, /* 20 */
&sensor_dev_attr_fan1_label.dev_attr.attr, /* 21 */ &sensor_dev_attr_fan1_label.dev_attr.attr, /* 21 */
&sensor_dev_attr_pwm1.dev_attr.attr, /* 22 */ &sensor_dev_attr_pwm1.dev_attr.attr, /* 22 */
&sensor_dev_attr_fan2_input.dev_attr.attr, /* 23 */ &sensor_dev_attr_pwm1_enable.dev_attr.attr, /* 23 */
&sensor_dev_attr_fan2_label.dev_attr.attr, /* 24 */ &sensor_dev_attr_fan2_input.dev_attr.attr, /* 24 */
&sensor_dev_attr_pwm2.dev_attr.attr, /* 25 */ &sensor_dev_attr_fan2_label.dev_attr.attr, /* 25 */
&sensor_dev_attr_fan3_input.dev_attr.attr, /* 26 */ &sensor_dev_attr_pwm2.dev_attr.attr, /* 26 */
&sensor_dev_attr_fan3_label.dev_attr.attr, /* 27 */ &sensor_dev_attr_fan3_input.dev_attr.attr, /* 27 */
&sensor_dev_attr_pwm3.dev_attr.attr, /* 28 */ &sensor_dev_attr_fan3_label.dev_attr.attr, /* 28 */
&sensor_dev_attr_pwm3.dev_attr.attr, /* 29 */
NULL NULL
}; };
...@@ -828,16 +875,19 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, ...@@ -828,16 +875,19 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
!(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP10)) !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP10))
return 0; return 0;
if (index >= 20 && index <= 22 && if (index >= 20 && index <= 23 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
return 0; return 0;
if (index >= 23 && index <= 25 && if (index >= 24 && index <= 26 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
return 0; return 0;
if (index >= 26 && index <= 28 && if (index >= 27 && index <= 29 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3)) !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3))
return 0; return 0;
if (index == 23 && !auto_fan)
return 0;
return attr->mode; return attr->mode;
} }
...@@ -1135,12 +1185,48 @@ static struct dmi_system_id i8k_blacklist_fan_support_dmi_table[] __initdata = { ...@@ -1135,12 +1185,48 @@ static struct dmi_system_id i8k_blacklist_fan_support_dmi_table[] __initdata = {
{ } { }
}; };
struct i8k_fan_control_data {
unsigned int manual_fan;
unsigned int auto_fan;
};
enum i8k_fan_controls {
I8K_FAN_34A3_35A3,
};
static const struct i8k_fan_control_data i8k_fan_control_data[] = {
[I8K_FAN_34A3_35A3] = {
.manual_fan = 0x34a3,
.auto_fan = 0x35a3,
},
};
static struct dmi_system_id i8k_whitelist_fan_control[] __initdata = {
{
.ident = "Dell Precision 5530",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Precision 5530"),
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{
.ident = "Dell Latitude E6440",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"),
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{ }
};
/* /*
* Probe for the presence of a supported laptop. * Probe for the presence of a supported laptop.
*/ */
static int __init i8k_probe(void) static int __init i8k_probe(void)
{ {
const struct dmi_system_id *id; const struct dmi_system_id *id, *fan_control;
int fan, ret; int fan, ret;
/* /*
...@@ -1200,6 +1286,15 @@ static int __init i8k_probe(void) ...@@ -1200,6 +1286,15 @@ static int __init i8k_probe(void)
i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
fan_control = dmi_first_match(i8k_whitelist_fan_control);
if (fan_control && fan_control->driver_data) {
const struct i8k_fan_control_data *data = fan_control->driver_data;
manual_fan = data->manual_fan;
auto_fan = data->auto_fan;
pr_info("enabling support for setting automatic/manual fan control\n");
}
if (!fan_mult) { if (!fan_mult) {
/* /*
* Autodetect fan multiplier based on nominal rpm * Autodetect fan multiplier based on nominal rpm
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices LTC2947 high precision power and energy monitor over I2C
*
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "ltc2947.h"
static const struct regmap_config ltc2947_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int ltc2947_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct regmap *map;
map = devm_regmap_init_i2c(i2c, &ltc2947_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
return ltc2947_core_probe(map, i2c->name);
}
static const struct i2c_device_id ltc2947_id[] = {
{"ltc2947", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc2947_id);
static struct i2c_driver ltc2947_driver = {
.driver = {
.name = "ltc2947",
.of_match_table = ltc2947_of_match,
.pm = &ltc2947_pm_ops,
},
.probe = ltc2947_probe,
.id_table = ltc2947_id,
};
module_i2c_driver(ltc2947_driver);
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
MODULE_DESCRIPTION("LTC2947 I2C power and energy monitor driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
/*
* Analog Devices LTC2947 high precision power and energy monitor over SPI
*
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "ltc2947.h"
static const struct regmap_config ltc2947_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.read_flag_mask = BIT(0),
};
static int ltc2947_probe(struct spi_device *spi)
{
struct regmap *map;
map = devm_regmap_init_spi(spi, &ltc2947_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
return ltc2947_core_probe(map, spi_get_device_id(spi)->name);
}
static const struct spi_device_id ltc2947_id[] = {
{"ltc2947", 0},
{}
};
MODULE_DEVICE_TABLE(spi, ltc2947_id);
static struct spi_driver ltc2947_driver = {
.driver = {
.name = "ltc2947",
.of_match_table = ltc2947_of_match,
.pm = &ltc2947_pm_ops,
},
.probe = ltc2947_probe,
.id_table = ltc2947_id,
};
module_spi_driver(ltc2947_driver);
MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
MODULE_DESCRIPTION("LTC2947 SPI power and energy monitor driver");
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_LTC2947_H
#define _LINUX_LTC2947_H
struct regmap;
extern const struct of_device_id ltc2947_of_match[];
extern const struct dev_pm_ops ltc2947_pm_ops;
int ltc2947_core_probe(struct regmap *map, const char *name);
#endif
...@@ -36,6 +36,15 @@ config SENSORS_ADM1275 ...@@ -36,6 +36,15 @@ config SENSORS_ADM1275
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called adm1275. be called adm1275.
config SENSORS_BEL_PFE
tristate "Bel PFE Compatible Power Supplies"
help
If you say yes here you get hardware monitoring support for BEL
PFE1100 and PFE3000 Power Supplies.
This driver can also be built as a module. If so, the module will
be called bel-pfe.
config SENSORS_IBM_CFFPS config SENSORS_IBM_CFFPS
tristate "IBM Common Form Factor Power Supply" tristate "IBM Common Form Factor Power Supply"
depends on LEDS_CLASS depends on LEDS_CLASS
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_PMBUS) += pmbus_core.o
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for BEL PFE family power supplies.
*
* Copyright (c) 2019 Facebook Inc.
*/
#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"
enum chips {pfe1100, pfe3000};
/*
* Disable status check for pfe3000 devices, because some devices report
* communication error (invalid command) for VOUT_MODE command (0x20)
* although correct VOUT_MODE (0x16) is returned: it leads to incorrect
* exponent in linear mode.
*/
static struct pmbus_platform_data pfe3000_plat_data = {
.flags = PMBUS_SKIP_STATUS_CHECK,
};
static struct pmbus_driver_info pfe_driver_info[] = {
[pfe1100] = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_FAN] = linear,
.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_POUT |
PMBUS_HAVE_VIN | PMBUS_HAVE_IIN |
PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
PMBUS_HAVE_STATUS_TEMP |
PMBUS_HAVE_FAN12,
},
[pfe3000] = {
.pages = 7,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_FAN] = linear,
/* Page 0: V1. */
.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_POUT | PMBUS_HAVE_FAN12 |
PMBUS_HAVE_VIN | PMBUS_HAVE_IIN |
PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP |
PMBUS_HAVE_VCAP,
/* Page 1: Vsb. */
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
PMBUS_HAVE_POUT,
/*
* Page 2: V1 Ishare.
* Page 3: Reserved.
* Page 4: V1 Cathode.
* Page 5: Vsb Cathode.
* Page 6: V1 Sense.
*/
.func[2] = PMBUS_HAVE_VOUT,
.func[4] = PMBUS_HAVE_VOUT,
.func[5] = PMBUS_HAVE_VOUT,
.func[6] = PMBUS_HAVE_VOUT,
},
};
static int pfe_pmbus_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int model;
model = (int)id->driver_data;
/*
* PFE3000-12-069RA devices may not stay in page 0 during device
* probe which leads to probe failure (read status word failed).
* So let's set the device to page 0 at the beginning.
*/
if (model == pfe3000) {
client->dev.platform_data = &pfe3000_plat_data;
i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
}
return pmbus_do_probe(client, id, &pfe_driver_info[model]);
}
static const struct i2c_device_id pfe_device_id[] = {
{"pfe1100", pfe1100},
{"pfe3000", pfe3000},
{}
};
MODULE_DEVICE_TABLE(i2c, pfe_device_id);
static struct i2c_driver pfe_pmbus_driver = {
.driver = {
.name = "bel-pfe",
},
.probe = pfe_pmbus_probe,
.remove = pmbus_do_remove,
.id_table = pfe_device_id,
};
module_i2c_driver(pfe_pmbus_driver);
MODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>");
MODULE_DESCRIPTION("PMBus driver for BEL PFE Family Power Supplies");
MODULE_LICENSE("GPL");
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* Copyright 2017 IBM Corp. * Copyright 2017 IBM Corp.
*/ */
#include <linux/bitfield.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
...@@ -29,6 +30,10 @@ ...@@ -29,6 +30,10 @@
#define CFFPS_INPUT_HISTORY_CMD 0xD6 #define CFFPS_INPUT_HISTORY_CMD 0xD6
#define CFFPS_INPUT_HISTORY_SIZE 100 #define CFFPS_INPUT_HISTORY_SIZE 100
#define CFFPS_CCIN_VERSION GENMASK(15, 8)
#define CFFPS_CCIN_VERSION_1 0x2b
#define CFFPS_CCIN_VERSION_2 0x2e
/* STATUS_MFR_SPECIFIC bits */ /* STATUS_MFR_SPECIFIC bits */
#define CFFPS_MFR_FAN_FAULT BIT(0) #define CFFPS_MFR_FAN_FAULT BIT(0)
#define CFFPS_MFR_THERMAL_FAULT BIT(1) #define CFFPS_MFR_THERMAL_FAULT BIT(1)
...@@ -39,9 +44,13 @@ ...@@ -39,9 +44,13 @@
#define CFFPS_MFR_VAUX_FAULT BIT(6) #define CFFPS_MFR_VAUX_FAULT BIT(6)
#define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7) #define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7)
/*
* LED off state actually relinquishes LED control to PSU firmware, so it can
* turn on the LED for faults.
*/
#define CFFPS_LED_OFF 0
#define CFFPS_LED_BLINK BIT(0) #define CFFPS_LED_BLINK BIT(0)
#define CFFPS_LED_ON BIT(1) #define CFFPS_LED_ON BIT(1)
#define CFFPS_LED_OFF BIT(2)
#define CFFPS_BLINK_RATE_MS 250 #define CFFPS_BLINK_RATE_MS 250
enum { enum {
...@@ -54,7 +63,7 @@ enum { ...@@ -54,7 +63,7 @@ enum {
CFFPS_DEBUGFS_NUM_ENTRIES CFFPS_DEBUGFS_NUM_ENTRIES
}; };
enum versions { cffps1, cffps2 }; enum versions { cffps1, cffps2, cffps_unknown };
struct ibm_cffps_input_history { struct ibm_cffps_input_history {
struct mutex update_lock; struct mutex update_lock;
...@@ -292,28 +301,38 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page, ...@@ -292,28 +301,38 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
return rc; return rc;
} }
static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev, static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness) enum led_brightness brightness)
{ {
int rc; int rc;
u8 next_led_state;
struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led); struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led);
if (brightness == LED_OFF) { if (brightness == LED_OFF) {
psu->led_state = CFFPS_LED_OFF; next_led_state = CFFPS_LED_OFF;
} else { } else {
brightness = LED_FULL; brightness = LED_FULL;
if (psu->led_state != CFFPS_LED_BLINK) if (psu->led_state != CFFPS_LED_BLINK)
psu->led_state = CFFPS_LED_ON; next_led_state = CFFPS_LED_ON;
else
next_led_state = CFFPS_LED_BLINK;
} }
dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n",
brightness, next_led_state);
pmbus_set_page(psu->client, 0); pmbus_set_page(psu->client, 0);
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
psu->led_state); next_led_state);
if (rc < 0) if (rc < 0)
return; return rc;
psu->led_state = next_led_state;
led_cdev->brightness = brightness; led_cdev->brightness = brightness;
return 0;
} }
static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev, static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
...@@ -323,10 +342,7 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev, ...@@ -323,10 +342,7 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
int rc; int rc;
struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led); struct ibm_cffps *psu = container_of(led_cdev, struct ibm_cffps, led);
psu->led_state = CFFPS_LED_BLINK; dev_dbg(&psu->client->dev, "LED blink set.\n");
if (led_cdev->brightness == LED_OFF)
return 0;
pmbus_set_page(psu->client, 0); pmbus_set_page(psu->client, 0);
...@@ -335,6 +351,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev, ...@@ -335,6 +351,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
if (rc < 0) if (rc < 0)
return rc; return rc;
psu->led_state = CFFPS_LED_BLINK;
led_cdev->brightness = LED_FULL;
*delay_on = CFFPS_BLINK_RATE_MS; *delay_on = CFFPS_BLINK_RATE_MS;
*delay_off = CFFPS_BLINK_RATE_MS; *delay_off = CFFPS_BLINK_RATE_MS;
...@@ -351,7 +369,7 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu) ...@@ -351,7 +369,7 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu)
client->addr); client->addr);
psu->led.name = psu->led_name; psu->led.name = psu->led_name;
psu->led.max_brightness = LED_FULL; psu->led.max_brightness = LED_FULL;
psu->led.brightness_set = ibm_cffps_led_brightness_set; psu->led.brightness_set_blocking = ibm_cffps_led_brightness_set;
psu->led.blink_set = ibm_cffps_led_blink_set; psu->led.blink_set = ibm_cffps_led_blink_set;
rc = devm_led_classdev_register(dev, &psu->led); rc = devm_led_classdev_register(dev, &psu->led);
...@@ -395,7 +413,7 @@ static int ibm_cffps_probe(struct i2c_client *client, ...@@ -395,7 +413,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
int i, rc; int i, rc;
enum versions vs; enum versions vs = cffps_unknown;
struct dentry *debugfs; struct dentry *debugfs;
struct dentry *ibm_cffps_dir; struct dentry *ibm_cffps_dir;
struct ibm_cffps *psu; struct ibm_cffps *psu;
...@@ -405,8 +423,27 @@ static int ibm_cffps_probe(struct i2c_client *client, ...@@ -405,8 +423,27 @@ static int ibm_cffps_probe(struct i2c_client *client,
vs = (enum versions)md; vs = (enum versions)md;
else if (id) else if (id)
vs = (enum versions)id->driver_data; vs = (enum versions)id->driver_data;
else
vs = cffps1; if (vs == cffps_unknown) {
u16 ccin_version = CFFPS_CCIN_VERSION_1;
int ccin = i2c_smbus_read_word_swapped(client, CFFPS_CCIN_CMD);
if (ccin > 0)
ccin_version = FIELD_GET(CFFPS_CCIN_VERSION, ccin);
switch (ccin_version) {
default:
case CFFPS_CCIN_VERSION_1:
vs = cffps1;
break;
case CFFPS_CCIN_VERSION_2:
vs = cffps2;
break;
}
/* Set the client name to include the version number. */
snprintf(client->name, I2C_NAME_SIZE, "cffps%d", vs + 1);
}
client->dev.platform_data = &ibm_cffps_pdata; client->dev.platform_data = &ibm_cffps_pdata;
rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]); rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]);
...@@ -465,6 +502,7 @@ static int ibm_cffps_probe(struct i2c_client *client, ...@@ -465,6 +502,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
static const struct i2c_device_id ibm_cffps_id[] = { static const struct i2c_device_id ibm_cffps_id[] = {
{ "ibm_cffps1", cffps1 }, { "ibm_cffps1", cffps1 },
{ "ibm_cffps2", cffps2 }, { "ibm_cffps2", cffps2 },
{ "ibm_cffps", cffps_unknown },
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, ibm_cffps_id); MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
...@@ -478,6 +516,10 @@ static const struct of_device_id ibm_cffps_of_match[] = { ...@@ -478,6 +516,10 @@ static const struct of_device_id ibm_cffps_of_match[] = {
.compatible = "ibm,cffps2", .compatible = "ibm,cffps2",
.data = (void *)cffps2 .data = (void *)cffps2
}, },
{
.compatible = "ibm,cffps",
.data = (void *)cffps_unknown
},
{} {}
}; };
MODULE_DEVICE_TABLE(of, ibm_cffps_of_match); MODULE_DEVICE_TABLE(of, ibm_cffps_of_match);
......
...@@ -127,7 +127,8 @@ static struct tmp421_data *tmp421_update_device(struct device *dev) ...@@ -127,7 +127,8 @@ static struct tmp421_data *tmp421_update_device(struct device *dev)
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { if (time_after(jiffies, data->last_updated + (HZ / 2)) ||
!data->valid) {
data->config = i2c_smbus_read_byte_data(client, data->config = i2c_smbus_read_byte_data(client,
TMP421_CONFIG_REG_1); TMP421_CONFIG_REG_1);
......
This diff is collapsed.
...@@ -2096,7 +2096,7 @@ static struct w83793_data *w83793_update_device(struct device *dev) ...@@ -2096,7 +2096,7 @@ static struct w83793_data *w83793_update_device(struct device *dev)
static u8 w83793_read_value(struct i2c_client *client, u16 reg) static u8 w83793_read_value(struct i2c_client *client, u16 reg)
{ {
struct w83793_data *data = i2c_get_clientdata(client); struct w83793_data *data = i2c_get_clientdata(client);
u8 res = 0xff; u8 res;
u8 new_bank = reg >> 8; u8 new_bank = reg >> 8;
new_bank |= data->bank & 0xfc; new_bank |= data->bank & 0xfc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment