Commit 241ed6ab authored by Linus Torvalds's avatar Linus Torvalds

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

Pull hwmon updates from Guenter Roeck:
 "New drivers:

   - Infineon TDA38640 Voltage Regulator

   - NXP MC34VR500 PMIC

   - GXP fan controller

   - MPQ7932 Power Management IC

  New chip or board support added to existing drivers:

   - it87: IT87952E; also other cleanup/improvements

   - intel-m10-bmc-hwmon: N6000

   - pmbus/max16601: MAX16600

   - aquacomputer_d5next: Aquacomputer Aquastream Ultimate, Aquacomputer
     Poweradjust 3, Aquacomputer Aquaero

   - nct6775: Support for B650/B660/X670 ASUS boards

   - oxp-sensors: AYANEO AIR and AIR Pro

  Other notable changes:

   - Various kernel documentation fixes

   - Various devicetree bindings fixes

   - Explicitly deprecated [devm_]hwmon_device_register_with_groups

   - ftsteutates: Support for fanX_fault and other cleanup

   - ltc2945: Support for setting shunt resistor and other cleanup/fixes

   - coretemp: Avoid RDMSR interrupts to isolated CPUs, and simplify
     platform device handling

  ... and various other minor cleanups and fixes"

* tag 'hwmon-for-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (66 commits)
  hwmon: Deprecate [devm_]hwmon_device_register_with_groups
  hwmon: (mlxreg-fan) Return zero speed for broken fan
  hwmon: (gxp-fan-ctrl) use devm_platform_get_and_ioremap_resource()
  hwmon: (aquacomputer_d5next) Add support for Aquacomputer Aquastream Ultimate
  hwmon: (aquacomputer_d5next) Add support for Aquacomputer Poweradjust 3
  hwmon: (iio_hwmon) use dev_err_probe
  hwmon: intel-m10-bmc-hwmon: Add N6000 sensors
  Docs/hwmon/index: Add missing SPDX License Identifier
  hwmon: (it87) Updated documentation for recent updates to it87
  hwmon: (it87) Add new chipset IT87952E
  hwmon: (it87) Allow multiple chip IDs for force_id
  hwmon: (it87) Add chip_id in some info message
  hwmon: (it87) List full chip model name
  hwmon: (it87) Disable configuration exit for certain chips
  hwmon: (it87) Allow disabling exiting of configuration mode
  Documentation: hwmon: correct spelling
  hwmon: (pmbus/max16601) Add support for MAX16600
  hwmon: (ltc2945) Allow setting shunt resistor
  hwmon: (ltc2945) Handle error case in ltc2945_value_store
  hwmon: (ltc2945) Add devicetree match table
  ...
