Commit fd276877 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull hwmon updates from Guenter Roeck:
 "New drivers:

   - Texas Instruments TMP464 and TMP468 driver

   - Vicor PLI1209BC Digital Supervisor driver

   - ASUS EC driver

  Improvements to existing drivers:

   - adt7x10:
       - Convert to use regmap
       - convert to use with_info API
       - use hwmon_notify_event
       - other cleanup

   - aquacomputer_d5next:
       - Add support for Aquacomputer Farbwerk 360

   - asus_wmi_sensors:
       - Add ASUS ROG STRIX B450-F GAMING II

   - asus_wmi_ec_sensors:
       - Support T_Sensor on Prime X570-Pro
       - Deprecate driver (replaced by new driver)

   - axi-fan-control:
       - Use hwmon_notify_event

   - dell-smm:
       - Clean up CONFIG_I8K
       - disable fan type support for Inspiron 3505
       - various other cleanup

   - hwmon core:
       - Report attribute name with udev events
       - Add "label" attribute to ABI,
       - Add support for pwm auto channels attribute

   - max6639:
       - Add regulator support

   - lm70:
       - Add support for TI TMP125

   - lm83:
       - Cleanup, convert to use with_info API

   - mlxreg-fan:
       - Use pwm attribute for setting fan speed low limit

   - nct6775:
       - Add board ID's for ASUS ROG STRIX Z390/Z490/X570-* / PRIME
         X570-P, PRIME B550-PLUS, ASUS Pro B550M-C/PRIME B550M-A
       - Add support for TSI temperature registers

   - occ:
       - Add various new sysfs attributes

   - pmbus core:
       - Handle VIN unit off status
       - Add regulator supply into macro
       - Add get_error_flags support to regulator ops

   - pmbus/adm1275:
       - Allow setting sample averaging

   - pmbus/lm25066:
       - Add regulator support

   - pmbus/xdpe12284:
       - Add support for xdpe11280
       - register as regulator

   - powr1220:
       - Convert to with_info API
       - Add support for Lattice's POWR1014 power manager IC

   - sch56xx:
       - Cleanup and minor improvements

   - sch5627:
       - Add pwmX_auto_channels_temp support

   - tc654:
       - Add thermal_cooling device support"

* tag 'hwmon-for-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (86 commits)
  hwmon: (dell-smm) Add Inspiron 3505 to fan type blacklist
  hwmon: (pmbus) Add Vin unit off handling
  hwmon: (scpi-hwmon): Use of_device_get_match_data()
  hwmon: (axi-fan-control) Use hwmon_notify_event
  hwmon: (vexpress-hwmon) Use of_device_get_match_data()
  hwmon: Add driver for Texas Instruments TMP464 and TMP468
  dt-bindings: hwmon: add tmp464.yaml
  dt-bindings: hwmon: Add sample averaging properties for ADM1275
  hwmon: (adm1275) Allow setting sample averaging
  hwmon: (xdpe12284) Add regulator support
  hwmon: (xdpe12284) Add support for xdpe11280
  dt-bindings: trivial-devices: Add xdpe11280
  hwmon: (aquacomputer_d5next) Add support for Aquacomputer Farbwerk 360
  hwmon: (sch5627) Add pwmX_auto_channels_temp support
  hwmon: (core) Add support for pwm auto channels attribute
  hwmon: (lm70) Add ti,tmp125 support
  dt-bindings: Add ti,tmp125 temperature sensor binding
  hwmon: (pmbus/pli1209bc) Add regulator support
  hwmon: (pmbus) Add support for pli1209bc
  dt-bindings:trivial-devices: Add pli1209bc
  ...
