hwmon updates for v5.16-rc1

New drivers:
 - Maxim MAX6620
 
 Notable functional enhancements:
 - Add Asus WMI support to nct6775 driver, and list boards supporting it
 - Move TMP461 support from tm401 driver to lm90 driver
 - Add support for fanX_min, fanX_max and fanX_target to dell-smm driver,
   and clean it up while doing so
 - Extend mlxreg-fan driver to support multiple cooling devices and
   multiple PWM channels. Also increase number of supported fan tachometers.
 - Add a new customer ID (for ASRock) to nct6683 driver
 - Make temperature/voltage sensors on nct7802 configurable
 - Add mfg_id debugfs entry to pmbus/ibm-cffps driver
 - Support configurable sense resistor values in pmbus/lm25066,
   and fix various coefficients
 - Use generic notification mechanism in raspberrypi driver
 
 Notable cleanup:
 - Convert various devicetree bindings to dtschema, and add missing bindings
 - Convert i5500_temp and tmp103 drivers to devm_hwmon_device_register_with_info
 - Clean up non-bool "valid" data fields
 - Improve devicetree configurability for tmp421 driver
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmGACskACgkQyx8mb86f
 mYGZxw//XHZhm/cJEPlL9Rw8HmDWV49QwknswQ5kmSJWPOO1XziB2r3WUNqCKK/5
 CVn/nvurp3MOdCjczywjYB1kz8FKXYW4savzkUbLypAGtYzMFaDRHFmyNj+t+Yw8
 0WwdvBufuxgj8iHoGlc+HsiO8lhzdTrj1DM5Bv9ulwTNKvSeYBH4uceME9hlDcdv
 W47RU0sM16gPE3yojn0f5qhQEjzWlcax3u7FWOC0Oy9rZSJsngTLeaFOnoBB1EAn
 Va79etOq2MG8oGeYQZGRRjvLQQqmUg+db8rN1acXkpQ2LldiWaMy2frzGeY6BpH0
 vYf00ScQieHgYn+HKQyYJPI2h0l/KyA4oCOr3KAoQwlwnNQBxJvX8jguvzTkwKmW
 RZySZuBNzP+RVWVD1bkkoEjmy8cjCjwKumHkF+Av3QSu743asjzKhNWdcSi1ZktD
 AE+3ihB/QFPVAx/XUHPk97EzkKeOUOsr9qcxwxMOakFMLbgi/y5jdPKWMIn4MFcT
 dn9lmLFM3fFwp/coSrAU2VWvw7lV3mkAb+qQ9l6bf5R28p42Vy+vw1ECPDc+TUL2
 i1P+PR55nr48TqzEwgUFBtRnO+emye6bmJ1SVgrncwejrMoOc7OAPtF9LBoqC9ro
 rZvIw6a9VTOJYIE4jgfWuX/xgJd9w43rWwHr2CoCbHZ0BumS9/M=
 =v5CO
 -----END PGP SIGNATURE-----

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

Pull hwmon updates from Guenter Roeck:
 "New driver:

   - Maxim MAX6620

  Notable functional enhancements:

   - Add Asus WMI support to nct6775 driver, and list boards supporting
     it

   - Move TMP461 support from tm401 driver to lm90 driver

   - Add support for fanX_min, fanX_max and fanX_target to dell-smm
     driver, and clean it up while doing so

   - Extend mlxreg-fan driver to support multiple cooling devices and
     multiple PWM channels. Also increase number of supported fan
     tachometers.

   - Add a new customer ID (for ASRock) to nct6683 driver

   - Make temperature/voltage sensors on nct7802 configurable

   - Add mfg_id debugfs entry to pmbus/ibm-cffps driver

   - Support configurable sense resistor values in pmbus/lm25066, and
     fix various coefficients

   - Use generic notification mechanism in raspberrypi driver

  Notable cleanups:

   - Convert various devicetree bindings to dtschema, and add missing
     bindings

   - Convert i5500_temp and tmp103 drivers to
     devm_hwmon_device_register_with_info

   - Clean up non-bool "valid" data fields

   - Improve devicetree configurability for tmp421 driver"

* tag 'hwmon-for-v5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (73 commits)
  hwmon: (nct7802) Add of_node_put() before return
  hwmon: (tmp401) Drop support for TMP461
  hwmon: (lm90) Add basic support for TI TMP461
  hwmon: (lm90) Introduce flag indicating extended temperature support
  hwmon: (nct6775) add ProArt X570-CREATOR WIFI.
  hwmon: (nct7802) Make temperature/voltage sensors configurable
  dt-bindings: hwmon: Add nct7802 bindings
  hwmon: (dell-smm) Speed up setting of fan speed
  hwmon: (dell-smm) Add comment explaining usage of i8k_config_data[]
  hwmon: (dell-smm) Return -ENOIOCTLCMD instead of -EINVAL
  hwmon: (dell-smm) Use strscpy_pad()
  hwmon: (dell-smm) Sort includes in alphabetical order
  hwmon: (tmp421) Add of_node_put() before return
  hwmon: (max31722) Warn about failure to put device in stand-by in .remove()
  hwmon: (acpi_power_meter) Use acpi_bus_get_acpi_device()
  hwmon: (dell-smm) Add support for fanX_min, fanX_max and fanX_target
  dt-bindings: hwmon: allow specifying channels for tmp421
  hwmon: (tmp421) ignore non-channel related DT nodes
  hwmon: (tmp421) update documentation
  hwmon: (tmp421) support HWMON_T_ENABLE
  ...
This commit is contained in:
Linus Torvalds 2021-11-01 19:16:49 -07:00
commit d54f486035
123 changed files with 2894 additions and 953 deletions

View File

@ -1,11 +0,0 @@
Bindings for Delta Electronics DPS-650-AB power supply
Required properties:
- compatible : "delta,dps650ab"
- reg : I2C address, one of 0x58, 0x59.
Example:
dps650ab@58 {
compatible = "delta,dps650ab";
reg = <0x58>;
};

View File

@ -1,12 +0,0 @@
Honeywell Humidicon HIH-6130 humidity/temperature sensor
--------------------------------------------------------
Requires node properties:
- compatible : "honeywell,hi6130"
- reg : the I2C address of the device. This is 0x27.
Example:
hih6130@27 {
compatible = "honeywell,hih6130";
reg = <0x27>;
};

View File

@ -1,26 +0,0 @@
Device-tree bindings for IBM Common Form Factor Power Supply Versions 1 and 2
-----------------------------------------------------------------------------
Required properties:
- compatible : Must be one of the following:
"ibm,cffps1"
"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
I2C bus.
Example:
i2c-bus@100 {
#address-cells = <1>;
#size-cells = <0>;
#interrupt-cells = <1>;
< more properties >
power-supply@68 {
compatible = "ibm,cffps1";
reg = <0x68>;
};
};

View File

@ -0,0 +1,37 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/hwmon/iio-hwmon.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: ADC-attached Hardware Sensor Device Tree Bindings
maintainers:
- Jonathan Cameron <jic23@kernel.org>
description: >
Bindings for hardware monitoring devices connected to ADC controllers
supporting the Industrial I/O bindings.
properties:
compatible:
const: iio-hwmon
io-channels:
minItems: 1
maxItems: 8 # Should be enough
description: >
List of phandles to ADC channels to read the monitoring values
required:
- compatible
- io-channels
additionalProperties: false
examples:
- |
iio-hwmon {
compatible = "iio-hwmon";
io-channels = <&adc 1>, <&adc 2>;
};

View File

@ -1,46 +0,0 @@
Properties for Jedec JC-42.4 compatible temperature sensors
Required properties:
- compatible: May include a device-specific string consisting of the
manufacturer and the name of the chip. A list of supported
chip names follows.
Must include "jedec,jc-42.4-temp" for any Jedec JC-42.4
compatible temperature sensor.
Supported chip names:
adi,adt7408
atmel,at30ts00
atmel,at30tse004
onnn,cat6095
onnn,cat34ts02
maxim,max6604
microchip,mcp9804
microchip,mcp9805
microchip,mcp9808
microchip,mcp98243
microchip,mcp98244
microchip,mcp9843
nxp,se97
nxp,se98
st,stts2002
st,stts2004
st,stts3000
st,stts424
st,stts424e
idt,tse2002
idt,tse2004
idt,ts3000
idt,ts3001
- reg: I2C address
Optional properties:
- smbus-timeout-disable: When set, the smbus timeout function will be disabled.
This is not supported on all chips.
Example:
temp-sensor@1a {
compatible = "jedec,jc-42.4-temp";
reg = <0x1a>;
};

View File

@ -0,0 +1,78 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/jedec,jc42.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Jedec JC-42.4 compatible temperature sensors
maintainers:
- Jean Delvare <jdelvare@suse.com>
- Guenter Roeck <linux@roeck-us.net>
select:
properties:
compatible:
const: jedec,jc-42.4-temp
required:
- compatible
properties:
compatible:
oneOf:
- const: jedec,jc-42.4-temp
- items:
- enum:
- adi,adt7408
- atmel,at30ts00
- atmel,at30tse004
- idt,tse2002
- idt,tse2004
- idt,ts3000
- idt,ts3001
- maxim,max6604
- microchip,mcp9804
- microchip,mcp9805
- microchip,mcp9808
- microchip,mcp98243
- microchip,mcp98244
- microchip,mcp9843
- nxp,se97
- nxp,se97b
- nxp,se98
- onnn,cat6095
- onnn,cat34ts02
- st,stts2002
- st,stts2004
- st,stts3000
- st,stts424
- st,stts424e
- const: jedec,jc-42.4-temp
reg:
maxItems: 1
smbus-timeout-disable:
description: |
When set, the smbus timeout function will be disabled. This is not
supported on all chips.
type: boolean
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
temp-sensor@1a {
compatible = "jedec,jc-42.4-temp";
reg = <0x1a>;
};
};

View File

@ -0,0 +1,41 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/lltc,ltc4151.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LTC4151 High Voltage I2C Current and Voltage Monitor
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
properties:
compatible:
const: lltc,ltc4151
reg:
maxItems: 1
shunt-resistor-micro-ohms:
description:
Shunt resistor value in micro-Ohms
default: 1000
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@6e {
compatible = "lltc,ltc4151";
reg = <0x6e>;
shunt-resistor-micro-ohms = <1500>;
};
};

View File

@ -1,22 +0,0 @@
* LM70/TMP121/LM71/LM74 thermometer.
Required properties:
- compatible: one of
"ti,lm70"
"ti,tmp121"
"ti,tmp122"
"ti,lm71"
"ti,lm74"
See Documentation/devicetree/bindings/spi/spi-bus.txt for more required and
optional properties.
Example:
spi_master {
temperature-sensor@0 {
compatible = "ti,lm70";
reg = <0>;
spi-max-frequency = <1000000>;
};
};

View File

@ -1,51 +0,0 @@
* LM90 series thermometer.
Required node properties:
- compatible: manufacturer and chip name, one of
"adi,adm1032"
"adi,adt7461"
"adi,adt7461a"
"gmt,g781"
"national,lm90"
"national,lm86"
"national,lm89"
"national,lm99"
"dallas,max6646"
"dallas,max6647"
"dallas,max6649"
"dallas,max6657"
"dallas,max6658"
"dallas,max6659"
"dallas,max6680"
"dallas,max6681"
"dallas,max6695"
"dallas,max6696"
"onnn,nct1008"
"winbond,w83l771"
"nxp,sa56004"
"ti,tmp451"
- reg: I2C bus address of the device
- vcc-supply: vcc regulator for the supply voltage.
Optional properties:
- interrupts: Contains a single interrupt specifier which describes the
LM90 "-ALERT" pin output.
See interrupt-controller/interrupts.txt for the format.
- #thermal-sensor-cells: should be set to 1. See thermal/thermal-sensor.yaml
for details. See <include/dt-bindings/thermal/lm90.h> for the
definition of the local, remote and 2nd remote sensor index
constants.
Example LM90 node:
temp-sensor {
compatible = "onnn,nct1008";
reg = <0x4c>;
vcc-supply = <&palmas_ldo6_reg>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(O, 4) IRQ_TYPE_LEVEL_LOW>;
#thermal-sensor-cells = <1>;
}

View File

@ -1,18 +0,0 @@
LTC4151 High Voltage I2C Current and Voltage Monitor
Required properties:
- compatible: Must be "lltc,ltc4151"
- reg: I2C address
Optional properties:
- shunt-resistor-micro-ohms
Shunt resistor value in micro-Ohms
Defaults to <1000> if unset.
Example:
ltc4151@6e {
compatible = "lltc,ltc4151";
reg = <0x6e>;
shunt-resistor-micro-ohms = <1500>;
};

View File

@ -1,21 +0,0 @@
mcp3021 properties
Required properties:
- compatible: Must be one of the following:
- "microchip,mcp3021" for mcp3021
- "microchip,mcp3221" for mcp3221
- reg: I2C address
Optional properties:
- reference-voltage-microvolt
Reference voltage in microvolt (uV)
Example:
mcp3021@4d {
compatible = "microchip,mcp3021";
reg = <0x4d>;
reference-voltage-microvolt = <4500000>; /* 4.5 V */
};

View File

@ -0,0 +1,43 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/microchip,mcp3021.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip MCP3021 A/D converter
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
properties:
compatible:
enum:
- microchip,mcp3021
- microchip,mcp3221
reg:
maxItems: 1
reference-voltage-microvolt:
description:
VDD supply power and reference voltage
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@4d {
compatible = "microchip,mcp3021";
reg = <0x4d>;
reference-voltage-microvolt = <4500000>; /* 4.5 V */
};
};

View File

@ -0,0 +1,78 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/national,lm90.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: LM90 series thermometer
maintainers:
- Jean Delvare <jdelvare@suse.com>
- Guenter Roeck <linux@roeck-us.net>
properties:
compatible:
enum:
- adi,adm1032
- adi,adt7461
- adi,adt7461a
- dallas,max6646
- dallas,max6647
- dallas,max6649
- dallas,max6657
- dallas,max6658
- dallas,max6659
- dallas,max6680
- dallas,max6681
- dallas,max6695
- dallas,max6696
- gmt,g781
- national,lm86
- national,lm89
- national,lm90
- national,lm99
- nxp,sa56004
- onnn,nct1008
- ti,tmp451
- winbond,w83l771
interrupts:
items:
- description: |
Single interrupt specifier which describes the LM90 "-ALERT" pin
output.
reg:
maxItems: 1
"#thermal-sensor-cells":
const: 1
vcc-supply:
description: phandle to the regulator that provides the +VCC supply
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@4c {
compatible = "onnn,nct1008";
reg = <0x4c>;
vcc-supply = <&palmas_ldo6_reg>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(O, 4) IRQ_TYPE_LEVEL_LOW>;
#thermal-sensor-cells = <1>;
};
};