parents 6c71297e 5720a18b
......@@ -276,6 +276,15 @@ Description:
RW
What: /sys/class/hwmon/hwmonX/fanY_fault
Description:
Reports if a fan has reported failure.
- 1: Failed
- 0: Ok
RO
What: /sys/class/hwmon/hwmonX/pwmY
Description:
Pulse width modulation fan control.
......
......@@ -52,16 +52,16 @@ examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
pwmon@5a {
compatible = "adi,adm1177";
reg = <0x5a>;
shunt-resistor-micro-ohms = <50000>; /* 50 mOhm */
adi,shutdown-threshold-microamp = <1059000>; /* 1.059 A */
adi,vrange-high-enable;
compatible = "adi,adm1177";
reg = <0x5a>;
shunt-resistor-micro-ohms = <50000>; /* 50 mOhm */
adi,shutdown-threshold-microamp = <1059000>; /* 1.059 A */
adi,vrange-high-enable;
};
};
...
......@@ -39,13 +39,13 @@ additionalProperties: false
examples:
- |
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
adm1266@40 {
compatible = "adi,adm1266";
reg = <0x40>;
compatible = "adi,adm1266";
reg = <0x40>;
};
};
...
......@@ -49,15 +49,15 @@ additionalProperties: false
examples:
- |
fpga_axi: fpga-axi {
#address-cells = <0x2>;
#size-cells = <0x1>;
axi_fan_control: axi-fan-control@80000000 {
compatible = "adi,axi-fan-control-1.00.a";
reg = <0x0 0x80000000 0x10000>;
clocks = <&clk 71>;
interrupts = <0 110 0>;
pulses-per-revolution = <2>;
};
#address-cells = <0x2>;
#size-cells = <0x1>;
axi_fan_control: axi-fan-control@80000000 {
compatible = "adi,axi-fan-control-1.00.a";
reg = <0x0 0x80000000 0x10000>;
clocks = <&clk 71>;
interrupts = <0 110 0>;
pulses-per-revolution = <2>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/adi,ltc2945.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices LTC2945 wide range i2c power monitor
maintainers:
- Guenter Roeck <linux@roeck-us.net>
description: |
Analog Devices LTC2945 wide range i2c power monitor over I2C.
https://www.analog.com/media/en/technical-documentation/data-sheets/LTC2945.pdf
properties:
compatible:
enum:
- adi,ltc2945
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>;
power-monitor@6e {
compatible = "adi,ltc2945";
reg = <0x6e>;
/* 10 milli-Ohm shunt resistor */
shunt-resistor-micro-ohms = <10000>;
};
};
...
......@@ -87,15 +87,15 @@ additionalProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
ltc2947_spi: ltc2947@0 {
compatible = "adi,ltc2947";
reg = <0>;
/* accumulation takes place always for energ1/charge1. */
/* accumulation only on positive current for energy2/charge2. */
adi,accumulator-ctl-pol = <0 1>;
};
#address-cells = <1>;
#size-cells = <0>;
ltc2947_spi: ltc2947@0 {
compatible = "adi,ltc2947";
reg = <0>;
/* accumulation takes place always for energ1/charge1. */
/* accumulation only on positive current for energy2/charge2. */
adi,accumulator-ctl-pol = <0 1>;
};
};
...
......@@ -55,26 +55,26 @@ additionalProperties: false
examples:
- |
i2c1 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
ltc2992@6F {
#address-cells = <1>;
#size-cells = <0>;
ltc2992@6f {
#address-cells = <1>;
#size-cells = <0>;
compatible = "adi,ltc2992";
reg = <0x6F>;
compatible = "adi,ltc2992";
reg = <0x6f>;
channel@0 {
reg = <0x0>;
shunt-resistor-micro-ohms = <10000>;
};
channel@0 {
reg = <0x0>;
shunt-resistor-micro-ohms = <10000>;
};
channel@1 {
reg = <0x1>;
shunt-resistor-micro-ohms = <10000>;
};
channel@1 {
reg = <0x1>;
shunt-resistor-micro-ohms = <10000>;
};
};
};
...
......@@ -41,13 +41,13 @@ additionalProperties: false
examples:
- |
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
sbrmi@3c {
compatible = "amd,sbrmi";
reg = <0x3c>;
compatible = "amd,sbrmi";
reg = <0x3c>;
};
};
...
......@@ -42,13 +42,13 @@ additionalProperties: false
examples:
- |
i2c0 {
i2c {
#address-cells = <1>;
#size-cells = <0>;
sbtsi@4c {
compatible = "amd,sbtsi";
reg = <0x4c>;
compatible = "amd,sbtsi";
reg = <0x4c>;
};
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/hpe,gxp-fan-ctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: HPE GXP Fan Controller
maintainers:
- Nick Hawkins <nick.hawkins@hpe.com>
description: |
The HPE GXP fan controller controls the fans through an external CPLD
device that connects to the fans.
properties:
compatible:
const: hpe,gxp-fan-ctrl
reg:
items:
- description: Fan controller PWM
- description: Programmable logic
- description: Function 2
reg-names:
items:
- const: base
- const: pl
- const: fn2
required:
- compatible
- reg
- reg-names
additionalProperties: false
examples:
- |
fan-controller@1000c00 {
compatible = "hpe,gxp-fan-ctrl";
reg = <0x1000c00 0x200>, <0xd1000000 0xff>, <0x80200000 0x100000>;
reg-names = "base", "pl", "fn2";
};
......@@ -31,7 +31,7 @@ additionalProperties: false
examples:
- |
iio-hwmon {
compatible = "iio-hwmon";
io-channels = <&adc 1>, <&adc 2>;
};
iio-hwmon {
compatible = "iio-hwmon";
io-channels = <&adc 1>, <&adc 2>;
};
......@@ -198,30 +198,30 @@ examples:
};
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@4c {
compatible = "adi,adt7481";
reg = <0x4c>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0x0>;
label = "local";
};
channel@1 {
reg = <0x1>;
label = "front";
temperature-offset-millicelsius = <4000>;
};
channel@2 {
reg = <0x2>;
label = "back";
temperature-offset-millicelsius = <750>;
sensor@4c {
compatible = "adi,adt7481";
reg = <0x4c>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0x0>;
label = "local";
};
channel@1 {
reg = <0x1>;
label = "front";
temperature-offset-millicelsius = <4000>;
};
channel@2 {
reg = <0x2>;
label = "back";
temperature-offset-millicelsius = <750>;
};
};
};
};
......@@ -131,7 +131,7 @@ additionalProperties: false
examples:
- |
thermistor0 {
thermistor {
compatible = "murata,ncp18wb473";
io-channels = <&gpadc 0x06>;
pullup-uv = <1800000>;
......
......@@ -123,23 +123,23 @@ examples:
#size-cells = <0>;
channel@0 { /* LTD */
reg = <0>;
reg = <0>;
};
channel@1 { /* RTD1 */
reg = <1>;
sensor-type = "voltage";
reg = <1>;
sensor-type = "voltage";
};
channel@2 { /* RTD2 */
reg = <2>;
sensor-type = "temperature";
temperature-mode = "thermal-diode";
reg = <2>;
sensor-type = "temperature";
temperature-mode = "thermal-diode";
};
channel@3 { /* RTD3 */
reg = <3>;
sensor-type = "temperature";
reg = <3>;
sensor-type = "temperature";
};
};
};
# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/nxp,mc34vr500.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP MC34VR500 hwmon sensor
maintainers:
- Mario Kicherer <dev@kicherer.org>
properties:
compatible:
enum:
- nxp,mc34vr500
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@8 {
compatible = "nxp,mc34vr500";
reg = <0x08>;
};
};
......@@ -77,15 +77,15 @@ additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
tmp513@5c {
compatible = "ti,tmp513";
reg = <0x5C>;
shunt-resistor-micro-ohms = <330000>;
ti,bus-range-microvolt = <32000000>;
ti,pga-gain = <8>;
ti,nfactor = <0x1 0xF3 0x00>;
};
#address-cells = <1>;
#size-cells = <0>;
tmp513@5c {
compatible = "ti,tmp513";
reg = <0x5c>;
shunt-resistor-micro-ohms = <330000>;
ti,bus-range-microvolt = <32000000>;
ti,pga-gain = <8>;
ti,nfactor = <0x1 0xf3 0x00>;
};
};
......@@ -40,12 +40,12 @@ additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
tps23861@30 {
compatible = "ti,tps23861";
reg = <0x30>;
shunt-resistor-micro-ohms = <255000>;
};
#address-cells = <1>;
#size-cells = <0>;
tps23861@30 {
compatible = "ti,tps23861";
reg = <0x30>;
shunt-resistor-micro-ohms = <255000>;
};
};
......@@ -143,6 +143,8 @@ properties:
- infineon,slb9645tt
# Infineon SLB9673 I2C TPM 2.0
- infineon,slb9673
# Infineon TDA38640 Voltage Regulator
- infineon,tda38640
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
- infineon,tlv493d-a1b6
# Infineon Multi-phase Digital VR Controller xdpe11280
......
......@@ -38,7 +38,7 @@ Sysfs entries
-------------
=============== ============================================
temp1_input Measured temperature in millidegrees Celcius
temp1_input Measured temperature in millidegrees Celsius
humidity1_input Measured humidity in %H
update_interval The minimum interval for polling the sensor,
in milliseconds. Writable. Must be at
......
......@@ -5,12 +5,15 @@ Kernel driver aquacomputer-d5next
Supported devices:
* Aquacomputer Aquaero 5/6 fan controllers
* Aquacomputer D5 Next watercooling pump
* Aquacomputer Farbwerk RGB controller
* Aquacomputer Farbwerk 360 RGB controller
* Aquacomputer Octo fan controller
* Aquacomputer Quadro fan controller
* Aquacomputer High Flow Next sensor
* Aquacomputer Aquastream Ultimate watercooling pump
* Aquacomputer Poweradjust 3 fan controller
Author: Aleksa Savic
......@@ -20,6 +23,10 @@ Description
This driver exposes hardware sensors of listed Aquacomputer devices, which
communicate through proprietary USB HID protocols.
The Aquaero devices expose eight physical, eight virtual and four calculated
virtual temperature sensors, as well as two flow sensors. The fans expose their
speed (in RPM), power, voltage and current.
For the D5 Next pump, available sensors are pump and fan speed, power, voltage
and current, as well as coolant temperature and eight virtual temp sensors. Also
available through debugfs are the serial number, firmware version and power-on
......@@ -48,6 +55,12 @@ The High Flow Next exposes +5V voltages, water quality, conductivity and flow re
A temperature sensor can be connected to it, in which case it provides its reading
and an estimation of the dissipated/absorbed power in the liquid cooling loop.
The Aquastream Ultimate pump exposes coolant temp and an external temp sensor, along
with speed, power, voltage and current of both the pump and optionally connected fan.
It also exposes pressure and flow speed readings.
The Poweradjust 3 controller exposes a single external temperature sensor.
Depending on the device, not all sysfs and debugfs entries will be available.
Writing to virtual temperature sensors is not currently supported.
......
......@@ -10,7 +10,7 @@ Authors:
Description:
------------
This driver implements support for ASPEED AST2400/2500 PWM and Fan Tacho
controller. The PWM controller supports upto 8 PWM outputs. The Fan tacho
controller. The PWM controller supports up to 8 PWM outputs. The Fan tacho
controller supports up to 16 tachometer inputs.
The driver provides the following sensor accesses in sysfs:
......
......@@ -23,6 +23,7 @@ Supported boards:
* ROG STRIX X570-I GAMING
* ROG STRIX Z690-A GAMING WIFI D4
* ROG ZENITH II EXTREME
* ROG ZENITH II EXTREME ALPHA
Authors:
- Eugene Shalygin <eugene.shalygin@gmail.com>
......
......@@ -40,7 +40,7 @@ This driver implements the sysfs interface for the Corsair PSUs with a HID proto
interface of the HXi and RMi series.
These power supplies provide access to a micro-controller with 2 attached
temperature sensors, 1 fan rpm sensor, 4 sensors for volt levels, 4 sensors for
power usage and 4 sensors for current levels and addtional non-sensor information
power usage and 4 sensors for current levels and additional non-sensor information
like uptimes.
Sysfs entries
......
......@@ -22,6 +22,15 @@ enhancements. It can monitor up to 4 voltages, 16 temperatures and
8 fans. It also contains an integrated watchdog which is currently
implemented in this driver.
The ``pwmX_auto_channels_temp`` attributes show which temperature sensor
is currently driving which fan channel. This value might dynamically change
during runtime depending on the temperature sensor selected by
the fan control circuit.
The 4 voltages require a board-specific multiplier, since the BMC can
only measure voltages up to 3.3V and thus relies on voltage dividers.
Consult your motherboard manual for details.
To clear a temperature or fan alarm, execute the following command with the
correct path to the alarm file::
......
......@@ -31,7 +31,7 @@ Temperature Monitoring
Temperatures are measured with 12-bit or 10-bit resolution and are scaled
either internally or by the driver depending on the GSC version and firmware.
The values returned by the driver reflect millidegree Celcius:
The values returned by the driver reflect millidegree Celsius:
tempX_input Measured temperature.
tempX_label Name of temperature input.
......@@ -41,8 +41,8 @@ PWM Output Control
------------------
The GSC features 1 PWM output that operates in automatic mode where the
PWM value will be scalled depending on 6 temperature boundaries.
The tempeature boundaries are read-write and in millidegree Celcius and the
PWM value will be scaled depending on 6 temperature boundaries.
The tempeature boundaries are read-write and in millidegree Celsius and the
read-only PWM values range from 0 (off) to 255 (full speed).
Fan speed will be set to minimum (off) when the temperature sensor reads
less than pwm1_auto_point1_temp and maximum when the temperature sensor
......
.. SPDX-License-Identifier: GPL-2.0-only
Kernel driver gxp-fan-ctrl
==========================
Supported chips:
* HPE GXP SOC
Author: Nick Hawkins <nick.hawkins@hpe.com>
Description
-----------
gxp-fan-ctrl is a driver which provides fan control for the hpe gxp soc.
The driver allows the gathering of fan status and the use of fan
PWM control.
Sysfs attributes
----------------
======================= ===========================================================
pwm[0-7] Fan 0 to 7 respective PWM value (0-255)
fan[0-7]_fault Fan 0 to 7 respective fault status: 1 fail, 0 ok
fan[0-7]_enable Fan 0 to 7 respective enabled status: 1 enabled, 0 disabled
======================= ===========================================================
......@@ -57,7 +57,7 @@ register/unregister functions::
hwmon_device_register_with_groups registers a hardware monitoring device.
The first parameter of this function is a pointer to the parent device.
The name parameter is a pointer to the hwmon device name. The registration
function wil create a name sysfs attribute pointing to this name.
function will create a name sysfs attribute pointing to this name.
The drvdata parameter is the pointer to the local driver data.
hwmon_device_register_with_groups will attach this pointer to the newly
allocated hwmon device. The pointer can be retrieved by the driver using
......@@ -299,7 +299,7 @@ Parameters:
Return value:
The file mode for this attribute. Typically, this will be 0 (the
attribute will not be created), S_IRUGO, or 'S_IRUGO | S_IWUSR'.
attribute will not be created), 0444, or 0644.
::
......@@ -360,7 +360,7 @@ functions is used.
The header file linux/hwmon-sysfs.h provides a number of useful macros to
declare and use hardware monitoring sysfs attributes.
In many cases, you can use the exsting define DEVICE_ATTR or its variants
In many cases, you can use the existing define DEVICE_ATTR or its variants
DEVICE_ATTR_{RW,RO,WO} to declare such attributes. This is feasible if an
attribute has no additional context. However, in many cases there will be
additional information such as a sensor index which will need to be passed
......
.. SPDX-License-Identifier: GPL-2.0
=========================
Linux Hardware Monitoring
=========================
......@@ -73,6 +75,7 @@ Hardware Monitoring Kernel Drivers
g762
gsc-hwmon
gl518sm
gxp-fan-ctrl
hih6130
ibmaem
ibm-cffps
......@@ -144,6 +147,7 @@ Hardware Monitoring Kernel Drivers
max6697
max8688
mc13783-adc
mc34vr500
mcp3021
menf21bmc
mlxreg-fan
......
......@@ -145,6 +145,22 @@ Supported chips:
Datasheet: Not publicly available
* IT8792E/IT8795E
Prefix: 'it8792'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
* IT87952E
Prefix: 'it87952'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
* SiS950 [clone of IT8705F]
Prefix: 'it87'
......@@ -162,7 +178,7 @@ Authors:
Module Parameters
-----------------
* update_vbat: int
* update_vbat bool
0 if vbat should report power on value, 1 if vbat should be updated after
each read. Default is 0. On some boards the battery voltage is provided
by either the battery or the onboard power supply. Only the first reading
......@@ -171,11 +187,31 @@ Module Parameters
the chip so can be read at any time. Excessive reading may decrease
battery life but no information is given in the datasheet.
* fix_pwm_polarity int
* fix_pwm_polarity bool
Force PWM polarity to active high (DANGEROUS). Some chips are
misconfigured by BIOS - PWM values would be inverted. This option tries
to fix this. Please contact your BIOS manufacturer and ask him for fix.
* force_id short, short
Force multiple chip ID to specified value, separated by ','.
For example "force_id=0x8689,0x8633". A value of 0 is ignored
for that chip.
Note: A single force_id value (e.g. "force_id=0x8689") is used for
all chips, to only set the first chip use "force_id=0x8689,0".
Should only be used for testing.
* ignore_resource_conflict bool
Similar to acpi_enforce_resources=lax, but only affects this driver.
ACPI resource conflicts are ignored if this parameter is provided and
set to 1.
Provided since there are reports that system-wide acpi_enfore_resources=lax
can result in boot failures on some systems.
Note: This is inherently risky since it means that both ACPI and this driver
may access the chip at the same time. This can result in race conditions and,
worst case, result in unexpected system reboots.
Hardware Interfaces
-------------------
......@@ -193,8 +229,8 @@ Description
This driver implements support for the IT8603E, IT8620E, IT8623E, IT8628E,
IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F,
IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, and
SiS950 chips.
IT8758E, IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E,
IT8792E/IT8795E, IT87952E and SiS950 chips.
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
joysticks and other miscellaneous stuff. For hardware monitoring, they
......@@ -238,7 +274,8 @@ of the fan is not supported (value 0 of pwmX_enable).
The IT8620E and IT8628E are custom designs, hardware monitoring part is similar
to IT8728F. It only supports 16-bit fan mode. Both chips support up to 6 fans.
The IT8790E supports up to 3 fans. 16-bit fan mode is always enabled.
The IT8790E, IT8792E/IT8795E and IT87952E support up to 3 fans. 16-bit fan
mode is always enabled.
The IT8732F supports a closed-loop mode for fan control, but this is not
currently implemented by the driver.
......
......@@ -333,7 +333,7 @@ temp[N]_input Measured temperature.
- On LTC3883, temp1 reports an external temperature,
and temp2 reports the chip temperature.
temp[N]_min Mimimum temperature.
temp[N]_min Minimum temperature.
LTC2972, LTC2974, LCT2977, LTM2980, LTC2978,
LTC2979, and LTM2987 only.
......
......@@ -13,6 +13,14 @@ Supported chips:
Datasheet: Not published
* Maxim MAX16600
Prefix: 'max16600'
Addresses scanned: -
Datasheet: Not published
* Maxim MAX16601
Prefix: 'max16601'
......@@ -36,7 +44,8 @@ Description
-----------
This driver supports the MAX16508 VR13 Dual-Output Voltage Regulator
as well as the MAX16601 VR13.HC Dual-Output Voltage Regulator chipsets.
as well as the MAX16600, MAX16601, and MAX16602 VR13.HC Dual-Output
Voltage Regulator chipsets.
The driver is a client driver to the core PMBus driver.
Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
......
......@@ -73,7 +73,7 @@ Description
This driver implements support for several MAX6697 compatible temperature sensor
chips. The chips support one local temperature sensor plus four, six, or seven
remote temperature sensors. Remote temperature sensors are diode-connected
thermal transitors, except for MAX6698 which supports three diode-connected
thermal transistors, except for MAX6698 which supports three diode-connected
thermal transistors plus three thermistors in addition to the local temperature
sensor.
......
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver mc34vr500
=======================
Supported Chips:
* NXP MC34VR500
Prefix: 'mc34vr500'
Datasheet: https://www.nxp.com/docs/en/data-sheet/MC34VR500.pdf
Author: Mario Kicherer <dev@kicherer.org>
Description
-----------
This driver implements initial support for the NXP MC34VR500 PMIC. The MC34VR500
monitors the temperature, input voltage and output currents and provides
corresponding alarms. For the temperature, the chip can send interrupts if
the temperature rises above one of the following values: 110°, 120°, 125° and
130° Celsius. For the input voltage, an interrupt is sent when the voltage
drops below 2.8V.
Currently, this driver only implements the input voltage and temperature
alarms. The interrupts are mapped as follows:
<= 2.8V -> in0_min_alarm
>110°c -> temp1_max_alarm
>120°c -> temp1_crit_alarm
>130°c -> temp1_emergency_alarm
......@@ -7,7 +7,7 @@ Supported chips:
Prefix: 'menf21bmc_hwmon'
Adresses scanned: -
Addresses scanned: -
Author: Andreas Werner <andreas.werner@men.de>
......
......@@ -3,18 +3,21 @@
Kernel driver oxp-sensors
=========================
Author:
Authors:
- Derek John Clark <derekjohn.clark@gmail.com>
- Joaquín Ignacio Aramendía <samsagax@gmail.com>
Description:
------------
One X Player devices from One Netbook provide fan readings and fan control
through its Embedded Controller.
Handheld devices from One Netbook and Aya Neo provide fan readings and fan
control through their embedded controllers.
Currently only supports AMD boards from the One X Player and AOK ZOE lineup.
Intel boards could be supported if we could figure out the EC registers and
values to write to since the EC layout and model is different.
Currently only supports AMD boards from One X Player, AOK ZOE, and some Aya
Neo devices. One X Player Intel boards could be supported if we could figure
out the EC registers and values to write to since the EC layout and model is
different. Aya Neo devices preceding the AIR may not be supportable as the EC
model is different and do not appear to have manual control capabilities.
Supported devices
-----------------
......@@ -22,6 +25,8 @@ Supported devices
Currently the driver supports the following handhelds:
- AOK ZOE A1
- Aya Neo AIR
- Aya Neo AIR Pro
- OneXPlayer AMD
- OneXPlayer mini AMD
- OneXPlayer mini AMD PRO
......
......@@ -174,7 +174,7 @@ Read byte from page <page>, register <reg>.
int (*read_word_data)(struct i2c_client *client, int page, int phase,
int reg);
Read word from page <page>, phase <pase>, register <reg>. If the chip does not
Read word from page <page>, phase <phase>, register <reg>. If the chip does not
support multiple phases, the phase parameter can be ignored. If the chip
supports multiple phases, a phase value of 0xff indicates all phases.
......
......@@ -37,7 +37,7 @@ Sysfs entries
-------------
=============== ============================================
temp1_input Measured temperature in millidegrees Celcius
temp1_input Measured temperature in millidegrees Celsius
humidity1_input Measured humidity in %H
update_interval The minimum interval for polling the sensor,
in milliseconds. Writable. Must be at least
......
......@@ -180,7 +180,7 @@ in9_crit_alarm AIN1 critical alarm
in10_crit_alarm AIN2 critical alarm
temp1_input Chip temperature
temp1_min Mimimum chip temperature
temp1_min Minimum chip temperature
temp1_max Maximum chip temperature
temp1_crit Critical chip temperature
temp1_crit_alarm Temperature critical alarm
......
......@@ -39,7 +39,7 @@ output voltage as a positive or negative offset in the interval 50mV to 400mV
in 50mV steps. This means that the absolute values of the limits will change
when the commanded output voltage changes. Also, care should be taken when
writing to those limits since in the worst case the commanded output voltage
could change at the same time as the limit is written to, wich will lead to
could change at the same time as the limit is written to, which will lead to
unpredictable results.
......
......@@ -126,7 +126,7 @@ increase the chances of your change being accepted.
* Use devm_hwmon_device_register_with_info() or, if your driver needs a remove
function, hwmon_device_register_with_info() to register your driver with the
hwmon subsystem. Try using devm_add_action() instead of a remove function if
possible. Do not use hwmon_device_register().
possible. Do not use any of the deprecated registration functions.
* Your driver should be buildable as module. If not, please be prepared to
explain why it has to be built into the kernel.
......
......@@ -27,7 +27,7 @@ Versatile Express platform (http://www.arm.com/versatileexpress/) is a
reference & prototyping system for ARM Ltd. processors. It can be set up
from a wide range of boards, each of them containing (apart of the main
chip/FPGA) a number of microcontrollers responsible for platform
configuration and control. Theses microcontrollers can also monitor the
configuration and control. These microcontrollers can also monitor the
board and its environment by a number of internal and external sensors,
providing information about power lines voltages and currents, board
temperature and power usage. Some of them also calculate consumed energy
......
......@@ -58,7 +58,7 @@ representable value is around 2600 RPM.
Voltage sensors (also known as IN sensors) report their values in volts.
An alarm is triggered if the voltage has crossed a programmable minimum
or maximum limit. Voltages are internally scalled, so each voltage channel
or maximum limit. Voltages are internally scaled, so each voltage channel
has a different resolution and range.
If an alarm triggers, it will remain triggered until the hardware register
......
......@@ -2234,13 +2234,16 @@ ARM/HPE GXP ARCHITECTURE
M: Jean-Marie Verdun <verdun@hpe.com>
M: Nick Hawkins <nick.hawkins@hpe.com>
S: Maintained
F: Documentation/hwmon/gxp-fan-ctrl.rst
F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml
F: Documentation/devicetree/bindings/hwmon/hpe,gxp-fan-ctrl.yaml
F: Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml
F: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
F: arch/arm/boot/dts/hpe-bmc*
F: arch/arm/boot/dts/hpe-gxp*
F: arch/arm/mach-hpe/
F: drivers/clocksource/timer-gxp.c
F: drivers/hwmon/gxp-fan-ctrl.c
F: drivers/spi/spi-gxp.c
F: drivers/watchdog/gxp-wdt.c
......@@ -14046,6 +14049,7 @@ M: Saravanan Sekar <sravanhome@gmail.com>
S: Maintained
F: Documentation/devicetree/bindings/mfd/mps,mp2629.yaml
F: Documentation/devicetree/bindings/regulator/mps,mp*.yaml
F: drivers/hwmon/pmbus/mpq7932.c
F: drivers/iio/adc/mp2629_adc.c
F: drivers/mfd/mp2629.c
F: drivers/power/supply/mp2629_charger.c
......@@ -15481,6 +15485,7 @@ F: drivers/mtd/nand/onenand/
F: include/linux/mtd/onenand*.h
ONEXPLAYER FAN DRIVER
M: Derek John Clark <derekjohn.clark@gmail.com>
M: Joaquín Ignacio Aramendía <samsagax@gmail.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
......
......@@ -714,6 +714,15 @@ config SENSORS_GPIO_FAN
This driver can also be built as a module. If so, the module
will be called gpio-fan.
config SENSORS_GXP_FAN_CTRL
tristate "HPE GXP fan controller"
depends on ARCH_HPE_GXP || COMPILE_TEST
help
If you say yes here you get support for GXP fan control functionality.
The GXP controls fan function via the CPLD through the use of PWM
registers. This driver reports status and pwm setting of the fans.
config SENSORS_HIH6130
tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor"
depends on I2C
......@@ -1166,6 +1175,13 @@ config SENSORS_MAX31790
This driver can also be built as a module. If so, the module
will be called max31790.
config SENSORS_MC34VR500
tristate "NXP MC34VR500 hardware monitoring driver"
depends on I2C
help
If you say yes here you get support for the temperature and input
voltage sensors of the NXP MC34VR500.
config SENSORS_MCP3021
tristate "Microchip MCP3021 and compatibles"
depends on I2C
......@@ -1516,7 +1532,7 @@ config SENSORS_NCT6775_CORE
config SENSORS_NCT6775
tristate "Platform driver for Nuvoton NCT6775F and compatibles"
depends on !PPC
depends on ACPI_WMI || ACPI_WMI=n
depends on ACPI || ACPI=n
select HWMON_VID
select SENSORS_NCT6775_CORE
help
......
......@@ -83,6 +83,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_GXP_FAN_CTRL) += gxp-fan-ctrl.o
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o
......@@ -149,6 +150,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
obj-$(CONFIG_SENSORS_MAX31790) += max31790.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
obj-$(CONFIG_SENSORS_TC654) += tc654.o
obj-$(CONFIG_SENSORS_TPS23861) += tps23861.o
......
......@@ -79,7 +79,6 @@ struct aht10_data {
/**
* aht10_init() - Initialize an AHT10 chip
* @client: the i2c client associated with the AHT10
* @data: the data associated with this AHT10 chip
* Return: 0 if succesfull, 1 if not
*/
......@@ -124,7 +123,7 @@ static int aht10_polltime_expired(struct aht10_data *data)
/**
* aht10_read_values() - read and parse the raw data from the AHT10
* @aht10_data: the struct aht10_data to use for the lock
* @data: the struct aht10_data to use for the lock
* Return: 0 if succesfull, 1 if not
*/
static int aht10_read_values(struct aht10_data *data)
......
This diff is collapsed.
......@@ -299,6 +299,7 @@ static const struct ec_board_info board_info_pro_art_x570_creator_wifi = {
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |
SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
.family = family_amd_500_series,
};
......@@ -466,6 +467,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_strix_z690_a_gaming_wifi_d4),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",
&board_info_zenith_ii_extreme),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA",
&board_info_zenith_ii_extreme),
{},
};
......
......@@ -27,6 +27,7 @@
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpu_device_id.h>
#include <linux/sched/isolation.h>
#define DRVNAME "coretemp"
......@@ -502,6 +503,9 @@ static int create_core_data(struct platform_device *pdev, unsigned int cpu,
u32 eax, edx;
int err, index, attr_no;
if (!housekeeping_cpu(cpu, HK_TYPE_MISC))
return 0;
/*
* Find attr number for sysfs:
* We map the attr number to core id of the CPU
......@@ -588,66 +592,49 @@ static void coretemp_remove_core(struct platform_data *pdata, int indx)
ida_free(&pdata->ida, indx - BASE_SYSFS_ATTR_NO);
}
static int coretemp_probe(struct platform_device *pdev)
static int coretemp_device_add(int zoneid)
{
struct device *dev = &pdev->dev;
struct platform_device *pdev;
struct platform_data *pdata;
int err;
/* Initialize the per-zone data structures */
pdata = devm_kzalloc(dev, sizeof(struct platform_data), GFP_KERNEL);
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdata->pkg_id = pdev->id;
pdata->pkg_id = zoneid;
ida_init(&pdata->ida);
platform_set_drvdata(pdev, pdata);
pdata->hwmon_dev = devm_hwmon_device_register_with_groups(dev, DRVNAME,
pdata, NULL);
return PTR_ERR_OR_ZERO(pdata->hwmon_dev);
}
static int coretemp_remove(struct platform_device *pdev)
{
struct platform_data *pdata = platform_get_drvdata(pdev);
int i;
pdev = platform_device_alloc(DRVNAME, zoneid);
if (!pdev) {
err = -ENOMEM;
goto err_free_pdata;
}
for (i = MAX_CORE_DATA - 1; i >= 0; --i)
if (pdata->core_data[i])
coretemp_remove_core(pdata, i);
err = platform_device_add(pdev);
if (err)
goto err_put_dev;
ida_destroy(&pdata->ida);
platform_set_drvdata(pdev, pdata);
zone_devices[zoneid] = pdev;
return 0;
}
static struct platform_driver coretemp_driver = {
.driver = {
.name = DRVNAME,
},
.probe = coretemp_probe,
.remove = coretemp_remove,
};
err_put_dev:
platform_device_put(pdev);
err_free_pdata:
kfree(pdata);
return err;
}
static struct platform_device *coretemp_device_add(unsigned int cpu)
static void coretemp_device_remove(int zoneid)
{
int err, zoneid = topology_logical_die_id(cpu);
struct platform_device *pdev;
if (zoneid < 0)
return ERR_PTR(-ENOMEM);
pdev = platform_device_alloc(DRVNAME, zoneid);
if (!pdev)
return ERR_PTR(-ENOMEM);
err = platform_device_add(pdev);
if (err) {
platform_device_put(pdev);
return ERR_PTR(err);
}
struct platform_device *pdev = zone_devices[zoneid];
struct platform_data *pdata = platform_get_drvdata(pdev);
zone_devices[zoneid] = pdev;
return pdev;
ida_destroy(&pdata->ida);
kfree(pdata);
platform_device_unregister(pdev);
}
static int coretemp_cpu_online(unsigned int cpu)
......@@ -671,7 +658,10 @@ static int coretemp_cpu_online(unsigned int cpu)
if (!cpu_has(c, X86_FEATURE_DTHERM))
return -ENODEV;
if (!pdev) {
pdata = platform_get_drvdata(pdev);
if (!pdata->hwmon_dev) {
struct device *hwmon;
/* Check the microcode version of the CPU */
if (chk_ucode_version(cpu))
return -EINVAL;
......@@ -682,9 +672,11 @@ static int coretemp_cpu_online(unsigned int cpu)
* online. So, initialize per-pkg data structures and
* then bring this core online.
*/
pdev = coretemp_device_add(cpu);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
hwmon = hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
pdata, NULL);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
pdata->hwmon_dev = hwmon;
/*
* Check whether pkgtemp support is available.
......@@ -694,7 +686,6 @@ static int coretemp_cpu_online(unsigned int cpu)
coretemp_add_core(pdev, cpu, 1);
}
pdata = platform_get_drvdata(pdev);
/*
* Check whether a thread sibling is already online. If not add the
* interface for this CPU core.
......@@ -713,18 +704,14 @@ static int coretemp_cpu_offline(unsigned int cpu)
struct temp_data *tdata;
int i, indx = -1, target;
/*
* Don't execute this on suspend as the device remove locks
* up the machine.
*/
/* No need to tear down any interfaces for suspend */
if (cpuhp_tasks_frozen)
return 0;
/* If the physical CPU device does not exist, just return */
if (!pdev)
return 0;
pd = platform_get_drvdata(pdev);
if (!pd->hwmon_dev)
return 0;
for (i = 0; i < NUM_REAL_CORES; i++) {
if (pd->cpu_map[i] == topology_core_id(cpu)) {
......@@ -756,13 +743,14 @@ static int coretemp_cpu_offline(unsigned int cpu)
}
/*
* If all cores in this pkg are offline, remove the device. This
* will invoke the platform driver remove function, which cleans up
* the rest.
* If all cores in this pkg are offline, remove the interface.
*/
tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
if (cpumask_empty(&pd->cpumask)) {
zone_devices[topology_logical_die_id(cpu)] = NULL;
platform_device_unregister(pdev);
if (tdata)
coretemp_remove_core(pd, PKG_SYSFS_ATTR_NO);
hwmon_device_unregister(pd->hwmon_dev);
pd->hwmon_dev = NULL;
return 0;
}
......@@ -770,7 +758,6 @@ static int coretemp_cpu_offline(unsigned int cpu)
* Check whether this core is the target for the package
* interface. We need to assign it to some other cpu.
*/
tdata = pd->core_data[PKG_SYSFS_ATTR_NO];
if (tdata && tdata->cpu == cpu) {
target = cpumask_first(&pd->cpumask);
mutex_lock(&tdata->update_lock);
......@@ -789,7 +776,7 @@ static enum cpuhp_state coretemp_hp_online;
static int __init coretemp_init(void)
{
int err;
int i, err;
/*
* CPUID.06H.EAX[0] indicates whether the CPU has thermal
......@@ -805,20 +792,22 @@ static int __init coretemp_init(void)
if (!zone_devices)
return -ENOMEM;
err = platform_driver_register(&coretemp_driver);
if (err)
goto outzone;
for (i = 0; i < max_zones; i++) {
err = coretemp_device_add(i);
if (err)
goto outzone;
}
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
coretemp_cpu_online, coretemp_cpu_offline);
if (err < 0)
goto outdrv;
goto outzone;
coretemp_hp_online = err;
return 0;
outdrv:
platform_driver_unregister(&coretemp_driver);
outzone:
while (i--)
coretemp_device_remove(i);
kfree(zone_devices);
return err;
}
......@@ -826,8 +815,11 @@ module_init(coretemp_init)
static void __exit coretemp_exit(void)
{
int i;
cpuhp_remove_state(coretemp_hp_online);
platform_driver_unregister(&coretemp_driver);
for (i = 0; i < max_zones; i++)
coretemp_device_remove(i);
kfree(zone_devices);
}
module_exit(coretemp_exit)
......
......@@ -59,10 +59,11 @@ static const struct i2c_device_id emc2305_ids[] = {
MODULE_DEVICE_TABLE(i2c, emc2305_ids);
/**
* @cdev: cooling device;
* @curr_state: cooling current state;
* @last_hwmon_state: last cooling state updated by hwmon subsystem;
* @last_thermal_state: last cooling state updated by thermal subsystem;
* struct emc2305_cdev_data - device-specific cooling device state
* @cdev: cooling device
* @cur_state: cooling current state
* @last_hwmon_state: last cooling state updated by hwmon subsystem
* @last_thermal_state: last cooling state updated by thermal subsystem
*
* The 'last_hwmon_state' and 'last_thermal_state' fields are provided to support fan low limit
* speed feature. The purpose of this feature is to provides ability to limit fan speed
......@@ -86,13 +87,14 @@ struct emc2305_cdev_data {
};
/**
* @client: i2c client;
* @hwmon_dev: hwmon device;
* @max_state: maximum cooling state of the cooling device;
* @pwm_num: number of PWM channels;
* @pwm_separate: separate PWM settings for every channel;
* @pwm_min: array of minimum PWM per channel;
* @cdev_data: array of cooling devices data;
* struct emc2305_data - device-specific data
* @client: i2c client
* @hwmon_dev: hwmon device
* @max_state: maximum cooling state of the cooling device
* @pwm_num: number of PWM channels
* @pwm_separate: separate PWM settings for every channel
* @pwm_min: array of minimum PWM per channel
* @cdev_data: array of cooling devices data
*/
struct emc2305_data {
struct i2c_client *client;
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */
#define OFS_FAN_FAIL 2 /* Is 2 bytes after base */
#define OFS_SEVSTAT 0 /* Is 0 because fn2 base will be set at SEVSTAT */
#define POWER_BIT 24
struct gxp_fan_ctrl_drvdata {
void __iomem *base;
void __iomem *plreg;
void __iomem *fn2;
};
static bool fan_installed(struct device *dev, int fan)
{
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
u8 val;
val = readb(drvdata->plreg + OFS_FAN_INST);
return !!(val & BIT(fan));
}
static long fan_failed(struct device *dev, int fan)
{
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
u8 val;
val = readb(drvdata->plreg + OFS_FAN_FAIL);
return !!(val & BIT(fan));
}
static long fan_enabled(struct device *dev, int fan)
{
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
u32 val;
/*
* Check the power status as if the platform is off the value
* reported for the PWM will be incorrect. Report fan as
* disabled.
*/
val = readl(drvdata->fn2 + OFS_SEVSTAT);
return !!((val & BIT(POWER_BIT)) && fan_installed(dev, fan));
}
static int gxp_pwm_write(struct device *dev, u32 attr, int channel, long val)
{
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
switch (attr) {
case hwmon_pwm_input:
if (val > 255 || val < 0)
return -EINVAL;
writeb(val, drvdata->base + channel);
return 0;
default:
return -EOPNOTSUPP;
}
}
static int gxp_fan_ctrl_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{
switch (type) {
case hwmon_pwm:
return gxp_pwm_write(dev, attr, channel, val);
default:
return -EOPNOTSUPP;
}
}
static int gxp_fan_read(struct device *dev, u32 attr, int channel, long *val)
{
switch (attr) {
case hwmon_fan_enable:
*val = fan_enabled(dev, channel);
return 0;
case hwmon_fan_fault:
*val = fan_failed(dev, channel);
return 0;
default:
return -EOPNOTSUPP;
}
}
static int gxp_pwm_read(struct device *dev, u32 attr, int channel, long *val)
{
struct gxp_fan_ctrl_drvdata *drvdata = dev_get_drvdata(dev);
u32 reg;
/*
* Check the power status of the platform. If the platform is off
* the value reported for the PWM will be incorrect. In this case
* report a PWM of zero.
*/
reg = readl(drvdata->fn2 + OFS_SEVSTAT);
if (reg & BIT(POWER_BIT))
*val = fan_installed(dev, channel) ? readb(drvdata->base + channel) : 0;
else
*val = 0;
return 0;
}
static int gxp_fan_ctrl_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
switch (type) {
case hwmon_fan:
return gxp_fan_read(dev, attr, channel, val);
case hwmon_pwm:
return gxp_pwm_read(dev, attr, channel, val);
default:
return -EOPNOTSUPP;
}
}
static umode_t gxp_fan_ctrl_is_visible(const void *_data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
umode_t mode = 0;
switch (type) {
case hwmon_fan:
switch (attr) {
case hwmon_fan_enable:
case hwmon_fan_fault:
mode = 0444;
break;
default:
break;
}
break;
case hwmon_pwm:
switch (attr) {
case hwmon_pwm_input:
mode = 0644;
break;
default:
break;
}
break;
default:
break;
}
return mode;
}
static const struct hwmon_ops gxp_fan_ctrl_ops = {
.is_visible = gxp_fan_ctrl_is_visible,
.read = gxp_fan_ctrl_read,
.write = gxp_fan_ctrl_write,
};
static const struct hwmon_channel_info *gxp_fan_ctrl_info[] = {
HWMON_CHANNEL_INFO(fan,
HWMON_F_FAULT | HWMON_F_ENABLE,
HWMON_F_FAULT | HWMON_F_ENABLE,
HWMON_F_FAULT | HWMON_F_ENABLE,
HWMON_F_FAULT | HWMON_F_ENABLE,
HWMON_F_FAULT | HWMON_F_ENABLE,
HWMON_F_FAULT | HWMON_F_ENABLE,
HWMON_F_FAULT | HWMON_F_ENABLE,
HWMON_F_FAULT | HWMON_F_ENABLE),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT,
HWMON_PWM_INPUT),
NULL
};
static const struct hwmon_chip_info gxp_fan_ctrl_chip_info = {
.ops = &gxp_fan_ctrl_ops,
.info = gxp_fan_ctrl_info,
};
static int gxp_fan_ctrl_probe(struct platform_device *pdev)
{
struct gxp_fan_ctrl_drvdata *drvdata;
struct device *dev = &pdev->dev;
struct device *hwmon_dev;
drvdata = devm_kzalloc(dev, sizeof(struct gxp_fan_ctrl_drvdata),
GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
drvdata->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(drvdata->base))
return dev_err_probe(dev, PTR_ERR(drvdata->base),
"failed to map base\n");
drvdata->plreg = devm_platform_ioremap_resource_byname(pdev,
"pl");
if (IS_ERR(drvdata->plreg))
return dev_err_probe(dev, PTR_ERR(drvdata->plreg),
"failed to map plreg\n");
drvdata->fn2 = devm_platform_ioremap_resource_byname(pdev,
"fn2");
if (IS_ERR(drvdata->fn2))
return dev_err_probe(dev, PTR_ERR(drvdata->fn2),
"failed to map fn2\n");
hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
"hpe_gxp_fan_ctrl",
drvdata,
&gxp_fan_ctrl_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct of_device_id gxp_fan_ctrl_of_match[] = {
{ .compatible = "hpe,gxp-fan-ctrl", },
{},
};
MODULE_DEVICE_TABLE(of, gxp_fan_ctrl_of_match);
static struct platform_driver gxp_fan_ctrl_driver = {
.probe = gxp_fan_ctrl_probe,
.driver = {
.name = "gxp-fan-ctrl",
.of_match_table = gxp_fan_ctrl_of_match,
},
};
module_platform_driver(gxp_fan_ctrl_driver);
MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>");
MODULE_DESCRIPTION("HPE GXP fan controller");
MODULE_LICENSE("GPL");
......@@ -150,7 +150,7 @@ static int hih6130_update_measurements(struct device *dev)
}
/**
* hih6130_show_temperature() - show temperature measurement value in sysfs
* hih6130_temperature_show() - show temperature measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
......@@ -172,7 +172,7 @@ static ssize_t hih6130_temperature_show(struct device *dev,
}
/**
* hih6130_show_humidity() - show humidity measurement value in sysfs
* hih6130_humidity_show() - show humidity measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
......
......@@ -546,7 +546,7 @@ static void ibmpex_bmc_gone(int iface)
static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
{
struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data;
struct ibmpex_bmc_data *data = user_msg_data;
if (msg->msgid != data->tx_msgid) {
dev_err(data->bmc_device,
......
......@@ -77,9 +77,11 @@ static int iio_hwmon_probe(struct platform_device *pdev)
channels = devm_iio_channel_get_all(dev);
if (IS_ERR(channels)) {
if (PTR_ERR(channels) == -ENODEV)
return -EPROBE_DEFER;
return PTR_ERR(channels);
ret = PTR_ERR(channels);
if (ret == -ENODEV)
ret = -EPROBE_DEFER;
return dev_err_probe(dev, ret,
"Failed to get channels\n");
}
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
......
This diff is collapsed.
This diff is collapsed.
......@@ -58,6 +58,22 @@
#define CONTROL_MULT_SELECT (1 << 0)
#define CONTROL_TEST_MODE (1 << 4)
static const struct of_device_id __maybe_unused ltc2945_of_match[] = {
{ .compatible = "adi,ltc2945" },
{ }
};
MODULE_DEVICE_TABLE(of, ltc2945_of_match);
/**
* struct ltc2945_data - LTC2945 device data
* @regmap: regmap device
* @shunt_resistor: shunt resistor value in micro ohms (1000 by default)
*/
struct ltc2945_data {
struct regmap *regmap;
u32 shunt_resistor;
};
static inline bool is_power_reg(u8 reg)
{
return reg < LTC2945_SENSE_H;
......@@ -66,7 +82,9 @@ static inline bool is_power_reg(u8 reg)
/* Return the value from the given register in uW, mV, or mA */
static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
{
struct regmap *regmap = dev_get_drvdata(dev);
struct ltc2945_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
u32 shunt_resistor = data->shunt_resistor;
unsigned int control;
u8 buf[3];
long long val;
......@@ -78,10 +96,10 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
return ret;
if (is_power_reg(reg)) {
/* power */
/* 24-bit power */
val = (buf[0] << 16) + (buf[1] << 8) + buf[2];
} else {
/* current, voltage */
/* 12-bit current, voltage */
val = (buf[0] << 4) + (buf[1] >> 4);
}
......@@ -92,9 +110,7 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
case LTC2945_MAX_POWER_THRES_H:
case LTC2945_MIN_POWER_THRES_H:
/*
* Convert to uW by assuming current is measured with
* an 1mOhm sense resistor, similar to current
* measurements.
* Convert to uW
* Control register bit 0 selects if voltage at SENSE+/VDD
* or voltage at ADIN is used to measure power.
*/
......@@ -108,6 +124,14 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
val = (val * 25LL) >> 1;
}
val *= 1000;
/* Overflow check: Assuming max 24-bit power, val is at most 53 bits right now. */
val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor);
/*
* Overflow check: After division, depending on shunt resistor,
* val can still be > 32 bits so returning long long makes sense
*/
break;
case LTC2945_VIN_H:
case LTC2945_MAX_VIN_H:
......@@ -130,14 +154,11 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
case LTC2945_MIN_SENSE_H:
case LTC2945_MAX_SENSE_THRES_H:
case LTC2945_MIN_SENSE_THRES_H:
/*
* 25 uV resolution. Convert to current as measured with
* an 1 mOhm sense resistor, in mA. If a different sense
* resistor is installed, calculate the actual current by
* dividing the reported current by the sense resistor value
* in mOhm.
*/
val *= 25;
/* 25 uV resolution. Convert to mA. */
val *= 25 * 1000;
/* Overflow check: Assuming max 12-bit sense, val is at most 27 bits right now */
val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor);
/* Overflow check: After division, <= 27 bits */
break;
default:
return -EINVAL;
......@@ -145,13 +166,18 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg)
return val;
}
static int ltc2945_val_to_reg(struct device *dev, u8 reg,
unsigned long val)
static long long ltc2945_val_to_reg(struct device *dev, u8 reg,
unsigned long long val)
{
struct regmap *regmap = dev_get_drvdata(dev);
struct ltc2945_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
u32 shunt_resistor = data->shunt_resistor;
unsigned int control;
int ret;
/* Ensure we don't overflow */
val = clamp_val(val, 0, U32_MAX);
switch (reg) {
case LTC2945_POWER_H:
case LTC2945_MAX_POWER_H:
......@@ -159,9 +185,6 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MAX_POWER_THRES_H:
case LTC2945_MIN_POWER_THRES_H:
/*
* Convert to register value by assuming current is measured
* with an 1mOhm sense resistor, similar to current
* measurements.
* Control register bit 0 selects if voltage at SENSE+/VDD
* or voltage at ADIN is used to measure power, which in turn
* determines register calculations.
......@@ -171,14 +194,16 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
return ret;
if (control & CONTROL_MULT_SELECT) {
/* 25 mV * 25 uV = 0.625 uV resolution. */
val = DIV_ROUND_CLOSEST(val, 625);
val *= shunt_resistor;
/* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */
val = DIV_ROUND_CLOSEST_ULL(val, 625 * 1000);
/* Overflow check: val is now <= 44 bits */
} else {
/*
* 0.5 mV * 25 uV = 0.0125 uV resolution.
* Divide first to avoid overflow;
* accept loss of accuracy.
*/
val = DIV_ROUND_CLOSEST(val, 25) * 2;
/* 0.5 mV * 25 uV = 0.0125 uV resolution. */
val *= shunt_resistor;
/* Overflow check: Assuming 32-bit val and shunt resistor, val <= 64bits */
val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000) * 2;
/* Overflow check: val is now <= 51 bits */
}
break;
case LTC2945_VIN_H:
......@@ -187,7 +212,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MAX_VIN_THRES_H:
case LTC2945_MIN_VIN_THRES_H:
/* 25 mV resolution. */
val /= 25;
val = DIV_ROUND_CLOSEST_ULL(val, 25);
break;
case LTC2945_ADIN_H:
case LTC2945_MAX_ADIN_H:
......@@ -202,14 +227,11 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg,
case LTC2945_MIN_SENSE_H:
case LTC2945_MAX_SENSE_THRES_H:
case LTC2945_MIN_SENSE_THRES_H:
/*
* 25 uV resolution. Convert to current as measured with
* an 1 mOhm sense resistor, in mA. If a different sense
* resistor is installed, calculate the actual current by
* dividing the reported current by the sense resistor value
* in mOhm.
*/
val = DIV_ROUND_CLOSEST(val, 25);
/* 25 uV resolution. Convert to mA. */
val *= shunt_resistor;
/* Overflow check: Assuming 32-bit val and 32-bit shunt resistor, val is 64bits */
val = DIV_ROUND_CLOSEST_ULL(val, 25 * 1000);
/* Overflow check: val is now <= 50 bits */
break;
default:
return -EINVAL;
......@@ -234,20 +256,23 @@ static ssize_t ltc2945_value_store(struct device *dev,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct regmap *regmap = dev_get_drvdata(dev);
struct ltc2945_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
u8 reg = attr->index;
unsigned long val;
unsigned int val;
u8 regbuf[3];
int num_regs;
int regval;
long long regval;
int ret;
ret = kstrtoul(buf, 10, &val);
ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
/* convert to register value, then clamp and write result */
regval = ltc2945_val_to_reg(dev, reg, val);
if (regval < 0)
return regval;
if (is_power_reg(reg)) {
regval = clamp_val(regval, 0, 0xffffff);
regbuf[0] = regval >> 16;
......@@ -269,7 +294,8 @@ static ssize_t ltc2945_history_store(struct device *dev,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct regmap *regmap = dev_get_drvdata(dev);
struct ltc2945_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
u8 reg = attr->index;
int num_regs = is_power_reg(reg) ? 3 : 2;
u8 buf_min[3] = { 0xff, 0xff, 0xff };
......@@ -321,7 +347,8 @@ static ssize_t ltc2945_bool_show(struct device *dev,
struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct regmap *regmap = dev_get_drvdata(dev);
struct ltc2945_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
unsigned int fault;
int ret;
......@@ -450,6 +477,12 @@ static int ltc2945_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct regmap *regmap;
struct ltc2945_data *data;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
dev_set_drvdata(dev, data);
regmap = devm_regmap_init_i2c(client, &ltc2945_regmap_config);
if (IS_ERR(regmap)) {
......@@ -457,11 +490,19 @@ static int ltc2945_probe(struct i2c_client *client)
return PTR_ERR(regmap);
}
data->regmap = regmap;
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
&data->shunt_resistor))
data->shunt_resistor = 1000;
if (data->shunt_resistor == 0)
return -EINVAL;
/* Clear faults */
regmap_write(regmap, LTC2945_FAULT, 0x00);
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
regmap,
data,
ltc2945_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
......@@ -475,8 +516,9 @@ MODULE_DEVICE_TABLE(i2c, ltc2945_id);
static struct i2c_driver ltc2945_driver = {
.driver = {
.name = "ltc2945",
},
.name = "ltc2945",
.of_match_table = of_match_ptr(ltc2945_of_match),
},
.probe_new = ltc2945_probe,
.id_table = ltc2945_id,
};
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* An hwmon driver for the NXP MC34VR500 PMIC
*
* Author: Mario Kicherer <dev@kicherer.org>
*/
#include <linux/bits.h>
#include <linux/dev_printk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#define MC34VR500_I2C_ADDR 0x08
#define MC34VR500_DEVICEID_VALUE 0x14
/* INTSENSE0 */
#define ENS_BIT BIT(0)
#define LOWVINS_BIT BIT(1)
#define THERM110S_BIT BIT(2)
#define THERM120S_BIT BIT(3)
#define THERM125S_BIT BIT(4)
#define THERM130S_BIT BIT(5)
#define MC34VR500_DEVICEID 0x00
#define MC34VR500_SILICONREVID 0x03
#define MC34VR500_FABID 0x04
#define MC34VR500_INTSTAT0 0x05
#define MC34VR500_INTMASK0 0x06
#define MC34VR500_INTSENSE0 0x07
struct mc34vr500_data {
struct device *hwmon_dev;
struct regmap *regmap;
};
static irqreturn_t mc34vr500_process_interrupt(int irq, void *userdata)
{
struct mc34vr500_data *data = (struct mc34vr500_data *)userdata;
unsigned int reg;
int ret;
ret = regmap_read(data->regmap, MC34VR500_INTSTAT0, &reg);
if (ret < 0)
return IRQ_HANDLED;
if (reg) {
if (reg & LOWVINS_BIT)
hwmon_notify_event(data->hwmon_dev, hwmon_in,
hwmon_in_min_alarm, 0);
if (reg & THERM110S_BIT)
hwmon_notify_event(data->hwmon_dev, hwmon_temp,
hwmon_temp_max_alarm, 0);
if (reg & THERM120S_BIT)
hwmon_notify_event(data->hwmon_dev, hwmon_temp,
hwmon_temp_crit_alarm, 0);
if (reg & THERM130S_BIT)
hwmon_notify_event(data->hwmon_dev, hwmon_temp,
hwmon_temp_emergency_alarm, 0);
/* write 1 to clear */
regmap_write(data->regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
THERM110S_BIT | THERM120S_BIT | THERM130S_BIT);
}
return IRQ_HANDLED;
}
static umode_t mc34vr500_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
switch (attr) {
case hwmon_in_min_alarm:
case hwmon_temp_max_alarm:
case hwmon_temp_crit_alarm:
case hwmon_temp_emergency_alarm:
return 0444;
default:
break;
}
return 0;
}
static int mc34vr500_alarm_read(struct mc34vr500_data *data, int index,
long *val)
{
unsigned int reg;
int ret;
ret = regmap_read(data->regmap, MC34VR500_INTSENSE0, &reg);
if (ret < 0)
return ret;
*val = !!(reg & index);
return 0;
}
static int mc34vr500_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct mc34vr500_data *data = dev_get_drvdata(dev);
switch (type) {
case hwmon_in:
switch (attr) {
case hwmon_in_min_alarm:
return mc34vr500_alarm_read(data, LOWVINS_BIT, val);
default:
return -EOPNOTSUPP;
}
case hwmon_temp:
switch (attr) {
case hwmon_temp_max_alarm:
return mc34vr500_alarm_read(data, THERM110S_BIT, val);
case hwmon_temp_crit_alarm:
return mc34vr500_alarm_read(data, THERM120S_BIT, val);
case hwmon_temp_emergency_alarm:
return mc34vr500_alarm_read(data, THERM130S_BIT, val);
default:
return -EOPNOTSUPP;
}
default:
return -EOPNOTSUPP;
}
}
static const struct hwmon_channel_info *mc34vr500_info[] = {
HWMON_CHANNEL_INFO(in, HWMON_I_MIN_ALARM),
HWMON_CHANNEL_INFO(temp, HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM
| HWMON_T_EMERGENCY_ALARM),
NULL,
};
static const struct hwmon_ops mc34vr500_hwmon_ops = {
.is_visible = mc34vr500_is_visible,
.read = mc34vr500_read,
};
static const struct hwmon_chip_info mc34vr500_chip_info = {
.ops = &mc34vr500_hwmon_ops,
.info = mc34vr500_info,
};
static const struct regmap_config mc34vr500_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MC34VR500_INTSENSE0,
};
static int mc34vr500_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct mc34vr500_data *data;
struct device *hwmon_dev;
int ret;
unsigned int reg, revid, fabid;
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &mc34vr500_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
data = devm_kzalloc(dev, sizeof(struct mc34vr500_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->regmap = regmap;
ret = regmap_read(regmap, MC34VR500_DEVICEID, &reg);
if (ret < 0)
return ret;
if (reg != MC34VR500_DEVICEID_VALUE)
return -ENODEV;
ret = regmap_read(regmap, MC34VR500_SILICONREVID, &revid);
if (ret < 0)
return ret;
ret = regmap_read(regmap, MC34VR500_FABID, &fabid);
if (ret < 0)
return ret;
dev_dbg(dev, "mc34vr500: revid 0x%x fabid 0x%x\n", revid, fabid);
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
data,
&mc34vr500_chip_info,
NULL);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
data->hwmon_dev = hwmon_dev;
if (client->irq) {
ret = devm_request_threaded_irq(dev, client->irq, NULL,
mc34vr500_process_interrupt,
IRQF_TRIGGER_RISING |
IRQF_ONESHOT |
IRQF_SHARED,
dev_name(dev), data);
if (ret)
return ret;
/* write 1 to clear interrupts */
ret = regmap_write(regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
THERM110S_BIT | THERM120S_BIT |
THERM130S_BIT);
if (ret)
return ret;
/* unmask interrupts */
ret = regmap_write(regmap, MC34VR500_INTMASK0,
(unsigned int) ~(LOWVINS_BIT | THERM110S_BIT |
THERM120S_BIT | THERM130S_BIT));
if (ret)
return ret;
}
return 0;
}
static const struct i2c_device_id mc34vr500_id[] = {
{ "mc34vr500", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, mc34vr500_id);
static const struct of_device_id __maybe_unused mc34vr500_of_match[] = {
{ .compatible = "nxp,mc34vr500" },
{ },
};
MODULE_DEVICE_TABLE(of, mc34vr500_of_match);
static struct i2c_driver mc34vr500_driver = {
.driver = {
.name = "mc34vr500",
.of_match_table = of_match_ptr(mc34vr500_of_match),
},
.probe_new = mc34vr500_probe,
.id_table = mc34vr500_id,
};
module_i2c_driver(mc34vr500_driver);
MODULE_AUTHOR("Mario Kicherer <dev@kicherer.org>");
MODULE_DESCRIPTION("MC34VR500 driver");
MODULE_LICENSE("GPL");
......@@ -155,6 +155,12 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
if (err)
return err;
if (MLXREG_FAN_GET_FAULT(regval, tacho->mask)) {
/* FAN is broken - return zero for FAN speed. */
*val = 0;
return 0;
}
*val = MLXREG_FAN_GET_RPM(regval, fan->divider,
fan->samples);
break;
......
......@@ -1150,7 +1150,7 @@ static int nct6775_write_fan_div(struct nct6775_data *data, int nr)
if (err)
return err;
reg &= 0x70 >> oddshift;
reg |= data->fan_div[nr] & (0x7 << oddshift);
reg |= (data->fan_div[nr] & 0x7) << oddshift;
return nct6775_write_value(data, fandiv_reg, reg);
}
......
......@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/wmi.h>
#include "nct6775.h"
......@@ -107,40 +106,51 @@ struct nct6775_sio_data {
void (*sio_exit)(struct nct6775_sio_data *sio_data);
};
#define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66"
#define ASUSWMI_METHOD "WMBD"
#define ASUSWMI_METHODID_RSIO 0x5253494F
#define ASUSWMI_METHODID_WSIO 0x5753494F
#define ASUSWMI_METHODID_RHWM 0x5248574D
#define ASUSWMI_METHODID_WHWM 0x5748574D
#define ASUSWMI_UNSUPPORTED_METHOD 0xFFFFFFFE
#define ASUSWMI_DEVICE_HID "PNP0C14"
#define ASUSWMI_DEVICE_UID "ASUSWMI"
#define ASUSMSI_DEVICE_UID "AsusMbSwInterface"
#if IS_ENABLED(CONFIG_ACPI)
/*
* ASUS boards have only one device with WMI "WMBD" method and have provided
* access to only one SuperIO chip at 0x0290.
*/
static struct acpi_device *asus_acpi_dev;
#endif
static int nct6775_asuswmi_evaluate_method(u32 method_id, u8 bank, u8 reg, u8 val, u32 *retval)
{
#if IS_ENABLED(CONFIG_ACPI_WMI)
#if IS_ENABLED(CONFIG_ACPI)
acpi_handle handle = acpi_device_handle(asus_acpi_dev);
u32 args = bank | (reg << 8) | (val << 16);
struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
union acpi_object params[3];
unsigned long long result;
acpi_status status;
union acpi_object *obj;
u32 tmp = ASUSWMI_UNSUPPORTED_METHOD;
status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0,
method_id, &input, &output);
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = 0;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = method_id;
params[2].type = ACPI_TYPE_BUFFER;
params[2].buffer.length = sizeof(args);
params[2].buffer.pointer = (void *)&args;
input.count = 3;
input.pointer = params;
status = acpi_evaluate_integer(handle, ASUSWMI_METHOD, &input, &result);
if (ACPI_FAILURE(status))
return -EIO;
obj = output.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
tmp = obj->integer.value;
if (retval)
*retval = tmp;
kfree(obj);
*retval = (u32)result & 0xFFFFFFFF;
if (tmp == ASUSWMI_UNSUPPORTED_METHOD)
return -ENODEV;
return 0;
#else
return -EOPNOTSUPP;
......@@ -1099,6 +1109,91 @@ static const char * const asus_wmi_boards[] = {
"TUF GAMING Z490-PLUS (WI-FI)",
};
static const char * const asus_msi_boards[] = {
"EX-B660M-V5 PRO D4",
"PRIME B650-PLUS",
"PRIME B650M-A",
"PRIME B650M-A AX",
"PRIME B650M-A II",
"PRIME B650M-A WIFI",
"PRIME B650M-A WIFI II",
"PRIME B660M-A D4",
"PRIME B660M-A WIFI D4",
"PRIME X670-P",
"PRIME X670-P WIFI",
"PRIME X670E-PRO WIFI",
"Pro B660M-C-D4",
"ProArt B660-CREATOR D4",
"ProArt X670E-CREATOR WIFI",
"ROG CROSSHAIR X670E EXTREME",
"ROG CROSSHAIR X670E GENE",
"ROG CROSSHAIR X670E HERO",
"ROG MAXIMUS XIII EXTREME GLACIAL",
"ROG MAXIMUS Z690 EXTREME",
"ROG MAXIMUS Z690 EXTREME GLACIAL",
"ROG STRIX B650-A GAMING WIFI",
"ROG STRIX B650E-E GAMING WIFI",
"ROG STRIX B650E-F GAMING WIFI",
"ROG STRIX B650E-I GAMING WIFI",
"ROG STRIX B660-A GAMING WIFI D4",
"ROG STRIX B660-F GAMING WIFI",
"ROG STRIX B660-G GAMING WIFI",
"ROG STRIX B660-I GAMING WIFI",
"ROG STRIX X670E-A GAMING WIFI",
"ROG STRIX X670E-E GAMING WIFI",
"ROG STRIX X670E-F GAMING WIFI",
"ROG STRIX X670E-I GAMING WIFI",
"ROG STRIX Z590-A GAMING WIFI II",
"ROG STRIX Z690-A GAMING WIFI D4",
"TUF GAMING B650-PLUS",
"TUF GAMING B650-PLUS WIFI",
"TUF GAMING B650M-PLUS",
"TUF GAMING B650M-PLUS WIFI",
"TUF GAMING B660M-PLUS WIFI",
"TUF GAMING X670E-PLUS",
"TUF GAMING X670E-PLUS WIFI",
"TUF GAMING Z590-PLUS WIFI",
};
#if IS_ENABLED(CONFIG_ACPI)
/*
* Callback for acpi_bus_for_each_dev() to find the right device
* by _UID and _HID and return 1 to stop iteration.
*/
static int nct6775_asuswmi_device_match(struct device *dev, void *data)
{
struct acpi_device *adev = to_acpi_device(dev);
const char *uid = acpi_device_uid(adev);
const char *hid = acpi_device_hid(adev);
if (hid && !strcmp(hid, ASUSWMI_DEVICE_HID) && uid && !strcmp(uid, data)) {
asus_acpi_dev = adev;
return 1;
}
return 0;
}
#endif
static enum sensor_access nct6775_determine_access(const char *device_uid)
{
#if IS_ENABLED(CONFIG_ACPI)
u8 tmp;
acpi_bus_for_each_dev(nct6775_asuswmi_device_match, (void *)device_uid);
if (!asus_acpi_dev)
return access_direct;
/* if reading chip id via ACPI succeeds, use WMI "WMBD" method for access */
if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
pr_debug("Using Asus WMBD method of %s to access %#x chip.\n", device_uid, tmp);
return access_asuswmi;
}
#endif
return access_direct;
}
static int __init sensors_nct6775_platform_init(void)
{
int i, err;
......@@ -1109,7 +1204,6 @@ static int __init sensors_nct6775_platform_init(void)
int sioaddr[2] = { 0x2e, 0x4e };
enum sensor_access access = access_direct;
const char *board_vendor, *board_name;
u8 tmp;
err = platform_driver_register(&nct6775_driver);
if (err)
......@@ -1122,15 +1216,13 @@ static int __init sensors_nct6775_platform_init(void)
!strcmp(board_vendor, "ASUSTeK COMPUTER INC.")) {
err = match_string(asus_wmi_boards, ARRAY_SIZE(asus_wmi_boards),
board_name);
if (err >= 0) {
/* if reading chip id via WMI succeeds, use WMI */
if (!nct6775_asuswmi_read(0, NCT6775_PORT_CHIPID, &tmp) && tmp) {
pr_info("Using Asus WMI to access %#x chip.\n", tmp);
access = access_asuswmi;
} else {
pr_err("Can't read ChipID by Asus WMI.\n");
}
}
if (err >= 0)
access = nct6775_determine_access(ASUSWMI_DEVICE_UID);
err = match_string(asus_msi_boards, ARRAY_SIZE(asus_msi_boards),
board_name);
if (err >= 0)
access = nct6775_determine_access(ASUSMSI_DEVICE_UID);
}
/*
......
......@@ -791,6 +791,7 @@ static const struct hid_device_id nzxt_smart2_hid_id_table[] = {
{ HID_USB_DEVICE(0x1e71, 0x2009) }, /* NZXT RGB & Fan Controller */
{ HID_USB_DEVICE(0x1e71, 0x200e) }, /* NZXT RGB & Fan Controller */
{ HID_USB_DEVICE(0x1e71, 0x2010) }, /* NZXT RGB & Fan Controller */
{ HID_USB_DEVICE(0x1e71, 0x2019) }, /* NZXT RGB & Fan Controller */
{},
};
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Platform driver for OXP Handhelds that expose fan reading and control
* via hwmon sysfs.
* Platform driver for OneXPlayer, AOK ZOE, and Aya Neo Handhelds that expose
* fan reading and control via hwmon sysfs.
*
* Old boards have the same DMI strings and they are told appart by the
* boot cpu vendor (Intel/AMD). Currently only AMD boards are supported
* but the code is made to be simple to add other handheld boards in the
* future.
* Old OXP boards have the same DMI strings and they are told apart by
* the boot cpu vendor (Intel/AMD). Currently only AMD boards are
* supported but the code is made to be simple to add other handheld
* boards in the future.
* Fan control is provided via pwm interface in the range [0-255].
* Old AMD boards use [0-100] as range in the EC, the written value is
* scaled to accommodate for that. Newer boards like the mini PRO and
......@@ -42,6 +42,8 @@ static bool unlock_global_acpi_lock(void)
enum oxp_board {
aok_zoe_a1 = 1,
aya_neo_air,
aya_neo_air_pro,
oxp_mini_amd,
oxp_mini_amd_pro,
};
......@@ -60,6 +62,20 @@ static const struct dmi_system_id dmi_table[] = {
},
.driver_data = (void *) &(enum oxp_board) {aok_zoe_a1},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
},
.driver_data = (void *) &(enum oxp_board) {aya_neo_air},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
},
.driver_data = (void *) &(enum oxp_board) {aya_neo_air_pro},
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
......@@ -161,8 +177,17 @@ static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
if (ret)
return ret;
if (board == oxp_mini_amd)
switch (board) {
case aya_neo_air:
case aya_neo_air_pro:
case oxp_mini_amd:
*val = (*val * 255) / 100;
break;
case oxp_mini_amd_pro:
case aok_zoe_a1:
default:
break;
}
return 0;
case hwmon_pwm_enable:
return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
......@@ -191,8 +216,17 @@ static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
case hwmon_pwm_input:
if (val < 0 || val > 255)
return -EINVAL;
if (board == oxp_mini_amd)
switch (board) {
case aya_neo_air:
case aya_neo_air_pro:
case oxp_mini_amd:
val = (val * 100) / 255;
break;
case aok_zoe_a1:
case oxp_mini_amd_pro:
default:
break;
}
return write_to_ec(dev, OXP_SENSOR_PWM_REG, val);
default:
break;
......@@ -233,7 +267,7 @@ static int oxp_platform_probe(struct platform_device *pdev)
/*
* Have to check for AMD processor here because DMI strings are the
* same between Intel and AMD boards, the only way to tell them appart
* same between Intel and AMD boards, the only way to tell them apart
* is the CPU.
* Intel boards seem to have different EC registers and values to
* read/write.
......
......@@ -402,7 +402,7 @@ static int create_temp_label(struct peci_cputemp *priv)
unsigned long core_max = find_last_bit(priv->core_mask, CORE_NUMS_MAX);
int i;
priv->coretemp_label = devm_kzalloc(priv->dev, core_max * sizeof(char *), GFP_KERNEL);
priv->coretemp_label = devm_kzalloc(priv->dev, (core_max + 1) * sizeof(char *), GFP_KERNEL);
if (!priv->coretemp_label)
return -ENOMEM;
......
......@@ -237,10 +237,10 @@ config SENSORS_MAX16064
be called max16064.
config SENSORS_MAX16601
tristate "Maxim MAX16508, MAX16601, MAX16602"
tristate "Maxim MAX16508, MAX16600, MAX16601, and MAX16602"
help
If you say yes here you get hardware monitoring support for Maxim
MAX16508, MAX16601 and MAX16602.
MAX16508, MAX16600, MAX16601, and MAX16602.
This driver can also be built as a module. If so, the module will
be called max16601.
......@@ -317,6 +317,22 @@ config SENSORS_MP5023
This driver can also be built as a module. If so, the module will
be called mp5023.
config SENSORS_MPQ7932_REGULATOR
bool "Regulator support for MPQ7932"
depends on SENSORS_MPQ7932 && REGULATOR
help
If you say yes here you get six integrated buck converter regulator
support for power management IC MPS MPQ7932.
config SENSORS_MPQ7932
tristate "MPS MPQ7932"
help
If you say yes here you get hardware monitoring functionality support
for power management IC MPS MPQ7932.
This driver can also be built as a module. If so, the module will
be called mpq7932.
config SENSORS_PIM4328
tristate "Flex PIM4328 and compatibles"
help
......@@ -379,6 +395,22 @@ config SENSORS_STPDDC60
This driver can also be built as a module. If so, the module will
be called stpddc60.
config SENSORS_TDA38640
tristate "Infineon TDA38640"
help
If you say yes here you get hardware monitoring support for Infineon
TDA38640.
This driver can also be built as a module. If so, the module will
be called tda38640.
config SENSORS_TDA38640_REGULATOR
bool "Regulator support for TDA38640 and compatibles"
depends on SENSORS_TDA38640 && REGULATOR
help
If you say yes here you get regulator support for Infineon
TDA38640 as regulator.
config SENSORS_TPS40422
tristate "TI TPS40422"
help
......
......@@ -34,11 +34,13 @@ obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_MP2888) += mp2888.o
obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
obj-$(CONFIG_SENSORS_MP5023) += mp5023.o
obj-$(CONFIG_SENSORS_MPQ7932) += mpq7932.o
obj-$(CONFIG_SENSORS_PLI1209BC) += pli1209bc.o
obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o
obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o
obj-$(CONFIG_SENSORS_TDA38640) += tda38640.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o
......
......@@ -570,14 +570,14 @@ MODULE_DEVICE_TABLE(i2c, ltc2978_id);
#define LTC2978_N_VOLTAGES ((LTC2978_MAX_UV / LTC2978_UV_STEP) + 1)
static const struct regulator_desc ltc2978_reg_desc[] = {
PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP, 0),
};
static const struct regulator_desc ltc2978_reg_desc_default[] = {
......
// SPDX-License-Identifier: GPL-2.0
/*
* Hardware monitoring driver for Maxim MAX16508, MAX16601 and MAX16602.
* Hardware monitoring driver for Maxim MAX16508, MAX16600, MAX16601,
* and MAX16602.
*
* Implementation notes:
*
......@@ -31,7 +32,7 @@
#include "pmbus.h"
enum chips { max16508, max16601, max16602 };
enum chips { max16508, max16600, max16601, max16602 };
#define REG_DEFAULT_NUM_POP 0xc4
#define REG_SETPT_DVID 0xd1
......@@ -202,7 +203,7 @@ static int max16601_identify(struct i2c_client *client,
else
info->vrm_version[0] = vr12;
if (data->id != max16601 && data->id != max16602)
if (data->id != max16600 && data->id != max16601 && data->id != max16602)
return 0;
reg = i2c_smbus_read_byte_data(client, REG_DEFAULT_NUM_POP);
......@@ -263,6 +264,7 @@ static void max16601_remove(void *_data)
static const struct i2c_device_id max16601_id[] = {
{"max16508", max16508},
{"max16600", max16600},
{"max16601", max16601},
{"max16602", max16602},
{}
......@@ -281,11 +283,13 @@ static int max16601_get_id(struct i2c_client *client)
return -ENODEV;
/*
* PMBUS_IC_DEVICE_ID is expected to return "MAX16601y.xx" or
* MAX16602y.xx or "MAX16500y.xx".cdxxcccccccccc
* PMBUS_IC_DEVICE_ID is expected to return MAX1660[012]y.xx" or
* "MAX16500y.xx".cdxxcccccccccc
*/
if (!strncmp(buf, "MAX16500", 8)) {
id = max16508;
} else if (!strncmp(buf, "MAX16600", 8)) {
id = max16600;
} else if (!strncmp(buf, "MAX16601", 8)) {
id = max16601;
} else if (!strncmp(buf, "MAX16602", 8)) {
......
// SPDX-License-Identifier: GPL-2.0+
/*
* mpq7932.c - hwmon with optional regulator driver for mps mpq7932
* Copyright 2022 Monolithic Power Systems, Inc
*
* Author: Saravanan Sekar <saravanan@linumiz.com>
*/
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pmbus.h>
#include "pmbus.h"
#define MPQ7932_BUCK_UV_MIN 206250
#define MPQ7932_UV_STEP 6250
#define MPQ7932_N_VOLTAGES 256
#define MPQ7932_VOUT_MAX 0xFF
#define MPQ7932_NUM_PAGES 6
#define MPQ7932_TON_DELAY 0x60
#define MPQ7932_VOUT_STARTUP_SLEW 0xA3
#define MPQ7932_VOUT_SHUTDOWN_SLEW 0xA5
#define MPQ7932_VOUT_SLEW_MASK GENMASK(1, 0)
#define MPQ7932_TON_DELAY_MASK GENMASK(4, 0)
struct mpq7932_data {
struct pmbus_driver_info info;
struct pmbus_platform_data pdata;
};
#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
static struct regulator_desc mpq7932_regulators_desc[] = {
PMBUS_REGULATOR_STEP("buck", 0, MPQ7932_N_VOLTAGES,
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
PMBUS_REGULATOR_STEP("buck", 1, MPQ7932_N_VOLTAGES,
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
PMBUS_REGULATOR_STEP("buck", 2, MPQ7932_N_VOLTAGES,
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
PMBUS_REGULATOR_STEP("buck", 3, MPQ7932_N_VOLTAGES,
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
PMBUS_REGULATOR_STEP("buck", 4, MPQ7932_N_VOLTAGES,
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
PMBUS_REGULATOR_STEP("buck", 5, MPQ7932_N_VOLTAGES,
MPQ7932_UV_STEP, MPQ7932_BUCK_UV_MIN),
};
#endif
static int mpq7932_write_word_data(struct i2c_client *client, int page, int reg,
u16 word)
{
switch (reg) {
/*
* chip supports only byte access for VOUT_COMMAND otherwise
* access results -EREMOTEIO
*/
case PMBUS_VOUT_COMMAND:
return pmbus_write_byte_data(client, page, reg, word & 0xFF);
default:
return -ENODATA;
}
}
static int mpq7932_read_word_data(struct i2c_client *client, int page,
int phase, int reg)
{
switch (reg) {
/*
* chip supports neither (PMBUS_VOUT_MARGIN_HIGH, PMBUS_VOUT_MARGIN_LOW)
* nor (PMBUS_MFR_VOUT_MIN, PMBUS_MFR_VOUT_MAX). As a result set voltage
* fails due to error in pmbus_regulator_get_low_margin, so faked.
*/
case PMBUS_MFR_VOUT_MIN:
return 0;
case PMBUS_MFR_VOUT_MAX:
return MPQ7932_VOUT_MAX;
/*
* chip supports only byte access for VOUT_COMMAND otherwise
* access results in -EREMOTEIO
*/
case PMBUS_READ_VOUT:
return pmbus_read_byte_data(client, page, PMBUS_VOUT_COMMAND);
default:
return -ENODATA;
}
}
static int mpq7932_probe(struct i2c_client *client)
{
struct mpq7932_data *data;
struct pmbus_driver_info *info;
struct device *dev = &client->dev;
int i;
data = devm_kzalloc(dev, sizeof(struct mpq7932_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
info = &data->info;
info->pages = MPQ7932_NUM_PAGES;
info->format[PSC_VOLTAGE_OUT] = direct;
info->m[PSC_VOLTAGE_OUT] = 160;
info->b[PSC_VOLTAGE_OUT] = -33;
for (i = 0; i < info->pages; i++) {
info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_STATUS_TEMP;
}
#if IS_ENABLED(CONFIG_SENSORS_MPQ7932_REGULATOR)
info->num_regulators = ARRAY_SIZE(mpq7932_regulators_desc);
info->reg_desc = mpq7932_regulators_desc;
#endif
info->read_word_data = mpq7932_read_word_data;
info->write_word_data = mpq7932_write_word_data;
data->pdata.flags = PMBUS_NO_CAPABILITY;
dev->platform_data = &data->pdata;
return pmbus_do_probe(client, info);
}
static const struct of_device_id mpq7932_of_match[] = {
{ .compatible = "mps,mpq7932"},
{},
};
MODULE_DEVICE_TABLE(of, mpq7932_of_match);
static const struct i2c_device_id mpq7932_id[] = {
{ "mpq7932", },
{ },
};
MODULE_DEVICE_TABLE(i2c, mpq7932_id);
static struct i2c_driver mpq7932_regulator_driver = {
.driver = {
.name = "mpq7932",
.of_match_table = mpq7932_of_match,
},
.probe_new = mpq7932_probe,
.id_table = mpq7932_id,
};
module_i2c_driver(mpq7932_regulator_driver);
MODULE_AUTHOR("Saravanan Sekar <saravanan@linumiz.com>");
MODULE_DESCRIPTION("MPQ7932 PMIC regulator driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -464,7 +464,7 @@ struct pmbus_driver_info {
extern const struct regulator_ops pmbus_regulator_ops;
/* Macros for filling in array of struct regulator_desc */
#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step) \
#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step, _min_uV) \
[_id] = { \
.name = (_name # _id), \
.id = (_id), \
......@@ -475,9 +475,10 @@ extern const struct regulator_ops pmbus_regulator_ops;
.owner = THIS_MODULE, \
.n_voltages = _voltages, \
.uV_step = _step, \
.min_uV = _min_uV, \
}
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0)
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0)
/* Function declarations */
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for Infineon TDA38640
*
* Copyright (c) 2023 9elements GmbH
*
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regulator/driver.h>
#include "pmbus.h"
static const struct regulator_desc __maybe_unused tda38640_reg_desc[] = {
PMBUS_REGULATOR("vout", 0),
};
static struct pmbus_driver_info tda38640_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_POWER] = linear,
.format[PSC_TEMPERATURE] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_IIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_POUT | PMBUS_HAVE_PIN,
#if IS_ENABLED(CONFIG_SENSORS_TDA38640_REGULATOR)
.num_regulators = 1,
.reg_desc = tda38640_reg_desc,
#endif
};
static int tda38640_probe(struct i2c_client *client)
{
return pmbus_do_probe(client, &tda38640_info);
}
static const struct i2c_device_id tda38640_id[] = {
{"tda38640", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, tda38640_id);
static const struct of_device_id __maybe_unused tda38640_of_match[] = {
{ .compatible = "infineon,tda38640"},
{ },
};
MODULE_DEVICE_TABLE(of, tda38640_of_match);
/* This is the driver that will be inserted */
static struct i2c_driver tda38640_driver = {
.driver = {
.name = "tda38640",
.of_match_table = of_match_ptr(tda38640_of_match),
},
.probe_new = tda38640_probe,
.id_table = tda38640_id,
};
module_i2c_driver(tda38640_driver);
MODULE_AUTHOR("Patrick Rudolph <patrick.rudolph@9elements.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon TDA38640");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -668,7 +668,7 @@ static inline int sht15_calc_humid(struct sht15_data *data)
}
/**
* sht15_show_status() - show status information in sysfs
* sht15_status_show() - show status information in sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer where information is written to.
......@@ -690,7 +690,7 @@ static ssize_t sht15_status_show(struct device *dev,
}
/**
* sht15_store_heater() - change heater state via sysfs
* sht15_status_store() - change heater state via sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer to read the new heater state from.
......@@ -725,7 +725,7 @@ static ssize_t sht15_status_store(struct device *dev,
}
/**
* sht15_show_temp() - show temperature measurement value in sysfs
* sht15_temp_show() - show temperature measurement value in sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer where measurement values are written to.
......@@ -747,7 +747,7 @@ static ssize_t sht15_temp_show(struct device *dev,
}
/**
* sht15_show_humidity() - show humidity measurement value in sysfs
* sht15_humidity_show() - show humidity measurement value in sysfs
* @dev: device.
* @attr: device attribute.
* @buf: sysfs buffer where measurement values are written to.
......
......@@ -114,7 +114,7 @@ static int sht21_update_measurements(struct device *dev)
}
/**
* sht21_show_temperature() - show temperature measurement value in sysfs
* sht21_temperature_show() - show temperature measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
......@@ -136,7 +136,7 @@ static ssize_t sht21_temperature_show(struct device *dev,
}
/**
* sht21_show_humidity() - show humidity measurement value in sysfs
* sht21_humidity_show() - show humidity measurement value in sysfs
* @dev: device
* @attr: device attribute
* @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
......
......@@ -436,6 +436,10 @@ struct hwmon_chip_info {
/* hwmon_device_register() is deprecated */
struct device *hwmon_device_register(struct device *dev);
/*
* hwmon_device_register_with_groups() and
* devm_hwmon_device_register_with_groups() are deprecated.
*/
struct device *
hwmon_device_register_with_groups(struct device *dev, const char *name,
void *drvdata,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment