Commit 64ae88ff authored by Linus Torvalds's avatar Linus Torvalds

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

Pull hwmon updates from Guenter Roeck:

 - Substantial rewrite of lm90 driver to support several additional
   chips and improve support for existing chips.

 - Add support of ROG ZENITH II EXTREME, Maximus XI Hero, and
   Strix Z690-a D4 to asus-ec-sensors driver

 - Add support of F71858AD to f71882fg driver

 - Add support of Aquacomputer Quadro to aquacomputer_d5next driver

 - Improved assembler code and add support for Dell G5 5590 as well as
   XPS 13 7390 in dell-smm driver

 - Add support for ASUS TUF GAMING B550-PLUS WIFI II to nct775 driver

 - Add support for IEEE 754 half precision to PMBus core. Also support
   for Analog Devices LT7182S, improve regulator support, and report
   various MFR register values in debugfs.

 - Various other minor improvements and fixes

* tag 'hwmon-for-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (85 commits)
  hwmon: (aquacomputer_d5next) Add support for Aquacomputer Quadro fan controller
  hwmon: (dell-smm) Improve documentation
  hwmon: (nct6775) add ASUS TUF GAMING B550-PLUS WIFI II
  hwmon: (occ) Replace open-coded variant of %*phN specifier
  hwmon: (sht15) Fix wrong assumptions in device remove callback
  hwmon: (aquacomputer_d5next) Add support for reading the +12V voltage sensor on D5 Next
  hwmon: (tps23861) fix byte order in current and voltage registers
  hwmon: (aspeed-pwm-tacho) increase fan tach period (again)
  hwmon: (aquacomputer_d5next) Add D5 Next fan control support
  hwmon: (mcp3021) improve driver support for newer hwmon interface
  hwmon: (asus-ec-sensors) add definitions for ROG ZENITH II EXTREME
  hwmon: (aquacomputer_d5next) Move device-specific data into struct aqc_data
  hwmon: (asus-ec-sensors) add missing sensors for X570-I GAMING
  hwmon: (drivetemp) Add module alias
  hwmon: (asus_wmi_sensors) Save a few bytes of memory
  hwmon: (lm90) Use worker for alarm notifications
  hwmon: (asus-ec-sensors) add support for Maximus XI Hero
  hwmon: (dell-smm) Improve assembly code
  hwmon: (pmbus/ltc2978) Set voltage resolution
  hwmon: (pmbus) Add list_voltage to pmbus ops
  ...