View File

@ -0,0 +1,141 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
---
$id: http://devicetree.org/schemas/hwmon/ntc-thermistor.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NTC thermistor temperature sensors
maintainers:
- Naveen Krishna Chatradhi <ch.naveen@samsung.com>
- Linus Walleij <linus.walleij@linaro.org>
description: |
Thermistors with negative temperature coefficient (NTC) are resistors that
vary in resistance in an often non-linear way in relation to temperature.
The negative temperature coefficient means that the resistance decreases
as the temperature rises. Since the relationship between resistance and
temperature is non-linear, software drivers most often need to use a look
up table and interpolation to get from resistance to temperature.
When used in practice, a thermistor is often connected between ground, a
pull-up resistor or/and a pull-down resistor and a fixed voltage like this:
+ e.g. 5V = pull-up voltage (puv)
|
+-+
| |
| | Pull-up resistor
| | (puo)
+-+
|-------------------------o
+-+ | ^
| |/ |
| / |
|/| Thermistor | Measured voltage (mv)
/ | | "connected ground"
/| | |
+-+ |
|-------------------------o
+-+ ^
| | |
| | Pull-down resistor | Measured voltage (mv)
| | (pdo) | "connected positive"
+-+ |
| |
| v
+ GND GND
The arrangements of where we measure the voltage over the thermistor are
called "connected ground" and "connected positive" and shall be understood as
the cases when either pull-up or pull-down resistance is zero.
If the pull-up resistance is 0 one end of the thermistor is connected to the
positive voltage and we get the thermistor on top of a pull-down resistor
and we take the measure between the thermistor and the pull-down resistor.
Conversely if the pull-down resistance is zero, one end of the thermistor is
connected to ground and we get the thermistor under the pull-up resistor
and we take the measure between the pull-up resistor and the thermistor.
We can use both pull-up and pull-down resistors at the same time, and then
the figure illustrates where the voltage will be measured for the "connected
ground" and "connected positive" cases.
properties:
$nodename:
pattern: "^thermistor(.*)?$"
compatible:
oneOf:
- const: epcos,b57330v2103
- const: epcos,b57891s0103
- const: murata,ncp15wb473
- const: murata,ncp18wb473
- const: murata,ncp21wb473
- const: murata,ncp03wb473
- const: murata,ncp15wl333
- const: murata,ncp03wf104
- const: murata,ncp15xh103
# Deprecated "ntp," compatible strings
- const: ntc,ncp15wb473
deprecated: true
- const: ntc,ncp18wb473
deprecated: true
- const: ntc,ncp21wb473
deprecated: true
- const: ntc,ncp03wb473
deprecated: true
- const: ntc,ncp15wl333
deprecated: true
"#thermal-sensor-cells":
description: Thermal sensor cells if used for thermal sensoring.
const: 0
pullup-uv:
$ref: /schemas/types.yaml#/definitions/uint32
description: Pull-up voltage in micro volts. Must always be specified.
pullup-ohm:
$ref: /schemas/types.yaml#/definitions/uint32
description: Pull-up resistance in ohms. Must always be specified, even
if zero.
pulldown-ohm:
$ref: /schemas/types.yaml#/definitions/uint32
description: Pull-down resistance in ohms. Must always be specified, even
if zero.
connected-positive:
$ref: /schemas/types.yaml#/definitions/flag
description: Indicates how the thermistor is connected in series with
a pull-up and/or a pull-down resistor. See the description above for
an illustration. If this flag is NOT specified, the thermistor is assumed
to be connected-ground, which usually means a pull-down resistance of
zero but complex arrangements are possible.
# See /schemas/iio/adc/adc.yaml
io-channels:
maxItems: 1
description: IIO ADC channel to read the voltage over the resistor. Must
always be specified.
required:
- compatible
- pullup-uv
- pullup-ohm
- pulldown-ohm
- io-channels
additionalProperties: false
examples:
- |
thermistor0 {
compatible = "murata,ncp18wb473";
io-channels = <&gpadc 0x06>;
pullup-uv = <1800000>;
pullup-ohm = <220000>;
pulldown-ohm = <0>;
#thermal-sensor-cells = <0>;
};

View File

@ -1,44 +0,0 @@
NTC Thermistor hwmon sensors
-------------------------------
Requires node properties:
- "compatible" value : one of
"epcos,b57330v2103"
"epcos,b57891s0103"
"murata,ncp15wb473"
"murata,ncp18wb473"
"murata,ncp21wb473"
"murata,ncp03wb473"
"murata,ncp15wl333"
"murata,ncp03wf104"
"murata,ncp15xh103"
/* Usage of vendor name "ntc" is deprecated */
<DEPRECATED> "ntc,ncp15wb473"
<DEPRECATED> "ntc,ncp18wb473"
<DEPRECATED> "ntc,ncp21wb473"
<DEPRECATED> "ntc,ncp03wb473"
<DEPRECATED> "ntc,ncp15wl333"
- "pullup-uv" Pull up voltage in micro volts
- "pullup-ohm" Pull up resistor value in ohms
- "pulldown-ohm" Pull down resistor value in ohms
- "connected-positive" Always ON, If not specified.
Status change is possible.
- "io-channels" Channel node of ADC to be used for
conversion.
Optional node properties:
- "#thermal-sensor-cells" Used to expose itself to thermal fw.
Read more about iio bindings at
https://github.com/devicetree-org/dt-schema/blob/master/schemas/iio/
Example:
ncp15wb473@0 {
compatible = "murata,ncp15wb473";
pullup-uv = <1800000>;
pullup-ohm = <47000>;
pulldown-ohm = <0>;
io-channels = <&adc 3>;
};

View File

@ -0,0 +1,145 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/nuvoton,nct7802.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Nuvoton NCT7802Y Hardware Monitoring IC
maintainers:
- Guenter Roeck <linux@roeck-us.net>
description: |
The NCT7802Y is a hardware monitor IC which supports one on-die and up to
5 remote temperature sensors with SMBus interface.
Datasheets:
https://www.nuvoton.com/export/resource-files/Nuvoton_NCT7802Y_Datasheet_V12.pdf
additionalProperties: false
properties:
compatible:
enum:
- nuvoton,nct7802
reg:
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^channel@[0-3]$":
type: object
additionalProperties: false
properties:
reg:
items:
- enum:
- 0 # Local Temperature Sensor ("LTD")
- 1 # Remote Temperature Sensor or Voltage Sensor 1 ("RTD1")
- 2 # Remote Temperature Sensor or Voltage Sensor 2 ("RTD2")
- 3 # Remote Temperature Sensor or Voltage Sensor 3 ("RTD3")
sensor-type:
items:
- enum:
- temperature
- voltage
temperature-mode:
items:
- enum:
- thermistor
- thermal-diode
required:
- reg
allOf:
# For channels RTD1, RTD2 and RTD3, require sensor-type to be set.
# Otherwise (for all other channels), do not allow temperature-mode to be
# set.
- if:
properties:
reg:
items:
- enum:
- 1
- 2
- 3
then:
required:
- sensor-type
else:
not:
required:
- sensor-type
# For channels RTD1 and RTD2 and if sensor-type is "temperature", require
# temperature-mode to be set. Otherwise (for all other channels or
# sensor-type settings), do not allow temperature-mode to be set
- if:
properties:
reg:
items:
- enum:
- 1
- 2
sensor-type:
items:
- enum:
- temperature
then:
required:
- temperature-mode
else:
not:
required:
- temperature-mode
required:
- compatible
- reg
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
nct7802@28 {
compatible = "nuvoton,nct7802";
reg = <0x28>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 { /* LTD */
reg = <0>;
};
channel@1 { /* RTD1 */
reg = <1>;
sensor-type = "voltage";
};
channel@2 { /* RTD2 */
reg = <2>;
sensor-type = "temperature";
temperature-mode = "thermal-diode";
};
channel@3 { /* RTD3 */
reg = <3>;
sensor-type = "temperature";
};
};
};

View File

@ -0,0 +1,54 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/pmbus/ti,lm25066.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: National Semiconductor/Texas Instruments LM250x6/LM506x power-management ICs
maintainers:
- Zev Weiss <zev@bewilderbeest.net>
description: |
The LM25066 family of power-management ICs (a.k.a. hot-swap
controllers or eFuses in various contexts) are PMBus devices that
offer temperature, current, voltage, and power monitoring.
Datasheet: https://www.ti.com/lit/ds/symlink/lm25066.pdf
properties:
compatible:
enum:
- ti,lm25056
- ti,lm25066
- ti,lm5064
- ti,lm5066
- ti,lm5066i
reg:
maxItems: 1
shunt-resistor-micro-ohms:
description:
Shunt (sense) resistor value in micro-Ohms
default: 1000
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@40 {
compatible = "ti,lm25066";
reg = <0x40>;
shunt-resistor-micro-ohms = <675>;
};
};

View File

@ -0,0 +1,43 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/sensirion,sht15.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Sensirion SHT15 humidity and temperature sensor
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
properties:
compatible:
const: sensirion,sht15
clk-gpios:
maxItems: 1
data-gpios:
maxItems: 1
vcc-supply:
description: regulator that drives the VCC pin
required:
- compatible
- clk-gpios
- data-gpios
- vcc-supply
additionalProperties: false
examples:
- |
sensor {
compatible = "sensirion,sht15";
clk-gpios = <&gpio4 12 0>;
data-gpios = <&gpio4 13 0>;
vcc-supply = <&reg_sht15>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sensor>;
};

View File

@ -1,19 +0,0 @@
Sensirion SHT15 Humidity and Temperature Sensor
Required properties:
- "compatible": must be "sensirion,sht15".
- "data-gpios": GPIO connected to the data line.
- "clk-gpios": GPIO connected to the clock line.
- "vcc-supply": regulator that drives the VCC pin.
Example:
sensor {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sensor>;
compatible = "sensirion,sht15";
clk-gpios = <&gpio4 12 0>;
data-gpios = <&gpio4 13 0>;
vcc-supply = <&reg_sht15>;
};

View File

@ -0,0 +1,47 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,tmp102.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TMP102 temperature sensor
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
properties:
compatible:
enum:
- ti,tmp102
interrupts:
maxItems: 1
reg:
maxItems: 1
"#thermal-sensor-cells":
const: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@48 {
compatible = "ti,tmp102";
reg = <0x48>;
interrupt-parent = <&gpio7>;
interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
#thermal-sensor-cells = <1>;
};
};

View File

@ -0,0 +1,50 @@
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,tmp108.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TMP108 temperature sensor
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
properties:
compatible:
enum:
- ti,tmp108
interrupts:
items:
- description: alert interrupt
reg:
maxItems: 1
"#thermal-sensor-cells":
const: 0
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@48 {
compatible = "ti,tmp108";
reg = <0x48>;
interrupt-parent = <&gpio1>;
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&tmp_alrt>;
#thermal-sensor-cells = <0>;
};
};

View File

@ -0,0 +1,110 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,tmp421.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TMP42x/TMP44x temperature sensor
maintainers:
- Guenter Roeck <linux@roeck-us.net>
description: |
±1°C Remote and Local temperature sensor
https://www.ti.com/lit/ds/symlink/tmp422.pdf
properties:
compatible:
enum:
- ti,tmp421
- ti,tmp422
- ti,tmp423
- ti,tmp441
- ti,tmp442
reg:
maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
required:
- compatible
- reg
additionalProperties: false
patternProperties:
"^channel@([0-3])$":
type: object
description: |
Represents channels of the device and their specific configuration.
properties:
reg:
description: |
The channel number. 0 is local channel, 1-3 are remote channels
items:
minimum: 0
maximum: 3
label:
description: |
A descriptive name for this channel, like "ambient" or "psu".
ti,n-factor:
description: |
The value (two's complement) to be programmed in the channel specific N correction register.
For remote channels only.
$ref: /schemas/types.yaml#/definitions/uint32
items:
minimum: 0
maximum: 255
required:
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@4c {
compatible = "ti,tmp422";
reg = <0x4c>;
};
};
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@4c {
compatible = "ti,tmp422";
reg = <0x4c>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0x0>;
ti,n-factor = <0x1>;
label = "local";
};
channel@1 {
reg = <0x1>;
ti,n-factor = <0x0>;
label = "somelabel";
};
channel@2 {
reg = <0x2>;
status = "disabled";
};
};
};

View File

@ -1,18 +0,0 @@
TMP108 temperature sensor
-------------------------
This device supports I2C only.
Requires node properties:
- compatible : "ti,tmp108"
- reg : the I2C address of the device. This is 0x48, 0x49, 0x4a, or 0x4b.
Optional properties:
- interrupts: Reference to the TMP108 alert interrupt.
- #thermal-sensor-cells: should be set to 0.
Example:
tmp108@48 {
compatible = "ti,tmp108";
reg = <0x48>;
};

View File

@ -41,10 +41,6 @@ properties:
- adi,adp5585-02
# Analog Devices ADP5589 Keypad Decoder and I/O Expansion
- adi,adp5589
# +/-1C TDM Extended Temp Range I.C
- adi,adt7461
# +/-1C TDM Extended Temp Range I.C
- adt7461
# AMS iAQ-Core VOC Sensor
- ams,iaq-core
# i2c serial eeprom (24cxx)
@ -77,6 +73,8 @@ properties:
- dallas,ds4510
# Digital Thermometer and Thermostat
- dallas,ds75
# Delta Electronics DPS-650-AB power supply
- delta,dps650ab
# Delta Electronics DPS920AB 920W 54V Power Supply
- delta,dps920ab
# 1/4 Brick DC/DC Regulated Power Module
@ -113,8 +111,14 @@ properties:
- mps,mp2888
# Monolithic Power Systems Inc. multi-phase controller mp2975
- mps,mp2975
# G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
- gmt,g751
# Honeywell Humidicon HIH-6130 humidity/temperature sensor
- honeywell,hi6130
# IBM Common Form Factor Power Supply Versions (all versions)
- ibm,cffps
# IBM Common Form Factor Power Supply Versions 1
- ibm,cffps1
# IBM Common Form Factor Power Supply Versions 2
- ibm,cffps2
# Infineon IR36021 digital POL buck controller
- infineon,ir36021
# Infineon IR38064 Voltage Regulator
@ -307,16 +311,22 @@ properties:
- ti,hdc1050
# Temperature and humidity sensor with i2c interface
- ti,hdc1080
# Thermometer with SPI interface
- ti,lm70
- ti,lm71
# Temperature sensor with 2-wire interface
- ti,lm73
# Thermometer with SPI interface
- ti,lm74
# Temperature sensor with integrated fan control
- ti,lm96000
# I2C Touch-Screen Controller
- ti,tsc2003
# Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface
- ti,tmp102
# Low Power Digital Temperature Sensor with SMBUS/Two Wire Serial Interface
- ti,tmp103
# Thermometer with SPI interface
- ti,tmp121
- ti,tmp122
# Digital Temperature Sensor
- ti,tmp275
# TI Dual channel DCAP+ multiphase controller TPS53676 with AVSBus

View File

@ -34,6 +34,9 @@ Name Perm Description
=============================== ======= =======================================
fan[1-3]_input RO Fan speed in RPM.
fan[1-3]_label RO Fan label.
fan[1-3]_min RO Minimal Fan speed in RPM
fan[1-3]_max RO Maximal Fan speed in RPM
fan[1-3]_target RO Expected Fan speed in RPM
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,

View File

@ -130,6 +130,7 @@ Hardware Monitoring Kernel Drivers
max31785
max31790
max34440
max6620
max6639
max6642
max6650

View File

@ -79,6 +79,8 @@ This driver does not auto-detect devices. You will have to instantiate the
devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
details.
The shunt (sense) resistor value can be configured by a device tree property;
see Documentation/devicetree/bindings/hwmon/pmbus/ti,lm25066.yaml for details.
Platform data support
---------------------

View File

@ -265,6 +265,16 @@ Supported chips:
https://www.ti.com/litv/pdf/sbos686
* Texas Instruments TMP461
Prefix: 'tmp461'
Addresses scanned: I2C 0x48 through 0x4F
Datasheet: Publicly available at TI website
https://www.ti.com/lit/gpn/tmp461
Author: Jean Delvare <jdelvare@suse.de>

View File

@ -0,0 +1,46 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver max6620
=====================
Supported chips:
Maxim MAX6620
Prefix: 'max6620'
Addresses scanned: none
Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6620.pdf
Authors:
- L\. Grunenberg <contact@lgrunenberg.de>
- Cumulus Networks <support@cumulusnetworks.com>
- Shuotian Cheng <shuche@microsoft.com>
- Arun Saravanan Balachandran <Arun_Saravanan_Balac@dell.com>
Description
-----------
This driver implements support for Maxim MAX6620 fan controller.
The driver configures the fan controller in RPM mode. To give the readings more
range or accuracy, the desired value can be set by a programmable register
(1, 2, 4, 8, 16 or 32). Set higher values for larger speeds.
The driver provides the following sensor access in sysfs:
================ ======= =====================================================
fan[1-4]_alarm ro Fan alarm.
fan[1-4]_div rw Sets the nominal RPM range of the fan. Valid values
are 1, 2, 4, 8, 16 and 32.
fan[1-4]_input ro Fan speed in RPM.
fan[1-4]_target rw Desired fan speed in RPM.
================ ======= =====================================================
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.

View File

@ -43,12 +43,6 @@ Supported chips:
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html
* Texas Instruments TMP461
Prefix: 'tmp461'
Datasheet: https://www.ti.com/product/tmp461
Authors:
@ -60,7 +54,7 @@ Description
-----------
This driver implements support for Texas Instruments TMP401, TMP411,
TMP431, TMP432, TMP435, and TMP461 chips. These chips implement one or two
TMP431, TMP432, and TMP435 chips. These chips implement one or two
remote and one local temperature sensors. Temperature is measured in degrees
Celsius. Resolution of the remote sensor is 0.0625 degree. Local
sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
@ -84,10 +78,3 @@ some additional features.
TMP432 is compatible with TMP401 and TMP431. It supports two external
temperature sensors.
TMP461 is compatible with TMP401. It supports offset correction
that is applied to the remote sensor.
* Sensor offset values are temperature values
Exported via sysfs attribute tempX_offset

View File

@ -64,3 +64,13 @@ the temperature values via the following sysfs files:
**temp[1-4]_input**
**temp[2-4]_fault**
Each sensor can be individually disabled via Devicetree or from sysfs
via:
**temp[1-4]_enable**
If labels were specified in Devicetree, additional sysfs files will
be present:
**temp[1-4]_label**

View File

@ -10038,6 +10038,7 @@ JC42.4 TEMPERATURE SENSOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/hwmon/jedec,jc42.yaml
F: Documentation/hwmon/jc42.rst
F: drivers/hwmon/jc42.c
@ -10932,7 +10933,7 @@ LM90 HARDWARE MONITOR DRIVER
M: Jean Delvare <jdelvare@suse.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/hwmon/lm90.txt
F: Documentation/devicetree/bindings/hwmon/national,lm90.yaml
F: Documentation/hwmon/lm90.rst
F: drivers/hwmon/lm90.c
F: include/dt-bindings/thermal/lm90.h
@ -14966,7 +14967,6 @@ S: Maintained
W: http://hwmon.wiki.kernel.org/
W: http://www.roeck-us.net/linux/drivers/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
F: Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt
F: Documentation/devicetree/bindings/hwmon/ltc2978.txt
F: Documentation/devicetree/bindings/hwmon/max31785.txt
F: Documentation/hwmon/adm1275.rst

View File

@ -608,6 +608,7 @@ struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
{
return handle_to_device(handle, get_acpi_device);
}
EXPORT_SYMBOL_GPL(acpi_bus_get_acpi_device);
static struct acpi_device_bus_id *acpi_device_bus_id_match(const char *dev_id)
{

View File

@ -1032,6 +1032,16 @@ config SENSORS_MAX31730
This driver can also be built as a module. If so, the module
will be called max31730.
config SENSORS_MAX6620
tristate "Maxim MAX6620 fan controller"
depends on I2C
help
If you say yes here you get support for the MAX6620
fan controller.
This driver can also be built as a module. If so, the module
will be called max6620.
config SENSORS_MAX6621
tristate "Maxim MAX6621 sensor chip"
depends on I2C
@ -1317,7 +1327,7 @@ config SENSORS_LM90
Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6654, MAX6657, MAX6658,
MAX6659, MAX6680, MAX6681, MAX6692, MAX6695, MAX6696,
ON Semiconductor NCT1008, Winbond/Nuvoton W83L771W/G/AWG/ASG,
Philips SA56004, GMT G781, and Texas Instruments TMP451
Philips SA56004, GMT G781, Texas Instruments TMP451 and TMP461
sensor chips.
This driver can also be built as a module. If so, the module
@ -1433,6 +1443,7 @@ config SENSORS_NCT6683
config SENSORS_NCT6775
tristate "Nuvoton NCT6775F and compatibles"
depends on !PPC
depends on ACPI_WMI || ACPI_WMI=n
select HWMON_VID
help
If you say yes here you get support for the hardware monitoring
@ -1930,7 +1941,7 @@ config SENSORS_TMP401
depends on I2C
help
If you say yes here you get support for Texas Instruments TMP401,
TMP411, TMP431, TMP432, TMP435, and TMP461 temperature sensor chips.
TMP411, TMP431, TMP432, and TMP435 temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called tmp401.

View File

@ -135,6 +135,7 @@ obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
obj-$(CONFIG_SENSORS_MAX197) += max197.o
obj-$(CONFIG_SENSORS_MAX31722) += max31722.o
obj-$(CONFIG_SENSORS_MAX31730) += max31730.o
obj-$(CONFIG_SENSORS_MAX6620) += max6620.o
obj-$(CONFIG_SENSORS_MAX6621) += max6621.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o

View File

@ -145,7 +145,7 @@ struct abituguru3_data {
struct device *hwmon_dev; /* hwmon registered device */
struct mutex update_lock; /* protect access to data and uGuru */
unsigned short addr; /* uguru base address */
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
/*
@ -1083,7 +1083,7 @@ static struct abituguru3_data *abituguru3_update_device(struct device *dev)
mutex_lock(&data->update_lock);
if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
/* Clear data->valid while updating */
data->valid = 0;
data->valid = false;
/* Read alarms */
if (abituguru3_read_increment_offset(data,
ABIT_UGURU3_SETTINGS_BANK,
@ -1117,7 +1117,7 @@ static struct abituguru3_data *abituguru3_update_device(struct device *dev)
goto LEAVE_UPDATE;
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
LEAVE_UPDATE:
mutex_unlock(&data->update_lock);

View File

@ -535,7 +535,7 @@ static void remove_domain_devices(struct acpi_power_meter_resource *resource)
sysfs_remove_link(resource->holders_dir,
kobject_name(&obj->dev.kobj));
put_device(&obj->dev);
acpi_dev_put(obj);
}
kfree(resource->domain_devices);
@ -597,18 +597,15 @@ static int read_domain_devices(struct acpi_power_meter_resource *resource)
continue;
/* Create a symlink to domain objects */
resource->domain_devices[i] = NULL;
if (acpi_bus_get_device(element->reference.handle,
&resource->domain_devices[i]))
obj = acpi_bus_get_acpi_device(element->reference.handle);
resource->domain_devices[i] = obj;
if (!obj)
continue;
obj = resource->domain_devices[i];
get_device(&obj->dev);
res = sysfs_create_link(resource->holders_dir, &obj->dev.kobj,
kobject_name(&obj->dev.kobj));
if (res) {
put_device(&obj->dev);
acpi_dev_put(obj);
resource->domain_devices[i] = NULL;
}
}

View File

@ -37,7 +37,7 @@ static u8 AD7414_REG_LIMIT[] = { AD7414_REG_T_HIGH, AD7414_REG_T_LOW };
struct ad7414_data {
struct i2c_client *client;
struct mutex lock; /* atomic read data updates */
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long next_update; /* In jiffies */
s16 temp_input; /* Register values */
s8 temps[ARRAY_SIZE(AD7414_REG_LIMIT)];
@ -95,7 +95,7 @@ static struct ad7414_data *ad7414_update_device(struct device *dev)
}
data->next_update = jiffies + HZ + HZ / 2;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->lock);

View File

@ -46,7 +46,7 @@ struct ad7418_data {
enum chips type;
struct mutex lock;
int adc_max; /* number of ADC channels */
char valid;
bool valid;
unsigned long last_updated; /* In jiffies */
s16 temp[3]; /* Register values */
u16 in[4];
@ -111,14 +111,14 @@ static int ad7418_update_device(struct device *dev)
goto abort;
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->lock);
return 0;
abort:
data->valid = 0;
data->valid = false;
mutex_unlock(&data->lock);
return val;
}

View File

@ -72,7 +72,7 @@ struct adm1021_data {
const struct attribute_group *groups[3];
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
char low_power; /* !=0 if device in low power mode */
unsigned long last_updated; /* In jiffies */
@ -135,7 +135,7 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
ADM1023_REG_REM_OFFSET_PREC);
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -97,7 +97,7 @@ struct adm1025_data {
struct i2c_client *client;
const struct attribute_group *groups[3];
struct mutex update_lock;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
u8 in[6]; /* register value */
@ -148,7 +148,7 @@ static struct adm1025_data *adm1025_update_device(struct device *dev)
ADM1025_REG_VID4) & 0x01) << 4);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -259,7 +259,7 @@ struct adm1026_data {
const struct attribute_group *groups[3];
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_reading; /* In jiffies */
unsigned long last_config; /* In jiffies */
@ -459,7 +459,7 @@ static struct adm1026_data *adm1026_update_device(struct device *dev)
data->last_config = jiffies;
} /* last_config */
data->valid = 1;
data->valid = true;
mutex_unlock(&data->update_lock);
return data;
}

View File