parents d347ee54 6ba463ed
What: /proc/i8k
Date: November 2001
KernelVersion: 2.4.14
Contact: Pali Rohár <pali@kernel.org>
Description: Legacy interface for getting/setting sensor information like
fan speed, temperature, serial number, hotkey status etc
on Dell Laptops.
Since the driver is now using the standard hwmon sysfs interface,
the procfs interface is deprecated.
Users: https://github.com/vitorafsr/i8kutils
......@@ -9,6 +9,14 @@ Description:
RO
What: /sys/class/hwmon/hwmonX/label
Description:
A descriptive label that allows to uniquely identify a
device within the system.
The contents of the label are free-form.
RO
What: /sys/class/hwmon/hwmonX/update_interval
Description:
The interval at which the chip will update readings.
......
......@@ -944,6 +944,30 @@
dump out devices still on the deferred probe list after
retrying.
dell_smm_hwmon.ignore_dmi=
[HW] Continue probing hardware even if DMI data
indicates that the driver is running on unsupported
hardware.
dell_smm_hwmon.force=
[HW] Activate driver even if SMM BIOS signature does
not match list of supported models and enable otherwise
blacklisted features.
dell_smm_hwmon.power_status=
[HW] Report power status in /proc/i8k
(disabled by default).
dell_smm_hwmon.restricted=
[HW] Allow controlling fans only if SYS_ADMIN
capability is set.
dell_smm_hwmon.fan_mult=
[HW] Factor to multiply fan speed with.
dell_smm_hwmon.fan_max=
[HW] Maximum configurable fan speed.
dfltcc= [HW,S390]
Format: { on | off | def_only | inf_only | always }
on: s390 zlib hardware support for compression on
......@@ -1703,17 +1727,6 @@
i810= [HW,DRM]
i8k.ignore_dmi [HW] Continue probing hardware even if DMI data
indicates that the driver is running on unsupported
hardware.
i8k.force [HW] Activate i8k driver even if SMM BIOS signature
does not match list of supported models.
i8k.power_status
[HW] Report power status in /proc/i8k
(disabled by default)
i8k.restricted [HW] Allow controlling fans only if SYS_ADMIN
capability is set.
i915.invert_brightness=
[DRM] Invert the sense of the variable that is used to
set the brightness of the panel backlight. Normally a
......
......@@ -37,6 +37,72 @@ properties:
description:
Shunt resistor value in micro-Ohm.
adi,volt-curr-sample-average:
description: |
Number of samples to be used to report voltage and current values.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32, 64, 128]
adi,power-sample-average:
description: |
Number of samples to be used to report power values.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8, 16, 32, 64, 128]
allOf:
- if:
properties:
compatible:
contains:
enum:
- adi,adm1075
- adi,adm1276
then:
properties:
adi,volt-curr-sample-average:
default: 128
adi,power-sample-average: false
- if:
properties:
compatible:
contains:
enum:
- adi,adm1275
then:
properties:
adi,volt-curr-sample-average:
default: 16
adi,power-sample-average: false
- if:
properties:
compatible:
contains:
enum:
- adi,adm1272
then:
properties:
adi,volt-curr-sample-average:
default: 128
adi,power-sample-average:
default: 128
- if:
properties:
compatible:
contains:
enum:
- adi,adm1278
- adi,adm1293
- adi,adm1294
then:
properties:
adi,volt-curr-sample-average:
default: 128
adi,power-sample-average:
default: 1
required:
- compatible
- reg
......@@ -53,5 +119,7 @@ examples:
compatible = "adi,adm1272";
reg = <0x10>;
shunt-resistor-micro-ohms = <500>;
adi,volt-curr-sample-average = <128>;
adi,power-sample-average = <128>;
};
};
......@@ -60,7 +60,6 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
......@@ -71,8 +70,7 @@ examples:
compatible = "onnn,nct1008";
reg = <0x4c>;
vcc-supply = <&palmas_ldo6_reg>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(O, 4) IRQ_TYPE_LEVEL_LOW>;
interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
#thermal-sensor-cells = <1>;
};
};
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/hwmon/ti,tmp464.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TMP464 and TMP468 temperature sensors
maintainers:
- Agathe Porte <agathe.porte@nokia.com>
description: |
±0.0625°C Remote and Local temperature sensor
https://www.ti.com/lit/ds/symlink/tmp464.pdf
https://www.ti.com/lit/ds/symlink/tmp468.pdf
properties:
compatible:
enum:
- ti,tmp464
- ti,tmp468
reg:
maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
required:
- compatible
- reg
additionalProperties: false
patternProperties:
"^channel@([0-8])$":
type: object
description: |
Represents channels of the device and their specific configuration.
properties:
reg:
description: |
The channel number. 0 is local channel, 1-8 are remote channels.
items:
minimum: 0
maximum: 8
label:
description: |
A descriptive name for this channel, like "ambient" or "psu".
ti,n-factor:
description: |
The value (two's complement) to be programmed in the channel specific N correction register.
For remote channels only.
$ref: /schemas/types.yaml#/definitions/int32
items:
minimum: -128
maximum: 127
required:
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@4b {
compatible = "ti,tmp464";
reg = <0x4b>;
};
};
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
sensor@4b {
compatible = "ti,tmp464";
reg = <0x4b>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0x0>;
label = "local";
};
channel@1 {
reg = <0x1>;
ti,n-factor = <(-10)>;
label = "external";
};
channel@2 {
reg = <0x2>;
ti,n-factor = <0x10>;
label = "somelabel";
};
channel@3 {
reg = <0x3>;
status = "disabled";
};
};
};
......@@ -137,6 +137,8 @@ properties:
- infineon,slb9645tt
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
- infineon,tlv493d-a1b6
# Infineon Multi-phase Digital VR Controller xdpe11280
- infineon,xdpe11280
# Infineon Multi-phase Digital VR Controller xdpe12254
- infineon,xdpe12254
# Infineon Multi-phase Digital VR Controller xdpe12284
......@@ -337,6 +339,7 @@ properties:
# Thermometer with SPI interface
- ti,tmp121
- ti,tmp122
- ti,tmp125
# Digital Temperature Sensor
- ti,tmp275
# TI DC-DC converter on PMBus
......@@ -354,6 +357,8 @@ properties:
- ti,tps544c25
# Winbond/Nuvoton H/W Monitor
- winbond,w83793
# Vicor Corporation Digital Supervisor
- vicor,pli1209bc
# i2c trusted platform module (TPM)
- winbond,wpct301
......
......@@ -1298,6 +1298,8 @@ patternProperties:
description: Vertexcom Technologies, Inc.
"^via,.*":
description: VIA Technologies, Inc.
"^vicor,.*":
description: Vicor Corporation
"^videostrong,.*":
description: Videostrong Technology Co., Ltd.
"^virtio,.*":
......
......@@ -6,22 +6,21 @@ Kernel driver aquacomputer-d5next
Supported devices:
* Aquacomputer D5 Next watercooling pump
* Aquacomputer Farbwerk 360 RGB controller
Author: Aleksa Savic
Description
-----------
This driver exposes hardware sensors of the Aquacomputer D5 Next watercooling
pump, which communicates through a proprietary USB HID protocol.
This driver exposes hardware sensors of listed Aquacomputer devices, which
communicate through proprietary USB HID protocols.
Available sensors are pump and fan speed, power, voltage and current, as
well as coolant temperature. Also available through debugfs are the serial
number, firmware version and power-on count.
Attaching a fan is optional and allows it to be controlled using temperature
curves directly from the pump. If it's not connected, the fan-related sensors
will report zeroes.
For the D5 Next pump, available sensors are pump and fan speed, power, voltage
and current, as well as coolant temperature. Also available through debugfs are
the serial number, firmware version and power-on count. Attaching a fan to it is
optional and allows it to be controlled using temperature curves directly from the
pump. If it's not connected, the fan-related sensors will report zeroes.
The pump can be configured either through software or via its physical
interface. Configuring the pump through this driver is not implemented, as it
......@@ -29,33 +28,31 @@ seems to require sending it a complete configuration. That includes addressable
RGB LEDs, for which there is no standard sysfs interface. Thus, that task is
better suited for userspace tools.
The Farbwerk 360 exposes four temperature sensors. Depending on the device,
not all sysfs and debugfs entries will be available.
Usage notes
-----------
The pump communicates via HID reports. The driver is loaded automatically by
The devices communicate via HID reports. The driver is loaded automatically by
the kernel and supports hotswapping.
Sysfs entries
-------------
============ =============================================
temp1_input Coolant temperature (in millidegrees Celsius)
fan1_input Pump speed (in RPM)
fan2_input Fan speed (in RPM)
power1_input Pump power (in micro Watts)
power2_input Fan power (in micro Watts)
in0_input Pump voltage (in milli Volts)
in1_input Fan voltage (in milli Volts)
in2_input +5V rail voltage (in milli Volts)
curr1_input Pump current (in milli Amperes)
curr2_input Fan current (in milli Amperes)
============ =============================================
================ =============================================
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)
================ =============================================
Debugfs entries
---------------
================ ===============================================
serial_number Serial number of the pump
================ =================================================
serial_number Serial number of the device
firmware_version Version of installed firmware
power_cycles Count of how many times the pump was powered on
================ ===============================================
power_cycles Count of how many times the device was powered on
================ =================================================
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver asus_ec_sensors
=================================
Supported boards:
* PRIME X570-PRO,
* Pro WS X570-ACE,
* ROG CROSSHAIR VIII DARK HERO,
* ROG CROSSHAIR VIII HERO (WI-FI)
* ROG CROSSHAIR VIII FORMULA,
* ROG CROSSHAIR VIII HERO,
* ROG CROSSHAIR VIII IMPACT,
* ROG STRIX B550-E GAMING,
* ROG STRIX B550-I GAMING,
* ROG STRIX X570-E GAMING,
* ROG STRIX X570-F GAMING,
* ROG STRIX X570-I GAMING
Authors:
- Eugene Shalygin <eugene.shalygin@gmail.com>
Description:
------------
ASUS mainboards publish hardware monitoring information via Super I/O
chip and the ACPI embedded controller (EC) registers. Some of the sensors
are only available via the EC.
The driver is aware of and reads the following sensors:
1. Chipset (PCH) temperature
2. CPU package temperature
3. Motherboard temperature
4. Readings from the T_Sensor header
5. VRM temperature
6. CPU_Opt fan RPM
7. VRM heatsink fan RPM
8. Chipset fan RPM
9. Readings from the "Water flow meter" header (RPM)
10. Readings from the "Water In" and "Water Out" temperature headers
11. CPU current
12. CPU core voltage
Sensor values are read from EC registers, and to avoid race with the board
firmware the driver acquires ACPI mutex, the one used by the WMI when its
methods access the EC.
Module Parameters
-----------------
* mutex_path: string
The driver holds path to the ACPI mutex for each board (actually,
the path is mostly identical for them). If ASUS changes this path
in a future BIOS update, this parameter can be used to override
the stored in the driver value until it gets updated.
......@@ -165,3 +165,183 @@ obtain the same information and to control the fan status. The ioctl
interface can be accessed from C programs or from shell using the
i8kctl utility. See the source file of ``i8kutils`` for more
information on how to use the ioctl interface.
SMM Interface
-------------
.. warning:: The SMM interface was reverse-engineered by trial-and-error
since Dell did not provide any Documentation,
please keep that in mind.
The driver uses the SMM interface to send commands to the system BIOS.
This interface is normally used by Dell's 32-bit diagnostic program or
on newer notebook models by the buildin BIOS diagnostics.
The SMM is triggered by writing to the special ioports ``0xb2`` and ``0x84``,
and may cause short hangs when the BIOS code is taking too long to
execute.
The SMM handler inside the system BIOS looks at the contents of the
``eax``, ``ebx``, ``ecx``, ``edx``, ``esi`` and ``edi`` registers.
Each register has a special purpose:
=============== ==================================
Register Purpose
=============== ==================================
eax Holds the command code before SMM,
holds the first result after SMM.
ebx Holds the arguments.
ecx Unknown, set to 0.
edx Holds the second result after SMM.
esi Unknown, set to 0.
edi Unknown, set to 0.
=============== ==================================
The SMM handler can signal a failure by either:
- setting the lower sixteen bits of ``eax`` to ``0xffff``
- not modifying ``eax`` at all
- setting the carry flag
SMM command codes
-----------------
=============== ======================= ================================================
Command Code Command Name Description
=============== ======================= ================================================
``0x0025`` Get Fn key status Returns the Fn key pressed after SMM:
- 9th bit in ``eax`` indicates Volume up
- 10th bit in ``eax`` indicates Volume down
- both bits indicate Volume mute
``0xa069`` Get power status Returns current power status after SMM:
- 1st bit in ``eax`` indicates Battery connected
- 3th bit in ``eax`` indicates AC connected
``0x00a3`` Get fan state Returns current fan state after SMM:
- 1st byte in ``eax`` holds the current
fan state (0 - 2 or 3)
``0x01a3`` Set fan state Sets the fan speed:
- 1st byte in ``ebx`` holds the fan number
- 2nd byte in ``ebx`` holds the desired
fan state (0 - 2 or 3)
``0x02a3`` Get fan speed Returns the current fan speed in RPM:
- 1st byte in ``ebx`` holds the fan number
- 1st word in ``eax`` holds the current
fan speed in RPM (after SMM)
``0x03a3`` Get fan type Returns the fan type:
- 1st byte in ``ebx`` holds the fan number
- 1st byte in ``eax`` holds the
fan type (after SMM):
- 5th bit indicates docking fan
- 1 indicates Processor fan
- 2 indicates Motherboard fan
- 3 indicates Video fan
- 4 indicates Power supply fan
- 5 indicates Chipset fan
- 6 indicates other fan type
``0x04a3`` Get nominal fan speed Returns the nominal RPM in each fan state:
- 1st byte in ``ebx`` holds the fan number
- 2nd byte in ``ebx`` holds the fan state
in question (0 - 2 or 3)
- 1st word in ``eax`` holds the nominal
fan speed in RPM (after SMM)
``0x05a3`` Get fan speed tolerance Returns the speed tolerance for each fan state:
- 1st byte in ``ebx`` holds the fan number
- 2nd byte in ``ebx`` holds the fan state
in question (0 - 2 or 3)
- 1st byte in ``eax`` returns the speed
tolerance
``0x10a3`` Get sensor temperature Returns the measured temperature:
- 1st byte in ``ebx`` holds the sensor number
- 1st byte in ``eax`` holds the measured
temperature (after SMM)
``0x11a3`` Get sensor type Returns the sensor type:
- 1st byte in ``ebx`` holds the sensor number
- 1st byte in ``eax`` holds the
temperature type (after SMM):
- 1 indicates CPU sensor
- 2 indicates GPU sensor
- 3 indicates SODIMM sensor
- 4 indicates other sensor type
- 5 indicates Ambient sensor
- 6 indicates other sensor type
``0xfea3`` Get SMM signature Returns Dell signature if interface
is supported (after SMM):
- ``eax`` holds 1145651527
(0x44494147 or "DIAG")
- ``edx`` holds 1145392204
(0x44454c4c or "DELL")
``0xffa3`` Get SMM signature Same as ``0xfea3``, check both.
=============== ======================= ================================================
There are additional commands for enabling (``0x31a3`` or ``0x35a3``) and
disabling (``0x30a3`` or ``0x34a3``) automatic fan speed control.
The commands are however causing severe sideeffects on many machines, so
they are not used by default.
On several machines (Inspiron 3505, Precision 490, Vostro 1720, ...), the
fans supports a 4th "magic" state, which signals the BIOS that automatic
fan control should be enabled for a specific fan.
However there are also some machines who do support a 4th regular fan state too,
but in case of the "magic" state, the nominal RPM reported for this state is a
placeholder value, which however is not always detectable.
Firmware Bugs
-------------
The SMM calls can behave erratic on some machines:
======================================================= =================
Firmware Bug Affected Machines
======================================================= =================
Reading of fan states return spurious errors. Precision 490
Reading of fan types causes erratic fan behaviour. Studio XPS 8000
Studio XPS 8100
Inspiron 580
Fan-related SMM calls take too long (about 500ms). Inspiron 7720
Vostro 3360
XPS 13 9333
XPS 15 L502X
======================================================= =================
In case you experience similar issues on your Dell machine, please
submit a bugreport on bugzilla to we can apply workarounds.
Limitations
-----------
The SMM calls can take too long to execute on some machines, causing
short hangs and/or audio glitches.
Also the fan state needs to be restored after suspend, as well as
the automatic mode settings.
When reading a temperature sensor, values above 127 degrees indicate
a BIOS read error or a deactivated sensor.
......@@ -43,6 +43,7 @@ Hardware Monitoring Kernel Drivers
asb100
asc7621
aspeed-pwm-tacho
asus_ec_sensors
asus_wmi_ec_sensors
asus_wmi_sensors
bcm54140
......@@ -160,6 +161,7 @@ Hardware Monitoring Kernel Drivers
pc87427
pcf8591
pim4328
pli1209bc
pm6764tr
pmbus
powr1220
......@@ -193,6 +195,7 @@ Hardware Monitoring Kernel Drivers
tmp108
tmp401
tmp421
tmp464
tmp513
tps23861
tps40422
......
......@@ -15,6 +15,10 @@ Supported chips:
Information: https://www.ti.com/product/tmp122
* Texas Instruments TMP125
Information: https://www.ti.com/product/tmp125
* National Semiconductor LM71
Datasheet: https://www.ti.com/product/LM71
......@@ -53,6 +57,9 @@ The LM74 and TMP121/TMP122/TMP123/TMP124 are very similar; main difference is
The TMP122/TMP124 also feature configurable temperature thresholds.
The TMP125 is less accurate and provides 10-bit temperature data
with 0.25 degrees Celsius resolution.
The LM71 is also very similar; main difference is 14-bit temperature
data (0.03125 degrees celsius resolution).
......
......@@ -9,7 +9,7 @@ Supported chips:
Addresses scanned: I2C 0x2c, 0x2e, 0x2f
Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6639.pdf
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX6639-MAX6639F.pdf
Authors:
- He Changqing <hechangqing@semptian.com>
......
.. SPDX-License-Identifier: GPL-2.0
Kernel driver pli1209bc
=======================
Supported chips:
* Digital Supervisor PLI1209BC
Prefix: 'pli1209bc'
Addresses scanned: 0x50 - 0x5F
Datasheet: https://www.vicorpower.com/documents/datasheets/ds-PLI1209BCxyzz-VICOR.pdf
Authors:
- Marcello Sylvester Bauer <sylv@sylv.io>
Description
-----------
The Vicor PLI1209BC is an isolated digital power system supervisor that provides
a communication interface between a host processor and one Bus Converter Module
(BCM). The PLI communicates with a system controller via a PMBus compatible
interface over an isolated UART interface. Through the PLI, the host processor
can configure, set protection limits, and monitor the BCM.
Sysfs entries
-------------
======================= ========================================================
in1_label "vin2"
in1_input Input voltage.
in1_rated_min Minimum rated input voltage.
in1_rated_max Maximum rated input voltage.
in1_max Maximum input voltage.
in1_max_alarm Input voltage high alarm.
in1_crit Critical input voltage.
in1_crit_alarm Input voltage critical alarm.
in2_label "vout2"
in2_input Output voltage.
in2_rated_min Minimum rated output voltage.
in2_rated_max Maximum rated output voltage.
in2_alarm Output voltage alarm
curr1_label "iin2"
curr1_input Input current.
curr1_max Maximum input current.
curr1_max_alarm Maximum input current high alarm.
curr1_crit Critical input current.
curr1_crit_alarm Input current critical alarm.
curr2_label "iout2"
curr2_input Output current.
curr2_crit Critical output current.
curr2_crit_alarm Output current critical alarm.
curr2_max Maximum output current.
curr2_max_alarm Output current high alarm.
power1_label "pin2"
power1_input Input power.
power1_alarm Input power alarm.
power2_label "pout2"
power2_input Output power.
power2_rated_max Maximum rated output power.
temp1_input Die temperature.
temp1_alarm Die temperature alarm.
temp1_max Maximum die temperature.
temp1_max_alarm Die temperature high alarm.
temp1_crit Critical die temperature.
temp1_crit_alarm Die temperature critical alarm.
======================= ========================================================
......@@ -20,6 +20,10 @@ Description
SMSC SCH5627 Super I/O chips include complete hardware monitoring
capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures.
In addition, the SCH5627 exports data describing which temperature sensors
affect the speed of each fan. Setting pwmX_auto_channels_temp to 0 forces
the corresponding fan to full speed until another value is written.
The SMSC SCH5627 hardware monitoring part also contains an integrated
watchdog. In order for this watchdog to function some motherboard specific
initialization most be done by the BIOS, so if the watchdog is not enabled
......
......@@ -99,6 +99,10 @@ Global attributes
`name`
The chip name.
`label`
A descriptive label that allows to uniquely identify a device
within the system.
`update_interval`
The interval at which the chip will update readings.
......
.. SPDX-License-Identifier: GPL-2.0
Kernel driver tmp464
====================
Supported chips:
* Texas Instruments TMP464
Prefix: 'tmp464'
Addresses scanned: I2C 0x48, 0x49, 0x4a and 0x4b
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp464.html
* Texas Instruments TMP468
Prefix: 'tmp468'
Addresses scanned: I2C 0x48, 0x49, 0x4a and 0x4b
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp468.html
Authors:
Agathe Porte <agathe.porte@nokia.com>
Guenter Roeck <linux@roeck-us.net>
Description
-----------
This driver implements support for Texas Instruments TMP464 and TMP468
temperature sensor chips. TMP464 provides one local and four remote
sensors. TMP468 provides one local and eight remote sensors.
Temperature is measured in degrees Celsius. The chips are wired over
I2C/SMBus and specified over a temperature range of -40 to +125 degrees
Celsius. Resolution for both the local and remote channels is 0.0625
degree C.
The chips support only temperature measurements. The driver exports
temperature values, limits, and alarms via the following sysfs files:
**temp[1-9]_input**
**temp[1-9]_max**
**temp[1-9]_max_hyst**
**temp[1-9]_max_alarm**
**temp[1-9]_crit**
**temp[1-9]_crit_alarm**
**temp[1-9]_crit_hyst**
**temp[2-9]_offset**
**temp[2-9]_fault**
Each sensor can be individually disabled via Devicetree or from sysfs
via:
**temp[1-9]_enable**
If labels were specified in Devicetree, additional sysfs files will
be present:
**temp[1-9]_label**
The update interval is configurable with the following sysfs attribute.
**update_interval**
......@@ -5,6 +5,10 @@ Kernel driver xdpe122
Supported chips:
* Infineon XDPE11280
Prefix: 'xdpe11280'
* Infineon XDPE12254
Prefix: 'xdpe12254'
......@@ -20,10 +24,10 @@ Authors:
Description
-----------
This driver implements support for Infineon Multi-phase XDPE122 family
dual loop voltage regulators.
The family includes XDPE12284 and XDPE12254 devices.
The devices from this family complaint with:
This driver implements support for Infineon Multi-phase XDPE112 and XDPE122
family dual loop voltage regulators.
These families include XDPE11280, XDPE12284 and XDPE12254 devices.
The devices from this family compliant with:
- Intel VR13 and VR13HC rev 1.3, IMVP8 rev 1.2 and IMPVP9 rev 1.3 DC-DC
converter specification.
......
......@@ -3057,6 +3057,12 @@ L: linux-hwmon@vger.kernel.org
S: Maintained
F: drivers/hwmon/asus_wmi_ec_sensors.c
ASUS EC HARDWARE MONITOR DRIVER
M: Eugene Shalygin <eugene.shalygin@gmail.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: drivers/hwmon/asus-ec-sensors.c
ASUS WIRELESS RADIO CONTROL DRIVER
M: João Paulo Rechi Vita <jprvita@gmail.com>
L: platform-driver-x86@vger.kernel.org
......@@ -5412,6 +5418,7 @@ F: drivers/platform/x86/dell/dell-rbtn.*
DELL LAPTOP SMM DRIVER
M: Pali Rohár <pali@kernel.org>
S: Maintained
F: Documentation/ABI/obsolete/procfs-i8k
F: drivers/hwmon/dell-smm-hwmon.c
F: include/uapi/linux/i8k.h
......@@ -19500,6 +19507,15 @@ S: Maintained
F: Documentation/hwmon/tmp401.rst
F: drivers/hwmon/tmp401.c
TMP464 HARDWARE MONITOR DRIVER
M: Agathe Porte <agathe.porte@nokia.com>
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/hwmon/ti,tmp464.yaml
F: Documentation/hwmon/tmp464.rst
F: drivers/hwmon/tmp464.c
TMP513 HARDWARE MONITOR DRIVER
M: Eric Tremblay <etremblay@distech-controls.com>
L: linux-hwmon@vger.kernel.org
......
......@@ -1276,23 +1276,6 @@ config TOSHIBA
Say Y if you intend to run this kernel on a Toshiba portable.
Say N otherwise.
config I8K
tristate "Dell i8k legacy laptop support"
depends on HWMON
depends on PROC_FS
select SENSORS_DELL_SMM
help
This option enables legacy /proc/i8k userspace interface in hwmon
dell-smm-hwmon driver. Character file /proc/i8k reports bios version,
temperature and allows controlling fan speeds of Dell laptops via
System Management Mode. For old Dell laptops (like Dell Inspiron 8000)
it reports also power and hotkey status. For fan speed control is
needed userspace package i8kutils.
Say Y if you intend to run this kernel on old Dell laptops or want to
use userspace package i8kutils.
Say N otherwise.
config X86_REBOOTFIXUPS
bool "Enable X86 board specific fixups for reboot"
depends on X86_32
......
......@@ -174,6 +174,7 @@ config SENSORS_ADM9240
config SENSORS_ADT7X10
tristate
select REGMAP
help
This module contains common code shared by the ADT7310/ADT7320 and
ADT7410/ADT7420 temperature monitoring chip drivers.
......@@ -505,6 +506,21 @@ config SENSORS_DELL_SMM
When option I8K is also enabled this driver provides legacy /proc/i8k
userspace interface for i8kutils package.
config I8K
bool "Legacy /proc/i8k interface of Dell laptop SMM BIOS hwmon driver"
depends on SENSORS_DELL_SMM
depends on PROC_FS
help
This option enables the legacy /proc/i8k userspace interface of the
dell-smm-hwmon driver. The character file /proc/i8k exposes the BIOS
version, temperatures and allows control of fan speeds of some Dell
laptops. Sometimes it also reports power and hotkey status.
This interface is required to run programs from the i8kutils package.
Say Y if you intend to run userspace programs that use this interface.
Say N otherwise.
config SENSORS_DA9052_ADC
tristate "Dialog DA9052/DA9053 ADC"
depends on PMIC_DA9052
......@@ -1208,8 +1224,8 @@ config SENSORS_LM70
depends on SPI_MASTER
help
If you say yes here you get support for the National Semiconductor
LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera-
ture sensor chips.
LM70, LM71, LM74 and Texas Instruments TMP121/TMP123, TMP122/TMP124,
TMP125 digital temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called lm70.
......@@ -1288,6 +1304,7 @@ config SENSORS_LM80
config SENSORS_LM83
tristate "National Semiconductor LM83 and compatibles"
depends on I2C
select REGMAP
help
If you say yes here you get support for National Semiconductor
LM82 and LM83 sensor chips.
......@@ -1979,6 +1996,17 @@ config SENSORS_TMP421
This driver can also be built as a module. If so, the module
will be called tmp421.
config SENSORS_TMP464
tristate "Texas Instruments TMP464 and compatible"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for Texas Instruments TMP464
and TMP468 temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called tmp464.
config SENSORS_TMP513
tristate "Texas Instruments TMP513 and compatibles"
depends on I2C
......@@ -2252,16 +2280,31 @@ config SENSORS_ASUS_WMI
config SENSORS_ASUS_WMI_EC
tristate "ASUS WMI B550/X570"
depends on ACPI_WMI
depends on ACPI_WMI && SENSORS_ASUS_EC=n
help
If you say yes here you get support for the ACPI embedded controller
hardware monitoring interface found in B550/X570 ASUS motherboards.
This driver will provide readings of fans, voltages and temperatures
through the system firmware.
This driver is deprecated in favor of the ASUS EC Sensors driver
which provides fully compatible output.
This driver can also be built as a module. If so, the module
will be called asus_wmi_sensors_ec.
config SENSORS_ASUS_EC
tristate "ASUS EC Sensors"
depends on X86
help
If you say yes here you get support for the ACPI embedded controller
hardware monitoring interface found in ASUS motherboards. The driver
currently supports B550/X570 boards, although other ASUS boards might
provide this monitoring interface as well.
This driver can also be built as a module. If so, the module
will be called asus_ec_sensors.
endif # ACPI
endif # HWMON
......@@ -9,6 +9,7 @@ obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
# APCI drivers
obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o
obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o
obj-$(CONFIG_SENSORS_ASUS_EC) += asus-ec-sensors.o
obj-$(CONFIG_SENSORS_ASUS_WMI) += asus_wmi_sensors.o
obj-$(CONFIG_SENSORS_ASUS_WMI_EC) += asus_wmi_ec_sensors.o
......@@ -194,6 +195,7 @@ obj-$(CONFIG_SENSORS_TMP103) += tmp103.o
obj-$(CONFIG_SENSORS_TMP108) += tmp108.o
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
obj-$(CONFIG_SENSORS_TMP464) += tmp464.o
obj-$(CONFIG_SENSORS_TMP513) += tmp513.o
obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
......
......@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <asm/unaligned.h>
......@@ -38,16 +39,13 @@ static const u8 adt7310_reg_table[] = {
#define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
static int adt7310_spi_read_word(struct device *dev, u8 reg)
static int adt7310_spi_read_word(struct spi_device *spi, u8 reg)
{
struct spi_device *spi = to_spi_device(dev);
return spi_w8r16be(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
}
static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
static int adt7310_spi_write_word(struct spi_device *spi, u8 reg, u16 data)
{
struct spi_device *spi = to_spi_device(dev);
u8 buf[3];
buf[0] = AD7310_COMMAND(reg);
......@@ -56,17 +54,13 @@ static int adt7310_spi_write_word(struct device *dev, u8 reg, u16 data)
return spi_write(spi, buf, sizeof(buf));
}
static int adt7310_spi_read_byte(struct device *dev, u8 reg)
static int adt7310_spi_read_byte(struct spi_device *spi, u8 reg)
{
struct spi_device *spi = to_spi_device(dev);
return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
}
static int adt7310_spi_write_byte(struct device *dev, u8 reg,
u8 data)
static int adt7310_spi_write_byte(struct spi_device *spi, u8 reg, u8 data)
{
struct spi_device *spi = to_spi_device(dev);
u8 buf[2];
buf[0] = AD7310_COMMAND(reg);
......@@ -75,25 +69,79 @@ static int adt7310_spi_write_byte(struct device *dev, u8 reg,
return spi_write(spi, buf, sizeof(buf));
}
static const struct adt7x10_ops adt7310_spi_ops = {
.read_word = adt7310_spi_read_word,
.write_word = adt7310_spi_write_word,
.read_byte = adt7310_spi_read_byte,
.write_byte = adt7310_spi_write_byte,
};
static int adt7310_spi_probe(struct spi_device *spi)
static bool adt7310_regmap_is_volatile(struct device *dev, unsigned int reg)
{
return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
&adt7310_spi_ops);
switch (reg) {
case ADT7X10_TEMPERATURE:
case ADT7X10_STATUS:
return true;
default:
return false;
}
}
static int adt7310_spi_remove(struct spi_device *spi)
static int adt7310_reg_read(void *context, unsigned int reg, unsigned int *val)
{
adt7x10_remove(&spi->dev, spi->irq);
struct spi_device *spi = context;
int regval;
switch (reg) {
case ADT7X10_TEMPERATURE:
case ADT7X10_T_ALARM_HIGH:
case ADT7X10_T_ALARM_LOW:
case ADT7X10_T_CRIT:
regval = adt7310_spi_read_word(spi, reg);
break;
default:
regval = adt7310_spi_read_byte(spi, reg);
break;
}
if (regval < 0)
return regval;
*val = regval;
return 0;
}
static int adt7310_reg_write(void *context, unsigned int reg, unsigned int val)
{
struct spi_device *spi = context;
int ret;
switch (reg) {
case ADT7X10_TEMPERATURE:
case ADT7X10_T_ALARM_HIGH:
case ADT7X10_T_ALARM_LOW:
case ADT7X10_T_CRIT:
ret = adt7310_spi_write_word(spi, reg, val);
break;
default:
ret = adt7310_spi_write_byte(spi, reg, val);
break;
}
return ret;
}
static const struct regmap_config adt7310_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = adt7310_regmap_is_volatile,
.reg_read = adt7310_reg_read,
.reg_write = adt7310_reg_write,
};
static int adt7310_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
regmap = devm_regmap_init(&spi->dev, NULL, spi, &adt7310_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
regmap);
}
static const struct spi_device_id adt7310_id[] = {
{ "adt7310", 0 },
{ "adt7320", 0 },
......@@ -107,7 +155,6 @@ static struct spi_driver adt7310_driver = {
.pm = ADT7X10_DEV_PM_OPS,
},
.probe = adt7310_spi_probe,
.remove = adt7310_spi_remove,
.id_table = adt7310_id,
};
module_spi_driver(adt7310_driver);
......
......@@ -9,49 +9,82 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include "adt7x10.h"
static int adt7410_i2c_read_word(struct device *dev, u8 reg)
static bool adt7410_regmap_is_volatile(struct device *dev, unsigned int reg)
{
return i2c_smbus_read_word_swapped(to_i2c_client(dev), reg);
switch (reg) {
case ADT7X10_TEMPERATURE:
case ADT7X10_STATUS:
return true;
default:
return false;
}
}
static int adt7410_i2c_write_word(struct device *dev, u8 reg, u16 data)
static int adt7410_reg_read(void *context, unsigned int reg, unsigned int *val)
{
return i2c_smbus_write_word_swapped(to_i2c_client(dev), reg, data);
}
struct i2c_client *client = context;
int regval;
static int adt7410_i2c_read_byte(struct device *dev, u8 reg)
{
return i2c_smbus_read_byte_data(to_i2c_client(dev), reg);
switch (reg) {
case ADT7X10_TEMPERATURE:
case ADT7X10_T_ALARM_HIGH:
case ADT7X10_T_ALARM_LOW:
case ADT7X10_T_CRIT:
regval = i2c_smbus_read_word_swapped(client, reg);
break;
default:
regval = i2c_smbus_read_byte_data(client, reg);
break;
}
if (regval < 0)
return regval;
*val = regval;
return 0;
}
static int adt7410_i2c_write_byte(struct device *dev, u8 reg, u8 data)
static int adt7410_reg_write(void *context, unsigned int reg, unsigned int val)
{
return i2c_smbus_write_byte_data(to_i2c_client(dev), reg, data);
struct i2c_client *client = context;
int ret;
switch (reg) {
case ADT7X10_TEMPERATURE:
case ADT7X10_T_ALARM_HIGH:
case ADT7X10_T_ALARM_LOW:
case ADT7X10_T_CRIT:
ret = i2c_smbus_write_word_swapped(client, reg, val);
break;
default:
ret = i2c_smbus_write_byte_data(client, reg, val);
break;
}
return ret;
}
static const struct adt7x10_ops adt7410_i2c_ops = {
.read_word = adt7410_i2c_read_word,
.write_word = adt7410_i2c_write_word,
.read_byte = adt7410_i2c_read_byte,
.write_byte = adt7410_i2c_write_byte,
static const struct regmap_config adt7410_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.max_register = ADT7X10_ID,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = adt7410_regmap_is_volatile,
.reg_read = adt7410_reg_read,
.reg_write = adt7410_reg_write,
};
static int adt7410_i2c_probe(struct i2c_client *client)
{
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
struct regmap *regmap;
return adt7x10_probe(&client->dev, NULL, client->irq, &adt7410_i2c_ops);
}
regmap = devm_regmap_init(&client->dev, NULL, client,
&adt7410_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
static int adt7410_i2c_remove(struct i2c_client *client)
{
adt7x10_remove(&client->dev, client->irq);
return 0;
return adt7x10_probe(&client->dev, client->name, client->irq, regmap);
}
static const struct i2c_device_id adt7410_ids[] = {
......@@ -68,7 +101,6 @@ static struct i2c_driver adt7410_driver = {
.pm = ADT7X10_DEV_PM_OPS,
},
.probe_new = adt7410_i2c_probe,
.remove = adt7410_i2c_remove,
.id_table = adt7410_ids,
.address_list = I2C_ADDRS(0x48, 0x49, 0x4a, 0x4b),
};
......
This diff is collapsed.
......@@ -17,16 +17,8 @@
struct device;
struct adt7x10_ops {
int (*read_byte)(struct device *, u8 reg);
int (*write_byte)(struct device *, u8 reg, u8 data);
int (*read_word)(struct device *, u8 reg);
int (*write_word)(struct device *, u8 reg, u16 data);
};
int adt7x10_probe(struct device *dev, const char *name, int irq,
const struct adt7x10_ops *ops);
void adt7x10_remove(struct device *dev, int irq);
struct regmap *regmap);
#ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops adt7x10_dev_pm_ops;
......
This diff is collapsed.
This diff is collapsed.
......@@ -112,7 +112,8 @@ struct asus_wmi_data {
/* boards with EC support */
static struct asus_wmi_data sensors_board_PW_X570_P = {
.known_board_sensors = {
SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB, SENSOR_TEMP_VRM,
SENSOR_TEMP_CHIPSET, SENSOR_TEMP_CPU, SENSOR_TEMP_MB,
SENSOR_TEMP_T_SENSOR, SENSOR_TEMP_VRM,
SENSOR_FAN_CHIPSET,
SENSOR_MAX
},
......
......@@ -77,6 +77,7 @@ static const struct dmi_system_id asus_wmi_dmi_table[] = {
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VII HERO (WI-FI)"),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-E GAMING"),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-F GAMING"),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-F GAMING II"),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-I GAMING"),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X399-E GAMING"),
DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X470-F GAMING"),
......
......@@ -339,7 +339,8 @@ static irqreturn_t axi_fan_control_irq_handler(int irq, void *data)
ctl->update_tacho_params = true;
} else {
ctl->hw_pwm_req = false;
sysfs_notify(&ctl->hdev->kobj, NULL, "pwm1");
hwmon_notify_event(ctl->hdev, hwmon_pwm,
hwmon_pwm_input, 0);
}
}
......
......@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
......@@ -86,8 +87,8 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("i8k");
static bool force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force loading without checking for supported models");
module_param_unsafe(force, bool, 0);
MODULE_PARM_DESC(force, "Force loading without checking for supported models and features");
static bool ignore_dmi;
module_param(ignore_dmi, bool, 0);
......@@ -250,46 +251,52 @@ static int i8k_smm(struct smm_regs *regs)
/*
* Read the fan status.
*/
static int i8k_get_fan_status(const struct dell_smm_data *data, int fan)
static int i8k_get_fan_status(const struct dell_smm_data *data, u8 fan)
{
struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
struct smm_regs regs = {
.eax = I8K_SMM_GET_FAN,
.ebx = fan,
};
if (data->disallow_fan_support)
return -EINVAL;
regs.ebx = fan & 0xff;
return i8k_smm(&regs) ? : regs.eax & 0xff;
}
/*
* Read the fan speed in RPM.
*/
static int i8k_get_fan_speed(const struct dell_smm_data *data, int fan)
static int i8k_get_fan_speed(const struct dell_smm_data *data, u8 fan)
{
struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
struct smm_regs regs = {
.eax = I8K_SMM_GET_SPEED,
.ebx = fan,
};
if (data->disallow_fan_support)
return -EINVAL;
regs.ebx = fan & 0xff;
return i8k_smm(&regs) ? : (regs.eax & 0xffff) * data->i8k_fan_mult;
}
/*
* Read the fan type.
*/
static int _i8k_get_fan_type(const struct dell_smm_data *data, int fan)
static int _i8k_get_fan_type(const struct dell_smm_data *data, u8 fan)
{
struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
struct smm_regs regs = {
.eax = I8K_SMM_GET_FAN_TYPE,
.ebx = fan,
};
if (data->disallow_fan_support || data->disallow_fan_type_call)
return -EINVAL;
regs.ebx = fan & 0xff;
return i8k_smm(&regs) ? : regs.eax & 0xff;
}
static int i8k_get_fan_type(struct dell_smm_data *data, int fan)
static int i8k_get_fan_type(struct dell_smm_data *data, u8 fan)
{
/* I8K_SMM_GET_FAN_TYPE SMM call is expensive, so cache values */
if (data->fan_type[fan] == INT_MIN)
......@@ -301,14 +308,16 @@ static int i8k_get_fan_type(struct dell_smm_data *data, int fan)
/*
* Read the fan nominal rpm for specific fan speed.
*/
static int __init i8k_get_fan_nominal_speed(const struct dell_smm_data *data, int fan, int speed)
static int __init i8k_get_fan_nominal_speed(const struct dell_smm_data *data, u8 fan, int speed)
{
struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };
struct smm_regs regs = {
.eax = I8K_SMM_GET_NOM_SPEED,
.ebx = fan | (speed << 8),
};
if (data->disallow_fan_support)
return -EINVAL;
regs.ebx = (fan & 0xff) | (speed << 8);
return i8k_smm(&regs) ? : (regs.eax & 0xffff) * data->i8k_fan_mult;
}
......@@ -329,7 +338,7 @@ static int i8k_enable_fan_auto_mode(const struct dell_smm_data *data, bool enabl
/*
* Set the fan speed (off, low, high, ...).
*/
static int i8k_set_fan(const struct dell_smm_data *data, int fan, int speed)
static int i8k_set_fan(const struct dell_smm_data *data, u8 fan, int speed)
{
struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
......@@ -337,33 +346,35 @@ static int i8k_set_fan(const struct dell_smm_data *data, int fan, int speed)
return -EINVAL;
speed = (speed < 0) ? 0 : ((speed > data->i8k_fan_max) ? data->i8k_fan_max : speed);
regs.ebx = (fan & 0xff) | (speed << 8);
regs.ebx = fan | (speed << 8);
return i8k_smm(&regs);
}
static int __init i8k_get_temp_type(int sensor)
static int __init i8k_get_temp_type(u8 sensor)
{
struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, };
struct smm_regs regs = {
.eax = I8K_SMM_GET_TEMP_TYPE,
.ebx = sensor,
};
regs.ebx = sensor & 0xff;
return i8k_smm(&regs) ? : regs.eax & 0xff;
}
/*
* Read the cpu temperature.
*/
static int _i8k_get_temp(int sensor)
static int _i8k_get_temp(u8 sensor)
{
struct smm_regs regs = {
.eax = I8K_SMM_GET_TEMP,
.ebx = sensor & 0xff,
.ebx = sensor,
};
return i8k_smm(&regs) ? : regs.eax & 0xff;
}
static int i8k_get_temp(int sensor)
static int i8k_get_temp(u8 sensor)
{
int temp = _i8k_get_temp(sensor);
......@@ -496,6 +507,9 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
if (copy_from_user(&val, argp, sizeof(int)))
return -EFAULT;
if (val > U8_MAX || val < 0)
return -EINVAL;
val = i8k_get_fan_speed(data, val);
break;
......@@ -503,6 +517,9 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
if (copy_from_user(&val, argp, sizeof(int)))
return -EFAULT;
if (val > U8_MAX || val < 0)
return -EINVAL;
val = i8k_get_fan_status(data, val);
break;
......@@ -513,6 +530,9 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
if (copy_from_user(&val, argp, sizeof(int)))
return -EFAULT;
if (val > U8_MAX || val < 0)
return -EINVAL;
if (copy_from_user(&speed, argp + 1, sizeof(int)))
return -EFAULT;
......@@ -631,6 +651,11 @@ static umode_t dell_smm_is_visible(const void *drvdata, enum hwmon_sensor_types
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
/* _i8k_get_temp() is fine since we do not care about the actual value */
if (data->temp_type[channel] >= 0 || _i8k_get_temp(channel) >= 0)
return 0444;
break;
case hwmon_temp_label:
if (data->temp_type[channel] >= 0)
return 0444;
......@@ -920,7 +945,8 @@ static int __init dell_smm_init_hwmon(struct device *dev)
{
struct dell_smm_data *data = dev_get_drvdata(dev);
struct device *dell_smm_hwmon_dev;
int i, state, err;
int state, err;
u8 i;
for (i = 0; i < DELL_SMM_NO_TEMP; i++) {
data->temp_type[i] = i8k_get_temp_type(i);
......@@ -1131,6 +1157,13 @@ static const struct dmi_system_id i8k_blacklist_fan_type_dmi_table[] __initconst
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 580 "),
},
},
{
.ident = "Dell Inspiron 3505",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Inspiron 3505"),
},
},
{ }
};
......@@ -1236,7 +1269,8 @@ static int __init dell_smm_probe(struct platform_device *pdev)
{
struct dell_smm_data *data;
const struct dmi_system_id *id, *fan_control;
int fan, ret;
int ret;
u8 fan;
data = devm_kzalloc(&pdev->dev, sizeof(struct dell_smm_data), GFP_KERNEL);
if (!data)
......
......@@ -18,6 +18,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/thermal.h>
......@@ -30,6 +31,7 @@
struct hwmon_device {
const char *name;
const char *label;
struct device dev;
const struct hwmon_chip_info *chip;
struct list_head tzdata;
......@@ -71,17 +73,29 @@ name_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(name);
static ssize_t
label_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%s\n", to_hwmon_device(dev)->label);
}
static DEVICE_ATTR_RO(label);
static struct attribute *hwmon_dev_attrs[] = {
&dev_attr_name.attr,
&dev_attr_label.attr,
NULL
};
static umode_t hwmon_dev_name_is_visible(struct kobject *kobj,
static umode_t hwmon_dev_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = kobj_to_dev(kobj);
struct hwmon_device *hdev = to_hwmon_device(dev);
if (to_hwmon_device(dev)->name == NULL)
if (attr == &dev_attr_name.attr && hdev->name == NULL)
return 0;
if (attr == &dev_attr_label.attr && hdev->label == NULL)
return 0;
return attr->mode;
......@@ -89,7 +103,7 @@ static umode_t hwmon_dev_name_is_visible(struct kobject *kobj,
static const struct attribute_group hwmon_dev_attr_group = {
.attrs = hwmon_dev_attrs,
.is_visible = hwmon_dev_name_is_visible,
.is_visible = hwmon_dev_attr_is_visible,
};
static const struct attribute_group *hwmon_dev_attr_groups[] = {
......@@ -117,6 +131,7 @@ static void hwmon_dev_release(struct device *dev)
if (hwdev->group.attrs)
hwmon_free_attrs(hwdev->group.attrs);
kfree(hwdev->groups);
kfree(hwdev->label);
kfree(hwdev);
}
......@@ -589,6 +604,7 @@ static const char * const hwmon_pwm_attr_templates[] = {
[hwmon_pwm_enable] = "pwm%d_enable",
[hwmon_pwm_mode] = "pwm%d_mode",
[hwmon_pwm_freq] = "pwm%d_freq",
[hwmon_pwm_auto_channels_temp] = "pwm%d_auto_channels_temp",
};
static const char * const hwmon_intrusion_attr_templates[] = {
......@@ -625,7 +641,9 @@ static const int __templates_size[] = {
int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel)
{
char event[MAX_SYSFS_ATTR_NAME_LENGTH + 5];
char sattr[MAX_SYSFS_ATTR_NAME_LENGTH];
char *envp[] = { event, NULL };
const char * const *templates;
const char *template;
int base;
......@@ -641,8 +659,9 @@ int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type,
base = hwmon_attr_base(type);
scnprintf(sattr, MAX_SYSFS_ATTR_NAME_LENGTH, template, base + channel);
scnprintf(event, sizeof(event), "NAME=%s", sattr);
sysfs_notify(&dev->kobj, NULL, sattr);
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
if (type == hwmon_temp)
hwmon_thermal_notify(dev, channel);
......@@ -735,6 +754,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
const struct attribute_group **groups)
{
struct hwmon_device *hwdev;
const char *label;
struct device *hdev;
int i, err, id;
......@@ -790,6 +810,18 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
hdev->groups = groups;
}
if (dev && device_property_present(dev, "label")) {
err = device_property_read_string(dev, "label", &label);
if (err < 0)
goto free_hwmon;
hwdev->label = kstrdup(label, GFP_KERNEL);
if (hwdev->label == NULL) {
err = -ENOMEM;
goto free_hwmon;
}
}
hwdev->name = name;
hdev->class = &hwmon_class;
hdev->parent = dev;
......
......@@ -34,6 +34,7 @@
#define LM70_CHIP_LM71 2 /* NS LM71 */
#define LM70_CHIP_LM74 3 /* NS LM74 */
#define LM70_CHIP_TMP122 4 /* TI TMP122/TMP124 */
#define LM70_CHIP_TMP125 5 /* TI TMP125 */
struct lm70 {
struct spi_device *spi;
......@@ -87,6 +88,12 @@ static ssize_t temp1_input_show(struct device *dev,
* LM71:
* 14 bits of 2's complement data, discard LSB 2 bits,
* resolution 0.0312 degrees celsius.
*
* TMP125:
* MSB/D15 is a leading zero. D14 is the sign-bit. This is
* followed by 9 temperature bits (D13..D5) in 2's complement
* data format with a resolution of 0.25 degrees celsius per unit.
* LSB 5 bits (D4..D0) share the same value as D5 and get discarded.
*/
switch (p_lm70->chip) {
case LM70_CHIP_LM70:
......@@ -102,6 +109,10 @@ static ssize_t temp1_input_show(struct device *dev,
case LM70_CHIP_LM71:
val = ((int)raw / 4) * 3125 / 100;
break;
case LM70_CHIP_TMP125:
val = (sign_extend32(raw, 14) / 32) * 250;
break;
}
status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
......@@ -135,6 +146,10 @@ static const struct of_device_id lm70_of_ids[] = {
.compatible = "ti,tmp122",
.data = (void *) LM70_CHIP_TMP122,
},
{
.compatible = "ti,tmp125",
.data = (void *) LM70_CHIP_TMP125,
},
{
.compatible = "ti,lm71",
.data = (void *) LM70_CHIP_LM71,
......@@ -184,6 +199,7 @@ static const struct spi_device_id lm70_ids[] = {
{ "lm70", LM70_CHIP_LM70 },
{ "tmp121", LM70_CHIP_TMP121 },
{ "tmp122", LM70_CHIP_TMP122 },
{ "tmp125", LM70_CHIP_TMP125 },
{ "lm71", LM70_CHIP_LM71 },
{ "lm74", LM70_CHIP_LM74 },
{ },
......
This diff is collapsed.
......@@ -87,6 +87,9 @@ struct max6639_data {
/* Register values initialized only once */
u8 ppr; /* Pulses per rotation 0..3 for 1..4 ppr */
u8 rpm_range; /* Index in above rpm_ranges table */
/* Optional regulator for FAN supply */
struct regulator *reg;
};
static struct max6639_data *max6639_update_device(struct device *dev)
......@@ -516,6 +519,11 @@ static int max6639_detect(struct i2c_client *client,
return 0;
}
static void max6639_regulator_disable(void *data)
{
regulator_disable(data);
}
static int max6639_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
......@@ -528,6 +536,28 @@ static int max6639_probe(struct i2c_client *client)
return -ENOMEM;
data->client = client;
data->reg = devm_regulator_get_optional(dev, "fan");
if (IS_ERR(data->reg)) {
if (PTR_ERR(data->reg) != -ENODEV)
return PTR_ERR(data->reg);
data->reg = NULL;
} else {
/* Spin up fans */
err = regulator_enable(data->reg);
if (err) {
dev_err(dev, "Failed to enable fan supply: %d\n", err);
return err;
}
err = devm_add_action_or_reset(dev, max6639_regulator_disable,
data->reg);
if (err) {
dev_err(dev, "Failed to register action: %d\n", err);
return err;
}
}
mutex_init(&data->update_lock);
/* Initialize the max6639 chip */
......@@ -545,23 +575,39 @@ static int max6639_probe(struct i2c_client *client)
static int max6639_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
if (data < 0)
return data;
struct max6639_data *data = dev_get_drvdata(dev);
int ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
if (ret < 0)
return ret;
if (data->reg)
regulator_disable(data->reg);
return i2c_smbus_write_byte_data(client,
MAX6639_REG_GCONFIG, data | MAX6639_GCONFIG_STANDBY);
MAX6639_REG_GCONFIG, ret | MAX6639_GCONFIG_STANDBY);
}
static int max6639_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int data = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
if (data < 0)
return data;
struct max6639_data *data = dev_get_drvdata(dev);
int ret;
if (data->reg) {
ret = regulator_enable(data->reg);
if (ret) {
dev_err(dev, "Failed to enable fan supply: %d\n", ret);
return ret;
}
}
ret = i2c_smbus_read_byte_data(client, MAX6639_REG_GCONFIG);
if (ret < 0)
return ret;
return i2c_smbus_write_byte_data(client,
MAX6639_REG_GCONFIG, data & ~MAX6639_GCONFIG_STANDBY);
MAX6639_REG_GCONFIG, ret & ~MAX6639_GCONFIG_STANDBY);
}
#endif /* CONFIG_PM_SLEEP */
......
......@@ -18,15 +18,6 @@
#define MLXREG_FAN_MAX_STATE 10
#define MLXREG_FAN_MIN_DUTY 51 /* 20% */
#define MLXREG_FAN_MAX_DUTY 255 /* 100% */
/*
* Minimum and maximum FAN allowed speed in percent: from 20% to 100%. Values
* MLXREG_FAN_MAX_STATE + x, where x is between 2 and 10 are used for
* setting FAN speed dynamic minimum. For example, if value is set to 14 (40%)
* cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to
* introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100.
*/
#define MLXREG_FAN_SPEED_MIN (MLXREG_FAN_MAX_STATE + 2)
#define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2)
#define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */
#define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44
#define MLXREG_FAN_TACHO_DIV_MIN 283
......@@ -87,13 +78,16 @@ struct mlxreg_fan_tacho {
* @connected: indicates if PWM is connected;
* @reg: register offset;
* @cooling: cooling device levels;
* @last_hwmon_state: last cooling state set by hwmon subsystem;
* @last_thermal_state: last cooling state set by thermal subsystem;
* @cdev: cooling device;
*/
struct mlxreg_fan_pwm {
struct mlxreg_fan *fan;
bool connected;
u32 reg;
u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1];
unsigned long last_hwmon_state;
unsigned long last_thermal_state;
struct thermal_cooling_device *cdev;
};
......@@ -119,6 +113,9 @@ struct mlxreg_fan {
int divider;
};
static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state);
static int
mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
......@@ -213,6 +210,18 @@ mlxreg_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
val > MLXREG_FAN_MAX_DUTY)
return -EINVAL;
pwm = &fan->pwm[channel];
/* If thermal is configured - handle PWM limit setting. */
if (IS_REACHABLE(CONFIG_THERMAL)) {
pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(val);
/*
* Update PWM only in case requested state is not less than the
* last thermal state.
*/
if (pwm->last_hwmon_state >= pwm->last_thermal_state)
return mlxreg_fan_set_cur_state(pwm->cdev,
pwm->last_hwmon_state);
return 0;
}
return regmap_write(fan->regmap, pwm->reg, val);
default:
return -EOPNOTSUPP;
......@@ -338,58 +347,22 @@ static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev,
{
struct mlxreg_fan_pwm *pwm = cdev->devdata;
struct mlxreg_fan *fan = pwm->fan;
unsigned long cur_state;
int i, config = 0;
u32 regval;
int err;
/*
* Verify if this request is for changing allowed FAN dynamical
* minimum. If it is - update cooling levels accordingly and update
* state, if current state is below the newly requested minimum state.
* For example, if current state is 5, and minimal state is to be
* changed from 4 to 6, fan->cooling_levels[0 to 5] will be changed all
* from 4 to 6. And state 5 (fan->cooling_levels[4]) should be
* overwritten.
*/
if (state >= MLXREG_FAN_SPEED_MIN && state <= MLXREG_FAN_SPEED_MAX) {
/*
* This is configuration change, which is only supported through sysfs.
* For configuration non-zero value is to be returned to avoid thermal
* statistics update.
*/
config = 1;
state -= MLXREG_FAN_MAX_STATE;
for (i = 0; i < state; i++)
pwm->cooling_levels[i] = state;
for (i = state; i <= MLXREG_FAN_MAX_STATE; i++)
pwm->cooling_levels[i] = i;
err = regmap_read(fan->regmap, pwm->reg, &regval);
if (err) {
dev_err(fan->dev, "Failed to query PWM duty\n");
return err;
}
cur_state = MLXREG_FAN_PWM_DUTY2STATE(regval);
if (state < cur_state)
return config;
state = cur_state;
}
if (state > MLXREG_FAN_MAX_STATE)
return -EINVAL;
/* Normalize the state to the valid speed range. */
state = pwm->cooling_levels[state];
/* Save thermal state. */
pwm->last_thermal_state = state;
state = max_t(unsigned long, state, pwm->last_hwmon_state);
err = regmap_write(fan->regmap, pwm->reg,
MLXREG_FAN_PWM_STATE2DUTY(state));
if (err) {
dev_err(fan->dev, "Failed to write PWM duty\n");
return err;
}
return config;
return 0;
}
static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = {
......@@ -564,7 +537,7 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan)
{
int i, j;
int i;
for (i = 0; i < MLXREG_FAN_MAX_PWM; i++) {
struct mlxreg_fan_pwm *pwm = &fan->pwm[i];
......@@ -579,11 +552,8 @@ static int mlxreg_fan_cooling_config(struct device *dev, struct mlxreg_fan *fan)
return PTR_ERR(pwm->cdev);
}
/* Init cooling levels per PWM state. */
for (j = 0; j < MLXREG_FAN_SPEED_MIN_LEVEL; j++)
pwm->cooling_levels[j] = MLXREG_FAN_SPEED_MIN_LEVEL;
for (j = MLXREG_FAN_SPEED_MIN_LEVEL; j <= MLXREG_FAN_MAX_STATE; j++)
pwm->cooling_levels[j] = j;
/* Set minimal PWM speed. */
pwm->last_hwmon_state = MLXREG_FAN_PWM_DUTY2STATE(MLXREG_FAN_MIN_DUTY);
}
return 0;
......
This diff is collapsed.
......@@ -674,6 +674,9 @@ static ssize_t occ_show_caps_3(struct device *dev,
case 7:
val = caps->user_source;
break;
case 8:
val = get_unaligned_be16(&caps->soft_min) * 1000000ULL;
break;
default:
return -EINVAL;
}
......@@ -835,12 +838,13 @@ static int occ_setup_sensor_attrs(struct occ *occ)
case 1:
num_attrs += (sensors->caps.num_sensors * 7);
break;
case 3:
show_caps = occ_show_caps_3;
fallthrough;
case 2:
num_attrs += (sensors->caps.num_sensors * 8);
break;
case 3:
show_caps = occ_show_caps_3;
num_attrs += (sensors->caps.num_sensors * 9);
break;
default:
sensors->caps.num_sensors = 0;
}
......@@ -1047,6 +1051,15 @@ static int occ_setup_sensor_attrs(struct occ *occ)
attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
show_caps, NULL, 7, 0);
attr++;
if (sensors->caps.version > 2) {
snprintf(attr->name, sizeof(attr->name),
"power%d_cap_min_soft", s);
attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
show_caps, NULL,
8, 0);
attr++;
}
}
}
......
......@@ -119,6 +119,8 @@ struct occ {
u8 prev_stat;
u8 prev_ext_stat;
u8 prev_occs_present;
u8 prev_ips_status;
u8 prev_mode;
};
int occ_setup(struct occ *occ, const char *name);
......
......@@ -19,6 +19,8 @@
#define OCC_EXT_STAT_DVFS_POWER BIT(6)
#define OCC_EXT_STAT_MEM_THROTTLE BIT(5)
#define OCC_EXT_STAT_QUICK_DROP BIT(4)
#define OCC_EXT_STAT_DVFS_VDD BIT(3)
#define OCC_EXT_STAT_GPU_THROTTLE GENMASK(2, 0)
static ssize_t occ_sysfs_show(struct device *dev,
struct device_attribute *attr, char *buf)
......@@ -63,6 +65,18 @@ static ssize_t occ_sysfs_show(struct device *dev,
else
val = 1;
break;
case 8:
val = header->ips_status;
break;
case 9:
val = header->mode;
break;
case 10:
val = !!(header->ext_status & OCC_EXT_STAT_DVFS_VDD);
break;
case 11:
val = header->ext_status & OCC_EXT_STAT_GPU_THROTTLE;
break;
default:
return -EINVAL;
}
......@@ -88,6 +102,10 @@ static SENSOR_DEVICE_ATTR(occ_mem_throttle, 0444, occ_sysfs_show, NULL, 4);
static SENSOR_DEVICE_ATTR(occ_quick_pwr_drop, 0444, occ_sysfs_show, NULL, 5);
static SENSOR_DEVICE_ATTR(occ_state, 0444, occ_sysfs_show, NULL, 6);
static SENSOR_DEVICE_ATTR(occs_present, 0444, occ_sysfs_show, NULL, 7);
static SENSOR_DEVICE_ATTR(occ_ips_status, 0444, occ_sysfs_show, NULL, 8);
static SENSOR_DEVICE_ATTR(occ_mode, 0444, occ_sysfs_show, NULL, 9);
static SENSOR_DEVICE_ATTR(occ_dvfs_vdd, 0444, occ_sysfs_show, NULL, 10);
static SENSOR_DEVICE_ATTR(occ_gpu_throttle, 0444, occ_sysfs_show, NULL, 11);
static DEVICE_ATTR_RO(occ_error);
static struct attribute *occ_attributes[] = {
......@@ -99,6 +117,10 @@ static struct attribute *occ_attributes[] = {
&sensor_dev_attr_occ_quick_pwr_drop.dev_attr.attr,
&sensor_dev_attr_occ_state.dev_attr.attr,
&sensor_dev_attr_occs_present.dev_attr.attr,
&sensor_dev_attr_occ_ips_status.dev_attr.attr,
&sensor_dev_attr_occ_mode.dev_attr.attr,
&sensor_dev_attr_occ_dvfs_vdd.dev_attr.attr,
&sensor_dev_attr_occ_gpu_throttle.dev_attr.attr,
&dev_attr_occ_error.attr,
NULL
};
......@@ -156,12 +178,34 @@ void occ_sysfs_poll_done(struct occ *occ)
sysfs_notify(&occ->bus_dev->kobj, NULL, name);
}
if ((header->ext_status & OCC_EXT_STAT_DVFS_VDD) !=
(occ->prev_ext_stat & OCC_EXT_STAT_DVFS_VDD)) {
name = sensor_dev_attr_occ_dvfs_vdd.dev_attr.attr.name;
sysfs_notify(&occ->bus_dev->kobj, NULL, name);
}
if ((header->ext_status & OCC_EXT_STAT_GPU_THROTTLE) !=
(occ->prev_ext_stat & OCC_EXT_STAT_GPU_THROTTLE)) {
name = sensor_dev_attr_occ_gpu_throttle.dev_attr.attr.name;
sysfs_notify(&occ->bus_dev->kobj, NULL, name);
}
if ((header->status & OCC_STAT_MASTER) &&
header->occs_present != occ->prev_occs_present) {
name = sensor_dev_attr_occs_present.dev_attr.attr.name;
sysfs_notify(&occ->bus_dev->kobj, NULL, name);
}
if (header->ips_status != occ->prev_ips_status) {
name = sensor_dev_attr_occ_ips_status.dev_attr.attr.name;
sysfs_notify(&occ->bus_dev->kobj, NULL, name);
}
if (header->mode != occ->prev_mode) {
name = sensor_dev_attr_occ_mode.dev_attr.attr.name;
sysfs_notify(&occ->bus_dev->kobj, NULL, name);
}
if (occ->error && occ->error != occ->prev_error) {
name = dev_attr_occ_error.attr.name;
sysfs_notify(&occ->bus_dev->kobj, NULL, name);
......@@ -174,6 +218,8 @@ void occ_sysfs_poll_done(struct occ *occ)
occ->prev_stat = header->status;
occ->prev_ext_stat = header->ext_status;
occ->prev_occs_present = header->occs_present;
occ->prev_ips_status = header->ips_status;
occ->prev_mode = header->mode;
}
int occ_setup_sysfs(struct occ *occ)
......
......@@ -174,6 +174,13 @@ config SENSORS_LM25066
This driver can also be built as a module. If so, the module will
be called lm25066.
config SENSORS_LM25066_REGULATOR
bool "Regulator support for LM25066 and compatibles"
depends on SENSORS_LM25066 && REGULATOR
help
If you say yes here you get regulator support for National
Semiconductor LM25066, LM5064, and LM5066.
config SENSORS_LTC2978
tristate "Linear Technologies LTC2978 and compatibles"
help
......@@ -189,8 +196,8 @@ config SENSORS_LTC2978_REGULATOR
depends on SENSORS_LTC2978 && REGULATOR
help
If you say yes here you get regulator support for Linear Technology
LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7880,
LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4686,
LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7880,
LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4686,
and LTM4700.
config SENSORS_LTC3815
......@@ -310,6 +317,22 @@ config SENSORS_PIM4328
This driver can also be built as a module. If so, the module will
be called pim4328.
config SENSORS_PLI1209BC
tristate "Vicor PLI1209BC"
help
If you say yes here you get hardware monitoring support for Vicor
PLI1209BC Digital Supervisor.
This driver can also be built as a module. If so, the module will
be called pli1209bc.
config SENSORS_PLI1209BC_REGULATOR
bool "Regulator support for PLI1209BC"
depends on SENSORS_PLI1209BC && REGULATOR
help
If you say yes here you get regulator support for Vicor PLI1209BC
Digital Supervisor.
config SENSORS_PM6764TR
tristate "ST PM6764TR"
help
......@@ -394,6 +417,12 @@ config SENSORS_XDPE122
This driver can also be built as a module. If so, the module will
be called xdpe12284.
config SENSORS_XDPE122_REGULATOR
bool "Regulator support for XDPE122 and compatibles"
depends on SENSORS_XDPE122 && REGULATOR
help
Uses the xdpe12284 or compatible as regulator.
config SENSORS_ZL6100
tristate "Intersil ZL6100 and compatibles"
help
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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