parents 530c28df cdbe34da
......@@ -938,3 +938,12 @@ Description:
- 1: enable
RW
What: /sys/class/hwmon/hwmonX/device/pec
Description:
PEC support on I2C devices
- 0, off, n: disable
- 1, on, y: enable
RW
......@@ -16,6 +16,7 @@ properties:
- adi,adm1032
- adi,adt7461
- adi,adt7461a
- adi,adt7481
- dallas,max6646
- dallas,max6647
- dallas,max6649
......@@ -50,6 +51,12 @@ properties:
"#thermal-sensor-cells":
const: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
vcc-supply:
description: phandle to the regulator that provides the +VCC supply
......@@ -61,6 +68,29 @@ required:
- compatible
- reg
patternProperties:
"^channel@([0-2])$":
type: object
description: Represents channels of the device and their specific configuration.
properties:
reg:
description: The channel number. 0 is local channel, 1-2 are remote channels.
items:
minimum: 0
maximum: 2
label:
description: A descriptive name for this channel, like "ambient" or "psu".
temperature-offset-millicelsius:
description: Temperature offset to be added to or subtracted from remote temperature measurements.
required:
- reg
additionalProperties: false
allOf:
- if:
not:
......@@ -70,12 +100,84 @@ allOf:
enum:
- adi,adt7461
- adi,adt7461a
- adi,adt7481
- ti,tmp451
- ti,tmp461
then:
properties:
ti,extended-range-enable: false
- if:
properties:
compatible:
contains:
enum:
- dallas,max6646
- dallas,max6647
- dallas,max6649
- dallas,max6657
- dallas,max6658
- dallas,max6659
- dallas,max6695
- dallas,max6696
then:
patternProperties:
"^channel@([0-2])$":
properties:
temperature-offset-millicelsius: false
- if:
properties:
compatible:
contains:
enum:
- adi,adt7461
- adi,adt7461a
- adi,adt7481
- onnn,nct1008
then:
patternProperties:
"^channel@([0-2])$":
properties:
temperature-offset-millicelsius:
maximum: 127750
- if:
properties:
compatible:
contains:
enum:
- adi,adm1032
- dallas,max6680
- dallas,max6681
- gmt,g781
- national,lm86
- national,lm89
- national,lm90
- national,lm99
- nxp,sa56004
- winbond,w83l771
then:
patternProperties:
"^channel@([0-2])$":
properties:
temperature-offset-millicelsius:
maximum: 127875
- if:
properties:
compatible:
contains:
enum:
- ti,tmp451
- ti,tmp461
then:
patternProperties:
"^channel@([0-2])$":
properties:
temperature-offset-millicelsius:
maximum: 127937
additionalProperties: false
examples:
......@@ -94,3 +196,32 @@ examples:
#thermal-sensor-cells = <1>;
};
};
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@4c {
compatible = "adi,adt7481";
reg = <0x4c>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0x0>;
label = "local";
};
channel@1 {
reg = <0x1>;
label = "front";
temperature-offset-millicelsius = <4000>;
};
channel@2 {
reg = <0x2>;
label = "back";
temperature-offset-millicelsius = <750>;
};
};
};
......@@ -41,6 +41,8 @@ properties:
- adi,adp5585-02
# Analog Devices ADP5589 Keypad Decoder and I/O Expansion
- adi,adp5589
# Analog Devices LT7182S Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher
- adi,lt7182s
# AMS iAQ-Core VOC Sensor
- ams,iaq-core
# i2c serial eeprom (24cxx)
......
......@@ -9,6 +9,7 @@ Supported devices:
* Aquacomputer Farbwerk RGB controller
* Aquacomputer Farbwerk 360 RGB controller
* Aquacomputer Octo fan controller
* Aquacomputer Quadro fan controller
Author: Aleksa Savic
......@@ -33,6 +34,9 @@ better suited for userspace tools.
The Octo exposes four temperature sensors and eight PWM controllable fans, along
with their speed (in RPM), power, voltage and current.
The Quadro exposes four temperature sensors, a flow sensor and four PWM controllable
fans, along with their speed (in RPM), power, voltage and current.
The Farbwerk and Farbwerk 360 expose four temperature sensors. Depending on the device,
not all sysfs and debugfs entries will be available.
......@@ -45,13 +49,14 @@ the kernel and supports hotswapping.
Sysfs entries
-------------
================ =============================================
================ ==============================================
temp[1-4]_input Temperature sensors (in millidegrees Celsius)
fan[1-2]_input Pump/fan speed (in RPM)
power[1-2]_input Pump/fan power (in micro Watts)
in[0-2]_input Pump/fan voltage (in milli Volts)
curr[1-2]_input Pump/fan current (in milli Amperes)
================ =============================================
fan[1-8]_input Pump/fan speed (in RPM) / Flow speed (in dL/h)
power[1-8]_input Pump/fan power (in micro Watts)
in[0-7]_input Pump/fan voltage (in milli Volts)
curr[1-8]_input Pump/fan current (in milli Amperes)
pwm[1-8] Fan PWM (0 - 255)
================ ==============================================
Debugfs entries
---------------
......
......@@ -13,12 +13,16 @@ Supported boards:
* ROG CROSSHAIR VIII FORMULA
* ROG CROSSHAIR VIII HERO
* ROG CROSSHAIR VIII IMPACT
* ROG MAXIMUS XI HERO
* ROG MAXIMUS XI HERO (WI-FI)
* ROG STRIX B550-E GAMING
* ROG STRIX B550-I GAMING
* ROG STRIX X570-E GAMING
* ROG STRIX X570-E GAMING WIFI II
* ROG STRIX X570-F GAMING
* ROG STRIX X570-I GAMING
* ROG STRIX Z690-A GAMING WIFI D4
* ROG ZENITH II EXTREME
Authors:
- Eugene Shalygin <eugene.shalygin@gmail.com>
......
......@@ -46,6 +46,9 @@ temp[1-10]_input RO Temperature reading in milli-degrees
temp[1-10]_label RO Temperature sensor label.
=============================== ======= =======================================
Due to the nature of the SMM interface, each pwmX attribute controls
fan number X.
Disabling automatic BIOS fan control
------------------------------------
......
......@@ -109,6 +109,7 @@ Hardware Monitoring Kernel Drivers
lm95234
lm95245
lochnagar
lt7182s
ltc2992
ltc2945
ltc2947
......
......@@ -3,6 +3,14 @@ Kernel driver lm90
Supported chips:
* National Semiconductor LM84
Prefix: 'lm84'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the National Semiconductor website
* National Semiconductor LM90
Prefix: 'lm90'
......@@ -43,6 +51,30 @@ Supported chips:
http://www.national.com/mpf/LM/LM86.html
* Analog Devices ADM1020
Prefix: 'adm1020'
Addresses scanned: I2C 0x4c - 0x4e
Datasheet: Publicly available at the Analog Devices website
* Analog Devices ADM1021
Prefix: 'adm1021'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the Analog Devices website
* Analog Devices ADM1021A/ADM1023
Prefix: 'adm1023'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the Analog Devices website
* Analog Devices ADM1032
Prefix: 'adm1032'
......@@ -73,6 +105,36 @@ Supported chips:
https://www.onsemi.com/PowerSolutions/product.do?id=ADT7461A
* Analog Devices ADT7481
Prefix: 'adt7481'
Addresses scanned: I2C 0x4b and 0x4c
Datasheet: Publicly available at the ON Semiconductor website
https://www.onsemi.com/PowerSolutions/product.do?id=ADT7481
* Analog Devices ADT7482
Prefix: 'adt7482'
Addresses scanned: I2C 0x4c
Datasheet: Publicly available at the ON Semiconductor website
https://www.onsemi.com/PowerSolutions/product.do?id=ADT7482
* Analog Devices ADT7483A
Prefix: 'adt7483a'
Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e
Datasheet: Publicly available at the ON Semiconductor website
https://www.onsemi.com/PowerSolutions/product.do?id=ADT7483A
* ON Semiconductor NCT1008
Prefix: 'nct1008'
......@@ -83,6 +145,72 @@ Supported chips:
https://www.onsemi.com/PowerSolutions/product.do?id=NCT1008
* ON Semiconductor NCT210
Prefix: 'adm1021'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the ON Semiconductor website
https://www.onsemi.com/PowerSolutions/product.do?id=NCT210
* ON Semiconductor NCT214
Prefix: 'nct214'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the ON Semiconductor website
https://www.onsemi.com/PowerSolutions/product.do?id=NCT214
* ON Semiconductor NCT218
Prefix: 'nct218'
Addresses scanned: I2C 0x4c - 0x4d
Datasheet: Publicly available at the ON Semiconductor website
https://www.onsemi.com/PowerSolutions/product.do?id=NCT218
* ON Semiconductor NCT72
Prefix: 'nct72'
Addresses scanned: I2C 0x4c - 0x4d
Datasheet: Publicly available at the ON Semiconductor website
https://www.onsemi.com/PowerSolutions/product.do?id=NCT72
* Maxim MAX1617
Prefix: 'max1617'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the Maxim website
* Maxim MAX1617A
Prefix: 'max1617a'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the Maxim website
* Maxim MAX6642
Prefix: 'max6642'
Addresses scanned: I2C 0x48-0x4f
Datasheet: Publicly available at the Maxim website
http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
* Maxim MAX6646
Prefix: 'max6646'
......@@ -105,7 +233,7 @@ Supported chips:
* Maxim MAX6648
Prefix: 'max6646'
Prefix: 'max6648'
Addresses scanned: I2C 0x4c
......@@ -191,7 +319,7 @@ Supported chips:
* Maxim MAX6692
Prefix: 'max6646'
Prefix: 'max6648'
Addresses scanned: I2C 0x4c
......@@ -275,6 +403,46 @@ Supported chips:
https://www.ti.com/lit/gpn/tmp461
* Philips NE1617, NE1617A
Prefix: 'max1617' (probably detected as a max1617)
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheets: Publicly available at the Philips website
* Philips NE1618
Prefix: 'ne1618'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheets: Publicly available at the Philips website
* Genesys Logic GL523SM
Prefix: 'gl523sm'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet:
* TI THMC10
Prefix: 'thmc10'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the TI website
* Onsemi MC1066
Prefix: 'mc1066'
Addresses scanned: I2C 0x18 - 0x1a, 0x29 - 0x2b, 0x4c - 0x4e
Datasheet: Publicly available at the Onsemi website
Author: Jean Delvare <jdelvare@suse.de>
......@@ -285,6 +453,12 @@ The LM90 is a digital temperature sensor. It senses its own temperature as
well as the temperature of up to one external diode. It is compatible
with many other devices, many of which are supported by this driver.
The family of chips supported by this driver is derived from MAX1617.
This chip as well as various compatible chips support a local and a remote
temperature sensor with 8 bit accuracy. Later chips provide improved accuracy
and other additional features such as hysteresis and temperature offset
registers.
Note that there is no easy way to differentiate between the MAX6657,
MAX6658 and MAX6659 variants. The extra features of the MAX6659 are only
supported by this driver if the chip is located at address 0x4d or 0x4e,
......@@ -292,15 +466,31 @@ or if the chip type is explicitly selected as max6659.
The MAX6680 and MAX6681 only differ in their pinout, therefore they obviously
can't (and don't need to) be distinguished.
The specificity of this family of chipsets over the ADM1021/LM84
family is that it features critical limits with hysteresis, and an
increased resolution of the remote temperature measurement.
The different chipsets of the family are not strictly identical, although
very similar. For reference, here comes a non-exhaustive list of specific
features:
LM84:
* 8 bit sensor resolution
ADM1020, ADM1021, GL523SM, MAX1617, NE1617, NE1617A, THMC10:
* 8 bit sensor resolution
* Low temperature limits
NCT210, NE1618:
* 11 bit sensor resolution for remote temperature sensor
* Low temperature limits
ADM1021A, ADM1023:
* Temperature offset register for remote temperature sensor
* 11 bit resolution for remote temperature sensor
* Low temperature limits
LM90:
* 11 bit resolution for remote temperature sensor
* Temperature offset register for remote temperature sensor
* Low and critical temperature limits
* Configurable conversion rate
* Filter and alert configuration register at 0xBF.
* ALERT is triggered by temperatures over critical limits.
......@@ -322,8 +512,31 @@ ADM1032:
ADT7461, ADT7461A, NCT1008:
* Extended temperature range (breaks compatibility)
* Lower resolution for remote temperature
* SMBus PEC support for Write Byte and Receive Byte transactions.
* 10 bit temperature resolution
ADT7481, ADT7482, ADT7483:
* Temperature offset register
* SMBus PEC support
* 10 bit temperature resolution for external sensors
* Two remote sensors
* Selectable address (ADT7483)
MAX6642:
* No critical limit register
* Conversion rate not configurable
* Better local resolution (10 bit)
* 10 bit external sensor resolution
MAX6646, MAX6647, MAX6649:
* Better local resolution
* Extended range unsigned external temperature
MAX6648, MAX6692:
* Better local resolution
* Unsigned temperature
MAX6654:
MAX6654, MAX6690:
* Better local resolution
* Selectable address
* Remote sensor type selection
......@@ -423,6 +636,6 @@ two transactions will typically mean twice as much delay waiting for
transaction completion, effectively doubling the register cache refresh time.
I guess reliability comes at a price, but it's quite expensive this time.
So, as not everyone might enjoy the slowdown, PEC can be disabled through
sysfs. Just write 0 to the "pec" file and PEC will be disabled. Write 1
to that file to enable PEC again.
So, as not everyone might enjoy the slowdown, PEC is disabled by default and
can be enabled through sysfs. Just write 1 to the "pec" file and PEC will be
enabled. Write 0 to that file to disable PEC again.
.. SPDX-License-Identifier: GPL-2.0
Kernel driver lt7182s
=====================
Supported chips:
* ADI LT7182S
Prefix: 'lt7182s'
Addresses scanned: -
Datasheet: https://www.analog.com/en/products/lt7182s.html
Author: Guenter Roeck <linux@roeck-us.net>
Description
-----------
LT7182S is a Dual Channel 6A, 20V PolyPhase Step-Down Silent Switcher with
Digital Power System Management support.
Usage Notes
-----------
This driver does not probe for PMBus devices. You will have to instantiate
devices explicitly.
Example: the following commands will load the driver for a LT7182S
at address 0x4f on I2C bus #4::
# modprobe lt7182s
# echo lt7182s 0x4f > /sys/bus/i2c/devices/i2c-4/new_device
It can also be instantiated by declaring an entry in device tree.
Sysfs attributes
----------------
======================= ====================================
curr[1-2]_label "iin[12]"
curr[1-2]_input Measured input current
curr[1-2]_max Maximum input current
curr[1-2]_max_alarm Current high alarm
curr[3-4]_label "iout[1-2]"
curr[3-4]_input Measured output current
curr[3-4]_highest Highest measured output current
curr[3-4]_max Maximum output current
curr[3-4]_max_alarm Output current high alarm
in[1-2]_label "vin[12]"
in[1-2]_input Measured input voltage
in[1-2]_highest Highest measured input voltage
in[1-2]_crit Critical maximum input voltage
in[1-2]_crit_alarm Input voltage critical high alarm
in[1-2]_min Minimum input voltage
in[1-2]_min_alarm Input voltage low alarm
in[1-2]_rated_min Rated minimum input voltage
in[1-2]_rated_max Rated maximum input voltage
in1_reset_history Write to reset history for all attributes
in[3-5]_label "vmon[1-3]"
in[3-5]_input Measured voltage on ITH1/ITH2/EXTVCC pins
Only available if enabled with MFR_ADC_CONTROL_LT7182S
command.
in[3-4|6-7]_label "vout[1-2]"
in[3-4|6-7]_input Measured output voltage
in[3-4|6-7]_highest Highest measured output voltage
in[3-4|6-7]_lcrit Critical minimum output voltage
in[3-4|6-7]_lcrit_alarm Output voltage critical low alarm
in[3-4|6-7]_min Minimum output voltage
in[3-4|6-7]_max_alarm Output voltage low alarm
in[3-4|6-7]_max Maximum output voltage
in[3-4|6-7]_max_alarm Output voltage high alarm
in[3-4|6-7]_crit Critical maximum output voltage
in[3-4|6-7]_crit_alarm Output voltage critical high alarm
power[1-2]_label "pout[1-2]"
power[1-2]_input Measured output power
temp1_input Measured temperature
temp1_crit Critical high temperature
temp1_crit_alarm Chip temperature critical high alarm
temp1_max Maximum temperature
temp1_max_alarm Chip temperature high alarm
======================= ====================================
......@@ -121,6 +121,15 @@ Specifically, it provides the following information.
non-standard PMBus commands to standard commands, or to augment standard
command return values with device specific information.
PEC Support
===========
Many PMBus devices support SMBus PEC (Packet Error Checking). If supported
by both the I2C adapter and by the PMBus chip, it is by default enabled.
If PEC is supported, the PMBus core driver adds an attribute named 'pec' to
the I2C device. This attribute can be used to control PEC support in the
communication with the PMBus chip.
API functions
=============
......
......@@ -100,6 +100,7 @@ config SENSORS_AD7418
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
depends on I2C
depends on SENSORS_LM90=n
help
If you say yes here you get support for Analog Devices ADM1021
and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
......@@ -256,13 +257,13 @@ config SENSORS_AHT10
will be called aht10.
config SENSORS_AQUACOMPUTER_D5NEXT
tristate "Aquacomputer D5 Next, Octo, Farbwerk, and Farbwerk 360"
tristate "Aquacomputer D5 Next, Octo, Quadro, Farbwerk, and Farbwerk 360"
depends on USB_HID
select CRC16
help
If you say yes here you get support for sensors and fans of
the Aquacomputer D5 Next watercooling pump, Octo fan
controller, Farbwerk and Farbwerk 360 RGB controllers, where
the Aquacomputer D5 Next watercooling pump, Octo and Quadro fan
controllers, Farbwerk and Farbwerk 360 RGB controllers, where
available.
This driver can also be built as a module. If so, the module
......@@ -381,7 +382,7 @@ config SENSORS_ARM_SCPI
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on X86 && I2C
depends on (X86 || COMPILE_TEST) && I2C
select HWMON_VID
help
If you say yes here you get support for the ASB100 Bach sensor
......@@ -626,7 +627,7 @@ config SENSORS_MC13783_ADC
config SENSORS_FSCHMD
tristate "Fujitsu Siemens Computers sensor chips"
depends on X86 && I2C
depends on (X86 || COMPILE_TEST) && I2C
help
If you say yes here you get support for the following Fujitsu
Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes,
......@@ -1102,6 +1103,7 @@ config SENSORS_MAX6639
config SENSORS_MAX6642
tristate "Maxim MAX6642 sensor chip"
depends on I2C
depends on SENSORS_LM90=n
help
If you say yes here you get support for MAX6642 sensor chip.
MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
......@@ -1357,12 +1359,15 @@ config SENSORS_LM90
tristate "National Semiconductor LM90 and compatibles"
depends on I2C
help
If you say yes here you get support for National Semiconductor LM90,
LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6654, MAX6657, MAX6658,
MAX6659, MAX6680, MAX6681, MAX6692, MAX6695, MAX6696,
ON Semiconductor NCT1008, Winbond/Nuvoton W83L771W/G/AWG/ASG,
Philips SA56004, GMT G781, Texas Instruments TMP451 and TMP461
If you say yes here you get support for National Semiconductor LM84,
LM90, LM86, LM89 and LM99, Analog Devices ADM1020, ADM2021, ADM1021A,
ADM1023, ADM1032, ADT7461, ADT7461A, ADT7481, ADT7482, and ADT7483A,
Maxim MAX1617, MAX6642, MAX6646, MAX6647, MAX6648, MAX6649, MAX6654,
MAX6657, MAX6658, MAX6659, MAX6680, MAX6681, MAX6692, MAX6695,
MAX6696,
ON Semiconductor NCT1008, NCT210, NCT72, NCT214, NCT218,
Winbond/Nuvoton W83L771W/G/AWG/ASG,
Philips NE1618, SA56004, GMT G781, Texas Instruments TMP451 and TMP461
sensor chips.
This driver can also be built as a module. If so, the module
......
This diff is collapsed.
......@@ -159,7 +159,7 @@
* 11: reserved.
*/
#define M_TACH_MODE 0x02 /* 10b */
#define M_TACH_UNIT 0x0210
#define M_TACH_UNIT 0x0420
#define INIT_FAN_CTRL 0xFF
/* How long we sleep in us while waiting for an RPM result. */
......
......@@ -54,6 +54,10 @@ static char *mutex_path_override;
/* ACPI mutex for locking access to the EC for the firmware */
#define ASUS_HW_ACCESS_MUTEX_ASMX "\\AMW0.ASMX"
#define ASUS_HW_ACCESS_MUTEX_RMTW_ASMX "\\RMTW.ASMX"
#define ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0 "\\_SB_.PCI0.SBRG.SIO1.MUT0"
#define MAX_IDENTICAL_BOARD_VARIATIONS 3
/* Moniker for the ACPI global lock (':' is not allowed in ASL identifiers) */
......@@ -119,6 +123,18 @@ enum ec_sensors {
ec_sensor_temp_water_in,
/* "Water_Out" temperature sensor reading [℃] */
ec_sensor_temp_water_out,
/* "Water_Block_In" temperature sensor reading [℃] */
ec_sensor_temp_water_block_in,
/* "Water_Block_Out" temperature sensor reading [℃] */
ec_sensor_temp_water_block_out,
/* "T_sensor_2" temperature sensor reading [℃] */
ec_sensor_temp_t_sensor_2,
/* "Extra_1" temperature sensor reading [℃] */
ec_sensor_temp_sensor_extra_1,
/* "Extra_2" temperature sensor reading [℃] */
ec_sensor_temp_sensor_extra_2,
/* "Extra_3" temperature sensor reading [℃] */
ec_sensor_temp_sensor_extra_3,
};
#define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset)
......@@ -134,11 +150,19 @@ enum ec_sensors {
#define SENSOR_CURR_CPU BIT(ec_sensor_curr_cpu)
#define SENSOR_TEMP_WATER_IN BIT(ec_sensor_temp_water_in)
#define SENSOR_TEMP_WATER_OUT BIT(ec_sensor_temp_water_out)
#define SENSOR_TEMP_WATER_BLOCK_IN BIT(ec_sensor_temp_water_block_in)
#define SENSOR_TEMP_WATER_BLOCK_OUT BIT(ec_sensor_temp_water_block_out)
#define SENSOR_TEMP_T_SENSOR_2 BIT(ec_sensor_temp_t_sensor_2)
#define SENSOR_TEMP_SENSOR_EXTRA_1 BIT(ec_sensor_temp_sensor_extra_1)
#define SENSOR_TEMP_SENSOR_EXTRA_2 BIT(ec_sensor_temp_sensor_extra_2)
#define SENSOR_TEMP_SENSOR_EXTRA_3 BIT(ec_sensor_temp_sensor_extra_3)
enum board_family {
family_unknown,
family_amd_400_series,
family_amd_500_series,
family_intel_300_series,
family_intel_600_series
};
/* All the known sensors for ASUS EC controllers */
......@@ -195,12 +219,53 @@ static const struct ec_sensor_info sensors_family_amd_500[] = {
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_temp_water_block_in] =
EC_SENSOR("Water_Block_In", hwmon_temp, 1, 0x01, 0x02),
[ec_sensor_temp_water_block_out] =
EC_SENSOR("Water_Block_Out", hwmon_temp, 1, 0x01, 0x03),
[ec_sensor_temp_sensor_extra_1] =
EC_SENSOR("Extra_1", hwmon_temp, 1, 0x01, 0x09),
[ec_sensor_temp_t_sensor_2] =
EC_SENSOR("T_sensor_2", hwmon_temp, 1, 0x01, 0x0a),
[ec_sensor_temp_sensor_extra_2] =
EC_SENSOR("Extra_2", hwmon_temp, 1, 0x01, 0x0b),
[ec_sensor_temp_sensor_extra_3] =
EC_SENSOR("Extra_3", hwmon_temp, 1, 0x01, 0x0c),
};
static const struct ec_sensor_info sensors_family_intel_300[] = {
[ec_sensor_temp_chipset] =
EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
[ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),
[ec_sensor_temp_mb] =
EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),
[ec_sensor_temp_t_sensor] =
EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
[ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
[ec_sensor_fan_cpu_opt] =
EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
[ec_sensor_fan_vrm_hs] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),
[ec_sensor_fan_water_flow] =
EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xbc),
[ec_sensor_temp_water_in] =
EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
[ec_sensor_temp_water_out] =
EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
};
static const struct ec_sensor_info sensors_family_intel_600[] = {
[ec_sensor_temp_t_sensor] =
EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
[ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
};
/* Shortcuts for common combinations */
#define SENSOR_SET_TEMP_CHIPSET_CPU_MB \
(SENSOR_TEMP_CHIPSET | SENSOR_TEMP_CPU | SENSOR_TEMP_MB)
#define SENSOR_SET_TEMP_WATER (SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT)
#define SENSOR_SET_WATER_BLOCK \
(SENSOR_TEMP_WATER_BLOCK_IN | SENSOR_TEMP_WATER_BLOCK_OUT)
struct ec_board_info {
const char *board_names[MAX_IDENTICAL_BOARD_VARIATIONS];
......@@ -272,6 +337,18 @@ static const struct ec_board_info board_info[] = {
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
.family = family_amd_500_series,
},
{
.board_names = {
"ROG MAXIMUS XI HERO",
"ROG MAXIMUS XI HERO (WI-FI)",
},
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
SENSOR_TEMP_T_SENSOR |
SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW,
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
.family = family_intel_300_series,
},
{
.board_names = {"ROG CROSSHAIR VIII IMPACT"},
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
......@@ -324,12 +401,31 @@ static const struct ec_board_info board_info[] = {
},
{
.board_names = {"ROG STRIX X570-I GAMING"},
.sensors = SENSOR_TEMP_T_SENSOR | SENSOR_FAN_VRM_HS |
SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
SENSOR_IN_CPU_CORE,
.sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
SENSOR_TEMP_T_SENSOR |
SENSOR_FAN_VRM_HS | SENSOR_FAN_CHIPSET |
SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
.mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
.family = family_amd_500_series,
},
{
.board_names = {"ROG STRIX Z690-A GAMING WIFI D4"},
.sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,
.mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
.family = family_intel_600_series,
},
{
.board_names = {"ROG ZENITH II EXTREME"},
.sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | SENSOR_FAN_VRM_HS |
SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE |
SENSOR_SET_WATER_BLOCK |
SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 |
SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,
.mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,
.family = family_amd_500_series,
},
{}
};
......@@ -799,6 +895,12 @@ static int __init asus_ec_probe(struct platform_device *pdev)
case family_amd_500_series:
ec_data->sensors_info = sensors_family_amd_500;
break;
case family_intel_300_series:
ec_data->sensors_info = sensors_family_intel_300;
break;
case family_intel_600_series:
ec_data->sensors_info = sensors_family_intel_600;
break;
default:
dev_err(dev, "Unknown board family: %d",
ec_data->board_info->family);
......
......@@ -514,22 +514,20 @@ static int asus_wmi_configure_sensor_setup(struct device *dev,
int i, idx;
int err;
temp_sensor = devm_kcalloc(dev, 1, sizeof(*temp_sensor), GFP_KERNEL);
if (!temp_sensor)
return -ENOMEM;
for (i = 0; i < sensor_data->wmi.sensor_count; i++) {
err = asus_wmi_sensor_info(i, temp_sensor);
struct asus_wmi_sensor_info sensor;
err = asus_wmi_sensor_info(i, &sensor);
if (err)
return err;
switch (temp_sensor->data_type) {
switch (sensor.data_type) {
case TEMPERATURE_C:
case VOLTAGE:
case CURRENT:
case FAN_RPM:
case WATER_FLOW:
type = asus_data_types[temp_sensor->data_type];
type = asus_data_types[sensor.data_type];
if (!nr_count[type])
nr_types++;
nr_count[type]++;
......
......@@ -130,7 +130,7 @@ struct smm_regs {
unsigned int edx;
unsigned int esi;
unsigned int edi;
} __packed;
};
static const char * const temp_labels[] = {
"CPU",
......@@ -175,77 +175,35 @@ static int i8k_smm_func(void *par)
struct smm_regs *regs = par;
int eax = regs->eax;
int ebx = regs->ebx;
unsigned char carry;
long long duration;
int rc;
/* SMM requires CPU 0 */
if (smp_processor_id() != 0)
return -EBUSY;
#if defined(CONFIG_X86_64)
asm volatile("pushq %%rax\n\t"
"movl 0(%%rax),%%edx\n\t"
"pushq %%rdx\n\t"
"movl 4(%%rax),%%ebx\n\t"
"movl 8(%%rax),%%ecx\n\t"
"movl 12(%%rax),%%edx\n\t"
"movl 16(%%rax),%%esi\n\t"
"movl 20(%%rax),%%edi\n\t"
"popq %%rax\n\t"
"out %%al,$0xb2\n\t"
"out %%al,$0x84\n\t"
"xchgq %%rax,(%%rsp)\n\t"
"movl %%ebx,4(%%rax)\n\t"
"movl %%ecx,8(%%rax)\n\t"
"movl %%edx,12(%%rax)\n\t"
"movl %%esi,16(%%rax)\n\t"
"movl %%edi,20(%%rax)\n\t"
"popq %%rdx\n\t"
"movl %%edx,0(%%rax)\n\t"
"pushfq\n\t"
"popq %%rax\n\t"
"andl $1,%%eax\n"
: "=a"(rc)
: "a"(regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
#else
asm volatile("pushl %%eax\n\t"
"movl 0(%%eax),%%edx\n\t"
"push %%edx\n\t"
"movl 4(%%eax),%%ebx\n\t"
"movl 8(%%eax),%%ecx\n\t"
"movl 12(%%eax),%%edx\n\t"
"movl 16(%%eax),%%esi\n\t"
"movl 20(%%eax),%%edi\n\t"
"popl %%eax\n\t"
"out %%al,$0xb2\n\t"
"out %%al,$0x84\n\t"
"xchgl %%eax,(%%esp)\n\t"
"movl %%ebx,4(%%eax)\n\t"
"movl %%ecx,8(%%eax)\n\t"
"movl %%edx,12(%%eax)\n\t"
"movl %%esi,16(%%eax)\n\t"
"movl %%edi,20(%%eax)\n\t"
"popl %%edx\n\t"
"movl %%edx,0(%%eax)\n\t"
"lahf\n\t"
"shrl $8,%%eax\n\t"
"andl $1,%%eax\n"
: "=a"(rc)
: "a"(regs)
: "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
#endif
if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
rc = -EINVAL;
asm volatile("out %%al,$0xb2\n\t"
"out %%al,$0x84\n\t"
"setc %0\n"
: "=mr" (carry),
"+a" (regs->eax),
"+b" (regs->ebx),
"+c" (regs->ecx),
"+d" (regs->edx),
"+S" (regs->esi),
"+D" (regs->edi));
duration = ktime_us_delta(ktime_get(), calltime);
pr_debug("smm(0x%.4x 0x%.4x) = 0x%.4x (took %7lld usecs)\n", eax, ebx,
(rc ? 0xffff : regs->eax & 0xffff), duration);
pr_debug("smm(0x%.4x 0x%.4x) = 0x%.4x carry: %d (took %7lld usecs)\n",
eax, ebx, regs->eax & 0xffff, carry, duration);
if (duration > DELL_SMM_MAX_DURATION)
pr_warn_once("SMM call took %lld usecs!\n", duration);
return rc;
if (carry || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
return -EINVAL;
return 0;
}
/*
......@@ -1131,6 +1089,13 @@ static const struct i8k_config_data i8k_config_data[] __initconst = {
};
static const struct dmi_system_id i8k_dmi_table[] __initconst = {
{
.ident = "Dell G5 5590",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "G5 5590"),
},
},
{
.ident = "Dell Inspiron",
.matches = {
......@@ -1365,6 +1330,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 7390",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 13 7390"),
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{ }
};
......
......@@ -621,3 +621,4 @@ module_exit(drivetemp_exit);
MODULE_AUTHOR("Guenter Roeck <linus@roeck-us.net>");
MODULE_DESCRIPTION("Hard drive temperature monitor");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:drivetemp");
......@@ -49,6 +49,7 @@
#define SIO_F81768D_ID 0x1210 /* Chipset ID */
#define SIO_F81865_ID 0x0704 /* Chipset ID */
#define SIO_F81866_ID 0x1010 /* Chipset ID */
#define SIO_F71858AD_ID 0x0903 /* Chipset ID */
#define SIO_F81966_ID 0x1502 /* Chipset ID */
#define REGION_LENGTH 8
......@@ -2638,6 +2639,7 @@ static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
sio_data->type = f71808a;
break;
case SIO_F71858_ID:
case SIO_F71858AD_ID:
sio_data->type = f71858fg;
break;
case SIO_F71862_ID:
......
......@@ -269,10 +269,13 @@ gsc_hwmon_get_devtree_pdata(struct device *dev)
/* fan controller base address */
fan = of_find_compatible_node(dev->parent->of_node, NULL, "gw,gsc-fan");
if (fan && of_property_read_u32(fan, "reg", &pdata->fan_base)) {
of_node_put(fan);
dev_err(dev, "fan node without base\n");
return ERR_PTR(-EINVAL);
}
of_node_put(fan);
/* allocate structures for channels and count instances of each type */
device_for_each_child_node(dev, child) {
if (fwnode_property_read_string(child, "label", &ch->name)) {
......
......@@ -11,7 +11,8 @@
* which contains this code, we don't worry about the wasted space.
*/
#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/types.h>
/* straight from the datasheet */
#define LM75_TEMP_MIN (-55000)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -7,7 +7,7 @@
* Reworked by Sven Schuchmann <schuchmann@schleissheimer.de>
* DT support added by Clemens Gruber <clemens.gruber@pqgruber.com>
*
* This driver export the value of analog input voltage to sysfs, the
* This driver exports the value of analog input voltage to sysfs, the
* voltage unit is mV. Through the sysfs interface, lm-sensors tool
* can also display the input voltage.
*/
......@@ -45,19 +45,29 @@ enum chips {
* Client data (each client gets its own)
*/
struct mcp3021_data {
struct device *hwmon_dev;
struct i2c_client *client;
u32 vdd; /* supply and reference voltage in millivolt */
u16 sar_shift;
u16 sar_mask;
u8 output_res;
};
static int mcp3021_read16(struct i2c_client *client)
static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
{
struct mcp3021_data *data = i2c_get_clientdata(client);
int ret;
u16 reg;
return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
}
static int mcp3021_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct mcp3021_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
__be16 buf;
u16 reg;
int ret;
if (type != hwmon_in)
return -EOPNOTSUPP;
ret = i2c_master_recv(client, (char *)&buf, 2);
if (ret < 0)
......@@ -74,39 +84,46 @@ static int mcp3021_read16(struct i2c_client *client)
*/
reg = (reg >> data->sar_shift) & data->sar_mask;
return reg;
}
*val = volts_from_reg(data, reg);
static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val)
{
return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res);
return 0;
}
static ssize_t in0_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
static umode_t mcp3021_is_visible(const void *_data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcp3021_data *data = i2c_get_clientdata(client);
int reg, in_input;
if (type != hwmon_in)
return 0;
reg = mcp3021_read16(client);
if (reg < 0)
return reg;
if (attr != hwmon_in_input)
return 0;
in_input = volts_from_reg(data, reg);
return sprintf(buf, "%d\n", in_input);
return 0444;
}
static DEVICE_ATTR_RO(in0_input);
static const struct hwmon_channel_info *mcp3021_info[] = {
HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
NULL
};
static const struct hwmon_ops mcp3021_hwmon_ops = {
.is_visible = mcp3021_is_visible,
.read = mcp3021_read,
};
static const struct hwmon_chip_info mcp3021_chip_info = {
.ops = &mcp3021_hwmon_ops,
.info = mcp3021_info,
};
static const struct i2c_device_id mcp3021_id[];
static int mcp3021_probe(struct i2c_client *client)
{
int err;
struct mcp3021_data *data = NULL;
struct device_node *np = client->dev.of_node;
struct device *hwmon_dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
......@@ -147,34 +164,17 @@ static int mcp3021_probe(struct i2c_client *client)
break;
}
data->client = client;
if (data->vdd > MCP3021_VDD_REF_MAX || data->vdd < MCP3021_VDD_REF_MIN)
return -EINVAL;
err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
if (err)
return err;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
return 0;
exit_remove:
sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
return err;
}
static int mcp3021_remove(struct i2c_client *client)
{
struct mcp3021_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
return 0;
hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
client->name,
data,
&mcp3021_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id mcp3021_id[] = {
......@@ -199,7 +199,6 @@ static struct i2c_driver mcp3021_driver = {
.of_match_table = of_match_ptr(of_mcp3021_match),
},
.probe_new = mcp3021_probe,
.remove = mcp3021_remove,
.id_table = mcp3021_id,
};
......
......@@ -1083,6 +1083,7 @@ static const char * const asus_wmi_boards[] = {
"TUF GAMING B550M-PLUS",
"TUF GAMING B550M-PLUS (WI-FI)",
"TUF GAMING B550-PLUS",
"TUF GAMING B550-PLUS WIFI II",
"TUF GAMING B550-PRO",
"TUF GAMING X570-PLUS",
"TUF GAMING X570-PLUS (WI-FI)",
......@@ -1200,10 +1201,8 @@ static int __init sensors_nct6775_platform_init(void)
exit_device_put:
platform_device_put(pdev[i]);
exit_device_unregister:
while (--i >= 0) {
if (pdev[i])
platform_device_unregister(pdev[i]);
}
while (i--)
platform_device_unregister(pdev[i]);
exit_unregister:
platform_driver_unregister(&nct6775_driver);
return err;
......@@ -1213,10 +1212,8 @@ static void __exit sensors_nct6775_platform_exit(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(pdev); i++) {
if (pdev[i])
platform_device_unregister(pdev[i]);
}
for (i = 0; i < ARRAY_SIZE(pdev); i++)
platform_device_unregister(pdev[i]);
platform_driver_unregister(&nct6775_driver);
}
......
......@@ -729,18 +729,14 @@ static ssize_t occ_show_extended(struct device *dev,
rc = sysfs_emit(buf, "%u",
get_unaligned_be32(&extn->sensor_id));
} else {
rc = sysfs_emit(buf, "%02x%02x%02x%02x\n",
extn->name[0], extn->name[1],
extn->name[2], extn->name[3]);
rc = sysfs_emit(buf, "%4phN\n", extn->name);
}
break;
case 1:
rc = sysfs_emit(buf, "%02x\n", extn->flags);
break;
case 2:
rc = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n",
extn->data[0], extn->data[1], extn->data[2],
extn->data[3], extn->data[4], extn->data[5]);
rc = sysfs_emit(buf, "%6phN\n", extn->data);
break;
default:
return -EINVAL;
......
......@@ -55,8 +55,7 @@ static bool p9_sbe_occ_save_ffdc(struct p9_sbe_occ *ctx, const void *resp,
mutex_lock(&ctx->sbe_error_lock);
if (!ctx->sbe_error) {
if (resp_len > ctx->ffdc_size) {
if (ctx->ffdc)
kvfree(ctx->ffdc);
kvfree(ctx->ffdc);
ctx->ffdc = kvmalloc(resp_len, GFP_KERNEL);
if (!ctx->ffdc) {
ctx->ffdc_len = 0;
......@@ -170,8 +169,7 @@ static int p9_sbe_occ_remove(struct platform_device *pdev)
ctx->sbe = NULL;
occ_shutdown(occ);
if (ctx->ffdc)
kvfree(ctx->ffdc);
kvfree(ctx->ffdc);
return 0;
}
......
......@@ -181,6 +181,15 @@ config SENSORS_LM25066_REGULATOR
If you say yes here you get regulator support for National
Semiconductor LM25066, LM5064, and LM5066.
config SENSORS_LT7182S
tristate "Analog Devices LT7182S"
help
If you say yes here you get hardware monitoring support for Analog
Devices LT7182S.
This driver can also be built as a module. If so, the module will
be called lt7182s.
config SENSORS_LTC2978
tristate "Linear Technologies LTC2978 and compatibles"
help
......
......@@ -20,6 +20,7 @@ obj-$(CONFIG_SENSORS_IR38064) += ir38064.o
obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o
obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
obj-$(CONFIG_SENSORS_LT7182S) += lt7182s.o
obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
obj-$(CONFIG_SENSORS_MAX15301) += max15301.o
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for Analog Devices LT7182S
*
* Copyright (c) 2022 Guenter Roeck
*
*/
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include "pmbus.h"
#define LT7182S_NUM_PAGES 2
#define MFR_READ_EXTVCC 0xcd
#define MFR_READ_ITH 0xce
#define MFR_CONFIG_ALL_LT7182S 0xd1
#define MFR_IOUT_PEAK 0xd7
#define MFR_ADC_CONTROL_LT7182S 0xd8
#define MFR_DEBUG_TELEMETRY BIT(0)
#define MFR_VOUT_PEAK 0xdd
#define MFR_VIN_PEAK 0xde
#define MFR_TEMPERATURE_1_PEAK 0xdf
#define MFR_CLEAR_PEAKS 0xe3
#define MFR_CONFIG_IEEE BIT(8)
static int lt7182s_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{
int ret;
switch (reg) {
case PMBUS_VIRT_READ_VMON:
if (page == 0 || page == 1)
ret = pmbus_read_word_data(client, page, phase, MFR_READ_ITH);
else
ret = pmbus_read_word_data(client, 0, phase, MFR_READ_EXTVCC);
break;
case PMBUS_VIRT_READ_IOUT_MAX:
ret = pmbus_read_word_data(client, page, phase, MFR_IOUT_PEAK);
break;
case PMBUS_VIRT_READ_VOUT_MAX:
ret = pmbus_read_word_data(client, page, phase, MFR_VOUT_PEAK);
break;
case PMBUS_VIRT_READ_VIN_MAX:
ret = pmbus_read_word_data(client, page, phase, MFR_VIN_PEAK);
break;
case PMBUS_VIRT_READ_TEMP_MAX:
ret = pmbus_read_word_data(client, page, phase, MFR_TEMPERATURE_1_PEAK);
break;
case PMBUS_VIRT_RESET_VIN_HISTORY:
ret = (page == 0) ? 0 : -ENODATA;
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static int lt7182s_write_word_data(struct i2c_client *client, int page, int reg, u16 word)
{
int ret;
switch (reg) {
case PMBUS_VIRT_RESET_VIN_HISTORY:
ret = pmbus_write_byte(client, 0, MFR_CLEAR_PEAKS);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static struct pmbus_driver_info lt7182s_info = {
.pages = LT7182S_NUM_PAGES,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_POWER] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT |
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP,
.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT |
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT | PMBUS_HAVE_POUT |
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_STATUS_INPUT,
.read_word_data = lt7182s_read_word_data,
.write_word_data = lt7182s_write_word_data,
};
static int lt7182s_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct pmbus_driver_info *info;
u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA |
I2C_FUNC_SMBUS_READ_WORD_DATA |
I2C_FUNC_SMBUS_READ_BLOCK_DATA))
return -ENODEV;
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
if (ret < 0) {
dev_err(dev, "Failed to read PMBUS_MFR_ID\n");
return ret;
}
if (ret != 3 || strncmp(buf, "ADI", 3)) {
buf[ret] = '\0';
dev_err(dev, "Manufacturer '%s' not supported\n", buf);
return -ENODEV;
}
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
if (ret < 0) {
dev_err(dev, "Failed to read PMBUS_MFR_MODEL\n");
return ret;
}
if (ret != 7 || strncmp(buf, "LT7182S", 7)) {
buf[ret] = '\0';
dev_err(dev, "Model '%s' not supported\n", buf);
return -ENODEV;
}
info = devm_kmemdup(dev, &lt7182s_info,
sizeof(struct pmbus_driver_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
/* Set data format to IEEE754 if configured */
ret = i2c_smbus_read_word_data(client, MFR_CONFIG_ALL_LT7182S);
if (ret < 0)
return ret;
if (ret & MFR_CONFIG_IEEE) {
info->format[PSC_VOLTAGE_IN] = ieee754;
info->format[PSC_VOLTAGE_OUT] = ieee754;
info->format[PSC_CURRENT_IN] = ieee754;
info->format[PSC_CURRENT_OUT] = ieee754;
info->format[PSC_TEMPERATURE] = ieee754;
info->format[PSC_POWER] = ieee754;
}
/* Enable VMON output if configured */
ret = i2c_smbus_read_byte_data(client, MFR_ADC_CONTROL_LT7182S);
if (ret < 0)
return ret;
if (ret & MFR_DEBUG_TELEMETRY) {
info->pages = 3;
info->func[0] |= PMBUS_HAVE_VMON;
info->func[1] |= PMBUS_HAVE_VMON;
info->func[2] = PMBUS_HAVE_VMON;
}
return pmbus_do_probe(client, info);
}
static const struct i2c_device_id lt7182s_id[] = {
{ "lt7182s", 0 },
{}
};
MODULE_DEVICE_TABLE(i2c, lt7182s_id);
static const struct of_device_id __maybe_unused lt7182s_of_match[] = {
{ .compatible = "adi,lt7182s" },
{}
};
static struct i2c_driver lt7182s_driver = {
.driver = {
.name = "lt7182s",
.of_match_table = of_match_ptr(lt7182s_of_match),
},
.probe_new = lt7182s_probe,
.id_table = lt7182s_id,
};
module_i2c_driver(lt7182s_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Analog Devices LT7182S");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -562,7 +562,24 @@ static const struct i2c_device_id ltc2978_id[] = {
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
#define LTC2978_ADC_RES 0xFFFF
#define LTC2978_N_ADC 122
#define LTC2978_MAX_UV (LTC2978_ADC_RES * LTC2978_N_ADC)
#define LTC2978_UV_STEP 1000
#define LTC2978_N_VOLTAGES ((LTC2978_MAX_UV / LTC2978_UV_STEP) + 1)
static const struct regulator_desc ltc2978_reg_desc[] = {
PMBUS_REGULATOR_STEP("vout", 0, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 1, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 2, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 3, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 4, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 5, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 6, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
PMBUS_REGULATOR_STEP("vout", 7, LTC2978_N_VOLTAGES, LTC2978_UV_STEP),
};
static const struct regulator_desc ltc2978_reg_desc_default[] = {
PMBUS_REGULATOR("vout", 0),
PMBUS_REGULATOR("vout", 1),
PMBUS_REGULATOR("vout", 2),
......@@ -839,10 +856,29 @@ static int ltc2978_probe(struct i2c_client *client)
#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
info->num_regulators = info->pages;
info->reg_desc = ltc2978_reg_desc;
if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
dev_err(&client->dev, "num_regulators too large!");
info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
switch (data->id) {
case ltc2972:
case ltc2974:
case ltc2975:
case ltc2977:
case ltc2978:
case ltc2979:
case ltc2980:
case ltm2987:
info->reg_desc = ltc2978_reg_desc;
if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
dev_warn(&client->dev, "num_regulators too large!");
info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
}
break;
default:
info->reg_desc = ltc2978_reg_desc_default;
if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc_default)) {
dev_warn(&client->dev, "num_regulators too large!");
info->num_regulators =
ARRAY_SIZE(ltc2978_reg_desc_default);
}
break;
}
#endif
......
......@@ -406,7 +406,7 @@ enum pmbus_sensor_classes {
#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */
#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */
enum pmbus_data_format { linear = 0, direct, vid };
enum pmbus_data_format { linear = 0, ieee754, direct, vid };
enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv };
struct pmbus_driver_info {
......@@ -463,8 +463,8 @@ struct pmbus_driver_info {
extern const struct regulator_ops pmbus_regulator_ops;
/* Macro for filling in array of struct regulator_desc */
#define PMBUS_REGULATOR(_name, _id) \
/* Macros for filling in array of struct regulator_desc */
#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step) \
[_id] = { \
.name = (_name # _id), \
.supply_name = "vin", \
......@@ -474,8 +474,12 @@ extern const struct regulator_ops pmbus_regulator_ops;
.ops = &pmbus_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.n_voltages = _voltages, \
.uV_step = _step, \
}
#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0)
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
......
This diff is collapsed.
......@@ -523,6 +523,28 @@ static int __init sch56xx_device_add(int address, const char *name)
return PTR_ERR_OR_ZERO(sch56xx_pdev);
}
static const struct dmi_system_id sch56xx_dmi_override_table[] __initconst = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS W380"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO P710"),
},
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO E9900"),
},
},
{ }
};
/* For autoloading only */
static const struct dmi_system_id sch56xx_dmi_table[] __initconst = {
{
......@@ -543,16 +565,18 @@ static int __init sch56xx_init(void)
if (!dmi_check_system(sch56xx_dmi_table))
return -ENODEV;
/*
* Some machines like the Esprimo P720 and Esprimo C700 have
* onboard devices named " Antiope"/" Theseus" instead of
* "Antiope"/"Theseus", so we need to check for both.
*/
if (!dmi_find_device(DMI_DEV_TYPE_OTHER, "Antiope", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OTHER, " Antiope", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OTHER, "Theseus", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OTHER, " Theseus", NULL))
return -ENODEV;
if (!dmi_check_system(sch56xx_dmi_override_table)) {
/*
* Some machines like the Esprimo P720 and Esprimo C700 have
* onboard devices named " Antiope"/" Theseus" instead of
* "Antiope"/"Theseus", so we need to check for both.
*/
if (!dmi_find_device(DMI_DEV_TYPE_OTHER, "Antiope", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OTHER, " Antiope", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OTHER, "Theseus", NULL) &&
!dmi_find_device(DMI_DEV_TYPE_OTHER, " Theseus", NULL))
return -ENODEV;
}
}
/*
......
......@@ -1020,25 +1020,20 @@ static int sht15_probe(struct platform_device *pdev)
static int sht15_remove(struct platform_device *pdev)
{
struct sht15_data *data = platform_get_drvdata(pdev);
int ret;
/*
* Make sure any reads from the device are done and
* prevent new ones beginning
*/
mutex_lock(&data->read_lock);
if (sht15_soft_reset(data)) {
mutex_unlock(&data->read_lock);
return -EFAULT;
}
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
ret = sht15_soft_reset(data);
if (ret)
dev_err(&pdev->dev, "Failed to reset device (%pe)\n", ERR_PTR(ret));
if (!IS_ERR(data->reg)) {
regulator_unregister_notifier(data->reg, &data->nb);
regulator_disable(data->reg);
}
mutex_unlock(&data->read_lock);
return 0;
}
......
......@@ -140,7 +140,8 @@ static int tps23861_read_temp(struct tps23861_data *data, long *val)
static int tps23861_read_voltage(struct tps23861_data *data, int channel,
long *val)
{
unsigned int regval;
__le16 regval;
long raw_val;
int err;
if (channel < TPS23861_NUM_PORTS) {
......@@ -155,7 +156,8 @@ static int tps23861_read_voltage(struct tps23861_data *data, int channel,
if (err < 0)
return err;
*val = (FIELD_GET(VOLTAGE_CURRENT_MASK, regval) * VOLTAGE_LSB) / 1000;
raw_val = le16_to_cpu(regval);
*val = (FIELD_GET(VOLTAGE_CURRENT_MASK, raw_val) * VOLTAGE_LSB) / 1000;
return 0;
}
......@@ -163,8 +165,9 @@ static int tps23861_read_voltage(struct tps23861_data *data, int channel,
static int tps23861_read_current(struct tps23861_data *data, int channel,
long *val)
{
unsigned int current_lsb;
unsigned int regval;
long raw_val, current_lsb;
__le16 regval;
int err;
if (data->shunt_resistor == SHUNT_RESISTOR_DEFAULT)
......@@ -178,7 +181,8 @@ static int tps23861_read_current(struct tps23861_data *data, int channel,
if (err < 0)
return err;
*val = (FIELD_GET(VOLTAGE_CURRENT_MASK, regval) * current_lsb) / 1000000;
raw_val = le16_to_cpu(regval);
*val = (FIELD_GET(VOLTAGE_CURRENT_MASK, raw_val) * current_lsb) / 1000000;
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment