summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-01-22 10:16:48 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2025-01-22 10:16:48 -0800
commita4910ed25d48eb06b81fe6beca7d4f31e6275be0 (patch)
tree02ff0305235a046b605dc574aa5bc50afe306ff5
parent11a7b03346e2ac4bf13783d409dd7ec0ecf1f3ac (diff)
parenta76539b293677c5c163b9285b0cd8dd420d33989 (diff)
Merge tag 'hwmon-for-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck: "New drivers: - PMBus client driver for Intel CRPS185 power supply - PMBus client driver for Texas Instruments TPS25990 Chip support added to existing drivers: - pmbus/max15301: Add support for MAX15303 - pmbus/adm1275: Add adm1273 support - lm75: Add NXP P3T1755 support; with it, add I3C support to the driver - asus-ec-sensors: Add TUF GAMING X670E PLUS Other notable changes: - nct6683: Add customer IDs for several MSI and ASRock boards - tmp108: Add regulator support - Improve write protect support in PMBus core - pmbus/dps920ab: Add ability to instantiate through i2c - The hwmon core now accepts NULL as device name parameter to [devm_]hwmon_device_register_with_info ans uses the parent device name as fallback in that case - The PMBus core now provides the PMBUs revision in a debugfs file - asus-ec-sensors: Support for optional CPU fan on AMD 600 motherboards - raspberrypi: Add PM suspend/resume support - dell-smm: Enable manual fan control support on Dell XPS 9370 - pwm-fan: Default to maximum cooling level if provided And various other minor fixes and improvements" * tag 'hwmon-for-v6.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (44 commits) hwmon: pmbus: dps920ab: Add ability to instantiate through i2c hwmon: (pwm-fan) Default to the Maximum cooling level if provided hwmon: (asus_atk0110) Use str_enabled_disabled() and str_enable_disable() helpers hwmon: Fix help text for aspeed-g6-pwm-tach hwmon: (dell-smm) Add Dell XPS 9370 to fan control whitelist hwmon: (acpi_power_meter) Fix update the power trip points on failure hwmon: (acpi_power_meter) Fix uninitialized variables hwmon: (core) Use device name as a fallback in devm_hwmon_device_register_with_info hwmon: (pmbus/max15301) Add support for MAX15303 hwmon: (pmbus/adm1275) add adm1273 support dt-bindings: hwmon: adm1275: add adm1273 hwmon: (nct6683) Add another customer ID for MSI hwmon: (pwm-fan): Make use of device properties everywhere hwmon: (lm75) add I3C support for P3T1755 hwmon: (lm75) separate probe into common and I2C parts hwmon: (lm75) Remove superfluous 'client' member from private struct hwmon: (lm75) simplify regulator handling hwmon: (lm75) simplify lm75_write_config() hwmon: (lm75) Hide register size differences in regmap access functions hwmon: (pmbus/crps) Add Intel CRPS185 power supply ...
-rw-r--r--Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml2
-rw-r--r--Documentation/devicetree/bindings/hwmon/lm75.yaml1
-rw-r--r--Documentation/devicetree/bindings/trivial-devices.yaml2
-rw-r--r--Documentation/hwmon/adm1275.rst28
-rw-r--r--Documentation/hwmon/asus_ec_sensors.rst1
-rw-r--r--Documentation/hwmon/crps.rst97
-rw-r--r--Documentation/hwmon/hwmon-kernel-api.rst3
-rw-r--r--Documentation/hwmon/index.rst2
-rw-r--r--Documentation/hwmon/isl28022.rst3
-rw-r--r--Documentation/hwmon/lm75.rst8
-rw-r--r--Documentation/hwmon/max15301.rst8
-rw-r--r--Documentation/hwmon/nct6683.rst24
-rw-r--r--Documentation/hwmon/pmbus-core.rst35
-rw-r--r--Documentation/hwmon/tps25990.rst147
-rw-r--r--MAINTAINERS11
-rw-r--r--drivers/hwmon/Kconfig6
-rw-r--r--drivers/hwmon/acpi_power_meter.c39
-rw-r--r--drivers/hwmon/asus-ec-sensors.c13
-rw-r--r--drivers/hwmon/asus_atk0110.c15
-rw-r--r--drivers/hwmon/chipcap2.c63
-rw-r--r--drivers/hwmon/dell-smm-hwmon.c8
-rw-r--r--drivers/hwmon/hwmon.c27
-rw-r--r--drivers/hwmon/isl28022.c11
-rw-r--r--drivers/hwmon/lm75.c339
-rw-r--r--drivers/hwmon/nct6683.c6
-rw-r--r--drivers/hwmon/nct6775-core.c6
-rw-r--r--drivers/hwmon/occ/p9_sbe.c4
-rw-r--r--drivers/hwmon/pmbus/Kconfig30
-rw-r--r--drivers/hwmon/pmbus/Makefile2
-rw-r--r--drivers/hwmon/pmbus/adm1275.c10
-rw-r--r--drivers/hwmon/pmbus/crps.c74
-rw-r--r--drivers/hwmon/pmbus/dps920ab.c7
-rw-r--r--drivers/hwmon/pmbus/max15301.c1
-rw-r--r--drivers/hwmon/pmbus/pmbus.h4
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c94
-rw-r--r--drivers/hwmon/pmbus/tps25990.c436
-rw-r--r--drivers/hwmon/pwm-fan.c26
-rw-r--r--drivers/hwmon/raspberrypi-hwmon.c22
-rw-r--r--drivers/hwmon/tmp108.c13
-rw-r--r--include/linux/pmbus.h14
-rw-r--r--include/linux/thermal.h4
41 files changed, 1378 insertions, 268 deletions
diff --git a/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml b/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml
index 5b076d677395..fd79bf2e0d16 100644
--- a/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml
+++ b/Documentation/devicetree/bindings/hwmon/adi,adm1275.yaml
@@ -24,6 +24,7 @@ properties:
enum:
- adi,adm1075
- adi,adm1272
+ - adi,adm1273
- adi,adm1275
- adi,adm1276
- adi,adm1278
@@ -79,6 +80,7 @@ allOf:
contains:
enum:
- adi,adm1272
+ - adi,adm1273
then:
properties:
adi,volt-curr-sample-average:
diff --git a/Documentation/devicetree/bindings/hwmon/lm75.yaml b/Documentation/devicetree/bindings/hwmon/lm75.yaml
index 29bd7460cc26..c38255243f57 100644
--- a/Documentation/devicetree/bindings/hwmon/lm75.yaml
+++ b/Documentation/devicetree/bindings/hwmon/lm75.yaml
@@ -28,6 +28,7 @@ properties:
- maxim,max31725
- maxim,max31726
- maxim,mcp980x
+ - nxp,p3t1755
- nxp,pct2075
- st,stds75
- st,stlm75
diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml
index 88abb5c174f3..6bdcd055e763 100644
--- a/Documentation/devicetree/bindings/trivial-devices.yaml
+++ b/Documentation/devicetree/bindings/trivial-devices.yaml
@@ -149,6 +149,8 @@ properties:
- injoinic,ip5209
# Inspur Power System power supply unit version 1
- inspur,ipsps1
+ # Intel common redudant power supply crps185
+ - intel,crps185
# Intersil ISL29028 Ambient Light and Proximity Sensor
- isil,isl29028
# Intersil ISL29030 Ambient Light and Proximity Sensor
diff --git a/Documentation/hwmon/adm1275.rst b/Documentation/hwmon/adm1275.rst
index 467daf8ce3c5..57bd7a850558 100644
--- a/Documentation/hwmon/adm1275.rst
+++ b/Documentation/hwmon/adm1275.rst
@@ -19,6 +19,14 @@ Supported chips:
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1272.pdf
+ * Analog Devices ADM1273
+
+ Prefix: 'adm1273'
+
+ Addresses scanned: -
+
+ Datasheet: Not yet publicly available
+
* Analog Devices ADM1275
Prefix: 'adm1275'
@@ -66,14 +74,14 @@ Description
-----------
This driver supports hardware monitoring for Analog Devices ADM1075, ADM1272,
-ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 Hot-Swap Controller and
-Digital Power Monitors.
+ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 Hot-Swap
+Controller and Digital Power Monitors.
-ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and ADM1294 are hot-swap
-controllers that allow a circuit board to be removed from or inserted into
-a live backplane. They also feature current and voltage readback via an
-integrated 12 bit analog-to-digital converter (ADC), accessed using a
-PMBus interface.
+ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281, ADM1293, and
+ADM1294 are hot-swap controllers that allow a circuit board to be removed from
+or inserted into a live backplane. They also feature current and voltage
+readback via an integrated 12 bit analog-to-digital converter (ADC), accessed
+using a PMBus interface.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
@@ -141,7 +149,7 @@ power1_input_highest Highest observed input power.
power1_reset_history Write any value to reset history.
Power attributes are supported on ADM1075, ADM1272,
- ADM1276, ADM1293, and ADM1294.
+ ADM1273, ADM1276, ADM1293, and ADM1294.
temp1_input Chip temperature.
temp1_max Maximum chip temperature.
@@ -151,6 +159,6 @@ temp1_crit_alarm Critical temperature high alarm.
temp1_highest Highest observed temperature.
temp1_reset_history Write any value to reset history.
- Temperature attributes are supported on ADM1272 and
- ADM1278, and ADM1281.
+ Temperature attributes are supported on ADM1272,
+ ADM1273, ADM1278, and ADM1281.
======================= =======================================================
diff --git a/Documentation/hwmon/asus_ec_sensors.rst b/Documentation/hwmon/asus_ec_sensors.rst
index ca38922f4ec5..739636cf7994 100644
--- a/Documentation/hwmon/asus_ec_sensors.rst
+++ b/Documentation/hwmon/asus_ec_sensors.rst
@@ -29,6 +29,7 @@ Supported boards:
* ROG STRIX Z690-A GAMING WIFI D4
* ROG ZENITH II EXTREME
* ROG ZENITH II EXTREME ALPHA
+ * TUF GAMING X670E PLUS
Authors:
- Eugene Shalygin <eugene.shalygin@gmail.com>
diff --git a/Documentation/hwmon/crps.rst b/Documentation/hwmon/crps.rst
new file mode 100644
index 000000000000..87380b496558
--- /dev/null
+++ b/Documentation/hwmon/crps.rst
@@ -0,0 +1,97 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+Kernel driver crps
+==================
+
+Supported chips:
+
+ * Intel CRPS185
+
+ Prefix: 'crps185'
+
+ Addresses scanned: -
+
+ Datasheet: Only available under NDA.
+
+Authors:
+ Ninad Palsule <ninad@linux.ibm.com>
+
+
+Description
+-----------
+
+This driver implements support for Intel Common Redundant Power supply with
+PMBus support.
+
+The driver is a client driver to the core PMBus driver.
+Please see Documentation/hwmon/pmbus.rst for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
+details.
+
+
+Sysfs entries
+-------------
+
+======================= ======================================================
+curr1_label "iin"
+curr1_input Measured input current
+curr1_max Maximum input current
+curr1_max_alarm Input maximum current high alarm
+curr1_crit Critial high input current
+curr1_crit_alarm Input critical current high alarm
+curr1_rated_max Maximum rated input current
+
+curr2_label "iout1"
+curr2_input Measured output current
+curr2_max Maximum output current
+curr2_max_alarm Output maximum current high alarm
+curr2_crit Critial high output current
+curr2_crit_alarm Output critical current high alarm
+curr2_rated_max Maximum rated output current
+
+in1_label "vin"
+in1_input Measured input voltage
+in1_crit Critical input over voltage
+in1_crit_alarm Critical input over voltage alarm
+in1_max Maximum input over voltage
+in1_max_alarm Maximum input over voltage alarm
+in1_rated_min Minimum rated input voltage
+in1_rated_max Maximum rated input voltage
+
+in2_label "vout1"
+in2_input Measured input voltage
+in2_crit Critical input over voltage
+in2_crit_alarm Critical input over voltage alarm
+in2_lcrit Critical input under voltage fault
+in2_lcrit_alarm Critical input under voltage fault alarm
+in2_max Maximum input over voltage
+in2_max_alarm Maximum input over voltage alarm
+in2_min Minimum input under voltage warning
+in2_min_alarm Minimum input under voltage warning alarm
+in2_rated_min Minimum rated input voltage
+in2_rated_max Maximum rated input voltage
+
+power1_label "pin"
+power1_input Measured input power
+power1_alarm Input power high alarm
+power1_max Maximum input power
+power1_rated_max Maximum rated input power
+
+temp[1-2]_input Measured temperature
+temp[1-2]_crit Critical temperature
+temp[1-2]_crit_alarm Critical temperature alarm
+temp[1-2]_max Maximum temperature
+temp[1-2]_max_alarm Maximum temperature alarm
+temp[1-2]_rated_max Maximum rated temperature
+
+fan1_alarm Fan 1 warning.
+fan1_fault Fan 1 fault.
+fan1_input Fan 1 speed in RPM.
+fan1_target Fan 1 target.
+======================= ======================================================
diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst
index 8297acfa3a2d..e47fc757e63e 100644
--- a/Documentation/hwmon/hwmon-kernel-api.rst
+++ b/Documentation/hwmon/hwmon-kernel-api.rst
@@ -64,7 +64,8 @@ hwmon_device_register_with_info.
All supported hwmon device registration functions only accept valid device
names. Device names including invalid characters (whitespace, '*', or '-')
-will be rejected. The 'name' parameter is mandatory.
+will be rejected. If NULL is passed as name parameter, the hardware monitoring
+device name will be derived from the parent device name.
If the driver doesn't use a static device name (for example it uses
dev_name()), and therefore cannot make sure the name only contains valid
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index d96fd542aab2..874f8fd26325 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -58,6 +58,7 @@ Hardware Monitoring Kernel Drivers
corsair-cpro
corsair-psu
cros_ec_hwmon
+ crps
da9052
da9055
dell-smm-hwmon
@@ -237,6 +238,7 @@ Hardware Monitoring Kernel Drivers
tmp464
tmp513
tps23861
+ tps25990
tps40422
tps53679
tps546d24
diff --git a/Documentation/hwmon/isl28022.rst b/Documentation/hwmon/isl28022.rst
index 8d4422a2dacd..273ce5460135 100644
--- a/Documentation/hwmon/isl28022.rst
+++ b/Documentation/hwmon/isl28022.rst
@@ -33,7 +33,7 @@ details.
The shunt value in micro-ohms, shunt voltage range and averaging can be set
with device properties.
-Please refer to the Documentation/devicetree/bindings/hwmon/isl,isl28022.yaml
+Please refer to the Documentation/devicetree/bindings/hwmon/renesas,isl28022.yaml
for bindings if the device tree is used.
The driver supports only shunt and bus continuous ADC mode at 15bit resolution.
@@ -48,6 +48,7 @@ The following attributes are supported. All attributes are read-only.
======================= =======================================================
in0_input bus voltage (milli Volt)
+in1_input shunt voltage (milli Volt)
curr1_input current (milli Ampere)
power1_input power (micro Watt)
diff --git a/Documentation/hwmon/lm75.rst b/Documentation/hwmon/lm75.rst
index 6adab608dd05..c6a54bbca3c5 100644
--- a/Documentation/hwmon/lm75.rst
+++ b/Documentation/hwmon/lm75.rst
@@ -121,15 +121,17 @@ Supported chips:
https://www.ti.com/product/TMP1075
- * NXP LM75B, PCT2075
+ * NXP LM75B, P3T1755, PCT2075
- Prefix: 'lm75b', 'pct2075'
+ Prefix: 'lm75b', 'p3t1755', 'pct2075'
Addresses scanned: none
Datasheet: Publicly available at the NXP website
- https://www.nxp.com/documents/data_sheet/LM75B.pdf
+ https://www.nxp.com/docs/en/data-sheet/LM75B.pdf
+
+ https://www.nxp.com/docs/en/data-sheet/P3T1755.pdf
https://www.nxp.com/docs/en/data-sheet/PCT2075.pdf
diff --git a/Documentation/hwmon/max15301.rst b/Documentation/hwmon/max15301.rst
index e3dc22fe1c6d..e2222e98304f 100644
--- a/Documentation/hwmon/max15301.rst
+++ b/Documentation/hwmon/max15301.rst
@@ -13,6 +13,14 @@ Supported chips:
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX15301.pdf
+ * Maxim MAX15303
+
+ Prefix: 'max15303'
+
+ Addresses scanned: -
+
+ Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/max15303.pdf
+
Author: Erik Rosen <erik.rosen@metormote.com>
diff --git a/Documentation/hwmon/nct6683.rst b/Documentation/hwmon/nct6683.rst
index 2a7a78eb1b46..8d4a20d99e59 100644
--- a/Documentation/hwmon/nct6683.rst
+++ b/Documentation/hwmon/nct6683.rst
@@ -55,14 +55,16 @@ Tested Boards and Firmware Versions
The driver has been reported to work with the following boards and
firmware versions.
-=============== ===============================================
-Board Firmware version
-=============== ===============================================
-Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13
-Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13
-Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13
-ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19
-ASRock X670E NCT6686D EC firmware version 1.0 build 05/19/22
-MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20
-MSI X670-P NCT6687D EC firmware version 0.0 build 09/27/22
-=============== ===============================================
+=============================== ===============================================
+Board Firmware version
+=============================== ===============================================
+Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13
+Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13
+Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13
+ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19
+ASRock X670E NCT6686D EC firmware version 1.0 build 05/19/22
+ASRock B650 Steel Legend WiFi NCT6686D EC firmware version 1.0 build 11/09/23
+MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20
+MSI X670-P NCT6687D EC firmware version 0.0 build 09/27/22
+MSI X870E NCT6687D EC firmware version 0.0 build 11/13/24
+=============================== ===============================================
diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst
index 686a00265bf7..fdfb23773148 100644
--- a/Documentation/hwmon/pmbus-core.rst
+++ b/Documentation/hwmon/pmbus-core.rst
@@ -312,6 +312,10 @@ currently provides a flags field with four bits used::
#define PMBUS_USE_COEFFICIENTS_CMD BIT(5)
+ #define PMBUS_OP_PROTECTED BIT(6)
+
+ #define PMBUS_VOUT_PROTECTED BIT(7)
+
struct pmbus_platform_data {
u32 flags; /* Device specific flags */
@@ -373,3 +377,34 @@ PMBUS_USE_COEFFICIENTS_CMD
When this flag is set the PMBus core driver will use the COEFFICIENTS
register to initialize the coefficients for the direct mode format.
+
+PMBUS_OP_PROTECTED
+
+Set if the chip OPERATION command is protected and protection is not
+determined by the standard WRITE_PROTECT command.
+
+PMBUS_VOUT_PROTECTED
+
+Set if the chip VOUT_COMMAND command is protected and protection is not
+determined by the standard WRITE_PROTECT command.
+
+Module parameter
+----------------
+
+pmbus_core.wp: PMBus write protect forced mode
+
+PMBus may come up with a variety of write protection configuration.
+'pmbus_core.wp' may be used if a particular write protection is necessary.
+The ability to actually alter the protection may also depend on the chip
+so the actual runtime write protection configuration may differ from
+the requested one. pmbus_core currently support the following value:
+
+* 0: write protection removed.
+* 1: Disable all writes except to the WRITE_PROTECT, OPERATION,
+ PAGE, ON_OFF_CONFIG and VOUT_COMMAND commands.
+* 2: Disable all writes except to the WRITE_PROTECT, OPERATION and
+ PAGE commands.
+* 3: Disable all writes except to the WRITE_PROTECT command. Note that
+ protection should include the PAGE register. This may be problematic
+ for multi-page chips, if the chips strictly follows the PMBus
+ specification, preventing the chip from changing the active page.
diff --git a/Documentation/hwmon/tps25990.rst b/Documentation/hwmon/tps25990.rst
new file mode 100644
index 000000000000..04faec780d26
--- /dev/null
+++ b/Documentation/hwmon/tps25990.rst
@@ -0,0 +1,147 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver tps25990
+======================
+
+Supported chips:
+
+ * TI TPS25990
+
+ Prefix: 'tps25990'
+
+ * Datasheet
+
+ Publicly available at Texas Instruments website: https://www.ti.com/lit/gpn/tps25990
+
+Author:
+
+ Jerome Brunet <jbrunet@baylibre.com>
+
+Description
+-----------
+
+This driver implements support for TI TPS25990 eFuse.
+This is an integrated, high-current circuit protection and power
+management device with PMBUS interface
+
+Device compliant with:
+
+- PMBus rev 1.3 interface.
+
+Device supports direct format for reading input voltages,
+output voltage, input current, input power and temperature.
+
+Due to the specificities of the chip, all history reset attributes
+are tied together. Resetting the history of a sensor, resets the
+history of all the sensors.
+
+The driver exports the following attributes via the 'sysfs' files
+for input current:
+
+**curr1_average**
+
+**curr1_crit**
+
+**curr1_crit_alarm**
+
+**curr1_highest**
+
+**curr1_input**
+
+**curr1_label**
+
+**curr1_max**
+
+**curr1_max_alarm**
+
+**curr1_reset_history**
+
+The driver provides the following attributes for main input voltage:
+
+**in1_average**
+
+**in1_crit**
+
+**in1_crit_alarm**
+
+**in1_highest**
+
+**in1_input**
+
+**in1_label**
+
+**in1_lcrit**
+
+**in1_lcrit_alarm**
+
+**in1_lowest**
+
+**in1_max**
+
+**in1_max_alarm**
+
+**in1_min**
+
+**in1_min_alarm**
+
+**in1_reset_history**
+
+The driver provides the following attributes for auxiliary input voltage:
+
+**in2_input**
+
+**in2_label**
+
+The driver provides the following attributes for output voltage:
+
+**in3_average**
+
+**in3_input**
+
+**in3_label**
+
+**in3_lowest**
+
+**in3_min**
+
+**in3_min_alarm**
+
+**in3_reset_history**
+
+The driver provides the following attributes for input power:
+
+**power1_alarm**
+
+**power1_average**
+
+**power1_input**
+
+**power1_input_highest**
+
+**power1_label**
+
+**power1_max**
+
+**power1_reset_history**
+
+The driver provides the following attributes for temperature:
+
+**temp1_average**
+
+**temp1_crit**
+
+**temp1_crit_alarm**
+
+**temp1_highest**
+
+**temp1_input**
+
+**temp1_max**
+
+**temp1_max_alarm**
+
+**temp1_reset_history**
+
+The driver provides the following attributes for sampling:
+
+**samples**
diff --git a/MAINTAINERS b/MAINTAINERS
index 11b0cf44383e..0ba9919cdea1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1252,7 +1252,7 @@ S: Maintained
F: Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
F: drivers/rtc/rtc-amlogic-a4.c
-AMPHENOL CHIPCAP 2 HUMIDITY-TEMPERATURE IIO DRIVER
+AMPHENOL CHIPCAP 2 DRIVER
M: Javier Carrasco <javier.carrasco.cruz@gmail.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
@@ -6098,6 +6098,13 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/hid-creative-sb0540.c
+INTEL CRPS COMMON REDUNDANT PSU DRIVER
+M: Ninad Palsule <ninad@linux.ibm.com>
+L: linux-hwmon@vger.kernel.org
+S: Maintained
+F: Documentation/hwmon/crps.rst
+F: drivers/hwmon/pmbus/crps.c
+
CRYPTO API
M: Herbert Xu <herbert@gondor.apana.org.au>
M: "David S. Miller" <davem@davemloft.net>
@@ -23284,6 +23291,8 @@ M: Jerome Brunet <jbrunet@baylibre.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml
+F: Documentation/hwmon/tps25990.rst
+F: drivers/hwmon/pmbus/tps25990.c
TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER
M: Robert Marko <robert.marko@sartura.hr>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index ea2f095da63e..4cbaba15d86e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -413,7 +413,7 @@ config SENSORS_ASPEED
will be called aspeed_pwm_tacho.
config SENSORS_ASPEED_G6
- tristate "ASPEED g6 PWM and Fan tach driver"
+ tristate "ASPEED G6 PWM and Fan tach driver"
depends on ARCH_ASPEED || COMPILE_TEST
depends on PWM
help
@@ -421,7 +421,7 @@ config SENSORS_ASPEED_G6
controllers.
This driver can also be built as a module. If so, the module
- will be called aspeed_pwm_tacho.
+ will be called aspeed_g6_pwm_tach.
config SENSORS_ATXP1
tristate "Attansic ATXP1 VID controller"
@@ -1412,7 +1412,9 @@ config SENSORS_LM73
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
depends on I2C
+ depends on I3C || !I3C
select REGMAP_I2C
+ select REGMAP_I3C if I3C
help
If you say yes here you get support for one common type of
temperature sensor chip, with models including:
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 3db1b9d09c32..44afb07409a4 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -84,6 +84,7 @@ struct acpi_power_meter_resource {
u64 power;
u64 cap;
u64 avg_interval;
+ bool power_alarm;
int sensors_valid;
unsigned long sensors_last_updated;
struct sensor_device_attribute sensors[NUM_SENSORS];
@@ -292,8 +293,8 @@ static ssize_t set_trip(struct device *dev, struct device_attribute *devattr,
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
+ unsigned long temp, trip_bk;
int res;
- unsigned long temp;
res = kstrtoul(buf, 10, &temp);
if (res)
@@ -301,13 +302,15 @@ static ssize_t set_trip(struct device *dev, struct device_attribute *devattr,
temp = DIV_ROUND_CLOSEST(temp, 1000);
- mutex_lock(&resource->lock);
+ guard(mutex)(&resource->lock);
+
+ trip_bk = resource->trip[attr->index - 7];
resource->trip[attr->index - 7] = temp;
res = set_acpi_trip(resource);
- mutex_unlock(&resource->lock);
-
- if (res)
+ if (res) {
+ resource->trip[attr->index - 7] = trip_bk;
return res;
+ }
return count;
}
@@ -396,6 +399,9 @@ static ssize_t show_val(struct device *dev,
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_power_meter_resource *resource = acpi_dev->driver_data;
u64 val = 0;
+ int ret;
+
+ guard(mutex)(&resource->lock);
switch (attr->index) {
case 0:
@@ -423,10 +429,17 @@ static ssize_t show_val(struct device *dev,
val = 0;
break;
case 6:
- if (resource->power > resource->cap)
- val = 1;
- else
- val = 0;
+ ret = update_meter(resource);
+ if (ret)
+ return ret;
+ /* need to update cap if not to support the notification. */
+ if (!(resource->caps.flags & POWER_METER_CAN_NOTIFY)) {
+ ret = update_cap(resource);
+ if (ret)
+ return ret;
+ }
+ val = resource->power_alarm || resource->power > resource->cap;
+ resource->power_alarm = resource->power > resource->cap;
break;
case 7:
case 8:
@@ -847,12 +860,20 @@ static void acpi_power_meter_notify(struct acpi_device *device, u32 event)
sysfs_notify(&device->dev.kobj, NULL, POWER_AVERAGE_NAME);
break;
case METER_NOTIFY_CAP:
+ mutex_lock(&resource->lock);
+ res = update_cap(resource);
+ if (res)
+ dev_err_once(&device->dev, "update cap failed when capping value is changed.\n");
+ mutex_unlock(&resource->lock);
sysfs_notify(&device->dev.kobj, NULL, POWER_CAP_NAME);
break;
case METER_NOTIFY_INTERVAL:
sysfs_notify(&device->dev.kobj, NULL, POWER_AVG_INTERVAL_NAME);
break;
case METER_NOTIFY_CAPPING:
+ mutex_lock(&resource->lock);
+ resource->power_alarm = true;
+ mutex_unlock(&resource->lock);
sysfs_notify(&device->dev.kobj, NULL, POWER_ALARM_NAME);
dev_info(&device->dev, "Capping in progress.\n");
break;
diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
index 9555366aeaf0..43e54dc513da 100644
--- a/drivers/hwmon/asus-ec-sensors.c
+++ b/drivers/hwmon/asus-ec-sensors.c
@@ -250,6 +250,8 @@ static const struct ec_sensor_info sensors_family_amd_600[] = {
EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
[ec_sensor_temp_water_out] =
EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
+ [ec_sensor_fan_cpu_opt] =
+ EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
};
static const struct ec_sensor_info sensors_family_intel_300[] = {
@@ -477,6 +479,15 @@ static const struct ec_board_info board_info_zenith_ii_extreme = {
.family = family_amd_500_series,
};
+static const struct ec_board_info board_info_tuf_gaming_x670e_plus = {
+ .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
+ SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
+ SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT |
+ SENSOR_FAN_CPU_OPT,
+ .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
+ .family = family_amd_600_series,
+};
+
#define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, board_info) \
{ \
.matches = { \
@@ -538,6 +549,8 @@ static const struct dmi_system_id dmi_table[] = {
&board_info_zenith_ii_extreme),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA",
&board_info_zenith_ii_extreme),
+ DMI_EXACT_MATCH_ASUS_BOARD_NAME("TUF GAMING X670E-PLUS",
+ &board_info_tuf_gaming_x670e_plus),
{},
};
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 1dc7e24fe4c5..c80350e499e9 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -17,6 +17,7 @@
#include <linux/jiffies.h>
#include <linux/err.h>
#include <linux/acpi.h>
+#include <linux/string_choices.h>
#define ATK_HID "ATK0110"
@@ -441,7 +442,7 @@ static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
flags->integer.value,
name->string.pointer,
limit1->integer.value, limit2->integer.value,
- enable->integer.value ? "enabled" : "disabled");
+ str_enabled_disabled(enable->integer.value));
#endif
}
@@ -1074,8 +1075,7 @@ static int atk_ec_enabled(struct atk_data *data)
err = -EIO;
} else {
err = (buf->value != 0);
- dev_dbg(dev, "EC is %sabled\n",
- err ? "en" : "dis");
+ dev_dbg(dev, "EC is %s\n", str_enabled_disabled(err));
}
ACPI_FREE(obj);
@@ -1096,18 +1096,15 @@ static int atk_ec_ctl(struct atk_data *data, int enable)
obj = atk_sitm(data, &sitm);
if (IS_ERR(obj)) {
- dev_err(dev, "Failed to %sable the EC\n",
- enable ? "en" : "dis");
+ dev_err(dev, "Failed to %s the EC\n", str_enable_disable(enable));
return PTR_ERR(obj);
}
ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
if (ec_ret->flags == 0) {
- dev_err(dev, "Failed to %sable the EC\n",
- enable ? "en" : "dis");
+ dev_err(dev, "Failed to %s the EC\n", str_enable_disable(enable));
err = -EIO;
} else {
- dev_info(dev, "EC %sabled\n",
- enable ? "en" : "dis");
+ dev_info(dev, "EC %s\n", str_enabled_disabled(enable));
}
ACPI_FREE(obj);
diff --git a/drivers/hwmon/chipcap2.c b/drivers/hwmon/chipcap2.c
index edf454474f11..9d071f7ca9d2 100644
--- a/drivers/hwmon/chipcap2.c
+++ b/drivers/hwmon/chipcap2.c
@@ -13,6 +13,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/hwmon.h>
@@ -556,55 +557,40 @@ static int cc2_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct cc2_data *data = dev_get_drvdata(dev);
- int ret = 0;
- mutex_lock(&data->dev_access_lock);
+ guard(mutex)(&data->dev_access_lock);
switch (type) {
case hwmon_temp:
- ret = cc2_measurement(data, type, val);
- break;
+ return cc2_measurement(data, type, val);
case hwmon_humidity:
switch (attr) {
case hwmon_humidity_input:
- ret = cc2_measurement(data, type, val);
- break;
+ return cc2_measurement(data, type, val);
case hwmon_humidity_min:
- ret = cc2_get_reg_val(data, CC2_R_ALARM_L_ON, val);
- break;
+ return cc2_get_reg_val(data, CC2_R_ALARM_L_ON, val);
case hwmon_humidity_min_hyst:
- ret = cc2_get_reg_val(data, CC2_R_ALARM_L_OFF, val);
- break;
+ return cc2_get_reg_val(data, CC2_R_ALARM_L_OFF, val);
case hwmon_humidity_max:
- ret = cc2_get_reg_val(data, CC2_R_ALARM_H_ON, val);
- break;
+ return cc2_get_reg_val(data, CC2_R_ALARM_H_ON, val);
case hwmon_humidity_max_hyst:
- ret = cc2_get_reg_val(data, CC2_R_ALARM_H_OFF, val);
- break;
+ return cc2_get_reg_val(data, CC2_R_ALARM_H_OFF, val);
case hwmon_humidity_min_alarm:
- ret = cc2_humidity_min_alarm_status(data, val);
- break;
+ return cc2_humidity_min_alarm_status(data, val);
case hwmon_humidity_max_alarm:
- ret = cc2_humidity_max_alarm_status(data, val);
- break;
+ return cc2_humidity_max_alarm_status(data, val);
default:
- ret = -EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
- break;
default:
- ret = -EOPNOTSUPP;
+ return -EOPNOTSUPP;
}
-
- mutex_unlock(&data->dev_access_lock);
-
- return ret;
}
static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long val)
{
struct cc2_data *data = dev_get_drvdata(dev);
- int ret;
u16 arg;
u8 cmd;
@@ -614,41 +600,28 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
if (val < 0 || val > CC2_RH_MAX)
return -EINVAL;
- mutex_lock(&data->dev_access_lock);
+ guard(mutex)(&data->dev_access_lock);
switch (attr) {
case hwmon_humidity_min:
cmd = CC2_W_ALARM_L_ON;
arg = cc2_rh_to_reg(val);
- ret = cc2_write_reg(data, cmd, arg);
- break;
-
+ return cc2_write_reg(data, cmd, arg);
case hwmon_humidity_min_hyst:
cmd = CC2_W_ALARM_L_OFF;
arg = cc2_rh_to_reg(val);
- ret = cc2_write_reg(data, cmd, arg);
- break;
-
+ return cc2_write_reg(data, cmd, arg);
case hwmon_humidity_max:
cmd = CC2_W_ALARM_H_ON;
arg = cc2_rh_to_reg(val);
- ret = cc2_write_reg(data, cmd, arg);
- break;
-
+ return cc2_write_reg(data, cmd, arg);
case hwmon_humidity_max_hyst:
cmd = CC2_W_ALARM_H_OFF;
arg = cc2_rh_to_reg(val);
- ret = cc2_write_reg(data, cmd, arg);
- break;
-
+ return cc2_write_reg(data, cmd, arg);
default:
- ret = -EOPNOTSUPP;
- break;
+ return -EOPNOTSUPP;
}
-
- mutex_unlock(&data->dev_access_lock);
-
- return ret;
}
static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev)
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index f5bdf842040e..cd00adaad1b4 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -1545,6 +1545,14 @@ static const struct dmi_system_id i8k_whitelist_fan_control[] __initconst = {
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{
+ .ident = "Dell XPS 13 9370",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 13 9370"),
+ },
+ .driver_data = (void *)&i8k_fan_control_data[I8K_FAN_30A3_31A3],
+ },
+ {
.ident = "Dell Optiplex 7000",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index bbb9cc44e29f..b7c0b1e3c23b 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -158,11 +158,6 @@ static umode_t hwmon_is_visible(const struct hwmon_ops *ops,
/* Thermal zone handling */
-/*
- * The complex conditional is necessary to avoid a cyclic dependency
- * between hwmon and thermal_sys modules.
- */
-#ifdef CONFIG_THERMAL_OF
static int hwmon_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
struct hwmon_thermal_data *tdata = thermal_zone_device_priv(tz);
@@ -268,6 +263,9 @@ static int hwmon_thermal_register_sensors(struct device *dev)
void *drvdata = dev_get_drvdata(dev);
int i;
+ if (!IS_ENABLED(CONFIG_THERMAL_OF))
+ return 0;
+
for (i = 1; info[i]; i++) {
int j;
@@ -296,6 +294,9 @@ static void hwmon_thermal_notify(struct device *dev, int index)
struct hwmon_device *hwdev = to_hwmon_device(dev);
struct hwmon_thermal_data *tzdata;
+ if (!IS_ENABLED(CONFIG_THERMAL_OF))
+ return;
+
list_for_each_entry(tzdata, &hwdev->tzdata, node) {
if (tzdata->index == index) {
thermal_zone_device_update(tzdata->tzd,
@@ -304,16 +305,6 @@ static void hwmon_thermal_notify(struct device *dev, int index)
}
}
-#else
-static int hwmon_thermal_register_sensors(struct device *dev)
-{
- return 0;
-}
-
-static void hwmon_thermal_notify(struct device *dev, int index) { }
-
-#endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */
-
static int hwmon_attr_base(enum hwmon_sensor_types type)
{
if (type == hwmon_in || type == hwmon_intrusion)
@@ -1179,6 +1170,12 @@ devm_hwmon_device_register_with_info(struct device *dev, const char *name,
if (!dev)
return ERR_PTR(-EINVAL);
+ if (!name) {
+ name = devm_hwmon_sanitize_name(dev, dev_name(dev));
+ if (IS_ERR(name))
+ return ERR_CAST(name);
+ }
+
ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/hwmon/isl28022.c b/drivers/hwmon/isl28022.c
index f9edcfd164c2..3f9b4520b53e 100644
--- a/drivers/hwmon/isl28022.c
+++ b/drivers/hwmon/isl28022.c
@@ -486,7 +486,7 @@ static int isl28022_probe(struct i2c_client *client)
}
static const struct i2c_device_id isl28022_ids[] = {
- { "isl28022", 0},
+ { "isl28022" },
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, isl28022_ids);
@@ -506,8 +506,7 @@ static struct i2c_driver isl28022_driver = {
.id_table = isl28022_ids,
};
-static int __init
-isl28022_init(void)
+static int __init isl28022_init(void)
{
int err;
@@ -519,15 +518,13 @@ isl28022_init(void)
debugfs_remove_recursive(isl28022_debugfs_root);
return err;
}
+module_init(isl28022_init);
-static void __exit
-isl28022_exit(void)
+static void __exit isl28022_exit(void)
{
i2c_del_driver(&isl28022_driver);
debugfs_remove_recursive(isl28022_debugfs_root);
}
-
-module_init(isl28022_init);
module_exit(isl28022_exit);
MODULE_AUTHOR("Carsten Spieß <mail@carsten-spiess.de>");
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 2c2205aec7d4..d95a3c6c245c 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
+#include <linux/i3c/device.h>
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/of.h>
@@ -38,6 +39,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
max6626,
max31725,
mcp980x,
+ p3t1755,
pct2075,
stds75,
stlm75,
@@ -104,17 +106,15 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
#define LM75_REG_MAX 0x03
#define PCT2075_REG_IDLE 0x04
-/* Each client has this additional data */
struct lm75_data {
- struct i2c_client *client;
struct regmap *regmap;
- struct regulator *vs;
u16 orig_conf;
- u16 current_conf;
u8 resolution; /* In bits, 9 to 16 */
unsigned int sample_time; /* In ms */
enum lm75_type kind;
const struct lm75_params *params;
+ u8 reg_buf[1];
+ u8 val_buf[3];
};
/*-----------------------------------------------------------------------*/
@@ -222,6 +222,13 @@ static const struct lm75_params device_params[] = {
.default_resolution = 9,
.default_sample_time = MSEC_PER_SEC / 18,
},
+ [p3t1755] = {
+ .clr_mask = 1 << 1 | 1 << 7, /* disable SMBAlert and one-shot */
+ .default_resolution = 12,
+ .default_sample_time = 55,
+ .num_sample_times = 4,
+ .sample_times = (unsigned int []){ 28, 55, 110, 220 },
+ },
[pct2075] = {
.default_resolution = 11,
.default_sample_time = MSEC_PER_SEC / 10,
@@ -276,6 +283,7 @@ static const struct lm75_params device_params[] = {
.default_sample_time = 125,
.num_sample_times = 4,
.sample_times = (unsigned int []){ 125, 250, 1000, 4000 },
+ .alarm = true,
},
[tmp175] = {
.set_mask = 3 << 5, /* 12-bit mode */
@@ -332,41 +340,11 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
}
-static int lm75_write_config(struct lm75_data *data, u16 set_mask,
- u16 clr_mask)
-{
- unsigned int value;
-
- clr_mask |= LM75_SHUTDOWN << (8 * data->params->config_reg_16bits);
- value = data->current_conf & ~clr_mask;
- value |= set_mask;
-
- if (data->current_conf != value) {
- s32 err;
- if (data->params->config_reg_16bits)
- err = regmap_write(data->regmap, LM75_REG_CONF, value);
- else
- err = i2c_smbus_write_byte_data(data->client,
- LM75_REG_CONF,
- value);
- if (err)
- return err;
- data->current_conf = value;
- }
- return 0;
-}
-
-static int lm75_read_config(struct lm75_data *data)
+static inline int lm75_write_config(struct lm75_data *data, u16 set_mask,
+ u16 clr_mask)
{
- int ret;
- unsigned int status;
-
- if (data->params->config_reg_16bits) {
- ret = regmap_read(data->regmap, LM75_REG_CONF, &status);
- return ret ? ret : status;
- }
-
- return i2c_smbus_read_byte_data(data->client, LM75_REG_CONF);
+ return regmap_update_bits(data->regmap, LM75_REG_CONF,
+ clr_mask | LM75_SHUTDOWN, set_mask);
}
static irqreturn_t lm75_alarm_handler(int irq, void *private)
@@ -418,7 +396,8 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
if (attr == hwmon_temp_alarm) {
switch (data->kind) {
case as6200:
- *val = (regval >> 5) & 0x1;
+ case tmp112:
+ *val = (regval >> 13) & 0x1;
break;
default:
return -EINVAL;
@@ -469,7 +448,6 @@ static int lm75_write_temp(struct device *dev, u32 attr, long temp)
static int lm75_update_interval(struct device *dev, long val)
{
struct lm75_data *data = dev_get_drvdata(dev);
- unsigned int reg;
u8 index;
s32 err;
@@ -489,19 +467,14 @@ static int lm75_update_interval(struct device *dev, long val)
break;
case tmp112:
case as6200:
- err = regmap_read(data->regmap, LM75_REG_CONF, &reg);
- if (err < 0)
- return err;
- reg &= ~0x00c0;
- reg |= (3 - index) << 6;
- err = regmap_write(data->regmap, LM75_REG_CONF, reg);
+ err = regmap_update_bits(data->regmap, LM75_REG_CONF,
+ 0xc000, (3 - index) << 14);
if (err < 0)
return err;
data->sample_time = data->params->sample_times[index];
break;
case pct2075:
- err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE,
- index + 1);
+ err = regmap_write(data->regmap, PCT2075_REG_IDLE, index + 1);
if (err)
return err;
data->sample_time = data->params->sample_times[index];
@@ -598,6 +571,115 @@ static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg)
return reg == LM75_REG_TEMP || reg == LM75_REG_CONF;
}
+static int lm75_i2c_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct i2c_client *client = context;
+ struct lm75_data *data = i2c_get_clientdata(client);
+ int ret;
+
+ if (reg == LM75_REG_CONF) {
+ if (!data->params->config_reg_16bits)
+ ret = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
+ else
+ ret = i2c_smbus_read_word_data(client, LM75_REG_CONF);
+ } else {
+ ret = i2c_smbus_read_word_swapped(client, reg);
+ }
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return 0;
+}
+
+static int lm75_i2c_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i2c_client *client = context;
+ struct lm75_data *data = i2c_get_clientdata(client);
+
+ if (reg == PCT2075_REG_IDLE ||
+ (reg == LM75_REG_CONF && !data->params->config_reg_16bits))
+ return i2c_smbus_write_byte_data(client, reg, val);
+ else if (reg == LM75_REG_CONF)
+ return i2c_smbus_write_word_data(client, reg, val);
+ return i2c_smbus_write_word_swapped(client, reg, val);
+}
+
+static const struct regmap_bus lm75_i2c_regmap_bus = {
+ .reg_read = lm75_i2c_reg_read,
+ .reg_write = lm75_i2c_reg_write,
+};
+
+static int lm75_i3c_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct i3c_device *i3cdev = context;
+ struct lm75_data *data = i3cdev_get_drvdata(i3cdev);
+ struct i3c_priv_xfer xfers[] = {
+ {
+ .rnw = false,
+ .len = 1,
+ .data.out = data->reg_buf,
+ },
+ {
+ .rnw = true,
+ .len = 2,
+ .data.out = data->val_buf,
+ },
+ };
+ int ret;
+
+ data->reg_buf[0] = reg;
+
+ if (reg == LM75_REG_CONF && !data->params->config_reg_16bits)
+ xfers[1].len--;
+
+ ret = i3c_device_do_priv_xfers(i3cdev, xfers, 2);
+ if (ret < 0)
+ return ret;
+
+ if (reg == LM75_REG_CONF && !data->params->config_reg_16bits)
+ *val = data->val_buf[0];
+ else if (reg == LM75_REG_CONF)
+ *val = data->val_buf[0] | (data->val_buf[1] << 8);
+ else
+ *val = data->val_buf[1] | (data->val_buf[0] << 8);
+
+ return 0;
+}
+
+static int lm75_i3c_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i3c_device *i3cdev = context;
+ struct lm75_data *data = i3cdev_get_drvdata(i3cdev);
+ struct i3c_priv_xfer xfers[] = {
+ {
+ .rnw = false,
+ .len = 3,
+ .data.out = data->val_buf,
+ },
+ };
+
+ data->val_buf[0] = reg;
+
+ if (reg == PCT2075_REG_IDLE ||
+ (reg == LM75_REG_CONF && !data->params->config_reg_16bits)) {
+ xfers[0].len--;
+ data->val_buf[1] = val & 0xff;
+ } else if (reg == LM75_REG_CONF) {
+ data->val_buf[1] = val & 0xff;
+ data->val_buf[2] = (val >> 8) & 0xff;
+ } else {
+ data->val_buf[1] = (val >> 8) & 0xff;
+ data->val_buf[2] = val & 0xff;
+ }
+
+ return i3c_device_do_priv_xfers(i3cdev, xfers, 1);
+}
+
+static const struct regmap_bus lm75_i3c_regmap_bus = {
+ .reg_read = lm75_i3c_reg_read,
+ .reg_write = lm75_i3c_reg_write,
+};
+
static const struct regmap_config lm75_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
@@ -610,46 +692,33 @@ static const struct regmap_config lm75_regmap_config = {
.use_single_write = true,
};
-static void lm75_disable_regulator(void *data)
-{
- struct lm75_data *lm75 = data;
-
- regulator_disable(lm75->vs);
-}
-
static void lm75_remove(void *data)
{
struct lm75_data *lm75 = data;
- struct i2c_client *client = lm75->client;
- i2c_smbus_write_byte_data(client, LM75_REG_CONF, lm75->orig_conf);
+ regmap_write(lm75->regmap, LM75_REG_CONF, lm75->orig_conf);
}
-static int lm75_probe(struct i2c_client *client)
+static int lm75_generic_probe(struct device *dev, const char *name,
+ enum lm75_type kind, int irq, struct regmap *regmap)
{
- struct device *dev = &client->dev;
struct device *hwmon_dev;
struct lm75_data *data;
int status, err;
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
- return -EIO;
-
data = devm_kzalloc(dev, sizeof(struct lm75_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->client = client;
- data->kind = (uintptr_t)i2c_get_match_data(client);
+ /* needed by custom regmap callbacks */
+ dev_set_drvdata(dev, data);
- data->vs = devm_regulator_get(dev, "vs");
- if (IS_ERR(data->vs))
- return PTR_ERR(data->vs);
+ data->kind = kind;
+ data->regmap = regmap;
- data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config);
- if (IS_ERR(data->regmap))
- return PTR_ERR(data->regmap);
+ err = devm_regulator_get_enable(dev, "vs");
+ if (err)
+ return err;
/* Set to LM75 resolution (9 bits, 1/2 degree C) and range.
* Then tweak to be more precise when appropriate.
@@ -661,25 +730,11 @@ static int lm75_probe(struct i2c_client *client)
data->sample_time = data->params->default_sample_time;
data->resolution = data->params->default_resolution;
- /* Enable the power */
- err = regulator_enable(data->vs);
- if (err) {
- dev_err(dev, "failed to enable regulator: %d\n", err);
- return err;
- }
-
- err = devm_add_action_or_reset(dev, lm75_disable_regulator, data);
+ /* Cache original configuration */
+ err = regmap_read(data->regmap, LM75_REG_CONF, &status);
if (err)
return err;
-
- /* Cache original configuration */
- status = lm75_read_config(data);
- if (status < 0) {
- dev_dbg(dev, "Can't read config? %d\n", status);
- return status;
- }
data->orig_conf = status;
- data->current_conf = status;
err = lm75_write_config(data, data->params->set_mask,
data->params->clr_mask);
@@ -690,20 +745,19 @@ static int lm75_probe(struct i2c_client *client)
if (err)
return err;
- hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
- data, &lm75_chip_info,
- NULL);
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, name, data,
+ &lm75_chip_info, NULL);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
- if (client->irq) {
+ if (irq) {
if (data->params->alarm) {
err = devm_request_threaded_irq(dev,
- client->irq,
+ irq,
NULL,
&lm75_alarm_handler,
IRQF_ONESHOT,
- client->name,
+ name,
hwmon_dev);
if (err)
return err;
@@ -713,12 +767,29 @@ static int lm75_probe(struct i2c_client *client)
}
}
- dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name);
+ dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), name);
return 0;
}
-static const struct i2c_device_id lm75_ids[] = {
+static int lm75_i2c_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct regmap *regmap;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+ return -EOPNOTSUPP;
+
+ regmap = devm_regmap_init(dev, &lm75_i2c_regmap_bus, client, &lm75_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return lm75_generic_probe(dev, client->name, (uintptr_t)i2c_get_match_data(client),
+ client->irq, regmap);
+}
+
+static const struct i2c_device_id lm75_i2c_ids[] = {
{ "adt75", adt75, },
{ "as6200", as6200, },
{ "at30ts74", at30ts74, },
@@ -734,6 +805,7 @@ static const struct i2c_device_id lm75_ids[] = {
{ "max31725", max31725, },
{ "max31726", max31725, },
{ "mcp980x", mcp980x, },
+ { "p3t1755", p3t1755, },
{ "pct2075", pct2075, },
{ "stds75", stds75, },
{ "stlm75", stlm75, },
@@ -750,7 +822,38 @@ static const struct i2c_device_id lm75_ids[] = {
{ "tmp1075", tmp1075, },
{ /* LIST END */ }
};
-MODULE_DEVICE_TABLE(i2c, lm75_ids);
+MODULE_DEVICE_TABLE(i2c, lm75_i2c_ids);
+
+struct lm75_i3c_device {
+ enum lm75_type type;
+ const char *name;
+};
+
+static const struct lm75_i3c_device lm75_i3c_p3t1755 = {
+ .name = "p3t1755",
+ .type = p3t1755,
+};
+
+static const struct i3c_device_id lm75_i3c_ids[] = {
+ I3C_DEVICE(0x011b, 0x152a, &lm75_i3c_p3t1755),
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i3c, lm75_i3c_ids);
+
+static int lm75_i3c_probe(struct i3c_device *i3cdev)
+{
+ struct device *dev = i3cdev_to_dev(i3cdev);
+ const struct lm75_i3c_device *id_data;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init(dev, &lm75_i3c_regmap_bus, i3cdev, &lm75_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ id_data = i3c_device_match_id(i3cdev, lm75_i3c_ids)->data;
+
+ return lm75_generic_probe(dev, id_data->name, id_data->type, 0, regmap);
+}
static const struct of_device_id __maybe_unused lm75_of_match[] = {
{
@@ -814,6 +917,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
.data = (void *)mcp980x
},
{
+ .compatible = "nxp,p3t1755",
+ .data = (void *)p3t1755
+ },
+ {
.compatible = "nxp,pct2075",
.data = (void *)pct2075
},
@@ -972,32 +1079,16 @@ static int lm75_detect(struct i2c_client *new_client,
#ifdef CONFIG_PM
static int lm75_suspend(struct device *dev)
{
- int status;
- struct i2c_client *client = to_i2c_client(dev);
+ struct lm75_data *data = dev_get_drvdata(dev);
- status = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
- if (status < 0) {
- dev_dbg(&client->dev, "Can't read config? %d\n", status);
- return status;
- }
- status = status | LM75_SHUTDOWN;
- i2c_smbus_write_byte_data(client, LM75_REG_CONF, status);
- return 0;
+ return regmap_update_bits(data->regmap, LM75_REG_CONF, LM75_SHUTDOWN, LM75_SHUTDOWN);
}
static int lm75_resume(struct device *dev)
{
- int status;
- struct i2c_client *client = to_i2c_client(dev);
+ struct lm75_data *data = dev_get_drvdata(dev);
- status = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
- if (status < 0) {
- dev_dbg(&client->dev, "Can't read config? %d\n", status);
- return status;
- }
- status = status & ~LM75_SHUTDOWN;
- i2c_smbus_write_byte_data(client, LM75_REG_CONF, status);
- return 0;
+ return regmap_update_bits(data->regmap, LM75_REG_CONF, LM75_SHUTDOWN, 0);
}
static const struct dev_pm_ops lm75_dev_pm_ops = {
@@ -1009,20 +1100,28 @@ static const struct dev_pm_ops lm75_dev_pm_ops = {
#define LM75_DEV_PM_OPS NULL
#endif /* CONFIG_PM */
-static struct i2c_driver lm75_driver = {
+static struct i2c_driver lm75_i2c_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm75",
.of_match_table = of_match_ptr(lm75_of_match),
.pm = LM75_DEV_PM_OPS,
},
- .probe = lm75_probe,
- .id_table = lm75_ids,
+ .probe = lm75_i2c_probe,
+ .id_table = lm75_i2c_ids,
.detect = lm75_detect,
.address_list = normal_i2c,
};
-module_i2c_driver(lm75_driver);
+static struct i3c_driver lm75_i3c_driver = {
+ .driver = {
+ .name = "lm75_i3c",
+ },
+ .probe = lm75_i3c_probe,
+ .id_table = lm75_i3c_ids,
+};
+
+module_i3c_i2c_driver(lm75_i3c_driver, &lm75_i2c_driver)
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
MODULE_DESCRIPTION("LM75 driver");
diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c
index f71615e06a8f..416ac02e9f74 100644
--- a/drivers/hwmon/nct6683.c
+++ b/drivers/hwmon/nct6683.c
@@ -175,9 +175,11 @@ superio_exit(int ioreg)
#define NCT6683_CUSTOMER_ID_MSI 0x201
#define NCT6683_CUSTOMER_ID_MSI2 0x200
#define NCT6683_CUSTOMER_ID_MSI3 0x207
+#define NCT6683_CUSTOMER_ID_MSI4 0x20d
#define NCT6683_CUSTOMER_ID_ASROCK 0xe2c
#define NCT6683_CUSTOMER_ID_ASROCK2 0xe1b
#define NCT6683_CUSTOMER_ID_ASROCK3 0x1631
+#define NCT6683_CUSTOMER_ID_ASROCK4 0x163e
#define NCT6683_REG_BUILD_YEAR 0x604
#define NCT6683_REG_BUILD_MONTH 0x605
@@ -1227,12 +1229,16 @@ static int nct6683_probe(struct platform_device *pdev)
break;
case NCT6683_CUSTOMER_ID_MSI3:
break;
+ case NCT6683_CUSTOMER_ID_MSI4:
+ break;
case NCT6683_CUSTOMER_ID_ASROCK:
break;
case NCT6683_CUSTOMER_ID_ASROCK2:
break;
case NCT6683_CUSTOMER_ID_ASROCK3:
break;
+ case NCT6683_CUSTOMER_ID_ASROCK4:
+ break;
default:
if (!force)
return -ENODEV;
diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c
index c243b51837d2..fa3351351825 100644
--- a/drivers/hwmon/nct6775-core.c
+++ b/drivers/hwmon/nct6775-core.c
@@ -42,6 +42,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#undef DEFAULT_SYMBOL_NAMESPACE
+#define DEFAULT_SYMBOL_NAMESPACE "HWMON_NCT6775"
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -56,9 +59,6 @@
#include "lm75.h"
#include "nct6775.h"
-#undef DEFAULT_SYMBOL_NAMESPACE
-#define DEFAULT_SYMBOL_NAMESPACE "HWMON_NCT6775"
-
#define USE_ALTERNATE
/* used to set data->name = nct6775_device_names[data->sio_kind] */
diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c
index 89761a9c8892..1e3749dfa598 100644
--- a/drivers/hwmon/occ/p9_sbe.c
+++ b/drivers/hwmon/occ/p9_sbe.c
@@ -30,7 +30,7 @@ struct p9_sbe_occ {
#define to_p9_sbe_occ(x) container_of((x), struct p9_sbe_occ, occ)
static ssize_t ffdc_read(struct file *filp, struct kobject *kobj,
- struct bin_attribute *battr, char *buf, loff_t pos,
+ const struct bin_attribute *battr, char *buf, loff_t pos,
size_t count)
{
ssize_t rc = 0;
@@ -48,7 +48,7 @@ static ssize_t ffdc_read(struct file *filp, struct kobject *kobj,
return rc;
}
-static BIN_ATTR_RO(ffdc, OCC_MAX_RESP_WORDS * 4);
+static const BIN_ATTR_RO(ffdc, OCC_MAX_RESP_WORDS * 4);
static bool p9_sbe_occ_save_ffdc(struct p9_sbe_occ *ctx, const void *resp,
size_t resp_len)
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index f6d352841953..419469f40ba0 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -51,7 +51,7 @@ config SENSORS_ADM1275
tristate "Analog Devices ADM1275 and compatibles"
help
If you say yes here you get hardware monitoring support for Analog
- Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1281,
+ Devices ADM1075, ADM1272, ADM1273, ADM1275, ADM1276, ADM1278, ADM1281,
ADM1293, and ADM1294 Hot-Swap Controller and Digital Power Monitors.
This driver can also be built as a module. If so, the module will
@@ -85,6 +85,15 @@ config SENSORS_BPA_RS600
This driver can also be built as a module. If so, the module will
be called bpa-rs600.
+config SENSORS_CRPS
+ tristate "Intel Common Redundant Power Supply"
+ help
+ If you say yes here you get hardware monitoring support for the Intel
+ Common Redundant Power Supply.
+
+ This driver can also be built as a module. If so, the module will
+ be called crps.
+
config SENSORS_DELTA_AHE50DC_FAN
tristate "Delta AHE-50DC fan control module"
help
@@ -251,7 +260,7 @@ config SENSORS_MAX15301
tristate "Maxim MAX15301"
help
If you say yes here you get hardware monitoring support for Maxim
- MAX15301, as well as for Flex BMR461.
+ MAX15301, MAX15303, as well as for Flex BMR461.
This driver can also be built as a module. If so, the module will
be called max15301.
@@ -510,6 +519,23 @@ config SENSORS_TDA38640_REGULATOR
If you say yes here you get regulator support for Infineon
TDA38640 as regulator.
+config SENSORS_TPS25990
+ tristate "TI TPS25990"
+ help
+ If you say yes here you get hardware monitoring support for TI
+ TPS25990.
+
+ This driver can also be built as a module. If so, the module will
+ be called tps25990.
+
+config SENSORS_TPS25990_REGULATOR
+ bool "Regulator support for TPS25990 and compatibles"
+ depends on SENSORS_TPS25990 && REGULATOR
+ default SENSORS_TPS25990
+ help
+ If you say yes here you get regulator support for Texas Instruments
+ TPS25990.
+
config SENSORS_TPS40422
tristate "TI TPS40422"
help
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index d00bcc758b97..c7eb7739b7f8 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -51,6 +51,7 @@ 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_TPS25990) += tps25990.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_TPS546D24) += tps546d24.o
@@ -61,3 +62,4 @@ obj-$(CONFIG_SENSORS_XDPE122) += xdpe12284.o
obj-$(CONFIG_SENSORS_XDPE152) += xdpe152c4.o
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
obj-$(CONFIG_SENSORS_PIM4328) += pim4328.o
+obj-$(CONFIG_SENSORS_CRPS) += crps.o
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index 127593e10a03..7d175baa5de2 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -18,7 +18,7 @@
#include <linux/log2.h>
#include "pmbus.h"
-enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1281, adm1293, adm1294 };
+enum chips { adm1075, adm1272, adm1273, adm1275, adm1276, adm1278, adm1281, adm1293, adm1294 };
#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0)
#define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5)
@@ -479,6 +479,7 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
static const struct i2c_device_id adm1275_id[] = {
{ "adm1075", adm1075 },
{ "adm1272", adm1272 },
+ { "adm1273", adm1273 },
{ "adm1275", adm1275 },
{ "adm1276", adm1276 },
{ "adm1278", adm1278 },
@@ -555,9 +556,9 @@ static int adm1275_probe(struct i2c_client *client)
"Device mismatch: Configured %s, detected %s\n",
client->name, mid->name);
- if (mid->driver_data == adm1272 || mid->driver_data == adm1278 ||
- mid->driver_data == adm1281 || mid->driver_data == adm1293 ||
- mid->driver_data == adm1294)
+ if (mid->driver_data == adm1272 || mid->driver_data == adm1273 ||
+ mid->driver_data == adm1278 || mid->driver_data == adm1281 ||
+ mid->driver_data == adm1293 || mid->driver_data == adm1294)
config_read_fn = i2c_smbus_read_word_data;
else
config_read_fn = i2c_smbus_read_byte_data;
@@ -630,6 +631,7 @@ static int adm1275_probe(struct i2c_client *client)
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
break;
case adm1272:
+ case adm1273:
data->have_vout = true;
data->have_pin_max = true;
data->have_temp_max = true;
diff --git a/drivers/hwmon/pmbus/crps.c b/drivers/hwmon/pmbus/crps.c
new file mode 100644
index 000000000000..164b33fed312
--- /dev/null
+++ b/drivers/hwmon/pmbus/crps.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2024 IBM Corp.
+ */
+
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/pmbus.h>
+
+#include "pmbus.h"
+
+static const struct i2c_device_id crps_id[] = {
+ { "intel_crps185" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, crps_id);
+
+static struct pmbus_driver_info crps_info = {
+ .pages = 1,
+ /* PSU uses default linear data format. */
+ .func[0] = PMBUS_HAVE_PIN | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_IIN |
+ PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
+ PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12,
+};
+
+static int crps_probe(struct i2c_client *client)
+{
+ int rc;
+ struct device *dev = &client->dev;
+ char buf[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
+
+ rc = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+ if (rc < 0)
+ return dev_err_probe(dev, rc, "Failed to read PMBUS_MFR_MODEL\n");
+
+ if (rc != 7 || strncmp(buf, "03NK260", 7)) {
+ buf[rc] = '\0';
+ return dev_err_probe(dev, -ENODEV, "Model '%s' not supported\n", buf);
+ }
+
+ rc = pmbus_do_probe(client, &crps_info);
+ if (rc)
+ return dev_err_probe(dev, rc, "Failed to probe\n");
+
+ return 0;
+}
+
+static const struct of_device_id crps_of_match[] = {
+ {
+ .compatible = "intel,crps185",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, crps_of_match);
+
+static struct i2c_driver crps_driver = {
+ .driver = {
+ .name = "crps",
+ .of_match_table = crps_of_match,
+ },
+ .probe = crps_probe,
+ .id_table = crps_id,
+};
+
+module_i2c_driver(crps_driver);
+
+MODULE_AUTHOR("Ninad Palsule");
+MODULE_DESCRIPTION("PMBus driver for Intel Common Redundant power supplies");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("PMBUS");
diff --git a/drivers/hwmon/pmbus/dps920ab.c b/drivers/hwmon/pmbus/dps920ab.c
index cc5aac9dfdb3..325111a955e6 100644
--- a/drivers/hwmon/pmbus/dps920ab.c
+++ b/drivers/hwmon/pmbus/dps920ab.c
@@ -190,12 +190,19 @@ static const struct of_device_id __maybe_unused dps920ab_of_match[] = {
MODULE_DEVICE_TABLE(of, dps920ab_of_match);
+static const struct i2c_device_id dps920ab_device_id[] = {
+ { "dps920ab" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, dps920ab_device_id);
+
static struct i2c_driver dps920ab_driver = {
.driver = {
.name = "dps920ab",
.of_match_table = of_match_ptr(dps920ab_of_match),
},
.probe = dps920ab_probe,
+ .id_table = dps920ab_device_id,
};
module_i2c_driver(dps920ab_driver);
diff --git a/drivers/hwmon/pmbus/max15301.c b/drivers/hwmon/pmbus/max15301.c
index 50dfd477772f..d5810b88ea8d 100644
--- a/drivers/hwmon/pmbus/max15301.c
+++ b/drivers/hwmon/pmbus/max15301.c
@@ -25,6 +25,7 @@
static const struct i2c_device_id max15301_id[] = {
{ "bmr461" },
{ "max15301" },
+ { "max15303" },
{}
};
MODULE_DEVICE_TABLE(i2c, max15301_id);
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index d605412a3173..ddb19c9726d6 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -487,6 +487,8 @@ struct pmbus_driver_info {
/* Regulator ops */
extern const struct regulator_ops pmbus_regulator_ops;
+int pmbus_regulator_init_cb(struct regulator_dev *rdev,
+ struct regulator_config *config);
/* Macros for filling in array of struct regulator_desc */
#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step, _min_uV) \
@@ -501,6 +503,7 @@ extern const struct regulator_ops pmbus_regulator_ops;
.n_voltages = _voltages, \
.uV_step = _step, \
.min_uV = _min_uV, \
+ .init_cb = pmbus_regulator_init_cb, \
}
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0, 0)
@@ -516,6 +519,7 @@ extern const struct regulator_ops pmbus_regulator_ops;
.n_voltages = _voltages, \
.uV_step = _step, \
.min_uV = _min_uV, \
+ .init_cb = pmbus_regulator_init_cb, \
}
#define PMBUS_REGULATOR_ONE(_name) PMBUS_REGULATOR_STEP_ONE(_name, 0, 0, 0)
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index a1375cb6b648..787683e83db6 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -31,6 +31,9 @@
#define PMBUS_ATTR_ALLOC_SIZE 32
#define PMBUS_NAME_SIZE 24
+static int wp = -1;
+module_param(wp, int, 0444);
+
struct pmbus_sensor {
struct pmbus_sensor *next;
char name[PMBUS_NAME_SIZE]; /* sysfs sensor name */
@@ -2665,6 +2668,56 @@ static void pmbus_remove_pec(void *dev)
device_remove_file(dev, &dev_attr_pec);
}
+static void pmbus_init_wp(struct i2c_client *client, struct pmbus_data *data)
+{
+ int ret;
+
+ switch (wp) {
+ case 0:
+ _pmbus_write_byte_data(client, -1,
+ PMBUS_WRITE_PROTECT, 0);
+ break;
+
+ case 1:
+ _pmbus_write_byte_data(client, -1,
+ PMBUS_WRITE_PROTECT, PB_WP_VOUT);
+ break;
+
+ case 2:
+ _pmbus_write_byte_data(client, -1,
+ PMBUS_WRITE_PROTECT, PB_WP_OP);
+ break;
+
+ case 3:
+ _pmbus_write_byte_data(client, -1,
+ PMBUS_WRITE_PROTECT, PB_WP_ALL);
+ break;
+
+ default:
+ /* Ignore the other values */
+ break;
+ }
+
+ ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT);
+ if (ret < 0)
+ return;
+
+ switch (ret & PB_WP_ANY) {
+ case PB_WP_ALL:
+ data->flags |= PMBUS_OP_PROTECTED;
+ fallthrough;
+ case PB_WP_OP:
+ data->flags |= PMBUS_VOUT_PROTECTED;
+ fallthrough;
+ case PB_WP_VOUT:
+ data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
+ break;
+
+ default:
+ break;
+ }
+}
+
static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
struct pmbus_driver_info *info)
{
@@ -2718,12 +2771,8 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
* faults, and we should not try it. Also, in that case, writes into
* limit registers need to be disabled.
*/
- if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) {
- ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT);
-
- if (ret > 0 && (ret & PB_WP_ANY))
- data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK;
- }
+ if (!(data->flags & PMBUS_NO_WRITE_PROTECT))
+ pmbus_init_wp(client, data);
ret = i2c_smbus_read_byte_data(client, PMBUS_REVISION);
if (ret >= 0)
@@ -3183,8 +3232,12 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
{
struct device *dev = rdev_get_dev(rdev);
struct i2c_client *client = to_i2c_client(dev->parent);
+ struct pmbus_data *data = i2c_get_clientdata(client);
int val, low, high;
+ if (data->flags & PMBUS_VOUT_PROTECTED)
+ return 0;
+
if (selector >= rdev->desc->n_voltages ||
selector < rdev->desc->linear_min_sel)
return -EINVAL;
@@ -3219,6 +3272,22 @@ const struct regulator_ops pmbus_regulator_ops = {
};
EXPORT_SYMBOL_NS_GPL(pmbus_regulator_ops, "PMBUS");
+int pmbus_regulator_init_cb(struct regulator_dev *rdev,
+ struct regulator_config *config)
+{
+ struct pmbus_data *data = config->driver_data;
+ struct regulation_constraints *constraints = rdev->constraints;
+
+ if (data->flags & PMBUS_OP_PROTECTED)
+ constraints->valid_ops_mask &= ~REGULATOR_CHANGE_STATUS;
+
+ if (data->flags & PMBUS_VOUT_PROTECTED)
+ constraints->valid_ops_mask &= ~REGULATOR_CHANGE_VOLTAGE;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(pmbus_regulator_init_cb, "PMBUS");
+
static int pmbus_regulator_register(struct pmbus_data *data)
{
struct device *dev = data->dev;
@@ -3465,11 +3534,11 @@ static int pmbus_init_debugfs(struct i2c_client *client,
/*
* Allocate the max possible entries we need.
- * 6 entries device-specific
+ * 7 entries device-specific
* 10 entries page-specific
*/
entries = devm_kcalloc(data->dev,
- 6 + data->info->pages * 10, sizeof(*entries),
+ 7 + data->info->pages * 10, sizeof(*entries),
GFP_KERNEL);
if (!entries)
return -ENOMEM;
@@ -3482,6 +3551,15 @@ static int pmbus_init_debugfs(struct i2c_client *client,
* assume that values of the following registers are the same for all
* pages and report values only for page 0.
*/
+ if (pmbus_check_byte_register(client, 0, PMBUS_REVISION)) {
+ entries[idx].client = client;
+ entries[idx].page = 0;
+ entries[idx].reg = PMBUS_REVISION;
+ debugfs_create_file("revision", 0444, data->debugfs,
+ &entries[idx++],
+ &pmbus_debugfs_ops);
+ }
+
if (pmbus_check_block_register(client, 0, PMBUS_MFR_ID)) {
entries[idx].client = client;
entries[idx].page = 0;
diff --git a/drivers/hwmon/pmbus/tps25990.c b/drivers/hwmon/pmbus/tps25990.c
new file mode 100644
index 000000000000..0d2655e69549
--- /dev/null
+++ b/drivers/hwmon/pmbus/tps25990.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 BayLibre, SAS.
+// Author: Jerome Brunet <jbrunet@baylibre.com>
+
+#include <linux/bitfield.h>
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "pmbus.h"
+
+#define TPS25990_READ_VAUX 0xd0
+#define TPS25990_READ_VIN_MIN 0xd1
+#define TPS25990_READ_VIN_PEAK 0xd2
+#define TPS25990_READ_IIN_PEAK 0xd4
+#define TPS25990_READ_PIN_PEAK 0xd5
+#define TPS25990_READ_TEMP_AVG 0xd6
+#define TPS25990_READ_TEMP_PEAK 0xd7
+#define TPS25990_READ_VOUT_MIN 0xda
+#define TPS25990_READ_VIN_AVG 0xdc
+#define TPS25990_READ_VOUT_AVG 0xdd
+#define TPS25990_READ_IIN_AVG 0xde
+#define TPS25990_READ_PIN_AVG 0xdf
+#define TPS25990_VIREF 0xe0
+#define TPS25990_PK_MIN_AVG 0xea
+#define PK_MIN_AVG_RST_PEAK BIT(7)
+#define PK_MIN_AVG_RST_AVG BIT(6)
+#define PK_MIN_AVG_RST_MIN BIT(5)
+#define PK_MIN_AVG_AVG_CNT GENMASK(2, 0)
+#define TPS25990_MFR_WRITE_PROTECT 0xf8
+#define TPS25990_UNLOCKED BIT(7)
+
+#define TPS25990_8B_SHIFT 2
+#define TPS25990_VIN_OVF_NUM 525100
+#define TPS25990_VIN_OVF_DIV 10163
+#define TPS25990_VIN_OVF_OFF 155
+#define TPS25990_IIN_OCF_NUM 953800
+#define TPS25990_IIN_OCF_DIV 129278
+#define TPS25990_IIN_OCF_OFF 157
+
+#define PK_MIN_AVG_RST_MASK (PK_MIN_AVG_RST_PEAK | \
+ PK_MIN_AVG_RST_AVG | \
+ PK_MIN_AVG_RST_MIN)
+
+/*
+ * Arbitrary default Rimon value: 1kOhm
+ * This correspond to an overcurrent limit of 55A, close to the specified limit
+ * of un-stacked TPS25990 and makes further calculation easier to setup in
+ * sensor.conf, if necessary
+ */
+#define TPS25990_DEFAULT_RIMON 1000000000
+
+static void tps25990_set_m(int *m, u32 rimon)
+{
+ u64 val = ((u64)*m) * rimon;
+
+ /* Make sure m fits the s32 type */
+ *m = DIV_ROUND_CLOSEST_ULL(val, 1000000);
+}
+
+static int tps25990_mfr_write_protect_set(struct i2c_client *client,
+ u8 protect)
+{
+ u8 val;
+
+ switch (protect) {
+ case 0:
+ val = 0xa2;
+ break;
+ case PB_WP_ALL:
+ val = 0x0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return pmbus_write_byte_data(client, -1, TPS25990_MFR_WRITE_PROTECT,
+ val);
+}
+
+static int tps25990_mfr_write_protect_get(struct i2c_client *client)
+{
+ int ret = pmbus_read_byte_data(client, -1, TPS25990_MFR_WRITE_PROTECT);
+
+ if (ret < 0)
+ return ret;
+
+ return (ret & TPS25990_UNLOCKED) ? 0 : PB_WP_ALL;
+}
+
+static int tps25990_read_word_data(struct i2c_client *client,
+ int page, int phase, int reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_READ_VIN_MAX:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_VIN_PEAK);
+ break;
+
+ case PMBUS_VIRT_READ_VIN_MIN:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_VIN_MIN);
+ break;
+
+ case PMBUS_VIRT_READ_VIN_AVG:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_VIN_AVG);
+ break;
+
+ case PMBUS_VIRT_READ_VOUT_MIN:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_VOUT_MIN);
+ break;
+
+ case PMBUS_VIRT_READ_VOUT_AVG:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_VOUT_AVG);
+ break;
+
+ case PMBUS_VIRT_READ_IIN_AVG:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_IIN_AVG);
+ break;
+
+ case PMBUS_VIRT_READ_IIN_MAX:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_IIN_PEAK);
+ break;
+
+ case PMBUS_VIRT_READ_TEMP_AVG:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_TEMP_AVG);
+ break;
+
+ case PMBUS_VIRT_READ_TEMP_MAX:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_TEMP_PEAK);
+ break;
+
+ case PMBUS_VIRT_READ_PIN_AVG:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_PIN_AVG);
+ break;
+
+ case PMBUS_VIRT_READ_PIN_MAX:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_PIN_PEAK);
+ break;
+
+ case PMBUS_VIRT_READ_VMON:
+ ret = pmbus_read_word_data(client, page, phase,
+ TPS25990_READ_VAUX);
+ break;
+
+ case PMBUS_VIN_UV_WARN_LIMIT:
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ case PMBUS_VOUT_UV_WARN_LIMIT:
+ case PMBUS_IIN_OC_WARN_LIMIT:
+ case PMBUS_OT_WARN_LIMIT:
+ case PMBUS_OT_FAULT_LIMIT:
+ case PMBUS_PIN_OP_WARN_LIMIT:
+ /*
+ * These registers provide an 8 bits value instead of a
+ * 10bits one. Just shifting twice the register value is
+ * enough to make the sensor type conversion work, even
+ * if the datasheet provides different m, b and R for
+ * those.
+ */
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ break;
+ ret <<= TPS25990_8B_SHIFT;
+ break;
+
+ case PMBUS_VIN_OV_FAULT_LIMIT:
+ ret = pmbus_read_word_data(client, page, phase, reg);
+ if (ret < 0)
+ break;
+ ret = DIV_ROUND_CLOSEST(ret * TPS25990_VIN_OVF_NUM,
+ TPS25990_VIN_OVF_DIV);
+ ret += TPS25990_VIN_OVF_OFF;
+ break;
+
+ case PMBUS_IIN_OC_FAULT_LIMIT:
+ /*
+ * VIREF directly sets the over-current limit at which the eFuse
+ * will turn the FET off and trigger a fault. Expose it through
+ * this generic property instead of a manufacturer specific one.
+ */
+ ret = pmbus_read_byte_data(client, page, TPS25990_VIREF);
+ if (ret < 0)
+ break;
+ ret = DIV_ROUND_CLOSEST(ret * TPS25990_IIN_OCF_NUM,
+ TPS25990_IIN_OCF_DIV);
+ ret += TPS25990_IIN_OCF_OFF;
+ break;
+
+ case PMBUS_VIRT_SAMPLES:
+ ret = pmbus_read_byte_data(client, page, TPS25990_PK_MIN_AVG);
+ if (ret < 0)
+ break;
+ ret = 1 << FIELD_GET(PK_MIN_AVG_AVG_CNT, ret);
+ break;
+
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ case PMBUS_VIRT_RESET_VIN_HISTORY:
+ case PMBUS_VIRT_RESET_IIN_HISTORY:
+ case PMBUS_VIRT_RESET_PIN_HISTORY:
+ case PMBUS_VIRT_RESET_VOUT_HISTORY:
+ ret = 0;
+ break;
+
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+static int tps25990_write_word_data(struct i2c_client *client,
+ int page, int reg, u16 value)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIN_UV_WARN_LIMIT:
+ case PMBUS_VIN_UV_FAULT_LIMIT:
+ case PMBUS_VIN_OV_WARN_LIMIT:
+ case PMBUS_VOUT_UV_WARN_LIMIT:
+ case PMBUS_IIN_OC_WARN_LIMIT:
+ case PMBUS_OT_WARN_LIMIT:
+ case PMBUS_OT_FAULT_LIMIT:
+ case PMBUS_PIN_OP_WARN_LIMIT:
+ value >>= TPS25990_8B_SHIFT;
+ value = clamp_val(value, 0, 0xff);
+ ret = pmbus_write_word_data(client, page, reg, value);
+ break;
+
+ case PMBUS_VIN_OV_FAULT_LIMIT:
+ value -= TPS25990_VIN_OVF_OFF;
+ value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_VIN_OVF_DIV,
+ TPS25990_VIN_OVF_NUM);
+ value = clamp_val(value, 0, 0xf);
+ ret = pmbus_write_word_data(client, page, reg, value);
+ break;
+
+ case PMBUS_IIN_OC_FAULT_LIMIT:
+ value -= TPS25990_IIN_OCF_OFF;
+ value = DIV_ROUND_CLOSEST(((unsigned int)value) * TPS25990_IIN_OCF_DIV,
+ TPS25990_IIN_OCF_NUM);
+ value = clamp_val(value, 0, 0x3f);
+ ret = pmbus_write_byte_data(client, page, TPS25990_VIREF, value);
+ break;
+
+ case PMBUS_VIRT_SAMPLES:
+ value = clamp_val(value, 1, 1 << PK_MIN_AVG_AVG_CNT);
+ value = ilog2(value);
+ ret = pmbus_update_byte_data(client, page, TPS25990_PK_MIN_AVG,
+ PK_MIN_AVG_AVG_CNT,
+ FIELD_PREP(PK_MIN_AVG_AVG_CNT, value));
+ break;
+
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ case PMBUS_VIRT_RESET_VIN_HISTORY:
+ case PMBUS_VIRT_RESET_IIN_HISTORY:
+ case PMBUS_VIRT_RESET_PIN_HISTORY:
+ case PMBUS_VIRT_RESET_VOUT_HISTORY:
+ /*
+ * TPS25990 has history resets based on MIN/AVG/PEAK instead of per
+ * sensor type. Exposing this quirk in hwmon is not desirable so
+ * reset MIN, AVG and PEAK together. Even is there effectively only
+ * one reset, which resets everything, expose the 5 entries so
+ * userspace is not required map a sensor type to another to trigger
+ * a reset
+ */
+ ret = pmbus_update_byte_data(client, 0, TPS25990_PK_MIN_AVG,
+ PK_MIN_AVG_RST_MASK,
+ PK_MIN_AVG_RST_MASK);
+ break;
+
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+static int tps25990_read_byte_data(struct i2c_client *client,
+ int page, int reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_WRITE_PROTECT:
+ ret = tps25990_mfr_write_protect_get(client);
+ break;
+
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+static int tps25990_write_byte_data(struct i2c_client *client,
+ int page, int reg, u8 byte)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_WRITE_PROTECT:
+ ret = tps25990_mfr_write_protect_set(client, byte);
+ break;
+
+ default:
+ ret = -ENODATA;
+ break;
+ }
+
+ return ret;
+}
+
+#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR)
+static const struct regulator_desc tps25990_reg_desc[] = {
+ PMBUS_REGULATOR_ONE("vout"),
+};
+#endif
+
+static const struct pmbus_driver_info tps25990_base_info = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = direct,
+ .m[PSC_VOLTAGE_IN] = 5251,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = -2,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .m[PSC_VOLTAGE_OUT] = 5251,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = -2,
+ .format[PSC_TEMPERATURE] = direct,
+ .m[PSC_TEMPERATURE] = 140,
+ .b[PSC_TEMPERATURE] = 32100,
+ .R[PSC_TEMPERATURE] = -2,
+ /*
+ * Current and Power measurement depends on the ohm value
+ * of Rimon. m is multiplied by 1000 below to have an integer
+ * and -3 is added to R to compensate.
+ */
+ .format[PSC_CURRENT_IN] = direct,
+ .m[PSC_CURRENT_IN] = 9538,
+ .b[PSC_CURRENT_IN] = 0,
+ .R[PSC_CURRENT_IN] = -6,
+ .format[PSC_POWER] = direct,
+ .m[PSC_POWER] = 4901,
+ .b[PSC_POWER] = 0,
+ .R[PSC_POWER] = -7,
+ .func[0] = (PMBUS_HAVE_VIN |
+ PMBUS_HAVE_VOUT |
+ PMBUS_HAVE_VMON |
+ PMBUS_HAVE_IIN |
+ PMBUS_HAVE_PIN |
+ PMBUS_HAVE_TEMP |
+ PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_SAMPLES),
+ .read_word_data = tps25990_read_word_data,
+ .write_word_data = tps25990_write_word_data,
+ .read_byte_data = tps25990_read_byte_data,
+ .write_byte_data = tps25990_write_byte_data,
+
+#if IS_ENABLED(CONFIG_SENSORS_TPS25990_REGULATOR)
+ .reg_desc = tps25990_reg_desc,
+ .num_regulators = ARRAY_SIZE(tps25990_reg_desc),
+#endif
+};
+
+static const struct i2c_device_id tps25990_i2c_id[] = {
+ { "tps25990" },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tps25990_i2c_id);
+
+static const struct of_device_id tps25990_of_match[] = {
+ { .compatible = "ti,tps25990" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tps25990_of_match);
+
+static int tps25990_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct pmbus_driver_info *info;
+ u32 rimon = TPS25990_DEFAULT_RIMON;
+ int ret;
+
+ ret = device_property_read_u32(dev, "ti,rimon-micro-ohms", &rimon);
+ if (ret < 0 && ret != -EINVAL)
+ return dev_err_probe(dev, ret, "failed to get rimon\n");
+
+ info = devm_kmemdup(dev, &tps25990_base_info, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ /* Adapt the current and power scale for each instance */
+ tps25990_set_m(&info->m[PSC_CURRENT_IN], rimon);
+ tps25990_set_m(&info->m[PSC_POWER], rimon);
+
+ return pmbus_do_probe(client, info);
+}
+
+static struct i2c_driver tps25990_driver = {
+ .driver = {
+ .name = "tps25990",
+ .of_match_table = tps25990_of_match,
+ },
+ .probe = tps25990_probe,
+ .id_table = tps25990_i2c_id,
+};
+module_i2c_driver(tps25990_driver);
+
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_DESCRIPTION("PMBUS driver for TPS25990 eFuse");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("PMBUS");
diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c
index 53a1a968d00d..579d31bb9ac7 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -497,7 +497,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
struct device *hwmon;
int ret;
const struct hwmon_channel_info **channels;
- u32 pwm_min_from_stopped = 0;
+ u32 initial_pwm, pwm_min_from_stopped = 0;
u32 *fan_channel_config;
int channel_count = 1; /* We always have a PWM channel. */
int i;
@@ -545,11 +545,21 @@ static int pwm_fan_probe(struct platform_device *pdev)
ctx->enable_mode = pwm_disable_reg_enable;
+ ret = pwm_fan_get_cooling_data(dev, ctx);
+ if (ret)
+ return ret;
+
+ /* use maximum cooling level if provided */
+ if (ctx->pwm_fan_cooling_levels)
+ initial_pwm = ctx->pwm_fan_cooling_levels[ctx->pwm_fan_max_state];
+ else
+ initial_pwm = MAX_PWM;
+
/*
* Set duty cycle to maximum allowed and enable PWM output as well as
* the regulator. In case of error nothing is changed
*/
- ret = set_pwm(ctx, MAX_PWM);
+ ret = set_pwm(ctx, initial_pwm);
if (ret) {
dev_err(dev, "Failed to configure PWM: %d\n", ret);
return ret;
@@ -638,16 +648,16 @@ static int pwm_fan_probe(struct platform_device *pdev)
channels[1] = &ctx->fan_channel;
}
- ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-percent",
- &pwm_min_from_stopped);
+ ret = device_property_read_u32(dev, "fan-stop-to-start-percent",
+ &pwm_min_from_stopped);
if (!ret && pwm_min_from_stopped) {
ctx->pwm_duty_cycle_from_stopped =
DIV_ROUND_UP_ULL(pwm_min_from_stopped *
(ctx->pwm_state.period - 1),
100);
}
- ret = of_property_read_u32(dev->of_node, "fan-stop-to-start-us",
- &ctx->pwm_usec_from_stopped);
+ ret = device_property_read_u32(dev, "fan-stop-to-start-us",
+ &ctx->pwm_usec_from_stopped);
if (ret)
ctx->pwm_usec_from_stopped = 250000;
@@ -661,10 +671,6 @@ static int pwm_fan_probe(struct platform_device *pdev)
return PTR_ERR(hwmon);
}
- ret = pwm_fan_get_cooling_data(dev, ctx);
- if (ret)
- return ret;
-
ctx->pwm_fan_state = ctx->pwm_fan_max_state;
if (IS_ENABLED(CONFIG_THERMAL)) {
cdev = devm_thermal_of_cooling_device_register(dev,
diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c
index 10ef1e1f9458..a2938881ccd2 100644
--- a/drivers/hwmon/raspberrypi-hwmon.c
+++ b/drivers/hwmon/raspberrypi-hwmon.c
@@ -128,10 +128,32 @@ static int rpi_hwmon_probe(struct platform_device *pdev)
return 0;
}
+static int rpi_hwmon_suspend(struct device *dev)
+{
+ struct rpi_hwmon_data *data = dev_get_drvdata(dev);
+
+ cancel_delayed_work_sync(&data->get_values_poll_work);
+
+ return 0;
+}
+
+static int rpi_hwmon_resume(struct device *dev)
+{
+ struct rpi_hwmon_data *data = dev_get_drvdata(dev);
+
+ get_values_poll(&data->get_values_poll_work.work);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rpi_hwmon_pm_ops, rpi_hwmon_suspend,
+ rpi_hwmon_resume);
+
static struct platform_driver rpi_hwmon_driver = {
.probe = rpi_hwmon_probe,
.driver = {
.name = "raspberrypi-hwmon",
+ .pm = pm_ptr(&rpi_hwmon_pm_ops),
},
};
module_platform_driver(rpi_hwmon_driver);
diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c
index fbe673009126..a971ff628435 100644
--- a/drivers/hwmon/tmp108.c
+++ b/drivers/hwmon/tmp108.c
@@ -8,15 +8,15 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of.h>
#include <linux/i2c.h>
#include <linux/i3c/device.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#define DRIVER_NAME "tmp108"
@@ -331,6 +331,10 @@ static int tmp108_common_probe(struct device *dev, struct regmap *regmap, char *
u32 config;
int err;
+ err = devm_regulator_get_enable(dev, "vcc");
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable regulator\n");
+
tmp108 = devm_kzalloc(dev, sizeof(*tmp108), GFP_KERNEL);
if (!tmp108)
return -ENOMEM;
@@ -417,25 +421,24 @@ static int tmp108_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(tmp108_dev_pm_ops, tmp108_suspend, tmp108_resume);
static const struct i2c_device_id tmp108_i2c_ids[] = {
+ { "p3t1085" },
{ "tmp108" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids);
-#ifdef CONFIG_OF
static const struct of_device_id tmp108_of_ids[] = {
{ .compatible = "nxp,p3t1085", },
{ .compatible = "ti,tmp108", },
{}
};
MODULE_DEVICE_TABLE(of, tmp108_of_ids);
-#endif
static struct i2c_driver tmp108_driver = {
.driver = {
.name = DRIVER_NAME,
.pm = pm_sleep_ptr(&tmp108_dev_pm_ops),
- .of_match_table = of_match_ptr(tmp108_of_ids),
+ .of_match_table = tmp108_of_ids,
},
.probe = tmp108_probe,
.id_table = tmp108_i2c_ids,
diff --git a/include/linux/pmbus.h b/include/linux/pmbus.h
index fa9f08164c36..884040e1383b 100644
--- a/include/linux/pmbus.h
+++ b/include/linux/pmbus.h
@@ -73,6 +73,20 @@
*/
#define PMBUS_USE_COEFFICIENTS_CMD BIT(5)
+/*
+ * PMBUS_OP_PROTECTED
+ * Set if the chip OPERATION command is protected and protection is not
+ * determined by the standard WRITE_PROTECT command.
+ */
+#define PMBUS_OP_PROTECTED BIT(6)
+
+/*
+ * PMBUS_VOUT_PROTECTED
+ * Set if the chip VOUT_COMMAND command is protected and protection is not
+ * determined by the standard WRITE_PROTECT command.
+ */
+#define PMBUS_VOUT_PROTECTED BIT(7)
+
struct pmbus_platform_data {
u32 flags; /* Device specific flags */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 754802478b96..69f9bedd0ee8 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -295,6 +295,10 @@ static inline struct thermal_zone_device *thermal_tripless_zone_device_register(
static inline void thermal_zone_device_unregister(struct thermal_zone_device *tz)
{ }
+static inline void thermal_zone_device_update(struct thermal_zone_device *tz,
+ enum thermal_notify_event event)
+{ }
+
static inline struct thermal_cooling_device *
thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)