@ -99,7 +99,7 @@ static const u8 ADM1029_REG_FAN_DIV[] = {
struct adm1029_data {
struct i2c_client *client;
struct mutex update_lock; /* protect register access */
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values, signed for temperature, unsigned for other stuff */
@ -143,7 +143,7 @@ static struct adm1029_data *adm1029_update_device(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -65,7 +65,7 @@ struct adm1031_data {
const struct attribute_group *groups[3];
struct mutex update_lock;
int chip_type;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
unsigned int update_interval; /* In milliseconds */
/*
@ -187,7 +187,7 @@ static struct adm1031_data *adm1031_update_device(struct device *dev)
ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);
@ -650,7 +650,7 @@ static ssize_t fan_div_store(struct device *dev,
data->fan_min[nr]);
/* Invalidate the cache: fan speed is no longer valid */
data->valid = 0;
data->valid = false;
mutex_unlock(&data->update_lock);
return count;
}

View File

@ -90,7 +90,8 @@ static int adt7310_spi_probe(struct spi_device *spi)
static int adt7310_spi_remove(struct spi_device *spi)
{
return adt7x10_remove(&spi->dev, spi->irq);
adt7x10_remove(&spi->dev, spi->irq);
return 0;
}
static const struct spi_device_id adt7310_id[] = {

View File

@ -50,7 +50,8 @@ static int adt7410_i2c_probe(struct i2c_client *client)
static int adt7410_i2c_remove(struct i2c_client *client)
{
return adt7x10_remove(&client->dev, client->irq);
adt7x10_remove(&client->dev, client->irq);
return 0;
}
static const struct i2c_device_id adt7410_ids[] = {

View File

@ -444,7 +444,7 @@ exit_restore:
}
EXPORT_SYMBOL_GPL(adt7x10_probe);
int adt7x10_remove(struct device *dev, int irq)
void adt7x10_remove(struct device *dev, int irq)
{
struct adt7x10_data *data = dev_get_drvdata(dev);
@ -457,7 +457,6 @@ int adt7x10_remove(struct device *dev, int irq)
sysfs_remove_group(&dev->kobj, &adt7x10_group);
if (data->oldconfig != data->config)
adt7x10_write_byte(dev, ADT7X10_CONFIG, data->oldconfig);
return 0;
}
EXPORT_SYMBOL_GPL(adt7x10_remove);

View File

@ -26,7 +26,7 @@ struct adt7x10_ops {
int adt7x10_probe(struct device *dev, const char *name, int irq,
const struct adt7x10_ops *ops);
int adt7x10_remove(struct device *dev, int irq);
void adt7x10_remove(struct device *dev, int irq);
#ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops adt7x10_dev_pm_ops;

View File

@ -141,7 +141,7 @@ static const u8 fan_reg_hi[] = {AMC6821_REG_TDATA_HI,
struct amc6821_data {
struct i2c_client *client;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* register values */
@ -258,7 +258,7 @@ static struct amc6821_data *amc6821_update_device(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);
return data;
@ -511,7 +511,7 @@ static ssize_t temp_auto_point_temp_store(struct device *dev,
}
mutex_lock(&data->update_lock);
data->valid = 0;
data->valid = false;
switch (ix) {
case 0:
@ -584,7 +584,7 @@ static ssize_t pwm1_auto_point_pwm_store(struct device *dev,
}
EXIT:
data->valid = 0;
data->valid = false;
mutex_unlock(&data->update_lock);
return count;
}

View File

@ -391,7 +391,7 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
cache->len = info[0];
memcpy(cache->type, &info[1], 4);
cache->flags = info[5];
cache->valid = 1;
cache->valid = true;
out:
mutex_unlock(&smcreg.mutex);

View File

@ -186,7 +186,7 @@ struct asb100_data {
/* array of 2 pointers to subclients */
struct i2c_client *lm75[2];
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
u8 in[7]; /* Register value */
u8 in_max[7]; /* Register value */
u8 in_min[7]; /* Register value */
@ -993,7 +993,7 @@ static struct asb100_data *asb100_update_device(struct device *dev)
(asb100_read_value(client, ASB100_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
dev_dbg(&client->dev, "... device update complete\n");
}

View File

@ -77,7 +77,7 @@ struct asc7621_data {
struct i2c_client client;
struct device *class_dev;
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_high_reading; /* In jiffies */
unsigned long last_low_reading; /* In jiffies */
/*
@ -1032,7 +1032,7 @@ static struct asc7621_data *asc7621_update_device(struct device *dev)
data->last_low_reading = jiffies;
} /* last_reading */
data->valid = 1;
data->valid = true;
mutex_unlock(&data->update_lock);

View File

@ -37,7 +37,7 @@ struct atxp1_data {
struct i2c_client *client;
struct mutex update_lock;
unsigned long last_updated;
u8 valid;
bool valid;
struct {
u8 vid; /* VID output register */
u8 cpu_vid; /* VID input from CPU */
@ -63,7 +63,7 @@ static struct atxp1_data *atxp1_update_device(struct device *dev)
data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);
@ -136,7 +136,7 @@ static ssize_t cpu0_vid_store(struct device *dev,
ATXP1_VID, cvid | ATXP1_VIDENA);
}
data->valid = 0;
data->valid = false;
return count;
}
@ -180,7 +180,7 @@ static ssize_t gpio1_store(struct device *dev, struct device_attribute *attr,
i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
data->valid = 0;
data->valid = false;
}
return count;
@ -224,7 +224,7 @@ static ssize_t gpio2_store(struct device *dev, struct device_attribute *attr,
i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
data->valid = 0;
data->valid = false;
}
return count;

View File

@ -167,7 +167,7 @@ static ssize_t show_temp(struct device *dev,
* really help at all.
*/
tdata->temp = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000;
tdata->valid = 1;
tdata->valid = true;
tdata->last_updated = jiffies;
}

View File

@ -12,24 +12,24 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/capability.h>
#include <linux/cpu.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/dmi.h>
#include <linux/capability.h>
#include <linux/mutex.h>
#include <linux/hwmon.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/i8k.h>
@ -76,6 +76,7 @@ struct dell_smm_data {
int temp_type[DELL_SMM_NO_TEMP];
bool fan[DELL_SMM_NO_FANS];
int fan_type[DELL_SMM_NO_FANS];
int *fan_nominal_speed[DELL_SMM_NO_FANS];
};
MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
@ -326,7 +327,7 @@ static int i8k_enable_fan_auto_mode(const struct dell_smm_data *data, bool enabl
}
/*
* Set the fan speed (off, low, high). Returns the new fan status.
* Set the fan speed (off, low, high, ...).
*/
static int i8k_set_fan(const struct dell_smm_data *data, int fan, int speed)
{
@ -338,7 +339,7 @@ static int i8k_set_fan(const struct dell_smm_data *data, int fan, int speed)
speed = (speed < 0) ? 0 : ((speed > data->i8k_fan_max) ? data->i8k_fan_max : speed);
regs.ebx = (fan & 0xff) | (speed << 8);
return i8k_smm(&regs) ? : i8k_get_fan_status(data, fan);
return i8k_smm(&regs);
}
static int __init i8k_get_temp_type(int sensor)
@ -452,7 +453,7 @@ static int
i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd, unsigned long arg)
{
int val = 0;
int speed;
int speed, err;
unsigned char buff[16];
int __user *argp = (int __user *)arg;
@ -473,8 +474,7 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
if (restricted && !capable(CAP_SYS_ADMIN))
return -EPERM;
memset(buff, 0, sizeof(buff));
strscpy(buff, data->bios_machineid, sizeof(buff));
strscpy_pad(buff, data->bios_machineid, sizeof(buff));
break;
case I8K_FN_STATUS:
@ -513,11 +513,15 @@ i8k_ioctl_unlocked(struct file *fp, struct dell_smm_data *data, unsigned int cmd
if (copy_from_user(&speed, argp + 1, sizeof(int)))
return -EFAULT;
val = i8k_set_fan(data, val, speed);
err = i8k_set_fan(data, val, speed);
if (err < 0)
return err;
val = i8k_get_fan_status(data, val);
break;
default:
return -EINVAL;
return -ENOIOCTLCMD;
}
if (val < 0)
@ -673,6 +677,13 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types
if (data->fan[channel] && !data->disallow_fan_type_call)
return 0444;
break;
case hwmon_fan_min:
case hwmon_fan_max:
case hwmon_fan_target:
if (data->fan_nominal_speed[channel])
return 0444;
break;
default:
break;
@ -740,6 +751,25 @@ static int dell_smm_read(struct device *dev, enum hwmon_sensor_types type, u32 a
*val = ret;
return 0;
case hwmon_fan_min:
*val = data->fan_nominal_speed[channel][0];
return 0;
case hwmon_fan_max:
*val = data->fan_nominal_speed[channel][data->i8k_fan_max];
return 0;
case hwmon_fan_target:
ret = i8k_get_fan_status(data, channel);
if (ret < 0)
return ret;
if (ret > data->i8k_fan_max)
ret = data->i8k_fan_max;
*val = data->fan_nominal_speed[channel][ret];
return 0;
default:
break;
@ -889,9 +919,12 @@ static const struct hwmon_channel_info *dell_smm_info[] = {
HWMON_T_INPUT | HWMON_T_LABEL
),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
HWMON_F_TARGET,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
HWMON_F_TARGET,
HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MIN | HWMON_F_MAX |
HWMON_F_TARGET
),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
@ -910,7 +943,7 @@ static int __init dell_smm_init_hwmon(struct device *dev)
{
struct dell_smm_data *data = dev_get_drvdata(dev);
struct device *dell_smm_hwmon_dev;
int i, err;
int i, state, err;
for (i = 0; i < DELL_SMM_NO_TEMP; i++) {
data->temp_type[i] = i8k_get_temp_type(i);
@ -926,8 +959,27 @@ static int __init dell_smm_init_hwmon(struct device *dev)
err = i8k_get_fan_status(data, i);
if (err < 0)
err = i8k_get_fan_type(data, i);
if (err >= 0)
data->fan[i] = true;
if (err < 0)
continue;
data->fan[i] = true;
data->fan_nominal_speed[i] = devm_kmalloc_array(dev, data->i8k_fan_max + 1,
sizeof(*data->fan_nominal_speed[i]),
GFP_KERNEL);
if (!data->fan_nominal_speed[i])
continue;
for (state = 0; state <= data->i8k_fan_max; state++) {
err = i8k_get_fan_nominal_speed(data, i, state);
if (err < 0) {
/* Mark nominal speed table as invalid in case of error */
devm_kfree(dev, data->fan_nominal_speed[i]);
data->fan_nominal_speed[i] = NULL;
break;
}
data->fan_nominal_speed[i][state] = err;
}
}
dell_smm_hwmon_dev = devm_hwmon_device_register_with_info(dev, "dell_smm", data,
@ -948,6 +1000,11 @@ enum i8k_configs {
DELL_XPS,
};
/*
* Only use for machines which need some special configuration
* in order to work correctly (e.g. if autoconfig fails on this machines).
*/
static const struct i8k_config_data i8k_config_data[] __initconst = {
[DELL_LATITUDE_D520] = {
.fan_mult = 1,

View File

@ -203,7 +203,7 @@ struct dme1737_data {
unsigned int addr; /* for ISA devices only */
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_update; /* in jiffies */
unsigned long last_vbat; /* in jiffies */
enum chips type;
@ -778,7 +778,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
}
data->last_update = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -109,7 +109,7 @@ static const u8 DS1621_REG_TEMP[3] = {
struct ds1621_data {
struct i2c_client *client;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
enum chips kind; /* device type */
@ -213,7 +213,7 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
new_conf);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -56,7 +56,7 @@ static const u8 DS620_REG_TEMP[3] = {
struct ds620_data {
struct i2c_client *client;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
s16 temp[3]; /* Register values, word */
@ -118,7 +118,7 @@ static struct ds620_data *ds620_update_client(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
abort:
mutex_unlock(&data->update_lock);

View File

@ -45,7 +45,7 @@ enum subfeature { input, min, max };
struct emc6w201_data {
struct i2c_client *client;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
@ -162,7 +162,7 @@ static struct emc6w201_data *emc6w201_update_device(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -165,7 +165,7 @@ struct f71805f_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
unsigned long last_limits; /* In jiffies */
@ -404,7 +404,7 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
+ (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -253,7 +253,7 @@ struct f71882fg_data {
struct mutex update_lock;
int temp_start; /* temp numbering start (0 or 1) */
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
char auto_point_temp_signed;
unsigned long last_updated; /* In jiffies */
unsigned long last_limits; /* In jiffies */
@ -1359,7 +1359,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
F71882FG_REG_IN(nr));
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -85,7 +85,7 @@ struct f75375_data {
const char *name;
int kind;
struct mutex update_lock; /* protect register access */
char valid;
bool valid;
unsigned long last_updated; /* In jiffies */
unsigned long last_limits; /* In jiffies */
@ -228,7 +228,7 @@ static struct f75375_data *f75375_update_device(struct device *dev)
f75375_read8(client, F75375_REG_VOLT(nr));
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -264,7 +264,7 @@ struct fschmd_data {
unsigned long watchdog_is_open;
char watchdog_expect_close;
char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* register values */
@ -1356,7 +1356,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
FSCHMD_REG_VOLT[data->kind][i]);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -95,7 +95,7 @@ static struct g760a_data *g760a_update_client(struct device *dev)
data->fan_sta = g760a_read_value(client, G760A_REG_FAN_STA);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -107,7 +107,7 @@ struct gl518_data {
enum chips type;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
u8 voltage_in[4]; /* Register values; [0] = VDD */
@ -211,7 +211,7 @@ static struct gl518_data *gl518_update_device(struct device *dev)
gl518_read_value(client, GL518_REG_VIN3);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -64,7 +64,7 @@ struct gl520_data {
struct i2c_client *client;
const struct attribute_group *groups[3];
struct mutex update_lock;
char valid; /* zero until the following fields are valid */
bool valid; /* false until the following fields are valid */
unsigned long last_updated; /* in jiffies */
u8 vid;
@ -174,7 +174,7 @@ static struct gl520_data *gl520_update_device(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -796,8 +796,10 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
dev_set_drvdata(hdev, drvdata);
dev_set_name(hdev, HWMON_ID_FORMAT, id);
err = device_register(hdev);
if (err)
goto free_hwmon;
if (err) {
put_device(hdev);
goto ida_remove;
}
INIT_LIST_HEAD(&hwdev->tzdata);

View File

@ -5,6 +5,7 @@
* Copyright (C) 2012, 2014 Jean Delvare <jdelvare@suse.de>
*/
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@ -12,7 +13,6 @@
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
@ -29,69 +29,78 @@
#define REG_CTCTRL 0xF7
#define REG_TSTIMER 0xF8
/*
* Sysfs stuff
*/
/* Sensor resolution : 0.5 degree C */
static ssize_t temp1_input_show(struct device *dev,
struct device_attribute *devattr, char *buf)
static umode_t i5500_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
int channel)
{
struct pci_dev *pdev = to_pci_dev(dev->parent);
long temp;
u16 tsthrhi;
s8 tsfsc;
pci_read_config_word(pdev, REG_TSTHRHI, &tsthrhi);
pci_read_config_byte(pdev, REG_TSFSC, &tsfsc);
temp = ((long)tsthrhi - tsfsc) * 500;
return sprintf(buf, "%ld\n", temp);
return 0444;
}
static ssize_t thresh_show(struct device *dev,
struct device_attribute *devattr, char *buf)
static int i5500_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
long *val)
{
struct pci_dev *pdev = to_pci_dev(dev->parent);
int reg = to_sensor_dev_attr(devattr)->index;
long temp;
u16 tsthr;
pci_read_config_word(pdev, reg, &tsthr);
temp = tsthr * 500;
return sprintf(buf, "%ld\n", temp);
}
static ssize_t alarm_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev->parent);
int nr = to_sensor_dev_attr(devattr)->index;
s8 tsfsc;
u8 ctsts;
pci_read_config_byte(pdev, REG_CTSTS, &ctsts);
return sprintf(buf, "%u\n", (unsigned int)ctsts & (1 << nr));
switch (type) {
case hwmon_temp:
switch (attr) {
/* Sensor resolution : 0.5 degree C */
case hwmon_temp_input:
pci_read_config_word(pdev, REG_TSTHRHI, &tsthr);
pci_read_config_byte(pdev, REG_TSFSC, &tsfsc);
*val = (tsthr - tsfsc) * 500;
return 0;
case hwmon_temp_max:
pci_read_config_word(pdev, REG_TSTHRHI, &tsthr);
*val = tsthr * 500;
return 0;
case hwmon_temp_max_hyst:
pci_read_config_word(pdev, REG_TSTHRLO, &tsthr);
*val = tsthr * 500;
return 0;
case hwmon_temp_crit:
pci_read_config_word(pdev, REG_TSTHRCATA, &tsthr);
*val = tsthr * 500;
return 0;
case hwmon_temp_max_alarm:
pci_read_config_byte(pdev, REG_CTSTS, &ctsts);
*val = !!(ctsts & BIT(1));
return 0;
case hwmon_temp_crit_alarm:
pci_read_config_byte(pdev, REG_CTSTS, &ctsts);
*val = !!(ctsts & BIT(0));
return 0;
default:
break;
}
break;
default:
break;
}
return -EOPNOTSUPP;
}
static DEVICE_ATTR_RO(temp1_input);
static SENSOR_DEVICE_ATTR_RO(temp1_crit, thresh, 0xE2);
static SENSOR_DEVICE_ATTR_RO(temp1_max_hyst, thresh, 0xEC);
static SENSOR_DEVICE_ATTR_RO(temp1_max, thresh, 0xEE);
static SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 0);
static SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 1);
static const struct hwmon_ops i5500_ops = {
.is_visible = i5500_is_visible,
.read = i5500_read,
};
static struct attribute *i5500_temp_attrs[] = {
&dev_attr_temp1_input.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
static const struct hwmon_channel_info *i5500_info[] = {
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | HWMON_T_CRIT |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM
),
NULL
};
ATTRIBUTE_GROUPS(i5500_temp);
static const struct hwmon_chip_info i5500_chip_info = {
.ops = &i5500_ops,
.info = i5500_info,
};
static const struct pci_device_id i5500_temp_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3438) },
@ -121,9 +130,8 @@ static int i5500_temp_probe(struct pci_dev *pdev,
return -ENODEV;
}
hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
"intel5500", NULL,
i5500_temp_groups);
hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "intel5500", NULL,
&i5500_chip_info, NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}

View File

@ -127,7 +127,7 @@ struct aem_data {
struct device *hwmon_dev;
struct platform_device *pdev;
struct mutex lock;
char valid;
bool valid;
unsigned long last_updated; /* In jiffies */
u8 ver_major;
u8 ver_minor;

View File

@ -66,7 +66,7 @@ struct ibmpex_bmc_data {
struct device *hwmon_dev;
struct device *bmc_device;
struct mutex lock;
char valid;
bool valid;
unsigned long last_updated; /* In jiffies */
struct ipmi_addr address;
@ -239,7 +239,7 @@ static void ibmpex_update_device(struct ibmpex_bmc_data *data)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
out:
mutex_unlock(&data->lock);

View File

@ -519,7 +519,7 @@ struct it87_data {
unsigned short addr;
const char *name;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 in_scaled; /* Internal voltage sensors are scaled */
@ -844,7 +844,7 @@ static struct it87_data *it87_update_device(struct device *dev)
data->vid &= 0x3f;
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);
@ -980,7 +980,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
regval |= 0x80;
it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
}
data->valid = 0;
data->valid = false;
reg = IT87_REG_TEMP_OFFSET[nr];
break;
}
@ -1079,7 +1079,7 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
if (has_temp_old_peci(data, nr))
it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
data->valid = 0; /* Force cache refresh */
data->valid = false; /* Force cache refresh */
mutex_unlock(&data->update_lock);
return count;
}
@ -1834,7 +1834,7 @@ static ssize_t clear_intrusion(struct device *dev,
config |= BIT(5);
it87_write_value(data, IT87_REG_CONFIG, config);
/* Invalidate cache to force re-read */
data->valid = 0;
data->valid = false;
}
mutex_unlock(&data->update_lock);
@ -3229,7 +3229,7 @@ static int __maybe_unused it87_resume(struct device *dev)
it87_start_monitoring(data);
/* force update */
data->valid = 0;
data->valid = false;
mutex_unlock(&data->update_lock);

View File

@ -191,7 +191,7 @@ static struct pem_data *pem_update_device(struct device *dev)
i2c_smbus_write_byte(client, PEM_CLEAR_INFO_FLAGS);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
abort:
mutex_unlock(&data->update_lock);

View File

@ -139,7 +139,7 @@ struct lm63_data {
struct i2c_client *client;
struct mutex update_lock;
const struct attribute_group *groups[5];
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
char lut_valid; /* zero until lut fields are valid */
unsigned long last_updated; /* in jiffies */
unsigned long lut_last_updated; /* in jiffies */
@ -289,7 +289,7 @@ static struct lm63_data *lm63_update_device(struct device *dev)
LM63_REG_ALERT_STATUS) & 0x7F;
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
lm63_update_lut(data);
@ -714,7 +714,7 @@ static ssize_t temp2_type_store(struct device *dev,
reg = i2c_smbus_read_byte_data(client, LM96163_REG_TRUTHERM) & ~0x02;
i2c_smbus_write_byte_data(client, LM96163_REG_TRUTHERM,
reg | (data->trutherm ? 0x02 : 0x00));
data->valid = 0;
data->valid = false;
mutex_unlock(&data->update_lock);
return count;

View File

@ -55,7 +55,7 @@ static const u8 temp_regs[t_num_temp] = {
struct lm77_data {
struct i2c_client *client;
struct mutex update_lock;
char valid;
bool valid;
unsigned long last_updated; /* In jiffies */
int temp[t_num_temp]; /* index using temp_index */
u8 alarms;
@ -118,7 +118,7 @@ static struct lm77_data *lm77_update_device(struct device *dev)
data->alarms =
lm77_read_value(client, LM77_REG_TEMP) & 0x0007;
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -117,7 +117,7 @@ struct lm78_data {
int isa_addr;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
u8 in[7]; /* Register value */
@ -772,7 +772,7 @@ static struct lm78_data *lm78_update_device(struct device *dev)
data->alarms = lm78_read_value(data, LM78_REG_ALARM1) +
(lm78_read_value(data, LM78_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
data->fan_div[2] = 1;
}

View File

@ -117,7 +117,7 @@ struct lm80_data {
struct i2c_client *client;
struct mutex update_lock;
char error; /* !=0 if error occurred during last update */
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
u8 in[i_num_in][7]; /* Register value, 1st index is enum in_index */
@ -236,14 +236,14 @@ static struct lm80_data *lm80_update_device(struct device *dev)
data->alarms = prev_rv + (rv << 8);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
data->error = 0;
}
goto done;
abort:
ret = ERR_PTR(rv);
data->valid = 0;
data->valid = false;
data->error = 1;
done:

View File

@ -105,7 +105,7 @@ struct lm83_data {
struct i2c_client *client;
const struct attribute_group *groups[3];
struct mutex update_lock;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
@ -137,7 +137,7 @@ static struct lm83_data *lm83_update_device(struct device *dev)
<< 8);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -294,7 +294,7 @@ struct lm85_data {
bool has_vid5; /* true if VID5 is configured for ADT7463 or ADT7468 */
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_reading; /* In jiffies */
unsigned long last_config; /* In jiffies */
@ -541,7 +541,7 @@ static struct lm85_data *lm85_update_device(struct device *dev)
data->last_config = jiffies;
} /* last_config */
data->valid = 1;
data->valid = true;
mutex_unlock(&data->update_lock);

View File

@ -141,7 +141,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
struct lm87_data {
struct mutex update_lock;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* In jiffies */
u8 channel; /* register value */
@ -251,7 +251,7 @@ static struct lm87_data *lm87_update_device(struct device *dev)
data->aout = lm87_read_value(client, LM87_REG_AOUT);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -69,10 +69,10 @@
* This driver also supports the G781 from GMT. This device is compatible
* with the ADM1032.
*
* This driver also supports TMP451 from Texas Instruments. This device is
* supported in both compatibility and extended mode. It's mostly compatible
* with ADT7461 except for local temperature low byte register and max
* conversion rate.
* This driver also supports TMP451 and TMP461 from Texas Instruments.
* Those devices are supported in both compatibility and extended mode.
* They are mostly compatible with ADT7461 except for local temperature
* low byte register and max conversion rate.
*
* Since the LM90 was the first chipset supported by this driver, most
* comments will refer to this chipset, but are actually general and
@ -112,7 +112,7 @@ static const unsigned short normal_i2c[] = {
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
max6646, w83l771, max6696, sa56004, g781, tmp451, max6654 };
max6646, w83l771, max6696, sa56004, g781, tmp451, tmp461, max6654 };
/*
* The LM90 registers
@ -168,8 +168,12 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
#define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */
/* TMP451 registers */
/* TMP451/TMP461 registers */
#define TMP451_REG_R_LOCAL_TEMPL 0x15
#define TMP451_REG_CONALERT 0x22
#define TMP461_REG_CHEN 0x16
#define TMP461_REG_DFC 0x24
/*
* Device flags
@ -182,7 +186,8 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm */
#define LM90_HAVE_TEMP3 (1 << 6) /* 3rd temperature sensor */
#define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert */
#define LM90_PAUSE_FOR_CONFIG (1 << 8) /* Pause conversion for config */
#define LM90_HAVE_EXTENDED_TEMP (1 << 8) /* extended temperature support*/
#define LM90_PAUSE_FOR_CONFIG (1 << 9) /* Pause conversion for config */
/* LM90 status */
#define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */
@ -229,6 +234,7 @@ static const struct i2c_device_id lm90_id[] = {
{ "w83l771", w83l771 },
{ "sa56004", sa56004 },
{ "tmp451", tmp451 },
{ "tmp461", tmp461 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm90_id);
@ -326,6 +332,10 @@ static const struct of_device_id __maybe_unused lm90_of_match[] = {
.compatible = "ti,tmp451",
.data = (void *)tmp451
},
{
.compatible = "ti,tmp461",
.data = (void *)tmp461
},
{ },
};
MODULE_DEVICE_TABLE(of, lm90_of_match);
@ -350,7 +360,7 @@ static const struct lm90_params lm90_params[] = {
},
[adt7461] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT,
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP,
.alert_alarms = 0x7c,
.max_convrate = 10,
},
@ -422,7 +432,14 @@ static const struct lm90_params lm90_params[] = {
},
[tmp451] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT,
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP,
.alert_alarms = 0x7c,
.max_convrate = 9,
.reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
},
[tmp461] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP,
.alert_alarms = 0x7c,
.max_convrate = 9,
.reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
@ -998,7 +1015,7 @@ static int lm90_get_temp11(struct lm90_data *data, int index)
s16 temp11 = data->temp11[index];
int temp;
if (data->kind == adt7461 || data->kind == tmp451)
if (data->flags & LM90_HAVE_EXTENDED_TEMP)
temp = temp_from_u16_adt7461(data, temp11);
else if (data->kind == max6646)
temp = temp_from_u16(temp11);
@ -1035,7 +1052,7 @@ static int lm90_set_temp11(struct lm90_data *data, int index, long val)
val -= 16000;
}
if (data->kind == adt7461 || data->kind == tmp451)
if (data->flags & LM90_HAVE_EXTENDED_TEMP)
data->temp11[index] = temp_to_u16_adt7461(data, val);
else if (data->kind == max6646)
data->temp11[index] = temp_to_u8(val) << 8;
@ -1062,7 +1079,7 @@ static int lm90_get_temp8(struct lm90_data *data, int index)
s8 temp8 = data->temp8[index];
int temp;
if (data->kind == adt7461 || data->kind == tmp451)
if (data->flags & LM90_HAVE_EXTENDED_TEMP)
temp = temp_from_u8_adt7461(data, temp8);
else if (data->kind == max6646)
temp = temp_from_u8(temp8);
@ -1098,7 +1115,7 @@ static int lm90_set_temp8(struct lm90_data *data, int index, long val)
val -= 16000;
}
if (data->kind == adt7461 || data->kind == tmp451)
if (data->flags & LM90_HAVE_EXTENDED_TEMP)
data->temp8[index] = temp_to_u8_adt7461(data, val);
else if (data->kind == max6646)
data->temp8[index] = temp_to_u8(val);
@ -1116,7 +1133,7 @@ static int lm90_get_temphyst(struct lm90_data *data, int index)
{
int temp;
if (data->kind == adt7461 || data->kind == tmp451)
if (data->flags & LM90_HAVE_EXTENDED_TEMP)
temp = temp_from_u8_adt7461(data, data->temp8[index]);
else if (data->kind == max6646)
temp = temp_from_u8(data->temp8[index]);
@ -1136,7 +1153,7 @@ static int lm90_set_temphyst(struct lm90_data *data, long val)
int temp;
int err;
if (data->kind == adt7461 || data->kind == tmp451)
if (data->flags & LM90_HAVE_EXTENDED_TEMP)
temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]);
else if (data->kind == max6646)
temp = temp_from_u8(data->temp8[LOCAL_CRIT]);
@ -1627,18 +1644,26 @@ static int lm90_detect(struct i2c_client *client,
&& convrate <= 0x08)
name = "g781";
} else
if (address == 0x4C
&& man_id == 0x55) { /* Texas Instruments */
int local_ext;
if (man_id == 0x55 && chip_id == 0x00 &&
(config1 & 0x1B) == 0x00 && convrate <= 0x09) {
int local_ext, conalert, chen, dfc;
local_ext = i2c_smbus_read_byte_data(client,
TMP451_REG_R_LOCAL_TEMPL);
conalert = i2c_smbus_read_byte_data(client,
TMP451_REG_CONALERT);
chen = i2c_smbus_read_byte_data(client, TMP461_REG_CHEN);
dfc = i2c_smbus_read_byte_data(client, TMP461_REG_DFC);
if (chip_id == 0x00 /* TMP451 */
&& (config1 & 0x1B) == 0x00
&& convrate <= 0x09
&& (local_ext & 0x0F) == 0x00)
name = "tmp451";
if ((local_ext & 0x0F) == 0x00 &&
(conalert & 0xf1) == 0x01 &&
(chen & 0xfc) == 0x00 &&
(dfc & 0xfc) == 0x00) {
if (address == 0x4c && !(chen & 0x03))
name = "tmp451";
else if (address >= 0x48 && address <= 0x4f)
name = "tmp461";
}
}
if (!name) { /* identification failed */
@ -1685,7 +1710,7 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
/* Check Temperature Range Select */
if (data->kind == adt7461 || data->kind == tmp451) {
if (data->flags & LM90_HAVE_EXTENDED_TEMP) {
if (config & 0x04)
data->flags |= LM90_FLAG_ADT7461_EXT;
}

View File

@ -99,7 +99,7 @@ static const u8 regs[t_num_regs] = {
struct lm92_data {
struct i2c_client *client;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
@ -126,7 +126,7 @@ static struct lm92_data *lm92_update_device(struct device *dev)
i2c_smbus_read_word_swapped(client, regs[i]);
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -202,7 +202,7 @@ struct lm93_data {
/* client update function */
void (*update)(struct lm93_data *, struct i2c_client *);
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
/* register values, arranged by block read groups */
struct block1_t block1;
@ -917,7 +917,7 @@ static struct lm93_data *lm93_update_device(struct device *dev)
data->update(data, client);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -78,7 +78,7 @@ struct lm95241_data {
struct mutex update_lock;
unsigned long last_updated; /* in jiffies */
unsigned long interval; /* in milli-seconds */
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
/* registers values */
u8 temp[ARRAY_SIZE(lm95241_reg_address)];
u8 status, config, model, trutherm;
@ -118,7 +118,7 @@ static struct lm95241_data *lm95241_update_device(struct device *dev)
data->status = i2c_smbus_read_byte_data(client,
LM95241_REG_R_STATUS);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);
@ -257,7 +257,7 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel,
else
data->config &= ~R2DF_MASK;
}
data->valid = 0;
data->valid = false;
ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
data->config);
break;
@ -273,7 +273,7 @@ static int lm95241_write_temp(struct device *dev, u32 attr, int channel,
else
data->config &= ~R2DF_MASK;
}
data->valid = 0;
data->valid = false;
ret = i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG,
data->config);
break;

View File

@ -77,7 +77,7 @@ static struct ltc4151_data *ltc4151_update_device(struct device *dev)
data->regs[i] = val;
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
abort:
mutex_unlock(&data->update_lock);

View File

@ -64,7 +64,7 @@ static struct ltc4215_data *ltc4215_update_device(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -73,13 +73,13 @@ static struct ltc4261_data *ltc4261_update_device(struct device *dev)
"Failed to read ADC value: error %d\n",
val);
ret = ERR_PTR(val);
data->valid = 0;
data->valid = false;
goto abort;
}
data->regs[i] = val;
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
abort:
mutex_unlock(&data->update_lock);

View File

@ -166,7 +166,7 @@ static struct max16065_data *max16065_update_device(struct device *dev)
= i2c_smbus_read_byte_data(client, MAX16065_FAULT(i));
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);
return data;

View File

@ -79,7 +79,7 @@ enum temp_index {
struct max1619_data {
struct i2c_client *client;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */
@ -124,7 +124,7 @@ static struct max1619_data *max1619_update_device(struct device *dev)
data->alarms ^= 0x02;
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -58,7 +58,7 @@ struct max1668_data {
enum chips type;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
/* 1x local and 4x remote */
@ -120,7 +120,7 @@ static struct max1668_data *max1668_update_device(struct device *dev)
data->alarms |= val;
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
abort:
mutex_unlock(&data->update_lock);

View File

@ -103,10 +103,16 @@ static int max31722_probe(struct spi_device *spi)
static int max31722_remove(struct spi_device *spi)
{
struct max31722_data *data = spi_get_drvdata(spi);
int ret;
hwmon_device_unregister(data->hwmon_dev);
return max31722_set_mode(data, MAX31722_MODE_STANDBY);
ret = max31722_set_mode(data, MAX31722_MODE_STANDBY);
if (ret)
/* There is nothing we can do about this ... */
dev_warn(&spi->dev, "Failed to put device in stand-by mode\n");
return 0;
}
static int __maybe_unused max31722_suspend(struct device *dev)

514
drivers/hwmon/max6620.c Normal file
View File

@ -0,0 +1,514 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hardware monitoring driver for Maxim MAX6620
*
* Originally from L. Grunenberg.
* (C) 2012 by L. Grunenberg <contact@lgrunenberg.de>
*
* Copyright (c) 2021 Dell Inc. or its subsidiaries. All Rights Reserved.
*
* based on code written by :
* 2007 by Hans J. Koch <hjk@hansjkoch.de>
* John Morris <john.morris@spirentcom.com>
* Copyright (c) 2003 Spirent Communications
* and Claus Gindhart <claus.gindhart@kontron.com>
*
* This module has only been tested with the MAX6620 chip.
*
* The datasheet was last seen at:
*
* http://pdfserv.maxim-ic.com/en/ds/MAX6620.pdf
*
*/
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
/*
* MAX 6620 registers
*/
#define MAX6620_REG_CONFIG 0x00
#define MAX6620_REG_FAULT 0x01
#define MAX6620_REG_CONF_FAN0 0x02
#define MAX6620_REG_CONF_FAN1 0x03
#define MAX6620_REG_CONF_FAN2 0x04
#define MAX6620_REG_CONF_FAN3 0x05
#define MAX6620_REG_DYN_FAN0 0x06
#define MAX6620_REG_DYN_FAN1 0x07
#define MAX6620_REG_DYN_FAN2 0x08
#define MAX6620_REG_DYN_FAN3 0x09
#define MAX6620_REG_TACH0 0x10
#define MAX6620_REG_TACH1 0x12
#define MAX6620_REG_TACH2 0x14
#define MAX6620_REG_TACH3 0x16
#define MAX6620_REG_VOLT0 0x18
#define MAX6620_REG_VOLT1 0x1A
#define MAX6620_REG_VOLT2 0x1C
#define MAX6620_REG_VOLT3 0x1E
#define MAX6620_REG_TAR0 0x20
#define MAX6620_REG_TAR1 0x22
#define MAX6620_REG_TAR2 0x24
#define MAX6620_REG_TAR3 0x26
#define MAX6620_REG_DAC0 0x28
#define MAX6620_REG_DAC1 0x2A
#define MAX6620_REG_DAC2 0x2C
#define MAX6620_REG_DAC3 0x2E
/*
* Config register bits
*/
#define MAX6620_CFG_RUN BIT(7)
#define MAX6620_CFG_POR BIT(6)
#define MAX6620_CFG_TIMEOUT BIT(5)
#define MAX6620_CFG_FULLFAN BIT(4)
#define MAX6620_CFG_OSC BIT(3)
#define MAX6620_CFG_WD_MASK (BIT(2) | BIT(1))
#define MAX6620_CFG_WD_2 BIT(1)
#define MAX6620_CFG_WD_6 BIT(2)
#define MAX6620_CFG_WD10 (BIT(2) | BIT(1))
#define MAX6620_CFG_WD BIT(0)
/*
* Failure status register bits
*/
#define MAX6620_FAIL_TACH0 BIT(4)
#define MAX6620_FAIL_TACH1 BIT(5)
#define MAX6620_FAIL_TACH2 BIT(6)
#define MAX6620_FAIL_TACH3 BIT(7)
#define MAX6620_FAIL_MASK0 BIT(0)
#define MAX6620_FAIL_MASK1 BIT(1)
#define MAX6620_FAIL_MASK2 BIT(2)
#define MAX6620_FAIL_MASK3 BIT(3)
#define MAX6620_CLOCK_FREQ 8192 /* Clock frequency in Hz */
#define MAX6620_PULSE_PER_REV 2 /* Tachometer pulses per revolution */
/* Minimum and maximum values of the FAN-RPM */
#define FAN_RPM_MIN 240
#define FAN_RPM_MAX 30000
static const u8 config_reg[] = {
MAX6620_REG_CONF_FAN0,
MAX6620_REG_CONF_FAN1,
MAX6620_REG_CONF_FAN2,
MAX6620_REG_CONF_FAN3,
};
static const u8 dyn_reg[] = {
MAX6620_REG_DYN_FAN0,
MAX6620_REG_DYN_FAN1,
MAX6620_REG_DYN_FAN2,
MAX6620_REG_DYN_FAN3,
};
static const u8 tach_reg[] = {
MAX6620_REG_TACH0,
MAX6620_REG_TACH1,
MAX6620_REG_TACH2,
MAX6620_REG_TACH3,
};
static const u8 target_reg[] = {
MAX6620_REG_TAR0,
MAX6620_REG_TAR1,
MAX6620_REG_TAR2,
MAX6620_REG_TAR3,
};
/*
* Client data (each client gets its own)
*/
struct max6620_data {
struct i2c_client *client;
struct mutex update_lock;
bool valid; /* false until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* register values */
u8 fancfg[4];
u8 fandyn[4];
u8 fault;
u16 tach[4];
u16 target[4];
};
static u8 max6620_fan_div_from_reg(u8 val)
{
return BIT((val & 0xE0) >> 5);
}
static u16 max6620_fan_rpm_to_tach(u8 div, int rpm)
{
return (60 * div * MAX6620_CLOCK_FREQ) / (rpm * MAX6620_PULSE_PER_REV);
}
static int max6620_fan_tach_to_rpm(u8 div, u16 tach)
{
return (60 * div * MAX6620_CLOCK_FREQ) / (tach * MAX6620_PULSE_PER_REV);
}
static int max6620_update_device(struct device *dev)
{
struct max6620_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int i;
int ret = 0;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
for (i = 0; i < 4; i++) {
ret = i2c_smbus_read_byte_data(client, config_reg[i]);
if (ret < 0)
goto error;
data->fancfg[i] = ret;
ret = i2c_smbus_read_byte_data(client, dyn_reg[i]);
if (ret < 0)
goto error;
data->fandyn[i] = ret;
ret = i2c_smbus_read_byte_data(client, tach_reg[i]);
if (ret < 0)
goto error;
data->tach[i] = (ret << 3) & 0x7f8;
ret = i2c_smbus_read_byte_data(client, tach_reg[i] + 1);
if (ret < 0)
goto error;
data->tach[i] |= (ret >> 5) & 0x7;
ret = i2c_smbus_read_byte_data(client, target_reg[i]);
if (ret < 0)
goto error;
data->target[i] = (ret << 3) & 0x7f8;
ret = i2c_smbus_read_byte_data(client, target_reg[i] + 1);
if (ret < 0)
goto error;
data->target[i] |= (ret >> 5) & 0x7;
}
/*
* Alarms are cleared on read in case the condition that
* caused the alarm is removed. Keep the value latched here
* for providing the register through different alarm files.
*/
ret = i2c_smbus_read_byte_data(client, MAX6620_REG_FAULT);
if (ret < 0)
goto error;
data->fault |= (ret >> 4) & (ret & 0x0F);
data->last_updated = jiffies;
data->valid = true;
}
error:
mutex_unlock(&data->update_lock);
return ret;
}
static umode_t
max6620_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
int channel)
{
switch (type) {
case hwmon_fan:
switch (attr) {
case hwmon_fan_alarm:
case hwmon_fan_input:
return 0444;
case hwmon_fan_div:
case hwmon_fan_target:
return 0644;
default:
break;
}
break;
default:
break;
}
return 0;
}
static int
max6620_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct max6620_data *data;
struct i2c_client *client;
int ret;
u8 div;
u8 val1;
u8 val2;
ret = max6620_update_device(dev);
if (ret < 0)
return ret;
data = dev_get_drvdata(dev);
client = data->client;
switch (type) {
case hwmon_fan:
switch (attr) {
case hwmon_fan_alarm:
mutex_lock(&data->update_lock);
*val = !!(data->fault & BIT(channel));
/* Setting TACH count to re-enable fan fault detection */
if (*val == 1) {
val1 = (data->target[channel] >> 3) & 0xff;
val2 = (data->target[channel] << 5) & 0xe0;
ret = i2c_smbus_write_byte_data(client,
target_reg[channel], val1);
if (ret < 0) {
mutex_unlock(&data->update_lock);
return ret;
}
ret = i2c_smbus_write_byte_data(client,
target_reg[channel] + 1, val2);
if (ret < 0) {
mutex_unlock(&data->update_lock);
return ret;
}
data->fault &= ~BIT(channel);
}
mutex_unlock(&data->update_lock);
break;
case hwmon_fan_div:
*val = max6620_fan_div_from_reg(data->fandyn[channel]);
break;
case hwmon_fan_input:
if (data->tach[channel] == 0) {
*val = 0;
} else {
div = max6620_fan_div_from_reg(data->fandyn[channel]);
*val = max6620_fan_tach_to_rpm(div, data->tach[channel]);
}
break;
case hwmon_fan_target:
if (data->target[channel] == 0) {
*val = 0;
} else {
div = max6620_fan_div_from_reg(data->fandyn[channel]);
*val = max6620_fan_tach_to_rpm(div, data->target[channel]);
}
break;
default:
return -EOPNOTSUPP;
}
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int
max6620_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long val)
{
struct max6620_data *data;
struct i2c_client *client;
int ret;
u8 div;
u16 tach;
u8 val1;
u8 val2;
ret = max6620_update_device(dev);
if (ret < 0)
return ret;
data = dev_get_drvdata(dev);
client = data->client;
mutex_lock(&data->update_lock);
switch (type) {
case hwmon_fan:
switch (attr) {
case hwmon_fan_div:
switch (val) {
case 1:
div = 0;
break;
case 2:
div = 1;
break;
case 4:
div = 2;
break;
case 8:
div = 3;
break;
case 16:
div = 4;
break;
case 32:
div = 5;
break;
default:
ret = -EINVAL;
goto error;
}
data->fandyn[channel] &= 0x1F;
data->fandyn[channel] |= div << 5;
ret = i2c_smbus_write_byte_data(client, dyn_reg[channel],
data->fandyn[channel]);
break;
case hwmon_fan_target:
val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX);
div = max6620_fan_div_from_reg(data->fandyn[channel]);
tach = max6620_fan_rpm_to_tach(div, val);
val1 = (tach >> 3) & 0xff;
val2 = (tach << 5) & 0xe0;
ret = i2c_smbus_write_byte_data(client, target_reg[channel], val1);
if (ret < 0)
break;
ret = i2c_smbus_write_byte_data(client, target_reg[channel] + 1, val2);
if (ret < 0)
break;
/* Setting TACH count re-enables fan fault detection */
data->fault &= ~BIT(channel);
break;
default:
ret = -EOPNOTSUPP;
break;
}
break;
default:
ret = -EOPNOTSUPP;
break;
}
error:
mutex_unlock(&data->update_lock);
return ret;
}
static const struct hwmon_channel_info *max6620_info[] = {
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM,
HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM,
HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM,
HWMON_F_INPUT | HWMON_F_DIV | HWMON_F_TARGET | HWMON_F_ALARM),
NULL
};
static const struct hwmon_ops max6620_hwmon_ops = {
.read = max6620_read,
.write = max6620_write,
.is_visible = max6620_is_visible,
};
static const struct hwmon_chip_info max6620_chip_info = {
.ops = &max6620_hwmon_ops,
.info = max6620_info,
};
static int max6620_init_client(struct max6620_data *data)
{
struct i2c_client *client = data->client;
int config;
int err;
int i;
int reg;
config = i2c_smbus_read_byte_data(client, MAX6620_REG_CONFIG);
if (config < 0) {
dev_err(&client->dev, "Error reading config, aborting.\n");
return config;
}
/*
* Set bit 4, disable other fans from going full speed on a fail
* failure.
*/
err = i2c_smbus_write_byte_data(client, MAX6620_REG_CONFIG, config | 0x10);
if (err < 0) {
dev_err(&client->dev, "Config write error, aborting.\n");
return err;
}
for (i = 0; i < 4; i++) {
reg = i2c_smbus_read_byte_data(client, config_reg[i]);
if (reg < 0)
return reg;
data->fancfg[i] = reg;
/* Enable RPM mode */
data->fancfg[i] |= 0xa8;
err = i2c_smbus_write_byte_data(client, config_reg[i], data->fancfg[i]);
if (err < 0)
return err;
/* 2 counts (001) and Rate change 100 (0.125 secs) */
data->fandyn[i] = 0x30;
err = i2c_smbus_write_byte_data(client, dyn_reg[i], data->fandyn[i]);
if (err < 0)
return err;
}
return 0;
}
static int max6620_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct max6620_data *data;
struct device *hwmon_dev;
int err;
data = devm_kzalloc(dev, sizeof(struct max6620_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
mutex_init(&data->update_lock);
err = max6620_init_client(data);
if (err)
return err;
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
data,
&max6620_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max6620_id[] = {
{ "max6620", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6620_id);
static struct i2c_driver max6620_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max6620",
},
.probe_new = max6620_probe,
.id_table = max6620_id,
};
module_i2c_driver(max6620_driver);
MODULE_AUTHOR("Lucas Grunenberg");
MODULE_DESCRIPTION("MAX6620 sensor driver");
MODULE_LICENSE("GPL");

View File

@ -69,7 +69,7 @@ static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 };
struct max6639_data {
struct i2c_client *client;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
/* Register values sampled regularly */
@ -141,7 +141,7 @@ static struct max6639_data *max6639_update_device(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
abort:
mutex_unlock(&data->update_lock);

View File

@ -181,7 +181,7 @@ static struct max6642_data *max6642_update_device(struct device *dev)
MAX6642_REG_R_STATUS);
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -12,7 +12,9 @@
#include <linux/regmap.h>
#include <linux/thermal.h>
#define MLXREG_FAN_MAX_TACHO 12
#define MLXREG_FAN_MAX_TACHO 14
#define MLXREG_FAN_MAX_PWM 4
#define MLXREG_FAN_PWM_NOT_CONNECTED 0xff
#define MLXREG_FAN_MAX_STATE 10
#define MLXREG_FAN_MIN_DUTY 51 /* 20% */
#define MLXREG_FAN_MAX_DUTY 255 /* 100% */
@ -61,6 +63,8 @@
MLXREG_FAN_MAX_DUTY, \
MLXREG_FAN_MAX_STATE))
struct mlxreg_fan;
/*
* struct mlxreg_fan_tacho - tachometer data (internal use):
*
@ -79,12 +83,18 @@ struct mlxreg_fan_tacho {
/*
* struct mlxreg_fan_pwm - PWM data (internal use):
*
* @fan: private data;
* @connected: indicates if PWM is connected;
* @reg: register offset;
* @cooling: cooling device levels;
* @cdev: cooling device;
*/
struct mlxreg_fan_pwm {
struct mlxreg_fan *fan;
bool connected;
u32 reg;
u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1];
struct thermal_cooling_device *cdev;
};
/*
@ -97,20 +107,16 @@ struct mlxreg_fan_pwm {
* @tachos_per_drwr - number of tachometers per drawer;
* @samples: minimum allowed samples per pulse;
* @divider: divider value for tachometer RPM calculation;
* @cooling: cooling device levels;
* @cdev: cooling device;
*/
struct mlxreg_fan {
struct device *dev;
void *regmap;
struct mlxreg_core_platform_data *pdata;
struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO];
struct mlxreg_fan_pwm pwm;
struct mlxreg_fan_pwm pwm[MLXREG_FAN_MAX_PWM];
int tachos_per_drwr;
int samples;
int divider;
u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1];
struct thermal_cooling_device *cdev;
};
static int
@ -119,6 +125,7 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
{
struct mlxreg_fan *fan = dev_get_drvdata(dev);
struct mlxreg_fan_tacho *tacho;
struct mlxreg_fan_pwm *pwm;
u32 regval;
int err;
@ -169,9 +176,10 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
break;
case hwmon_pwm:
pwm = &fan->pwm[channel];
switch (attr) {
case hwmon_pwm_input:
err = regmap_read(fan->regmap, fan->pwm.reg, &regval);
err = regmap_read(fan->regmap, pwm->reg, &regval);
if (err)
return err;
@ -195,6 +203,7 @@ mlxreg_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long val)
{
struct mlxreg_fan *fan = dev_get_drvdata(dev);
struct mlxreg_fan_pwm *pwm;
switch (type) {
case hwmon_pwm:
@ -203,7 +212,8 @@ mlxreg_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
if (val < MLXREG_FAN_MIN_DUTY ||
val > MLXREG_FAN_MAX_DUTY)
return -EINVAL;
return regmap_write(fan->regmap, fan->pwm.reg, val);
pwm = &fan->pwm[channel];
return regmap_write(fan->regmap, pwm->reg, val);
default:
return -EOPNOTSUPP;
}
@ -235,7 +245,7 @@ mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
break;
case hwmon_pwm:
if (!(((struct mlxreg_fan *)data)->pwm.connected))
if (!(((struct mlxreg_fan *)data)->pwm[channel].connected))
return 0;
switch (attr) {
@ -253,6 +263,13 @@ mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
return 0;
}
static char *mlxreg_fan_name[] = {
"mlxreg_fan",
"mlxreg_fan1",
"mlxreg_fan2",
"mlxreg_fan3",
};
static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = {
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_FAULT,
@ -266,8 +283,13 @@ static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = {
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT,
HWMON_F_INPUT | HWMON_F_FAULT),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT),
NULL
};
@ -294,11 +316,12 @@ static int mlxreg_fan_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct mlxreg_fan *fan = cdev->devdata;
struct mlxreg_fan_pwm *pwm = cdev->devdata;
struct mlxreg_fan *fan = pwm->fan;
u32 regval;
int err;
err = regmap_read(fan->regmap, fan->pwm.reg, &regval);
err = regmap_read(fan->regmap, pwm->reg, &regval);
if (err) {
dev_err(fan->dev, "Failed to query PWM duty\n");
return err;
@ -313,7 +336,8 @@ static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct mlxreg_fan *fan = cdev->devdata;
struct mlxreg_fan_pwm *pwm = cdev->devdata;
struct mlxreg_fan *fan = pwm->fan;
unsigned long cur_state;
int i, config = 0;
u32 regval;
@ -337,11 +361,11 @@ static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
config = 1;
state -= MLXREG_FAN_MAX_STATE;
for (i = 0; i < state; i++)
fan->cooling_levels[i] = state;
pwm->cooling_levels[i] = state;
for (i = state; i <= MLXREG_FAN_MAX_STATE; i++)
fan->cooling_levels[i] = i;
pwm->cooling_levels[i] = i;
err = regmap_read(fan->regmap, fan->pwm.reg, &regval);
err = regmap_read(fan->regmap, pwm->reg, &regval);
if (err) {
dev_err(fan->dev, "Failed to query PWM duty\n");
return err;
@ -358,8 +382,8 @@ static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
return -EINVAL;
/* Normalize the state to the valid speed range. */
state = fan->cooling_levels[state];
err = regmap_write(fan->regmap, fan->pwm.reg,
state = pwm->cooling_levels[state];
err = regmap_write(fan->regmap, pwm->reg,
MLXREG_FAN_PWM_STATE2DUTY(state));
if (err) {
dev_err(fan->dev, "Failed to write PWM duty\n");
@ -390,6 +414,22 @@ static int mlxreg_fan_connect_verify(struct mlxreg_fan *fan,
return !!(regval & data->bit);
}
static int mlxreg_pwm_connect_verify(struct mlxreg_fan *fan,
struct mlxreg_core_data *data)
{
u32 regval;
int err;
err = regmap_read(fan->regmap, data->reg, &regval);
if (err) {
dev_err(fan->dev, "Failed to query pwm register 0x%08x\n",
data->reg);
return err;
}
return regval != MLXREG_FAN_PWM_NOT_CONNECTED;
}
static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan,
struct mlxreg_core_data *data)
{
@ -418,8 +458,8 @@ static int mlxreg_fan_speed_divider_get(struct mlxreg_fan *fan,
static int mlxreg_fan_config(struct mlxreg_fan *fan,
struct mlxreg_core_platform_data *pdata)
{
int tacho_num = 0, tacho_avail = 0, pwm_num = 0, i;
struct mlxreg_core_data *data = pdata->data;
int tacho_num = 0, tacho_avail = 0, i;
bool configured = false;
int err;
@ -449,13 +489,24 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
fan->tacho[tacho_num++].connected = true;
tacho_avail++;
} else if (strnstr(data->label, "pwm", sizeof(data->label))) {
if (fan->pwm.connected) {
dev_err(fan->dev, "duplicate pwm entry: %s\n",
if (pwm_num == MLXREG_FAN_MAX_TACHO) {
dev_err(fan->dev, "too many pwm entries: %s\n",
data->label);
return -EINVAL;
}
fan->pwm.reg = data->reg;
fan->pwm.connected = true;
/* Validate if more then one PWM is connected. */
if (pwm_num) {
err = mlxreg_pwm_connect_verify(fan, data);
if (err < 0)
return err;
else if (!err)
continue;
}
fan->pwm[pwm_num].reg = data->reg;
fan->pwm[pwm_num].connected = true;
pwm_num++;
} else if (strnstr(data->label, "conf", sizeof(data->label))) {
if (configured) {
dev_err(fan->dev, "duplicate conf entry: %s\n",
@ -508,11 +559,32 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
fan->tachos_per_drwr = tacho_avail / drwr_avail;
}
/* Init cooling levels per PWM state. */
for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++)
fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL;
for (i = MLXREG_FAN_SPEED_MIN_LEVEL; i <= MLXREG_FAN_MAX_STATE; i++)
fan->cooling_levels[i] = i;
return 0;
}
static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan)
{
int i, j;
for (i = 0; i < MLXREG_FAN_MAX_PWM; i++) {
struct mlxreg_fan_pwm *pwm = &fan->pwm[i];
if (!pwm->connected)
continue;
pwm->fan = fan;
pwm->cdev = devm_thermal_of_cooling_device_register(dev, NULL, mlxreg_fan_name[i],
pwm, &mlxreg_fan_cooling_ops);
if (IS_ERR(pwm->cdev)) {
dev_err(dev, "Failed to register cooling device\n");
return PTR_ERR(pwm->cdev);
}
/* Init cooling levels per PWM state. */
for (j = 0; j < MLXREG_FAN_SPEED_MIN_LEVEL; j++)
pwm->cooling_levels[j] = MLXREG_FAN_SPEED_MIN_LEVEL;
for (j = MLXREG_FAN_SPEED_MIN_LEVEL; j <= MLXREG_FAN_MAX_STATE; j++)
pwm->cooling_levels[j] = j;
}
return 0;
}
@ -551,16 +623,10 @@ static int mlxreg_fan_probe(struct platform_device *pdev)
return PTR_ERR(hwm);
}
if (IS_REACHABLE(CONFIG_THERMAL)) {
fan->cdev = devm_thermal_of_cooling_device_register(dev,
NULL, "mlxreg_fan", fan, &mlxreg_fan_cooling_ops);
if (IS_ERR(fan->cdev)) {
dev_err(dev, "Failed to register cooling device\n");
return PTR_ERR(fan->cdev);
}
}
if (IS_REACHABLE(CONFIG_THERMAL))
err = mlxreg_fan_cooling_config(dev, fan);
return 0;
return err;
}
static struct platform_driver mlxreg_fan_driver = {

View File

@ -174,6 +174,7 @@ superio_exit(int ioreg)
#define NCT6683_CUSTOMER_ID_MITAC 0xa0e
#define NCT6683_CUSTOMER_ID_MSI 0x201
#define NCT6683_CUSTOMER_ID_ASROCK 0xe2c
#define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b
#define NCT6683_REG_BUILD_YEAR 0x604
#define NCT6683_REG_BUILD_MONTH 0x605
@ -1221,6 +1222,8 @@ static int nct6683_probe(struct platform_device *pdev)
break;
case NCT6683_CUSTOMER_ID_ASROCK:
break;
case NCT6683_CUSTOMER_ID_ASROCK2:
break;
default:
if (!force)
return -ENODEV;

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,23 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = {
#define REG_CHIP_ID 0xfe
#define REG_VERSION_ID 0xff
/*
* Resistance temperature detector (RTD) modes according to 7.2.32 Mode
* Selection Register
*/
#define RTD_MODE_CURRENT 0x1
#define RTD_MODE_THERMISTOR 0x2
#define RTD_MODE_VOLTAGE 0x3
#define MODE_RTD_MASK 0x3
#define MODE_LTD_EN 0x40
/*
* Bit offset for sensors modes in REG_MODE.
* Valid for index 0..2, indicating RTD1..3.
*/
#define MODE_BIT_OFFSET_RTD(index) ((index) * 2)
/*
* Data structures and manipulation thereof
*/
@ -1038,7 +1055,114 @@ static const struct regmap_config nct7802_regmap_config = {
.volatile_reg = nct7802_regmap_is_volatile,
};
static int nct7802_init_chip(struct nct7802_data *data)
static int nct7802_get_channel_config(struct device *dev,
struct device_node *node, u8 *mode_mask,
u8 *mode_val)
{
u32 reg;
const char *type_str, *md_str;
u8 md;
if (!node->name || of_node_cmp(node->name, "channel"))
return 0;
if (of_property_read_u32(node, "reg", &reg)) {
dev_err(dev, "Could not read reg value for '%s'\n",
node->full_name);
return -EINVAL;
}
if (reg > 3) {
dev_err(dev, "Invalid reg (%u) in '%s'\n", reg,
node->full_name);
return -EINVAL;
}
if (reg == 0) {
if (!of_device_is_available(node))
*mode_val &= ~MODE_LTD_EN;
else
*mode_val |= MODE_LTD_EN;
*mode_mask |= MODE_LTD_EN;
return 0;
}
/* At this point we have reg >= 1 && reg <= 3 */
if (!of_device_is_available(node)) {
*mode_val &= ~(MODE_RTD_MASK << MODE_BIT_OFFSET_RTD(reg - 1));
*mode_mask |= MODE_RTD_MASK << MODE_BIT_OFFSET_RTD(reg - 1);
return 0;
}
if (of_property_read_string(node, "sensor-type", &type_str)) {
dev_err(dev, "No type for '%s'\n", node->full_name);
return -EINVAL;
}
if (!strcmp(type_str, "voltage")) {
*mode_val |= (RTD_MODE_VOLTAGE & MODE_RTD_MASK)
<< MODE_BIT_OFFSET_RTD(reg - 1);
*mode_mask |= MODE_RTD_MASK << MODE_BIT_OFFSET_RTD(reg - 1);
return 0;
}
if (strcmp(type_str, "temperature")) {
dev_err(dev, "Invalid type '%s' for '%s'\n", type_str,
node->full_name);
return -EINVAL;
}
if (reg == 3) {
/* RTD3 only supports thermistor mode */
md = RTD_MODE_THERMISTOR;
} else {
if (of_property_read_string(node, "temperature-mode",
&md_str)) {
dev_err(dev, "No mode for '%s'\n", node->full_name);
return -EINVAL;
}
if (!strcmp(md_str, "thermal-diode"))
md = RTD_MODE_CURRENT;
else if (!strcmp(md_str, "thermistor"))
md = RTD_MODE_THERMISTOR;
else {
dev_err(dev, "Invalid mode '%s' for '%s'\n", md_str,
node->full_name);
return -EINVAL;
}
}
*mode_val |= (md & MODE_RTD_MASK) << MODE_BIT_OFFSET_RTD(reg - 1);
*mode_mask |= MODE_RTD_MASK << MODE_BIT_OFFSET_RTD(reg - 1);
return 0;
}
static int nct7802_configure_channels(struct device *dev,
struct nct7802_data *data)
{
/* Enable local temperature sensor by default */
u8 mode_mask = MODE_LTD_EN, mode_val = MODE_LTD_EN;
struct device_node *node;
int err;
if (dev->of_node) {
for_each_child_of_node(dev->of_node, node) {
err = nct7802_get_channel_config(dev, node, &mode_mask,
&mode_val);
if (err) {
of_node_put(node);
return err;
}
}
}
return regmap_update_bits(data->regmap, REG_MODE, mode_mask, mode_val);
}
static int nct7802_init_chip(struct device *dev, struct nct7802_data *data)
{
int err;
@ -1047,8 +1171,7 @@ static int nct7802_init_chip(struct nct7802_data *data)
if (err)
return err;
/* Enable local temperature sensor */
err = regmap_update_bits(data->regmap, REG_MODE, 0x40, 0x40);
err = nct7802_configure_channels(dev, data);
if (err)
return err;
@ -1074,7 +1197,7 @@ static int nct7802_probe(struct i2c_client *client)
mutex_init(&data->access_lock);
mutex_init(&data->in_alarm_lock);
ret = nct7802_init_chip(data);
ret = nct7802_init_chip(dev, data);
if (ret < 0)
return ret;

View File

@ -178,7 +178,7 @@ struct pc87360_data {
struct device *hwmon_dev;
struct mutex lock;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
int address[3];
@ -1673,7 +1673,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
}
data->last_updated = jiffies;
data->valid = 1;
data->valid = true;
}
mutex_unlock(&data->update_lock);

View File

@ -18,6 +18,7 @@
#include "pmbus.h"
#define CFFPS_MFG_ID_CMD 0x99
#define CFFPS_FRU_CMD 0x9A
#define CFFPS_PN_CMD 0x9B
#define CFFPS_HEADER_CMD 0x9C
@ -34,7 +35,7 @@
#define CFFPS_INPUT_HISTORY_SIZE 100
#define CFFPS_CCIN_REVISION GENMASK(7, 0)
#define CFFPS_CCIN_REVISION_LEGACY 0xde
#define CFFPS_CCIN_REVISION_LEGACY 0xde
#define CFFPS_CCIN_VERSION GENMASK(15, 8)
#define CFFPS_CCIN_VERSION_1 0x2b
#define CFFPS_CCIN_VERSION_2 0x2e
@ -57,6 +58,7 @@
enum {
CFFPS_DEBUGFS_INPUT_HISTORY = 0,
CFFPS_DEBUGFS_MFG_ID,
CFFPS_DEBUGFS_FRU,
CFFPS_DEBUGFS_PN,
CFFPS_DEBUGFS_HEADER,
@ -158,6 +160,9 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
switch (idx) {
case CFFPS_DEBUGFS_INPUT_HISTORY:
return ibm_cffps_read_input_history(psu, buf, count, ppos);
case CFFPS_DEBUGFS_MFG_ID:
cmd = CFFPS_MFG_ID_CMD;
break;
case CFFPS_DEBUGFS_FRU:
cmd = CFFPS_FRU_CMD;
break;
@ -503,16 +508,27 @@ static int ibm_cffps_probe(struct i2c_client *client)
u16 ccin_revision = 0;
u16 ccin_version = CFFPS_CCIN_VERSION_1;
int ccin = i2c_smbus_read_word_swapped(client, CFFPS_CCIN_CMD);
char mfg_id[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
if (ccin > 0) {
ccin_revision = FIELD_GET(CFFPS_CCIN_REVISION, ccin);
ccin_version = FIELD_GET(CFFPS_CCIN_VERSION, ccin);
}
rc = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, mfg_id);
if (rc < 0) {
dev_err(&client->dev, "Failed to read Manufacturer ID\n");
return rc;
}
switch (ccin_version) {
default:
case CFFPS_CCIN_VERSION_1:
vs = cffps1;
if ((strncmp(mfg_id, "ACBE", 4) == 0) ||
(strncmp(mfg_id, "ARTE", 4) == 0))
vs = cffps1;
else
vs = cffps2;
break;
case CFFPS_CCIN_VERSION_2:
vs = cffps2;
@ -564,6 +580,9 @@ static int ibm_cffps_probe(struct i2c_client *client)
debugfs_create_file("input_history", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_INPUT_HISTORY],
&ibm_cffps_fops);
debugfs_create_file("mfg_id", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_MFG_ID],
&ibm_cffps_fops);
debugfs_create_file("fru", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_FRU],
&ibm_cffps_fops);

View File

@ -14,6 +14,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/log2.h>
#include <linux/of_device.h>
#include "pmbus.h"
enum chips { lm25056, lm25066, lm5064, lm5066, lm5066i };
@ -51,26 +52,31 @@ struct __coeff {
#define PSC_CURRENT_IN_L (PSC_NUM_CLASSES)
#define PSC_POWER_L (PSC_NUM_CLASSES + 1)
static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
static const struct __coeff lm25066_coeff[][PSC_NUM_CLASSES + 2] = {
[lm25056] = {
[PSC_VOLTAGE_IN] = {
.m = 16296,
.b = 1343,
.R = -2,
},
[PSC_CURRENT_IN] = {
.m = 13797,
.b = -1833,
.R = -2,
},
[PSC_CURRENT_IN_L] = {
.m = 6726,
.b = -537,
.R = -2,
},
[PSC_POWER] = {
.m = 5501,
.b = -2908,
.R = -3,
},
[PSC_POWER_L] = {
.m = 26882,
.b = -5646,
.R = -4,
},
[PSC_TEMPERATURE] = {
@ -82,26 +88,32 @@ static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
[lm25066] = {
[PSC_VOLTAGE_IN] = {
.m = 22070,
.b = -1800,
.R = -2,
},
[PSC_VOLTAGE_OUT] = {
.m = 22070,
.b = -1800,
.R = -2,
},
[PSC_CURRENT_IN] = {
.m = 13661,
.b = -5200,
.R = -2,
},
[PSC_CURRENT_IN_L] = {
.m = 6852,
.m = 6854,
.b = -3100,
.R = -2,
},
[PSC_POWER] = {
.m = 736,
.b = -3300,
.R = -2,
},
[PSC_POWER_L] = {
.m = 369,
.b = -1900,
.R = -2,
},
[PSC_TEMPERATURE] = {
@ -111,26 +123,32 @@ static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
[lm5064] = {
[PSC_VOLTAGE_IN] = {
.m = 4611,
.b = -642,
.R = -2,
},
[PSC_VOLTAGE_OUT] = {
.m = 4621,
.b = 423,
.R = -2,
},
[PSC_CURRENT_IN] = {
.m = 10742,
.b = 1552,
.R = -2,
},
[PSC_CURRENT_IN_L] = {
.m = 5456,
.b = 2118,
.R = -2,
},
[PSC_POWER] = {
.m = 1204,
.b = 8524,
.R = -3,
},
[PSC_POWER_L] = {
.m = 612,
.b = 11202,
.R = -3,
},
[PSC_TEMPERATURE] = {
@ -140,26 +158,32 @@ static struct __coeff lm25066_coeff[6][PSC_NUM_CLASSES + 2] = {
[lm5066] = {
[PSC_VOLTAGE_IN] = {
.m = 4587,
.b = -1200,
.R = -2,
},
[PSC_VOLTAGE_OUT] = {
.m = 4587,
.b = -2400,
.R = -2,
},
[PSC_CURRENT_IN] = {
.m = 10753,
.b = -1200,
.R = -2,
},
[PSC_CURRENT_IN_L] = {
.m = 5405,
.b = -600,
.R = -2,
},
[PSC_POWER] = {
.m = 1204,
.b = -6000,
.R = -3,
},
[PSC_POWER_L] = {
.m = 605,
.b = -8000,
.R = -3,
},
[PSC_TEMPERATURE] = {
@ -211,8 +235,6 @@ struct lm25066_data {
#define to_lm25066_data(x) container_of(x, struct lm25066_data, info)
static const struct i2c_device_id lm25066_id[];
static int lm25066_read_word_data(struct i2c_client *client, int page,
int phase, int reg)
{
@ -413,12 +435,35 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg,
return ret;
}
static const struct i2c_device_id lm25066_id[] = {
{"lm25056", lm25056},
{"lm25066", lm25066},
{"lm5064", lm5064},
{"lm5066", lm5066},
{"lm5066i", lm5066i},
{ }
};
MODULE_DEVICE_TABLE(i2c, lm25066_id);
static const struct of_device_id __maybe_unused lm25066_of_match[] = {
{ .compatible = "ti,lm25056", .data = (void *)lm25056, },
{ .compatible = "ti,lm25066", .data = (void *)lm25066, },
{ .compatible = "ti,lm5064", .data = (void *)lm5064, },
{ .compatible = "ti,lm5066", .data = (void *)lm5066, },
{ .compatible = "ti,lm5066i", .data = (void *)lm5066i, },
{ },
};
MODULE_DEVICE_TABLE(of, lm25066_of_match);
static int lm25066_probe(struct i2c_client *client)
{
int config;
u32 shunt;
struct lm25066_data *data;
struct pmbus_driver_info *info;
struct __coeff *coeff;
const struct __coeff *coeff;
const struct of_device_id *of_id;
const struct i2c_device_id *i2c_id;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA))
@ -433,7 +478,14 @@ static int lm25066_probe(struct i2c_client *client)
if (config < 0)
return config;
data->id = i2c_match_id(lm25066_id, client)->driver_data;
i2c_id = i2c_match_id(lm25066_id, client);
of_id = of_match_device(lm25066_of_match, &client->dev);
if (of_id && (unsigned long)of_id->data != i2c_id->driver_data)
dev_notice(&client->dev, "Device mismatch: %s in device tree, %s detected\n",
of_id->name, i2c_id->name);
data->id = i2c_id->driver_data;
info = &data->info;
info->pages = 1;
@ -483,25 +535,25 @@ static int lm25066_probe(struct i2c_client *client)
info->b[PSC_POWER] = coeff[PSC_POWER].b;
}
/*
* Values in the TI datasheets are normalized for a 1mOhm sense
* resistor; assume that unless DT specifies a value explicitly.
*/
if (of_property_read_u32(client->dev.of_node, "shunt-resistor-micro-ohms", &shunt))
shunt = 1000;
info->m[PSC_CURRENT_IN] = info->m[PSC_CURRENT_IN] * shunt / 1000;
info->m[PSC_POWER] = info->m[PSC_POWER] * shunt / 1000;
return pmbus_do_probe(client, info);
}
static const struct i2c_device_id lm25066_id[] = {
{"lm25056", lm25056},
{"lm25066", lm25066},
{"lm5064", lm5064},
{"lm5066", lm5066},
{"lm5066i", lm5066i},
{ }
};
MODULE_DEVICE_TABLE(i2c, lm25066_id);
/* This is the driver that will be inserted */
static struct i2c_driver lm25066_driver = {
.driver = {
.name = "lm25066",
},
.of_match_table = of_match_ptr(lm25066_of_match),
},
.probe_new = lm25066_probe,
.id_table = lm25066_id,
};

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