Commit 0f974581 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull hwmon updates from Guenter Roeck:
 "New drivers:
   - SB-TSI sensors
   - Lineat Technology LTC2992
   - Delta power supplies Q54SJ108A2
   - Maxim MAX127
   - Corsair PSU
   - STMicroelectronics PM6764 Voltage Regulator

  New chip support:
   - P10 added to fsi/occ driver
   - NCT6687D added to nct6883 driver
   - Intel-based Xserves added to applesmc driver
   - AMD family 19h model 01h added to amd_energy driver

  And various minor bug fixes and improvements"

* tag 'hwmon-for-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (41 commits)
  dt-bindings: (hwmon/sbtsi_temp) Add SB-TSI hwmon driver bindings
  hwmon: (sbtsi) Add documentation
  hwmon: (sbtsi) Add basic support for SB-TSI sensors
  hwmon: (iio_hwmon) Drop bogus __refdata annotation
  hwmon: (xgene) Drop bogus __refdata annotation
  dt-bindings: hwmon: convert AD ADM1275 bindings to dt-schema
  hwmon: (occ) Add new temperature sensor type
  fsi: occ: Add support for P10
  dt-bindings: fsi: Add P10 OCC device documentation
  dt-bindings: hwmon: convert TI ADS7828 bindings to dt-schema
  dt-bindings: hwmon: convert AD AD741x bindings to dt-schema
  dt-bindings: hwmon: convert TI INA2xx bindings to dt-schema
  hwmon: (ltc2992) Fix less than zero comparisons with an unsigned integer
  hwmon: (pmbus/q54sj108a2) Correct title underline length
  dt-bindings: hwmon: Add documentation for ltc2992
  hwmon: (ltc2992) Add support for GPIOs.
  hwmon: (ltc2992) Add support
  hwmon: (pmbus) Driver for Delta power supplies Q54SJ108A2
  hwmon: Add driver for STMicroelectronics PM6764 Voltage Regulator
  hwmon: (nct6683) Support NCT6687D.
  ...
parents ce51c2b7 1a033769
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:
......
* 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>;
};
# 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>;
};
};
# 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>;
};
};
# 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>;
};
};
};
...
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>;
};
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;
};
# 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>;
};
};
...
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>;
};
# 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;
};
};
# 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>;
};
};
......@@ -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
......
......@@ -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.
.. 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
......
.. 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.
.. 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
=============== ===============================================
.. 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,
};
......
.. 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
===================== ===== ==================================================
.. 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.
......@@ -4513,6 +4513,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
......@@ -8675,7 +8682,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
......@@ -14035,6 +14042,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
......
......@@ -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 @@ static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
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 @@ static int occ_putsram(struct occ *occ, u32 address, const void *data,
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 */
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;
}
buf[0] = cpu_to_be32(cmd_len); /* 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;
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, 7, buf, &resp_len);
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
},
{ },
};
......
......@@ -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 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
ADT7470_REG_PWM_TMIN(i));
}
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 }
};
......
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
// 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");
// 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,
};
......
// 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,
};
......
This diff is collapsed.
......@@ -43,7 +43,6 @@ static struct i2c_driver tps40422_driver = {
.name = "tps40422",
},
.probe_new = tps40422_probe,
.remove = pmbus_do_remove,
.id_table = tps40422_id,
};
......
......@@ -251,7 +251,6 @@ static struct i2c_driver tps53679_driver = {
.of_match_table = of_match_ptr(tps53679_of_match),
},
.probe_new = tps53679_probe,
.remove = pmbus_do_remove,
.id_table = tps53679_id,
};
......
......@@ -621,7 +621,6 @@ static struct i2c_driver ucd9000_driver = {
.of_match_table = of_match_ptr(ucd9000_of_match),
},
.probe_new = ucd9000_probe,
.remove = pmbus_do_remove,
.id_table = ucd9000_id,
};
......
......@@ -201,7 +201,6 @@ static struct i2c_driver ucd9200_driver = {
.of_match_table = of_match_ptr(ucd9200_of_match),
},
.probe_new = ucd9200_probe,
.remove = pmbus_do_remove,
.id_table = ucd9200_id,
};
......
......@@ -160,7 +160,6 @@ static struct i2c_driver xdpe122_driver = {
.of_match_table = of_match_ptr(xdpe122_of_match),
},
.probe_new = xdpe122_probe,
.remove = pmbus_do_remove,
.id_table = xdpe122_id,
};
......
......@@ -396,7 +396,6 @@ static struct i2c_driver zl6100_driver = {
.name = "zl6100",
},
.probe_new = zl6100_probe,
.remove = pmbus_do_remove,
.id_table = zl6100_id,
};
......
......@@ -8,7 +8,6 @@
*/
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mutex.h>
......@@ -39,6 +38,28 @@ struct pwm_fan_ctx {
unsigned int pwm_fan_max_state;
unsigned int *pwm_fan_cooling_levels;
struct thermal_cooling_device *cdev;
struct hwmon_chip_info info;
};
static const u32 pwm_fan_channel_config_pwm[] = {
HWMON_PWM_INPUT,
0
};
static const struct hwmon_channel_info pwm_fan_channel_pwm = {
.type = hwmon_pwm,
.config = pwm_fan_channel_config_pwm,
};
static const u32 pwm_fan_channel_config_fan[] = {
HWMON_F_INPUT,
0
};
static const struct hwmon_channel_info pwm_fan_channel_fan = {
.type = hwmon_fan,
.config = pwm_fan_channel_config_fan,
};
/* This handler assumes self resetting edge triggered interrupt. */
......@@ -103,70 +124,62 @@ static void pwm_fan_update_state(struct pwm_fan_ctx *ctx, unsigned long pwm)
ctx->pwm_fan_state = i;
}
static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
static int pwm_fan_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
unsigned long pwm;
int ret;
if (kstrtoul(buf, 10, &pwm) || pwm > MAX_PWM)
if (val < 0 || val > MAX_PWM)
return -EINVAL;
ret = __set_pwm(ctx, pwm);
ret = __set_pwm(ctx, val);
if (ret)
return ret;
pwm_fan_update_state(ctx, pwm);
return count;
pwm_fan_update_state(ctx, val);
return 0;
}
static ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
char *buf)
static int pwm_fan_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", ctx->pwm_value);
}
switch (type) {
case hwmon_pwm:
*val = ctx->pwm_value;
return 0;
static ssize_t rpm_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
case hwmon_fan:
*val = ctx->rpm;
return 0;
return sprintf(buf, "%u\n", ctx->rpm);
default:
return -ENOTSUPP;
}
}
static SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0);
static SENSOR_DEVICE_ATTR_RO(fan1_input, rpm, 0);
static struct attribute *pwm_fan_attrs[] = {
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
NULL,
};
static umode_t pwm_fan_attrs_visible(struct kobject *kobj, struct attribute *a,
int n)
static umode_t pwm_fan_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pwm_fan_ctx *ctx = dev_get_drvdata(dev);
switch (type) {
case hwmon_pwm:
return 0644;
/* Hide fan_input in case no interrupt is available */
if (n == 1 && ctx->irq <= 0)
return 0;
case hwmon_fan:
return 0444;
return a->mode;
default:
return 0;
}
}
static const struct attribute_group pwm_fan_group = {
.attrs = pwm_fan_attrs,
.is_visible = pwm_fan_attrs_visible,
};
static const struct attribute_group *pwm_fan_groups[] = {
&pwm_fan_group,
NULL,
static const struct hwmon_ops pwm_fan_hwmon_ops = {
.is_visible = pwm_fan_is_visible,
.read = pwm_fan_read,
.write = pwm_fan_write,
};
/* thermal cooling device callbacks */
......@@ -286,7 +299,8 @@ static int pwm_fan_probe(struct platform_device *pdev)
struct device *hwmon;
int ret;
struct pwm_state state = { };
u32 ppr = 2;
int tach_count;
const struct hwmon_channel_info **channels;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
......@@ -300,10 +314,6 @@ static int pwm_fan_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
ctx->irq = platform_get_irq_optional(pdev, 0);
if (ctx->irq == -EPROBE_DEFER)
return ctx->irq;
ctx->reg_en = devm_regulator_get_optional(dev, "fan");
if (IS_ERR(ctx->reg_en)) {
if (PTR_ERR(ctx->reg_en) != -ENODEV)
......@@ -339,26 +349,58 @@ static int pwm_fan_probe(struct platform_device *pdev)
if (ret)
return ret;
of_property_read_u32(dev->of_node, "pulses-per-revolution", &ppr);
ctx->pulses_per_revolution = ppr;
if (!ctx->pulses_per_revolution) {
dev_err(dev, "pulses-per-revolution can't be zero.\n");
return -EINVAL;
}
tach_count = platform_irq_count(pdev);
if (tach_count < 0)
return dev_err_probe(dev, tach_count,
"Could not get number of fan tachometer inputs\n");
channels = devm_kcalloc(dev, tach_count + 2,
sizeof(struct hwmon_channel_info *), GFP_KERNEL);
if (!channels)
return -ENOMEM;
channels[0] = &pwm_fan_channel_pwm;
if (tach_count > 0) {
u32 ppr = 2;
ctx->irq = platform_get_irq(pdev, 0);
if (ctx->irq == -EPROBE_DEFER)
return ctx->irq;
if (ctx->irq > 0) {
ret = devm_request_irq(dev, ctx->irq, pulse_handler, 0,
pdev->name, ctx);
if (ret) {
dev_err(dev, "Failed to request interrupt: %d\n", ret);
dev_err(dev,
"Failed to request interrupt: %d\n",
ret);
return ret;
}
}
of_property_read_u32(dev->of_node,
"pulses-per-revolution",
&ppr);
ctx->pulses_per_revolution = ppr;
if (!ctx->pulses_per_revolution) {
dev_err(dev, "pulses-per-revolution can't be zero.\n");
return -EINVAL;
}
dev_dbg(dev, "tach: irq=%d, pulses_per_revolution=%d\n",
ctx->irq, ctx->pulses_per_revolution);
ctx->sample_start = ktime_get();
mod_timer(&ctx->rpm_timer, jiffies + HZ);
channels[1] = &pwm_fan_channel_fan;
}
hwmon = devm_hwmon_device_register_with_groups(dev, "pwmfan",
ctx, pwm_fan_groups);
ctx->info.ops = &pwm_fan_hwmon_ops;
ctx->info.info = channels;
hwmon = devm_hwmon_device_register_with_info(dev, "pwmfan",
ctx, &ctx->info, NULL);
if (IS_ERR(hwmon)) {
dev_err(dev, "Failed to register hwmon device\n");
return PTR_ERR(hwmon);
......
This diff is collapsed.
......@@ -784,7 +784,7 @@ static const struct of_device_id xgene_hwmon_of_match[] = {
};
MODULE_DEVICE_TABLE(of, xgene_hwmon_of_match);
static struct platform_driver xgene_hwmon_driver __refdata = {
static struct platform_driver xgene_hwmon_driver = {
.probe = xgene_hwmon_probe,
.remove = xgene_hwmon_remove,
.driver = {
......
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