1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00

hwmon updates for v6.14-rc1

* 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
 
 * Various other minor fixes and improvements
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmeOX+AACgkQyx8mb86f
 mYG4bA/+PJ4hkttSuwK6eR4F1o5l2VQhWPkWn2XzruEJGixhKLJKxKVkUCymmSsd
 hepHZnw+aUKUmVeb0StSReshp6oGeOHHlKXUM1zv95HI1NMxMrflzeRuqjVNUnDK
 ZitZkOb2WuUWhZIKIu82ole+3tw/0QyAYmSa9FPyp63rQ7C/QAWl2g4h6m3VdDLZ
 1ZOimR/OOFAesZMOuEIBMIHnIqzKLr2QEFd5cZVKM5JbpB7LAHah3fPOvRC3sKco
 02OOzFOrtZrXIIPDpsnznm6DF8jgbiKjGb8frR6DLAm/uGvPhuXuS0tYnWHAZs5D
 nJHDCud1XROK2r9NHDiMZGxCxGOXmB+Fx71jUvY9692NMD2XWUzrqqoOs+c97eeG
 YszAe1FL9QpgbLJnsFWurU72uvOMmkIeETZUE2cmkupwH+Ja5sc4sDPwf6S8Pwus
 Y0ZonVqsLQb4UasGcfvFUEb8P6LQdshWx5IWxhfDs+xBo+n5pOEtu+ZCF5Z18k6A
 A6g4SWWu8QtZOD9fEW0Rt/d9/QtPCTQc8UrJpCofWyKWpLzuoU0Xcs9g/ajLK3Vz
 +YxM5Pgj7XMWtvPVx2ntnr5VAVKWCUv/jchWuKYKrGI58g3laPagmJMVEy8wrW9+
 MpUGzaNDEMlvv7n4Jr4ipkYv9ltOIheu8pmzuI2PcadvAcKmF28=
 =/7Qs
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2025-01-22 10:16:48 -08:00
commit a4910ed25d
41 changed files with 1378 additions and 268 deletions

View file

@ -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:

View file

@ -28,6 +28,7 @@ properties:
- maxim,max31725
- maxim,max31726
- maxim,mcp980x
- nxp,p3t1755
- nxp,pct2075
- st,stds75
- st,stlm75

View file

@ -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

View file

@ -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.
======================= =======================================================

View file

@ -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>

View file

@ -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.
======================= ======================================================

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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>

View file

@ -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
=============================== ===============================================

View file

@ -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.

View file

@ -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**

View file

@ -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>

View file

@ -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:

View file

@ -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;

View file

@ -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),
{},
};

View file

@ -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);

View file

@ -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)

View file

@ -1544,6 +1544,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 = {

View file

@ -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);

View file

@ -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>");

View file

@ -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)
static inline 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)
{
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[] = {
{
@ -813,6 +916,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
.compatible = "maxim,mcp980x",
.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");

View file

@ -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;

View file

@ -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] */

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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");

View file

@ -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);

View file

@ -25,6 +25,7 @@
static const struct i2c_device_id max15301_id[] = {
{ "bmr461" },
{ "max15301" },
{ "max15303" },
{}
};
MODULE_DEVICE_TABLE(i2c, max15301_id);

View file

@ -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)

View file

@ -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;

View file

@ -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");

View file

@ -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,

View file

@ -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);

View file

@ -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,

View file

@ -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 */

View file

@ -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)