Commit 47080f22 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull hwmon updates from Guenter Roeck:
 "The most notable change is the removal of the amd_energy driver. It
  was rendered all but unusable by making its attributes privileged-only
  to work around a security issue. A suggested remedy was rejected by
  AMD, so the only real solution was to remove the driver. For the
  future, we'll have to make sure that no privileged-access-only drivers
  are accepted into the hwmon subsystem in the first place. The hwmon
  ABI document was updated accordingly.

  Other changes:

  PMBus drivers:
   - Added driver for MAX15301
   - Added driver for BluTek BPA-RS600
   - Added driver for fsp-3y PSUs and PDUs
   - Added driver for Infineon IR36021
   - Added driver for ST STPDDC60
   - Added support for TI TPS53676 to tps53679 driver
   - Introduced PMBUS symbol namespace. This was made necessary by a
     suggestion to use its exported functions from outside the hwmon
     subsystem.
   - Minor improvements and bug fixes

  New drivers:
   - Driver for NZXT Kraken X42/X52/X62/X72

  Driver enhancements:
   - Added support for Intel D5005 to intel-m10-bmc-hwmon driver
   - Added support for NCT6686D to nct6683 driver

  Other:
   - Converted sch5627 and amd9240 drivers to
     hwmon_device_register_with_info()
   - Added support for fan drawers capability and present registers to
     mlxreg-fan driver
   - Added Dell Latitude E7440 to fan control whitelist in dell-smm
     driver
   - Replaced snprintf in show functions with sysfs_emit. Done with
     coccinelle script for all drivers to preempt endless per-driver
     submissions of the same change.
   - Use kobj_to_dev().  Another coccinelle based change to preempt
     endless per-driver submissions of the same change.
   - Various minor fixes and improvements"

* tag 'hwmon-for-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (38 commits)
  hwmon: Remove amd_energy driver
  hwmon: Clarify scope of attribute access
  hwmon: (pmbus) Introduce PMBUS symbol namespace
  hwmon: (pmbus) Add pmbus driver for MAX15301
  hwmon: (sch5627) Remove unnecessary error path
  hwmon: (sch5627) Use devres function
  hwmon: (pmbus/pxe1610) don't bail out when not all pages are active
  hwmon: Add driver for fsp-3y PSUs and PDUs
  hwmon: (intel-m10-bmc-hwmon) add sensor support of Intel D5005 card
  hwmon: (sch5627) Split sch5627_update_device()
  hwmon: (sch5627) Convert to hwmon_device_register_with_info()
  hwmon: (nct6683) remove useless function
  hwmon: (dell-smm) Add Dell Latitude E7440 to fan control whitelist
  MAINTAINERS: Add keyword pattern for hwmon registration functions
  hwmon: (mlxreg-fan) Add support for fan drawers capability and present registers
  hwmon: (pmbus/tps53679) Add support for TI TPS53676
  dt-bindings: Add trivial device entry for TPS53676
  hwmon: (ftsteutates) Rudimentary typo fixes
  hwmon: (pmbus) Add driver for BluTek BPA-RS600
  dt-bindings: Add vendor prefix and trivial device for BluTek BPA-RS600
  ...
parents 55ba0fe0 9049572f
......@@ -50,6 +50,8 @@ properties:
- atmel,atsha204a
# i2c h/w elliptic curve crypto module
- atmel,atecc508a
# BPA-RS600: Power Supply
- blutek,bpa-rs600
# Bosch Sensortec pressure, temperature, humididty and VOC sensor
- bosch,bme680
# CM32181: Ambient Light Sensor
......@@ -102,6 +104,8 @@ properties:
- mps,mp2975
# G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire Interface
- gmt,g751
# Infineon IR36021 digital POL buck controller
- infineon,ir36021
# Infineon IR38064 Voltage Regulator
- infineon,ir38064
# Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
......@@ -288,6 +292,8 @@ properties:
- ti,tmp103
# Digital Temperature Sensor
- ti,tmp275
# TI Dual channel DCAP+ multiphase controller TPS53676 with AVSBus
- ti,tps53676
# TI Dual channel DCAP+ multiphase controller TPS53679
- ti,tps53679
# TI Dual channel DCAP+ multiphase controller TPS53688
......
......@@ -171,6 +171,8 @@ patternProperties:
description: Beckhoff Automation GmbH & Co. KG
"^bitmain,.*":
description: Bitmain Technologies
"^blutek,.*":
description: BluTek Power
"^boe,.*":
description: BOE Technology Group Co., Ltd.
"^bosch,.*":
......
.. SPDX-License-Identifier: GPL-2.0
Kernel driver amd_energy
==========================
Supported chips:
* AMD Family 17h Processors: Model 30h
* AMD Family 19h Processors: Model 01h
Prefix: 'amd_energy'
Addresses used: RAPL MSRs
Datasheets:
- Processor Programming Reference (PPR) for AMD Family 17h Model 01h, Revision B1 Processors
https://developer.amd.com/wp-content/resources/55570-B1_PUB.zip
- Preliminary Processor Programming Reference (PPR) for AMD Family 17h Model 31h, Revision B0 Processors
https://developer.amd.com/wp-content/resources/56176_ppr_Family_17h_Model_71h_B0_pub_Rev_3.06.zip
Author: Naveen Krishna Chatradhi <nchatrad@amd.com>
Description
-----------
The Energy driver exposes the energy counters that are
reported via the Running Average Power Limit (RAPL)
Model-specific Registers (MSRs) via the hardware monitor
(HWMON) sysfs interface.
1. Power, Energy and Time Units
MSR_RAPL_POWER_UNIT/ C001_0299:
shared with all cores in the socket
2. Energy consumed by each Core
MSR_CORE_ENERGY_STATUS/ C001_029A:
32-bitRO, Accumulator, core-level power reporting
3. Energy consumed by Socket
MSR_PACKAGE_ENERGY_STATUS/ C001_029B:
32-bitRO, Accumulator, socket-level power reporting,
shared with all cores in socket
These registers are updated every 1ms and cleared on
reset of the system.
Note: If SMT is enabled, Linux enumerates all threads as cpus.
Since, the energy status registers are accessed at core level,
reading those registers from the sibling threads would result
in duplicate values. Hence, energy counter entries are not
populated for the siblings.
Energy Caluclation
------------------
Energy information (in Joules) is based on the multiplier,
1/2^ESU; where ESU is an unsigned integer read from
MSR_RAPL_POWER_UNIT register. Default value is 10000b,
indicating energy status unit is 15.3 micro-Joules increment.
Reported values are scaled as per the formula
scaled value = ((1/2^ESU) * (Raw value) * 1000000UL) in uJoules
Users calculate power for a given domain by calculating
dEnergy/dTime for that domain.
Energy accumulation
--------------------------
Current, Socket energy status register is 32bit, assuming a 240W
2P system, the register would wrap around in
2^32*15.3 e-6/240 * 2 = 547.60833024 secs to wrap(~9 mins)
The Core energy register may wrap around after several days.
To improve the wrap around time, a kernel thread is implemented
to accumulate the socket energy counters and one core energy counter
per run to a respective 64-bit counter. The kernel thread starts
running during probe, wakes up every 100secs and stops running
when driver is removed.
Frequency of the accumulator thread is set during the probe
based on the chosen energy unit resolution. For example
A. fine grain (1.625 micro J)
B. course grain (0.125 milli J)
A socket and core energy read would return the current register
value added to the respective energy accumulator.
Sysfs attributes
----------------
=============== ======== =====================================
Attribute Label Description
=============== ======== =====================================
* For index N between [1] and [nr_cpus]
=============== ======== ======================================
energy[N]_input EcoreX Core Energy X = [0] to [nr_cpus - 1]
Measured input core energy
=============== ======== ======================================
* For N between [nr_cpus] and [nr_cpus + nr_socks]
=============== ======== ======================================
energy[N]_input EsocketX Socket Energy X = [0] to [nr_socks -1]
Measured input socket energy
=============== ======== ======================================
Note: To address CVE-2020-12912, the visibility of the energy[N]_input
attributes is restricted to owner and groups only.
.. SPDX-License-Identifier: GPL-2.0
Kernel driver bpa-rs600
=======================
Supported chips:
* BPA-RS600-120
Datasheet: Publicly available at the BluTek website
http://blutekpower.com/wp-content/uploads/2019/01/BPA-RS600-120-07-19-2018.pdf
Authors:
- Chris Packham <chris.packham@alliedtelesis.co.nz>
Description
-----------
The BPA-RS600 is a compact 600W removable power supply module.
Usage Notes
-----------
This driver does not probe for PMBus devices. You will have to instantiate
devices explicitly.
Sysfs attributes
----------------
======================= ============================================
curr1_label "iin"
curr1_input Measured input current
curr1_max Maximum input current
curr1_max_alarm Input current high alarm
curr2_label "iout1"
curr2_input Measured output current
curr2_max Maximum output current
curr2_max_alarm Output current high alarm
fan1_input Measured fan speed
fan1_alarm Fan warning
fan1_fault Fan fault
in1_label "vin"
in1_input Measured input voltage
in1_max Maximum input voltage
in1_max_alarm Input voltage high alarm
in1_min Minimum input voltage
in1_min_alarm Input voltage low alarm
in2_label "vout1"
in2_input Measured output voltage
in2_max Maximum output voltage
in2_max_alarm Output voltage high alarm
in2_min Maximum output voltage
in2_min_alarm Output voltage low alarm
power1_label "pin"
power1_input Measured input power
power1_alarm Input power alarm
power1_max Maximum input power
power2_label "pout1"
power2_input Measured output power
power2_max Maximum output power
power2_max_alarm Output power high alarm
temp1_input Measured temperature around input connector
temp1_alarm Temperature alarm
temp2_input Measured temperature around output connector
temp2_alarm Temperature alarm
======================= ============================================
......@@ -47,19 +47,30 @@ Sysfs entries
======================= ========================================================
curr1_input Total current usage
curr2_input Current on the 12v psu rail
curr2_crit Current max critical value on the 12v psu rail
curr3_input Current on the 5v psu rail
curr3_crit Current max critical value on the 5v psu rail
curr4_input Current on the 3.3v psu rail
curr4_crit Current max critical value on the 3.3v psu rail
fan1_input RPM of psu fan
in0_input Voltage of the psu ac input
in1_input Voltage of the 12v psu rail
in1_crit Voltage max critical value on the 12v psu rail
in1_lcrit Voltage min critical value on the 12v psu rail
in2_input Voltage of the 5v psu rail
in3_input Voltage of the 3.3 psu rail
in2_crit Voltage max critical value on the 5v psu rail
in2_lcrit Voltage min critical value on the 5v psu rail
in3_input Voltage of the 3.3v psu rail
in3_crit Voltage max critical value on the 3.3v psu rail
in3_lcrit Voltage min critical value on the 3.3v psu rail
power1_input Total power usage
power2_input Power usage of the 12v psu rail
power3_input Power usage of the 5v psu rail
power4_input Power usage of the 3.3v psu rail
temp1_input Temperature of the psu vrm component
temp1_crit Temperature max cirtical value of the psu vrm component
temp2_input Temperature of the psu case
temp2_crit Temperature max critical value of psu case
======================= ========================================================
Usage Notes
......
.. SPDX-License-Identifier: GPL-2.0
Kernel driver fsp3y
======================
Supported devices:
* 3Y POWER YH-5151E
* 3Y POWER YM-2151E
Author: Václav Kubernát <kubernat@cesnet.cz>
Description
-----------
This driver implements limited support for two 3Y POWER devices.
Sysfs entries
-------------
* in1_input input voltage
* in2_input 12V output voltage
* in3_input 5V output voltage
* curr1_input input current
* curr2_input 12V output current
* curr3_input 5V output current
* fan1_input fan rpm
* temp1_input temperature 1
* temp2_input temperature 2
* temp3_input temperature 3
* power1_input input power
* power2_input output power
......@@ -39,12 +39,12 @@ Hardware Monitoring Kernel Drivers
adt7475
aht10
amc6821
amd_energy
asb100
asc7621
aspeed-pwm-tacho
bcm54140
bel-pfe
bpa-rs600
bt1-pvt
coretemp
corsair-cpro
......@@ -62,6 +62,7 @@ Hardware Monitoring Kernel Drivers
f71805f
f71882fg
fam15h_power
fsp-3y
ftsteutates
g760a
g762
......@@ -77,6 +78,7 @@ Hardware Monitoring Kernel Drivers
intel-m10-bmc-hwmon
ir35221
ir38064
ir36021
isl68137
it87
jc42
......@@ -112,6 +114,7 @@ Hardware Monitoring Kernel Drivers
ltc4260
ltc4261
max127
max15301
max16064
max16065
max1619
......@@ -142,6 +145,7 @@ Hardware Monitoring Kernel Drivers
npcm750-pwm-fan
nsa320
ntc_thermistor
nzxt-kraken2
occ
pc87360
pc87427
......@@ -168,6 +172,7 @@ Hardware Monitoring Kernel Drivers
smsc47m192
smsc47m1
sparx5-temp
stpddc60
tc654
tc74
thmc50
......
.. SPDX-License-Identifier: GPL-2.0
Kernel driver ir36021
=====================
Supported chips:
* Infineon IR36021
Prefix: ir36021
Addresses scanned: -
Datasheet: Publicly available at the Infineon website
https://www.infineon.com/dgdl/ir36021.pdf?fileId=5546d462533600a4015355d0aa2d1775
Authors:
- Chris Packham <chris.packham@alliedtelesis.co.nz>
Description
-----------
The IR36021 is a dual‐loop digital multi‐phase buck controller designed for
point of load applications.
Usage Notes
-----------
This driver does not probe for PMBus devices. You will have to instantiate
devices explicitly.
Sysfs attributes
----------------
======================= ===========================
curr1_label "iin"
curr1_input Measured input current
curr1_alarm Input fault alarm
curr2_label "iout1"
curr2_input Measured output current
curr2_alarm Output over-current alarm
in1_label "vin"
in1_input Measured input voltage
in1_alarm Input under-voltage alarm
in2_label "vout1"
in2_input Measured output voltage
in2_alarm Output over-voltage alarm
power1_label "pin"
power1_input Measured input power
power1_alarm Input under-voltage alarm
power2_label "pout1"
power2_input Measured output power
temp1_input Measured temperature
temp1_alarm Temperature alarm
temp2_input Measured other loop temperature
temp2_alarm Temperature alarm
======================= ===========================
.. SPDX-License-Identifier: GPL-2.0
Kernel driver max15301
======================
Supported chips:
* Maxim MAX15301
Prefix: 'max15301', 'bmr461'
Addresses scanned: -
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX15301.pdf
Author: Erik Rosen <erik.rosen@metormote.com>
Description
-----------
This driver supports hardware monitoring for Maxim MAX15301 controller chip and
compatible modules.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details
on PMBus client drivers.
Usage Notes
-----------
This driver does not auto-detect devices. You will have to instantiate the
devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
details.
Platform data support
---------------------
The driver supports standard PMBus driver platform data.
Module parameters
-----------------
delay
-----
The controller requires a minimum interval between I2C bus accesses.
The default interval is set to 100 us. For manual override, the driver
provides a writeable module parameter, 'delay', which can be used to
set the interval to a value between 0 and 65,535 microseconds.
Sysfs entries
-------------
The following attributes are supported. Limits are read-write; all other
attributes are read-only.
======================= ========================================================
in1_label "vin"
in1_input Measured input voltage.
in1_lcrit Critical minimum input voltage.
in1_crit Critical maximum input voltage.
in1_lcrit_alarm Input voltage critical low alarm.
in1_crit_alarm Input voltage critical high alarm.
in2_label "vout1"
in2_input Measured output voltage.
in2_lcrit Critical minimum output Voltage.
in2_crit Critical maximum output voltage.
in2_lcrit_alarm Critical output voltage critical low alarm.
in2_crit_alarm Critical output voltage critical high alarm.
curr1_label "iout1"
curr1_input Measured output current.
curr1_crit Critical maximum output current.
curr1_crit_alarm Output current critical high alarm.
temp1_input Measured maximum temperature of all phases.
temp1_max Maximum temperature limit.
temp1_max_alarm High temperature alarm.
temp1_crit Critical maximum temperature limit.
temp1_crit_alarm Critical maximum temperature alarm.
======================= ========================================================
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver nzxt-kraken2
==========================
Supported devices:
* NZXT Kraken X42
* NZXT Kraken X52
* NZXT Kraken X62
* NZXT Kraken X72
Author: Jonas Malaco
Description
-----------
This driver enables hardware monitoring support for NZXT Kraken X42/X52/X62/X72
all-in-one CPU liquid coolers. Three sensors are available: fan speed, pump
speed and coolant temperature.
Fan and pump control, while supported by the firmware, are not currently
exposed. The addressable RGB LEDs, present in the integrated CPU water block
and pump head, are not supported either. But both features can be found in
existing user-space tools (e.g. `liquidctl`_).
.. _liquidctl: https://github.com/liquidctl/liquidctl
Usage Notes
-----------
As these are USB HIDs, the driver can be loaded automatically by the kernel and
supports hot swapping.
Sysfs entries
-------------
======================= ========================================================
fan1_input Fan speed (in rpm)
fan2_input Pump speed (in rpm)
temp1_input Coolant temperature (in millidegrees Celsius)
======================= ========================================================
.. SPDX-License-Identifier: GPL-2.0
Kernel driver stpddc60
======================
Supported chips:
* ST STPDDC60
Prefix: 'stpddc60', 'bmr481'
Addresses scanned: -
Datasheet: https://flexpowermodules.com/documents/fpm-techspec-bmr481
Author: Erik Rosen <erik.rosen@metormote.com>
Description
-----------
This driver supports hardware monitoring for ST STPDDC60 controller chip and
compatible modules.
The driver is a client driver to the core PMBus driver. Please see
Documentation/hwmon/pmbus.rst and Documentation.hwmon/pmbus-core for details
on PMBus client drivers.
Usage Notes
-----------
This driver does not auto-detect devices. You will have to instantiate the
devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for
details.
The vout under- and over-voltage limits are set in relation to the commanded
output voltage as a positive or negative offset in the interval 50mV to 400mV
in 50mV steps. This means that the absolute values of the limits will change
when the commanded output voltage changes. Also, care should be taken when
writing to those limits since in the worst case the commanded output voltage
could change at the same time as the limit is written to, wich will lead to
unpredictable results.
Platform data support
---------------------
The driver supports standard PMBus driver platform data.
Sysfs entries
-------------
The following attributes are supported. Vin, iout, pout and temp limits
are read-write; all other attributes are read-only.
======================= ========================================================
in1_label "vin"
in1_input Measured input voltage.
in1_lcrit Critical minimum input voltage.
in1_crit Critical maximum input voltage.
in1_lcrit_alarm Input voltage critical low alarm.
in1_crit_alarm Input voltage critical high alarm.
in2_label "vout1"
in2_input Measured output voltage.
in2_lcrit Critical minimum output voltage.
in2_crit Critical maximum output voltage.
in2_lcrit_alarm Critical output voltage critical low alarm.
in2_crit_alarm Critical output voltage critical high alarm.
curr1_label "iout1"
curr1_input Measured output current.
curr1_max Maximum output current.
curr1_max_alarm Output current high alarm.
curr1_crit Critical maximum output current.
curr1_crit_alarm Output current critical high alarm.
power1_label "pout1"
power1_input Measured output power.
power1_crit Critical maximum output power.
power1_crit_alarm Output power critical high alarm.
temp1_input Measured maximum temperature of all phases.
temp1_max Maximum temperature limit.
temp1_max_alarm High temperature alarm.
temp1_crit Critical maximum temperature limit.
temp1_crit_alarm Critical maximum temperature alarm.
======================= ========================================================
......@@ -65,6 +65,14 @@ the desired value must be written, note that strings which are not a number
are interpreted as 0! For more on how written strings are interpreted see the
"sysfs attribute writes interpretation" section at the end of this file.
Attribute access
----------------
Hardware monitoring sysfs attributes are displayed by unrestricted userspace
applications. For this reason, all standard ABI attributes shall be world
readable. Writeable standard ABI attributes shall be writeable only for
privileged users.
-------------------------------------------------------------------------
======= ===========================================
......
......@@ -19,6 +19,14 @@ Supported chips:
Datasheet: https://www.ti.com/lit/gpn/TPS53667
* Texas Instruments TPS53676
Prefix: 'tps53676'
Addresses scanned: -
Datasheet: https://www.ti.com/lit/gpn/TPS53676
* Texas Instruments TPS53679
Prefix: 'tps53679'
......@@ -136,7 +144,7 @@ power1_input Measured input power.
power[N]_label "pout[1-2]".
- TPS53647, TPS53667: N=2
- TPS53679, TPS53681, TPS53588: N=2,3
- TPS53676, TPS53679, TPS53681, TPS53588: N=2,3
power[N]_input Measured output power.
......@@ -156,10 +164,11 @@ curr[N]_label "iout[1-2]" or "iout1.[0-5]".
The first digit is the output channel, the second
digit is the phase within the channel. Per-phase
telemetry supported on TPS53681 only.
telemetry supported on TPS53676 and TPS53681 only.
- TPS53647, TPS53667: N=2
- TPS53679, TPS53588: N=2,3
- TPS53676: N=2-8
- TPS53681: N=2-9
curr[N]_input Measured output current.
......
......@@ -880,13 +880,6 @@ S: Supported
T: git git://people.freedesktop.org/~agd5f/linux
F: drivers/gpu/drm/amd/display/
AMD ENERGY DRIVER
M: Naveen Krishna Chatradhi <nchatrad@amd.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/amd_energy.rst
F: drivers/hwmon/amd_energy.c
AMD FAM15H PROCESSOR POWER MONITORING DRIVER
M: Huang Rui <ray.huang@amd.com>
L: linux-hwmon@vger.kernel.org
......@@ -7927,6 +7920,7 @@ F: Documentation/hwmon/
F: drivers/hwmon/
F: include/linux/hwmon*.h
F: include/trace/events/hwmon*.h
K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info)
HARDWARE RANDOM NUMBER GENERATOR CORE
M: Matt Mackall <mpm@selenic.com>
......@@ -10898,6 +10892,13 @@ S: Orphan
F: drivers/video/fbdev/matrox/matroxfb_*
F: include/uapi/linux/matroxfb.h
MAX15301 DRIVER
M: Daniel Nilsson <daniel.nilsson@flex.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/max15301.rst
F: drivers/hwmon/pmbus/max15301.c
MAX16065 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org
......@@ -13027,6 +13028,13 @@ L: linux-nfc@lists.01.org (moderated for non-subscribers)
S: Supported
F: drivers/nfc/nxp-nci
NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
M: Jonas Malaco <jonas@protocubo.io>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/nzxt-kraken2.rst
F: drivers/hwmon/nzxt-kraken2.c
OBJAGG
M: Jiri Pirko <jiri@nvidia.com>
L: netdev@vger.kernel.org
......@@ -17068,6 +17076,13 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-stm32*
ST STPDDC60 DRIVER
M: Daniel Nilsson <daniel.nilsson@flex.com>
L: linux-hwmon@vger.kernel.org
S: Maintained
F: Documentation/hwmon/stpddc60.rst
F: drivers/hwmon/pmbus/stpddc60.c
ST VL53L0X ToF RANGER(I2C) IIO DRIVER
M: Song Qiang <songqiang1304521@gmail.com>
L: linux-iio@vger.kernel.org
......
......@@ -321,16 +321,6 @@ config SENSORS_FAM15H_POWER
This driver can also be built as a module. If so, the module
will be called fam15h_power.
config SENSORS_AMD_ENERGY
tristate "AMD RAPL MSR based Energy driver"
depends on X86
help
If you say yes here you get support for core and package energy
sensors, based on RAPL MSR for AMD family 17h and above CPUs.
This driver can also be built as a module. If so, the module
will be called as amd_energy.
config SENSORS_APPLESMC
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
depends on INPUT && X86
......@@ -1492,6 +1482,16 @@ config SENSORS_NSA320
This driver can also be built as a module. If so, the module
will be called nsa320-hwmon.
config SENSORS_NZXT_KRAKEN2
tristate "NZXT Kraken X42/X51/X62/X72 liquid coolers"
depends on USB_HID
help
If you say yes here you get support for hardware monitoring for the
NZXT Kraken X42/X52/X62/X72 all-in-one CPU liquid coolers.
This driver can also be built as a module. If so, the module
will be called nzxt-kraken2.
source "drivers/hwmon/occ/Kconfig"
config SENSORS_PCF8591
......
......@@ -155,6 +155,7 @@ obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o
obj-$(CONFIG_SENSORS_NPCM7XX) += npcm750-pwm-fan.o
obj-$(CONFIG_SENSORS_NSA320) += nsa320-hwmon.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_NZXT_KRAKEN2) += nzxt-kraken2.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
......
......@@ -248,7 +248,7 @@ static ssize_t adc128_alarm_show(struct device *dev,
static umode_t adc128_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct adc128_data *data = dev_get_drvdata(dev);
if (index < ADC128_ATTR_NUM_VOLT) {
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020 Advanced Micro Devices, Inc.
*/
#include <asm/cpu_device_id.h>
#include <linux/bits.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/hwmon.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/processor.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/topology.h>
#include <linux/types.h>
#define DRVNAME "amd_energy"
#define ENERGY_PWR_UNIT_MSR 0xC0010299
#define ENERGY_CORE_MSR 0xC001029A
#define ENERGY_PKG_MSR 0xC001029B
#define AMD_ENERGY_UNIT_MASK 0x01F00
#define AMD_ENERGY_MASK 0xFFFFFFFF
struct sensor_accumulator {
u64 energy_ctr;
u64 prev_value;
};
struct amd_energy_data {
struct hwmon_channel_info energy_info;
const struct hwmon_channel_info *info[2];
struct hwmon_chip_info chip;
struct task_struct *wrap_accumulate;
/* Lock around the accumulator */
struct mutex lock;
/* An accumulator for each core and socket */
struct sensor_accumulator *accums;
unsigned int timeout_ms;
/* Energy Status Units */
int energy_units;
int nr_cpus;
int nr_socks;
int core_id;
char (*label)[10];
};
static int amd_energy_read_labels(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel,
const char **str)
{
struct amd_energy_data *data = dev_get_drvdata(dev);
*str = data->label[channel];
return 0;
}
static void get_energy_units(struct amd_energy_data *data)
{
u64 rapl_units;
rdmsrl_safe(ENERGY_PWR_UNIT_MSR, &rapl_units);
data->energy_units = (rapl_units & AMD_ENERGY_UNIT_MASK) >> 8;
}
static void accumulate_delta(struct amd_energy_data *data,
int channel, int cpu, u32 reg)
{
struct sensor_accumulator *accum;
u64 input;
mutex_lock(&data->lock);
rdmsrl_safe_on_cpu(cpu, reg, &input);
input &= AMD_ENERGY_MASK;
accum = &data->accums[channel];
if (input >= accum->prev_value)
accum->energy_ctr +=
input - accum->prev_value;
else
accum->energy_ctr += UINT_MAX -
accum->prev_value + input;
accum->prev_value = input;
mutex_unlock(&data->lock);
}
static void read_accumulate(struct amd_energy_data *data)
{
int sock, scpu, cpu;
for (sock = 0; sock < data->nr_socks; sock++) {
scpu = cpumask_first_and(cpu_online_mask,
cpumask_of_node(sock));
accumulate_delta(data, data->nr_cpus + sock,
scpu, ENERGY_PKG_MSR);
}
if (data->core_id >= data->nr_cpus)
data->core_id = 0;
cpu = data->core_id;
if (cpu_online(cpu))
accumulate_delta(data, cpu, cpu, ENERGY_CORE_MSR);
data->core_id++;
}
static void amd_add_delta(struct amd_energy_data *data, int ch,
int cpu, long *val, u32 reg)
{
struct sensor_accumulator *accum;
u64 input;
mutex_lock(&data->lock);
rdmsrl_safe_on_cpu(cpu, reg, &input);
input &= AMD_ENERGY_MASK;
accum = &data->accums[ch];
if (input >= accum->prev_value)
input += accum->energy_ctr -
accum->prev_value;
else
input += UINT_MAX - accum->prev_value +
accum->energy_ctr;
/* Energy consumed = (1/(2^ESU) * RAW * 1000000UL) μJoules */
*val = div64_ul(input * 1000000UL, BIT(data->energy_units));
mutex_unlock(&data->lock);
}
static int amd_energy_read(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct amd_energy_data *data = dev_get_drvdata(dev);
u32 reg;
int cpu;
if (channel >= data->nr_cpus) {
cpu = cpumask_first_and(cpu_online_mask,
cpumask_of_node
(channel - data->nr_cpus));
reg = ENERGY_PKG_MSR;
} else {
cpu = channel;
if (!cpu_online(cpu))
return -ENODEV;
reg = ENERGY_CORE_MSR;
}
amd_add_delta(data, channel, cpu, val, reg);
return 0;
}
static umode_t amd_energy_is_visible(const void *_data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
return 0440;
}
static int energy_accumulator(void *p)
{
struct amd_energy_data *data = (struct amd_energy_data *)p;
unsigned int timeout = data->timeout_ms;
while (!kthread_should_stop()) {
/*
* Ignoring the conditions such as
* cpu being offline or rdmsr failure
*/
read_accumulate(data);
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
break;
schedule_timeout(msecs_to_jiffies(timeout));
}
return 0;
}
static const struct hwmon_ops amd_energy_ops = {
.is_visible = amd_energy_is_visible,
.read = amd_energy_read,
.read_string = amd_energy_read_labels,
};
static int amd_create_sensor(struct device *dev,
struct amd_energy_data *data,
enum hwmon_sensor_types type, u32 config)
{
struct hwmon_channel_info *info = &data->energy_info;
struct sensor_accumulator *accums;
int i, num_siblings, cpus, sockets;
u32 *s_config;
char (*label_l)[10];
/* Identify the number of siblings per core */
num_siblings = ((cpuid_ebx(0x8000001e) >> 8) & 0xff) + 1;
sockets = num_possible_nodes();
/*
* Energy counter register is accessed at core level.
* Hence, filterout the siblings.
*/
cpus = num_present_cpus() / num_siblings;
s_config = devm_kcalloc(dev, cpus + sockets + 1,
sizeof(u32), GFP_KERNEL);
if (!s_config)
return -ENOMEM;
accums = devm_kcalloc(dev, cpus + sockets,
sizeof(struct sensor_accumulator),
GFP_KERNEL);
if (!accums)
return -ENOMEM;
label_l = devm_kcalloc(dev, cpus + sockets,
sizeof(*label_l), GFP_KERNEL);
if (!label_l)
return -ENOMEM;
info->type = type;
info->config = s_config;
data->nr_cpus = cpus;
data->nr_socks = sockets;
data->accums = accums;
data->label = label_l;
for (i = 0; i < cpus + sockets; i++) {
s_config[i] = config;
if (i < cpus)
scnprintf(label_l[i], 10, "Ecore%03u", i);
else
scnprintf(label_l[i], 10, "Esocket%u", (i - cpus));
}
s_config[i] = 0;
return 0;
}
static int amd_energy_probe(struct platform_device *pdev)
{
struct device *hwmon_dev;
struct amd_energy_data *data;
struct device *dev = &pdev->dev;
int ret;
data = devm_kzalloc(dev,
sizeof(struct amd_energy_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->chip.ops = &amd_energy_ops;
data->chip.info = data->info;
dev_set_drvdata(dev, data);
/* Populate per-core energy reporting */
data->info[0] = &data->energy_info;
ret = amd_create_sensor(dev, data, hwmon_energy,
HWMON_E_INPUT | HWMON_E_LABEL);
if (ret)
return ret;
mutex_init(&data->lock);
get_energy_units(data);
hwmon_dev = devm_hwmon_device_register_with_info(dev, DRVNAME,
data,
&data->chip,
NULL);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
/*
* On a system with peak wattage of 250W
* timeout = 2 ^ 32 / 2 ^ energy_units / 250 secs
*/
data->timeout_ms = 1000 *
BIT(min(28, 31 - data->energy_units)) / 250;
data->wrap_accumulate = kthread_run(energy_accumulator, data,
"%s", dev_name(hwmon_dev));
return PTR_ERR_OR_ZERO(data->wrap_accumulate);
}
static int amd_energy_remove(struct platform_device *pdev)
{
struct amd_energy_data *data = dev_get_drvdata(&pdev->dev);
if (data && data->wrap_accumulate)
kthread_stop(data->wrap_accumulate);
return 0;
}
static const struct platform_device_id amd_energy_ids[] = {
{ .name = DRVNAME, },
{}
};
MODULE_DEVICE_TABLE(platform, amd_energy_ids);
static struct platform_driver amd_energy_driver = {
.probe = amd_energy_probe,
.remove = amd_energy_remove,
.id_table = amd_energy_ids,
.driver = {
.name = DRVNAME,
},
};
static struct platform_device *amd_energy_platdev;
static const struct x86_cpu_id cpu_ids[] __initconst = {
X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x17, 0x31, NULL),
X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x19, 0x01, NULL),
X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x19, 0x30, NULL),
{}
};
MODULE_DEVICE_TABLE(x86cpu, cpu_ids);
static int __init amd_energy_init(void)
{
int ret;
if (!x86_match_cpu(cpu_ids))
return -ENODEV;
ret = platform_driver_register(&amd_energy_driver);
if (ret)
return ret;
amd_energy_platdev = platform_device_alloc(DRVNAME, 0);
if (!amd_energy_platdev) {
platform_driver_unregister(&amd_energy_driver);
return -ENOMEM;
}
ret = platform_device_add(amd_energy_platdev);
if (ret) {
platform_device_put(amd_energy_platdev);
platform_driver_unregister(&amd_energy_driver);
return ret;
}
return ret;
}
static void __exit amd_energy_exit(void)
{
platform_device_unregister(amd_energy_platdev);
platform_driver_unregister(&amd_energy_driver);
}
module_init(amd_energy_init);
module_exit(amd_energy_exit);
MODULE_DESCRIPTION("Driver for AMD Energy reporting from RAPL MSR via HWMON interface");
MODULE_AUTHOR("Naveen Krishna Chatradhi <nchatrad@amd.com>");
MODULE_LICENSE("GPL");
......@@ -741,7 +741,7 @@ static void applesmc_idev_poll(struct input_dev *idev)
static ssize_t applesmc_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "applesmc\n");
return sysfs_emit(buf, "applesmc\n");
}
static ssize_t applesmc_position_show(struct device *dev,
......@@ -763,8 +763,8 @@ static ssize_t applesmc_position_show(struct device *dev,
out:
if (ret)
return ret;
else
return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
return sysfs_emit(buf, "(%d,%d,%d)\n", x, y, z);
}
static ssize_t applesmc_light_show(struct device *dev,
......@@ -804,8 +804,8 @@ static ssize_t applesmc_light_show(struct device *dev,
out:
if (ret)
return ret;
else
return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
return sysfs_emit(sysfsbuf, "(%d,%d)\n", left, right);
}
/* Displays sensor key as label */
......@@ -814,7 +814,7 @@ static ssize_t applesmc_show_sensor_label(struct device *dev,
{
const char *key = smcreg.index[to_index(devattr)];
return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
return sysfs_emit(sysfsbuf, "%s\n", key);
}
/* Displays degree Celsius * 1000 */
......@@ -832,7 +832,7 @@ static ssize_t applesmc_show_temperature(struct device *dev,
temp = 250 * (value >> 6);
return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", temp);
return sysfs_emit(sysfsbuf, "%d\n", temp);
}
static ssize_t applesmc_show_fan_speed(struct device *dev,
......@@ -851,7 +851,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
return ret;
speed = ((buffer[0] << 8 | buffer[1]) >> 2);
return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
return sysfs_emit(sysfsbuf, "%u\n", speed);
}
static ssize_t applesmc_store_fan_speed(struct device *dev,
......@@ -891,7 +891,7 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
return ret;
manual = ((buffer[0] << 8 | buffer[1]) >> to_index(attr)) & 0x01;
return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
return sysfs_emit(sysfsbuf, "%d\n", manual);
}
static ssize_t applesmc_store_fan_manual(struct device *dev,
......@@ -943,14 +943,14 @@ static ssize_t applesmc_show_fan_position(struct device *dev,
if (ret)
return ret;
else
return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
return sysfs_emit(sysfsbuf, "%s\n", buffer + 4);
}
static ssize_t applesmc_calibrate_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
return sysfs_emit(sysfsbuf, "(%d,%d)\n", rest_x, rest_y);
}
static ssize_t applesmc_calibrate_store(struct device *dev,
......@@ -992,7 +992,7 @@ static ssize_t applesmc_key_count_show(struct device *dev,
count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
((u32)buffer[2]<<8) + buffer[3];
return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
return sysfs_emit(sysfsbuf, "%d\n", count);
}
static ssize_t applesmc_key_at_index_read_show(struct device *dev,
......@@ -1020,7 +1020,7 @@ static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
if (IS_ERR(entry))
return PTR_ERR(entry);
return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", entry->len);
return sysfs_emit(sysfsbuf, "%d\n", entry->len);
}
static ssize_t applesmc_key_at_index_type_show(struct device *dev,
......@@ -1032,7 +1032,7 @@ static ssize_t applesmc_key_at_index_type_show(struct device *dev,
if (IS_ERR(entry))
return PTR_ERR(entry);
return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->type);
return sysfs_emit(sysfsbuf, "%s\n", entry->type);
}
static ssize_t applesmc_key_at_index_name_show(struct device *dev,
......@@ -1044,13 +1044,13 @@ static ssize_t applesmc_key_at_index_name_show(struct device *dev,
if (IS_ERR(entry))
return PTR_ERR(entry);
return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", entry->key);
return sysfs_emit(sysfsbuf, "%s\n", entry->key);
}
static ssize_t applesmc_key_at_index_show(struct device *dev,
struct device_attribute *attr, char *sysfsbuf)
{
return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
return sysfs_emit(sysfsbuf, "%d\n", key_at_index);
}
static ssize_t applesmc_key_at_index_store(struct device *dev,
......
This diff is collapsed.
......@@ -1210,6 +1210,14 @@ static struct dmi_system_id i8k_whitelist_fan_control[] __initdata = {
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{
.ident = "Dell Latitude E7440",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude E7440"),
},
.driver_data = (void *)&i8k_fan_control_data[I8K_FAN_34A3_35A3],
},
{ }
};
......
......@@ -326,7 +326,7 @@ static struct attribute *ds1621_attributes[] = {
static umode_t ds1621_attribute_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct ds1621_data *data = dev_get_drvdata(dev);
if (attr == &dev_attr_update_interval.attr)
......
......@@ -509,7 +509,7 @@ fan_alarm_store(struct device *dev, struct device_attribute *devattr,
/* SysFS structs */
/*****************************************************************************/
/* Temprature sensors */
/* Temperature sensors */
static SENSOR_DEVICE_ATTR_RO(temp1_input, temp_value, 0);
static SENSOR_DEVICE_ATTR_RO(temp2_input, temp_value, 1);
static SENSOR_DEVICE_ATTR_RO(temp3_input, temp_value, 2);
......@@ -713,7 +713,7 @@ static int fts_detect(struct i2c_client *client,
{
int val;
/* detection works with revsion greater or equal to 0x2b */
/* detection works with revision greater or equal to 0x2b */
val = i2c_smbus_read_byte_data(client, FTS_DEVICE_REVISION_REG);
if (val < 0x2b)
return -ENODEV;
......
......@@ -79,7 +79,7 @@ static struct attribute *hwmon_dev_attrs[] = {
static umode_t hwmon_dev_name_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
if (to_hwmon_device(dev)->name == NULL)
return 0;
......
......@@ -259,7 +259,7 @@ static ssize_t ina209_interval_show(struct device *dev,
{
struct ina209_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval);
return sysfs_emit(buf, "%d\n", data->update_interval);
}
/*
......@@ -343,7 +343,7 @@ static ssize_t ina209_value_show(struct device *dev,
return PTR_ERR(data);
val = ina209_from_reg(attr->index, data->regs[attr->index]);
return snprintf(buf, PAGE_SIZE, "%ld\n", val);
return sysfs_emit(buf, "%ld\n", val);
}
static ssize_t ina209_alarm_show(struct device *dev,
......@@ -363,7 +363,7 @@ static ssize_t ina209_alarm_show(struct device *dev,
* All alarms are in the INA209_STATUS register. To avoid a long
* switch statement, the mask is passed in attr->index
*/
return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask));
return sysfs_emit(buf, "%u\n", !!(status & mask));
}
/* Shunt voltage, history, limits, alarms */
......
......@@ -310,8 +310,7 @@ static ssize_t ina2xx_value_show(struct device *dev,
if (err < 0)
return err;
return snprintf(buf, PAGE_SIZE, "%d\n",
ina2xx_get_value(data, attr->index, regval));
return sysfs_emit(buf, "%d\n", ina2xx_get_value(data, attr->index, regval));
}
static int ina226_reg_to_alert(struct ina2xx_data *data, u8 bit, u16 regval)
......@@ -386,7 +385,7 @@ static ssize_t ina226_alert_show(struct device *dev,
val = ina226_reg_to_alert(data, attr->index, regval);
}
ret = snprintf(buf, PAGE_SIZE, "%d\n", val);
ret = sysfs_emit(buf, "%d\n", val);
abort:
mutex_unlock(&data->config_lock);
return ret;
......@@ -450,7 +449,7 @@ static ssize_t ina226_alarm_show(struct device *dev,
alarm = (regval & BIT(attr->index)) &&
(regval & INA226_ALERT_FUNCTION_FLAG);
return snprintf(buf, PAGE_SIZE, "%d\n", alarm);
return sysfs_emit(buf, "%d\n", alarm);
}
/*
......@@ -481,7 +480,7 @@ static ssize_t ina2xx_shunt_show(struct device *dev,
{
struct ina2xx_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%li\n", data->rshunt);
return sysfs_emit(buf, "%li\n", data->rshunt);
}
static ssize_t ina2xx_shunt_store(struct device *dev,
......@@ -537,7 +536,7 @@ static ssize_t ina226_interval_show(struct device *dev,
if (status)
return status;
return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval));
return sysfs_emit(buf, "%d\n", ina226_reg_to_interval(regval));
}
/* shunt voltage */
......
......@@ -698,7 +698,7 @@ static ssize_t ina3221_shunt_show(struct device *dev,
unsigned int channel = sd_attr->index;
struct ina3221_input *input = &ina->inputs[channel];
return snprintf(buf, PAGE_SIZE, "%d\n", input->shunt_resistor);
return sysfs_emit(buf, "%d\n", input->shunt_resistor);
}
static ssize_t ina3221_shunt_store(struct device *dev,
......
......@@ -99,6 +99,50 @@ static const struct hwmon_channel_info *n3000bmc_hinfo[] = {
NULL
};
static const struct m10bmc_sdata d5005bmc_temp_tbl[] = {
{ 0x100, 0x104, 0x108, 0x10c, 0x0, 500, "Board Inlet Air Temperature" },
{ 0x110, 0x114, 0x118, 0x0, 0x0, 500, "FPGA Core Temperature" },
{ 0x11c, 0x120, 0x124, 0x128, 0x0, 500, "Board Exhaust Air Temperature" },
{ 0x12c, 0x130, 0x134, 0x0, 0x0, 500, "FPGA Transceiver Temperature" },
{ 0x138, 0x13c, 0x140, 0x144, 0x0, 500, "RDIMM0 Temperature" },
{ 0x148, 0x14c, 0x150, 0x154, 0x0, 500, "RDIMM1 Temperature" },
{ 0x158, 0x15c, 0x160, 0x164, 0x0, 500, "RDIMM2 Temperature" },
{ 0x168, 0x16c, 0x170, 0x174, 0x0, 500, "RDIMM3 Temperature" },
{ 0x178, 0x17c, 0x180, 0x0, 0x0, 500, "QSFP0 Temperature" },
{ 0x188, 0x18c, 0x190, 0x0, 0x0, 500, "QSFP1 Temperature" },
{ 0x1a0, 0x1a4, 0x1a8, 0x0, 0x0, 500, "3.3v Temperature" },
{ 0x1bc, 0x1c0, 0x1c4, 0x0, 0x0, 500, "VCCERAM Temperature" },
{ 0x1d8, 0x1dc, 0x1e0, 0x0, 0x0, 500, "VCCR Temperature" },
{ 0x1f4, 0x1f8, 0x1fc, 0x0, 0x0, 500, "VCCT Temperature" },
{ 0x210, 0x214, 0x218, 0x0, 0x0, 500, "1.8v Temperature" },
{ 0x22c, 0x230, 0x234, 0x0, 0x0, 500, "12v Backplane Temperature" },
{ 0x248, 0x24c, 0x250, 0x0, 0x0, 500, "12v AUX Temperature" },
};
static const struct m10bmc_sdata d5005bmc_in_tbl[] = {
{ 0x184, 0x0, 0x0, 0x0, 0x0, 1, "QSFP0 Supply Voltage" },
{ 0x194, 0x0, 0x0, 0x0, 0x0, 1, "QSFP1 Supply Voltage" },
{ 0x198, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Voltage" },
{ 0x1ac, 0x1b0, 0x1b4, 0x0, 0x0, 1, "3.3v Voltage" },
{ 0x1c8, 0x1cc, 0x1d0, 0x0, 0x0, 1, "VCCERAM Voltage" },
{ 0x1e4, 0x1e8, 0x1ec, 0x0, 0x0, 1, "VCCR Voltage" },
{ 0x200, 0x204, 0x208, 0x0, 0x0, 1, "VCCT Voltage" },
{ 0x21c, 0x220, 0x224, 0x0, 0x0, 1, "1.8v Voltage" },
{ 0x238, 0x0, 0x0, 0x0, 0x23c, 1, "12v Backplane Voltage" },
{ 0x254, 0x0, 0x0, 0x0, 0x258, 1, "12v AUX Voltage" },
};
static const struct m10bmc_sdata d5005bmc_curr_tbl[] = {
{ 0x19c, 0x0, 0x0, 0x0, 0x0, 1, "FPGA Core Current" },
{ 0x1b8, 0x0, 0x0, 0x0, 0x0, 1, "3.3v Current" },
{ 0x1d4, 0x0, 0x0, 0x0, 0x0, 1, "VCCERAM Current" },
{ 0x1f0, 0x0, 0x0, 0x0, 0x0, 1, "VCCR Current" },
{ 0x20c, 0x0, 0x0, 0x0, 0x0, 1, "VCCT Current" },
{ 0x228, 0x0, 0x0, 0x0, 0x0, 1, "1.8v Current" },
{ 0x240, 0x244, 0x0, 0x0, 0x0, 1, "12v Backplane Current" },
{ 0x25c, 0x260, 0x0, 0x0, 0x0, 1, "12v AUX Current" },
};
static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
.tables = {
[hwmon_temp] = n3000bmc_temp_tbl,
......@@ -110,6 +154,80 @@ static const struct m10bmc_hwmon_board_data n3000bmc_hwmon_bdata = {
.hinfo = n3000bmc_hinfo,
};
static const struct hwmon_channel_info *d5005bmc_hinfo[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_LABEL),
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_CRIT |
HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_LABEL),
HWMON_CHANNEL_INFO(curr,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL,
HWMON_C_INPUT | HWMON_C_MAX | HWMON_C_LABEL),
NULL
};
static const struct m10bmc_hwmon_board_data d5005bmc_hwmon_bdata = {
.tables = {
[hwmon_temp] = d5005bmc_temp_tbl,
[hwmon_in] = d5005bmc_in_tbl,
[hwmon_curr] = d5005bmc_curr_tbl,
},
.hinfo = d5005bmc_hinfo,
};
static umode_t
m10bmc_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
......@@ -316,6 +434,10 @@ static const struct platform_device_id intel_m10bmc_hwmon_ids[] = {
.name = "n3000bmc-hwmon",
.driver_data = (unsigned long)&n3000bmc_hwmon_bdata,
},
{
.name = "d5005bmc-hwmon",
.driver_data = (unsigned long)&d5005bmc_hwmon_bdata,
},
{ }
};
......
......@@ -1981,7 +1981,7 @@ static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3);
static umode_t it87_in_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 5; /* voltage index */
int a = index % 5; /* attribute index */
......@@ -2065,7 +2065,7 @@ static const struct attribute_group it87_group_in = {
static umode_t it87_temp_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 7; /* temperature index */
int a = index % 7; /* attribute index */
......@@ -2126,7 +2126,7 @@ static const struct attribute_group it87_group_temp = {
static umode_t it87_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
if ((index == 2 || index == 3) && !data->has_vid)
......@@ -2158,7 +2158,7 @@ static const struct attribute_group it87_group = {
static umode_t it87_fan_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 5; /* fan index */
int a = index % 5; /* attribute index */
......@@ -2229,7 +2229,7 @@ static const struct attribute_group it87_group_fan = {
static umode_t it87_pwm_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 4; /* pwm index */
int a = index % 4; /* attribute index */
......@@ -2290,7 +2290,7 @@ static const struct attribute_group it87_group_pwm = {
static umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 11; /* pwm index */
int a = index % 11; /* attribute index */
......
......@@ -280,7 +280,7 @@ static ssize_t pem_bool_show(struct device *dev, struct device_attribute *da,
return PTR_ERR(data);
status = data->data_string[attr->nr] & attr->index;
return snprintf(buf, PAGE_SIZE, "%d\n", !!status);
return sysfs_emit(buf, "%d\n", !!status);
}
static ssize_t pem_data_show(struct device *dev, struct device_attribute *da,
......@@ -296,7 +296,7 @@ static ssize_t pem_data_show(struct device *dev, struct device_attribute *da,
value = pem_get_data(data->data_string, sizeof(data->data_string),
attr->index);
return snprintf(buf, PAGE_SIZE, "%ld\n", value);
return sysfs_emit(buf, "%ld\n", value);
}
static ssize_t pem_input_show(struct device *dev, struct device_attribute *da,
......@@ -312,7 +312,7 @@ static ssize_t pem_input_show(struct device *dev, struct device_attribute *da,
value = pem_get_input(data->input_string, sizeof(data->input_string),
attr->index);
return snprintf(buf, PAGE_SIZE, "%ld\n", value);
return sysfs_emit(buf, "%ld\n", value);
}
static ssize_t pem_fan_show(struct device *dev, struct device_attribute *da,
......@@ -328,7 +328,7 @@ static ssize_t pem_fan_show(struct device *dev, struct device_attribute *da,
value = pem_get_fan(data->fan_speed, sizeof(data->fan_speed),
attr->index);
return snprintf(buf, PAGE_SIZE, "%ld\n", value);
return sysfs_emit(buf, "%ld\n", value);
}
/* Voltages */
......
......@@ -931,7 +931,7 @@ static const struct attribute_group lm63_group_extra_lut = {
static umode_t lm63_attribute_mode(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct lm63_data *data = dev_get_drvdata(dev);
if (attr == &sensor_dev_attr_temp2_crit.dev_attr.attr
......
......@@ -226,7 +226,7 @@ static ssize_t ltc2945_value_show(struct device *dev,
value = ltc2945_reg_to_val(dev, attr->index);
if (value < 0)
return value;
return snprintf(buf, PAGE_SIZE, "%lld\n", value);
return sysfs_emit(buf, "%lld\n", value);
}
static ssize_t ltc2945_value_store(struct device *dev,
......@@ -333,7 +333,7 @@ static ssize_t ltc2945_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
regmap_update_bits(regmap, LTC2945_FAULT, attr->index, 0);
return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
return sysfs_emit(buf, "%d\n", !!fault);
}
/* Input voltages */
......
......@@ -147,13 +147,13 @@ static ssize_t ltc2990_value_show(struct device *dev,
if (unlikely(ret < 0))
return ret;
return snprintf(buf, PAGE_SIZE, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static umode_t ltc2990_attrs_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct ltc2990_data *data = dev_get_drvdata(dev);
struct device_attribute *da =
container_of(a, struct device_attribute, attr);
......
......@@ -128,7 +128,7 @@ static ssize_t ltc4151_value_show(struct device *dev,
return PTR_ERR(data);
value = ltc4151_get_value(data, attr->index);
return snprintf(buf, PAGE_SIZE, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
/*
......
......@@ -139,7 +139,7 @@ static ssize_t ltc4215_voltage_show(struct device *dev,
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
const int voltage = ltc4215_get_voltage(dev, attr->index);
return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
return sysfs_emit(buf, "%d\n", voltage);
}
static ssize_t ltc4215_current_show(struct device *dev,
......@@ -147,7 +147,7 @@ static ssize_t ltc4215_current_show(struct device *dev,
{
const unsigned int curr = ltc4215_get_current(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", curr);
return sysfs_emit(buf, "%u\n", curr);
}
static ssize_t ltc4215_power_show(struct device *dev,
......@@ -159,7 +159,7 @@ static ssize_t ltc4215_power_show(struct device *dev,
/* current in mA * voltage in mV == power in uW */
const unsigned int power = abs(output_voltage * curr);
return snprintf(buf, PAGE_SIZE, "%u\n", power);
return sysfs_emit(buf, "%u\n", power);
}
static ssize_t ltc4215_alarm_show(struct device *dev,
......@@ -170,7 +170,7 @@ static ssize_t ltc4215_alarm_show(struct device *dev,
const u8 reg = data->regs[LTC4215_STATUS];
const u32 mask = attr->index;
return snprintf(buf, PAGE_SIZE, "%u\n", !!(reg & mask));
return sysfs_emit(buf, "%u\n", !!(reg & mask));
}
/*
......
......@@ -94,7 +94,7 @@ static ssize_t ltc4222_value_show(struct device *dev,
value = ltc4222_get_value(dev, attr->index);
if (value < 0)
return value;
return snprintf(buf, PAGE_SIZE, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static ssize_t ltc4222_bool_show(struct device *dev,
......@@ -112,7 +112,7 @@ static ssize_t ltc4222_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
regmap_update_bits(regmap, attr->nr, attr->index, 0);
return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
return sysfs_emit(buf, "%d\n", !!fault);
}
/* Voltages */
......
......@@ -79,7 +79,7 @@ static ssize_t ltc4260_value_show(struct device *dev,
value = ltc4260_get_value(dev, attr->index);
if (value < 0)
return value;
return snprintf(buf, PAGE_SIZE, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static ssize_t ltc4260_bool_show(struct device *dev,
......@@ -98,7 +98,7 @@ static ssize_t ltc4260_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
regmap_update_bits(regmap, LTC4260_FAULT, attr->index, 0);
return snprintf(buf, PAGE_SIZE, "%d\n", !!fault);
return sysfs_emit(buf, "%d\n", !!fault);
}
/* Voltages */
......
......@@ -130,7 +130,7 @@ static ssize_t ltc4261_value_show(struct device *dev,
return PTR_ERR(data);
value = ltc4261_get_value(data, attr->index);
return snprintf(buf, PAGE_SIZE, "%d\n", value);
return sysfs_emit(buf, "%d\n", value);
}
static ssize_t ltc4261_bool_show(struct device *dev,
......@@ -147,7 +147,7 @@ static ssize_t ltc4261_bool_show(struct device *dev,
if (fault) /* Clear reported faults in chip register */
i2c_smbus_write_byte_data(data->client, LTC4261_FAULT, ~fault);
return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
return sysfs_emit(buf, "%d\n", fault ? 1 : 0);
}
/*
......
......@@ -187,7 +187,7 @@ static ssize_t max16065_alarm_show(struct device *dev,
i2c_smbus_write_byte_data(data->client,
MAX16065_FAULT(attr2->nr), val);
return snprintf(buf, PAGE_SIZE, "%d\n", !!val);
return sysfs_emit(buf, "%d\n", !!val);
}
static ssize_t max16065_input_show(struct device *dev,
......@@ -200,8 +200,8 @@ static ssize_t max16065_input_show(struct device *dev,
if (unlikely(adc < 0))
return adc;
return snprintf(buf, PAGE_SIZE, "%d\n",
ADC_TO_MV(adc, data->range[attr->index]));
return sysfs_emit(buf, "%d\n",
ADC_TO_MV(adc, data->range[attr->index]));
}
static ssize_t max16065_current_show(struct device *dev,
......@@ -212,8 +212,8 @@ static ssize_t max16065_current_show(struct device *dev,
if (unlikely(data->curr_sense < 0))
return data->curr_sense;
return snprintf(buf, PAGE_SIZE, "%d\n",
ADC_TO_CURR(data->curr_sense, data->curr_gain));
return sysfs_emit(buf, "%d\n",
ADC_TO_CURR(data->curr_sense, data->curr_gain));
}
static ssize_t max16065_limit_store(struct device *dev,
......@@ -249,8 +249,8 @@ static ssize_t max16065_limit_show(struct device *dev,
struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
struct max16065_data *data = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n",
data->limit[attr2->nr][attr2->index]);
return sysfs_emit(buf, "%d\n",
data->limit[attr2->nr][attr2->index]);
}
/* Construct a sensor_device_attribute structure for each register */
......@@ -454,7 +454,7 @@ static struct attribute *max16065_max_attributes[] = {
static umode_t max16065_basic_is_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct max16065_data *data = dev_get_drvdata(dev);
int index = n / 4;
......@@ -466,7 +466,7 @@ static umode_t max16065_basic_is_visible(struct kobject *kobj,
static umode_t max16065_secondary_is_visible(struct kobject *kobj,
struct attribute *a, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct max16065_data *data = dev_get_drvdata(dev);
if (index >= data->num_adc)
......
......@@ -460,7 +460,7 @@ static DEVICE_ATTR(dummy, 0, NULL, NULL);
static umode_t max6697_is_visible(struct kobject *kobj, struct attribute *attr,
int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct max6697_data *data = dev_get_drvdata(dev);
const struct max6697_chip_data *chip = data->chip;
int channel = index / 7; /* channel number */
......
......@@ -67,11 +67,13 @@
* @connected: indicates if tachometer is connected;
* @reg: register offset;
* @mask: fault mask;
* @prsnt: present register offset;
*/
struct mlxreg_fan_tacho {
bool connected;
u32 reg;
u32 mask;
u32 prsnt;
};
/*
......@@ -92,6 +94,7 @@ struct mlxreg_fan_pwm {
* @regmap: register map of parent device;
* @tacho: tachometer data;
* @pwm: PWM data;
* @tachos_per_drwr - number of tachometers per drawer;
* @samples: minimum allowed samples per pulse;
* @divider: divider value for tachometer RPM calculation;
* @cooling: cooling device levels;
......@@ -103,6 +106,7 @@ struct mlxreg_fan {
struct mlxreg_core_platform_data *pdata;
struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO];
struct mlxreg_fan_pwm pwm;
int tachos_per_drwr;
int samples;
int divider;
u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1];
......@@ -123,6 +127,26 @@ mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
tacho = &fan->tacho[channel];
switch (attr) {
case hwmon_fan_input:
/*
* Check FAN presence: FAN related bit in presence register is one,
* if FAN is physically connected, zero - otherwise.
*/
if (tacho->prsnt && fan->tachos_per_drwr) {
err = regmap_read(fan->regmap, tacho->prsnt, &regval);
if (err)
return err;
/*
* Map channel to presence bit - drawer can be equipped with
* one or few FANs, while presence is indicated per drawer.
*/
if (BIT(channel / fan->tachos_per_drwr) & regval) {
/* FAN is not connected - return zero for FAN speed. */
*val = 0;
return 0;
}
}
err = regmap_read(fan->regmap, tacho->reg, &regval);
if (err)
return err;
......@@ -389,8 +413,8 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
struct mlxreg_core_platform_data *pdata)
{
struct mlxreg_core_data *data = pdata->data;
int tacho_num = 0, tacho_avail = 0, i;
bool configured = false;
int tacho_num = 0, i;
int err;
fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF;
......@@ -415,7 +439,9 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
fan->tacho[tacho_num].reg = data->reg;
fan->tacho[tacho_num].mask = data->mask;
fan->tacho[tacho_num].prsnt = data->reg_prsnt;
fan->tacho[tacho_num++].connected = true;
tacho_avail++;
} else if (strnstr(data->label, "pwm", sizeof(data->label))) {
if (fan->pwm.connected) {
dev_err(fan->dev, "duplicate pwm entry: %s\n",
......@@ -453,6 +479,29 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
}
}
if (pdata->capability) {
int drwr_avail;
u32 regval;
/* Obtain the number of FAN drawers, supported by system. */
err = regmap_read(fan->regmap, pdata->capability, &regval);
if (err) {
dev_err(fan->dev, "Failed to query capability register 0x%08x\n",
pdata->capability);
return err;
}
drwr_avail = hweight32(regval);
if (!tacho_avail || !drwr_avail || tacho_avail < drwr_avail) {
dev_err(fan->dev, "Configuration is invalid: drawers num %d tachos num %d\n",
drwr_avail, tacho_avail);
return -EINVAL;
}
/* Set the number of tachometers per one drawer. */
fan->tachos_per_drwr = tacho_avail / drwr_avail;
}
/* Init cooling levels per PWM state. */
for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++)
fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL;
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* nct6683 - Driver for the hardware monitoring functionality of
* Nuvoton NCT6683D/NCT6687D eSIO
* Nuvoton NCT6683D/NCT6686D/NCT6687D eSIO
*
* Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net>
*
......@@ -12,6 +12,7 @@
*
* Chip #vin #fan #pwm #temp chip ID
* nct6683d 21(1) 16 8 32(1) 0xc730
* nct6686d 21(1) 16 8 32(1) 0xd440
* nct6687d 21(1) 16 8 32(1) 0xd590
*
* Notes:
......@@ -33,7 +34,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
enum kinds { nct6683, nct6687 };
enum kinds { nct6683, nct6686, nct6687 };
static bool force;
module_param(force, bool, 0);
......@@ -41,11 +42,13 @@ MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
static const char * const nct6683_device_names[] = {
"nct6683",
"nct6686",
"nct6687",
};
static const char * const nct6683_chip_names[] = {
"NCT6683D",
"NCT6686D",
"NCT6687D",
};
......@@ -66,6 +69,7 @@ static const char * const nct6683_chip_names[] = {
#define SIO_NCT6681_ID 0xb270 /* for later */
#define SIO_NCT6683_ID 0xc730
#define SIO_NCT6686_ID 0xd440
#define SIO_NCT6687_ID 0xd590
#define SIO_ID_MASK 0xFFF0
......@@ -488,17 +492,6 @@ static inline long in_from_reg(u16 reg, u8 src)
return reg * scale;
}
static inline u16 in_to_reg(u32 val, u8 src)
{
int scale = 16;
if (src == MON_SRC_VCC || src == MON_SRC_VSB || src == MON_SRC_AVSB ||
src == MON_SRC_VBAT)
scale <<= 1;
return clamp_val(DIV_ROUND_CLOSEST(val, scale), 0, 127);
}
static u16 nct6683_read(struct nct6683_data *data, u16 reg)
{
int res;
......@@ -1362,6 +1355,9 @@ static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
case SIO_NCT6683_ID:
sio_data->kind = nct6683;
break;
case SIO_NCT6686_ID:
sio_data->kind = nct6686;
break;
case SIO_NCT6687_ID:
sio_data->kind = nct6687;
break;
......
// SPDX-License-Identifier: GPL-2.0+
/*
* nzxt-kraken2.c - hwmon driver for NZXT Kraken X42/X52/X62/X72 coolers
*
* The device asynchronously sends HID reports (with id 0x04) twice a second to
* communicate current fan speed, pump speed and coolant temperature. The
* device does not respond to Get_Report requests for this status report.
*
* Copyright 2019-2021 Jonas Malaco <jonas@protocubo.io>
*/
#include <asm/unaligned.h>
#include <linux/hid.h>
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#define STATUS_REPORT_ID 0x04
#define STATUS_VALIDITY 2 /* seconds; equivalent to 4 missed updates */
static const char *const kraken2_temp_label[] = {
"Coolant",
};
static const char *const kraken2_fan_label[] = {
"Fan",
"Pump",
};
struct kraken2_priv_data {
struct hid_device *hid_dev;
struct device *hwmon_dev;
s32 temp_input[1];
u16 fan_input[2];
unsigned long updated; /* jiffies */
};
static umode_t kraken2_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
return 0444;
}
static int kraken2_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct kraken2_priv_data *priv = dev_get_drvdata(dev);
if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ))
return -ENODATA;
switch (type) {
case hwmon_temp:
*val = priv->temp_input[channel];
break;
case hwmon_fan:
*val = priv->fan_input[channel];
break;
default:
return -EOPNOTSUPP; /* unreachable */
}
return 0;
}
static int kraken2_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
switch (type) {
case hwmon_temp:
*str = kraken2_temp_label[channel];
break;
case hwmon_fan:
*str = kraken2_fan_label[channel];
break;
default:
return -EOPNOTSUPP; /* unreachable */
}
return 0;
}
static const struct hwmon_ops kraken2_hwmon_ops = {
.is_visible = kraken2_is_visible,
.read = kraken2_read,
.read_string = kraken2_read_string,
};
static const struct hwmon_channel_info *kraken2_info[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL),
NULL
};
static const struct hwmon_chip_info kraken2_chip_info = {
.ops = &kraken2_hwmon_ops,
.info = kraken2_info,
};
static int kraken2_raw_event(struct hid_device *hdev,
struct hid_report *report, u8 *data, int size)
{
struct kraken2_priv_data *priv;
if (size < 7 || report->id != STATUS_REPORT_ID)
return 0;
priv = hid_get_drvdata(hdev);
/*
* The fractional byte of the coolant temperature has been observed to
* be in the interval [1,9], but some of these steps are also
* consistently skipped for certain integer parts.
*
* For the lack of a better idea, assume that the resolution is 0.1°C,
* and that the missing steps are artifacts of how the firmware
* processes the raw sensor data.
*/
priv->temp_input[0] = data[1] * 1000 + data[2] * 100;
priv->fan_input[0] = get_unaligned_be16(data + 3);
priv->fan_input[1] = get_unaligned_be16(data + 5);
priv->updated = jiffies;
return 0;
}
static int kraken2_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
struct kraken2_priv_data *priv;
int ret;
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->hid_dev = hdev;
hid_set_drvdata(hdev, priv);
/*
* Initialize ->updated to STATUS_VALIDITY seconds in the past, making
* the initial empty data invalid for kraken2_read without the need for
* a special case there.
*/
priv->updated = jiffies - STATUS_VALIDITY * HZ;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "hid parse failed with %d\n", ret);
return ret;
}
/*
* Enable hidraw so existing user-space tools can continue to work.
*/
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret) {
hid_err(hdev, "hid hw start failed with %d\n", ret);
goto fail_and_stop;
}
ret = hid_hw_open(hdev);
if (ret) {
hid_err(hdev, "hid hw open failed with %d\n", ret);
goto fail_and_close;
}
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "kraken2",
priv, &kraken2_chip_info,
NULL);
if (IS_ERR(priv->hwmon_dev)) {
ret = PTR_ERR(priv->hwmon_dev);
hid_err(hdev, "hwmon registration failed with %d\n", ret);
goto fail_and_close;
}
return 0;
fail_and_close:
hid_hw_close(hdev);
fail_and_stop:
hid_hw_stop(hdev);
return ret;
}
static void kraken2_remove(struct hid_device *hdev)
{
struct kraken2_priv_data *priv = hid_get_drvdata(hdev);
hwmon_device_unregister(priv->hwmon_dev);
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
static const struct hid_device_id kraken2_table[] = {
{ HID_USB_DEVICE(0x1e71, 0x170e) }, /* NZXT Kraken X42/X52/X62/X72 */
{ }
};
MODULE_DEVICE_TABLE(hid, kraken2_table);
static struct hid_driver kraken2_driver = {
.name = "nzxt-kraken2",
.id_table = kraken2_table,
.probe = kraken2_probe,
.remove = kraken2_remove,
.raw_event = kraken2_raw_event,
};
static int __init kraken2_init(void)
{
return hid_register_driver(&kraken2_driver);
}
static void __exit kraken2_exit(void)
{
hid_unregister_driver(&kraken2_driver);
}
/*
* When compiled into the kernel, initialize after the hid bus.
*/
late_initcall(kraken2_init);
module_exit(kraken2_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jonas Malaco <jonas@protocubo.io>");
MODULE_DESCRIPTION("Hwmon driver for NZXT Kraken X42/X52/X62/X72 coolers");
......@@ -261,7 +261,7 @@ static ssize_t occ_show_temp_1(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_temp_2(struct device *dev,
......@@ -312,7 +312,7 @@ static ssize_t occ_show_temp_2(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_temp_10(struct device *dev,
......@@ -366,7 +366,7 @@ static ssize_t occ_show_temp_10(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_freq_1(struct device *dev,
......@@ -396,7 +396,7 @@ static ssize_t occ_show_freq_1(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_freq_2(struct device *dev,
......@@ -426,7 +426,7 @@ static ssize_t occ_show_freq_2(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
return sysfs_emit(buf, "%u\n", val);
}
static ssize_t occ_show_power_1(struct device *dev,
......@@ -465,7 +465,7 @@ static ssize_t occ_show_power_1(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
return sysfs_emit(buf, "%llu\n", val);
}
static u64 occ_get_powr_avg(u64 *accum, u32 *samples)
......@@ -494,9 +494,9 @@ static ssize_t occ_show_power_2(struct device *dev,
switch (sattr->nr) {
case 0:
return snprintf(buf, PAGE_SIZE - 1, "%u_%u_%u\n",
get_unaligned_be32(&power->sensor_id),
power->function_id, power->apss_channel);
return sysfs_emit(buf, "%u_%u_%u\n",
get_unaligned_be32(&power->sensor_id),
power->function_id, power->apss_channel);
case 1:
val = occ_get_powr_avg(&power->accumulator,
&power->update_tag);
......@@ -512,7 +512,7 @@ static ssize_t occ_show_power_2(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_show_power_a0(struct device *dev,
......@@ -533,8 +533,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
switch (sattr->nr) {
case 0:
return snprintf(buf, PAGE_SIZE - 1, "%u_system\n",
get_unaligned_be32(&power->sensor_id));
return sysfs_emit(buf, "%u_system\n",
get_unaligned_be32(&power->sensor_id));
case 1:
val = occ_get_powr_avg(&power->system.accumulator,
&power->system.update_tag);
......@@ -547,8 +547,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
val = get_unaligned_be16(&power->system.value) * 1000000ULL;
break;
case 4:
return snprintf(buf, PAGE_SIZE - 1, "%u_proc\n",
get_unaligned_be32(&power->sensor_id));
return sysfs_emit(buf, "%u_proc\n",
get_unaligned_be32(&power->sensor_id));
case 5:
val = occ_get_powr_avg(&power->proc.accumulator,
&power->proc.update_tag);
......@@ -561,8 +561,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
val = get_unaligned_be16(&power->proc.value) * 1000000ULL;
break;
case 8:
return snprintf(buf, PAGE_SIZE - 1, "%u_vdd\n",
get_unaligned_be32(&power->sensor_id));
return sysfs_emit(buf, "%u_vdd\n",
get_unaligned_be32(&power->sensor_id));
case 9:
val = occ_get_powr_avg(&power->vdd.accumulator,
&power->vdd.update_tag);
......@@ -575,8 +575,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
val = get_unaligned_be16(&power->vdd.value) * 1000000ULL;
break;
case 12:
return snprintf(buf, PAGE_SIZE - 1, "%u_vdn\n",
get_unaligned_be32(&power->sensor_id));
return sysfs_emit(buf, "%u_vdn\n",
get_unaligned_be32(&power->sensor_id));
case 13:
val = occ_get_powr_avg(&power->vdn.accumulator,
&power->vdn.update_tag);
......@@ -592,7 +592,7 @@ static ssize_t occ_show_power_a0(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_show_caps_1_2(struct device *dev,
......@@ -613,7 +613,7 @@ static ssize_t occ_show_caps_1_2(struct device *dev,
switch (sattr->nr) {
case 0:
return snprintf(buf, PAGE_SIZE - 1, "system\n");
return sysfs_emit(buf, "system\n");
case 1:
val = get_unaligned_be16(&caps->cap) * 1000000ULL;
break;
......@@ -642,7 +642,7 @@ static ssize_t occ_show_caps_1_2(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_show_caps_3(struct device *dev,
......@@ -663,7 +663,7 @@ static ssize_t occ_show_caps_3(struct device *dev,
switch (sattr->nr) {
case 0:
return snprintf(buf, PAGE_SIZE - 1, "system\n");
return sysfs_emit(buf, "system\n");
case 1:
val = get_unaligned_be16(&caps->cap) * 1000000ULL;
break;
......@@ -689,7 +689,7 @@ static ssize_t occ_show_caps_3(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%llu\n", val);
return sysfs_emit(buf, "%llu\n", val);
}
static ssize_t occ_store_caps_user(struct device *dev,
......@@ -732,21 +732,22 @@ static ssize_t occ_show_extended(struct device *dev,
switch (sattr->nr) {
case 0:
if (extn->flags & EXTN_FLAG_SENSOR_ID)
rc = snprintf(buf, PAGE_SIZE - 1, "%u",
get_unaligned_be32(&extn->sensor_id));
else
rc = snprintf(buf, PAGE_SIZE - 1, "%02x%02x%02x%02x\n",
extn->name[0], extn->name[1],
extn->name[2], extn->name[3]);
if (extn->flags & EXTN_FLAG_SENSOR_ID) {
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]);
}
break;
case 1:
rc = snprintf(buf, PAGE_SIZE - 1, "%02x\n", extn->flags);
rc = sysfs_emit(buf, "%02x\n", extn->flags);
break;
case 2:
rc = snprintf(buf, PAGE_SIZE - 1, "%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, "%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]);
break;
default:
return -EINVAL;
......
......@@ -67,7 +67,7 @@ static ssize_t occ_sysfs_show(struct device *dev,
return -EINVAL;
}
return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
return sysfs_emit(buf, "%d\n", val);
}
static ssize_t occ_error_show(struct device *dev,
......@@ -77,7 +77,7 @@ static ssize_t occ_error_show(struct device *dev,
occ_update_response(occ);
return snprintf(buf, PAGE_SIZE - 1, "%d\n", occ->error);
return sysfs_emit(buf, "%d\n", occ->error);
}
static SENSOR_DEVICE_ATTR(occ_master, 0444, occ_sysfs_show, NULL, 0);
......
......@@ -56,6 +56,25 @@ config SENSORS_BEL_PFE
This driver can also be built as a module. If so, the module will
be called bel-pfe.
config SENSORS_BPA_RS600
tristate "BluTek BPA-RS600 Power Supplies"
help
If you say yes here you get hardware monitoring support for BluTek
BPA-RS600 Power Supplies.
This driver can also be built as a module. If so, the module will
be called bpa-rs600.
config SENSORS_FSP_3Y
tristate "FSP/3Y-Power power supplies"
help
If you say yes here you get hardware monitoring support for
FSP/3Y-Power hot-swap power supplies.
Supported models: YH-5151E, YM-2151E
This driver can also be built as a module. If so, the module will
be called fsp-3y.
config SENSORS_IBM_CFFPS
tristate "IBM Common Form Factor Power Supply"
depends on LEDS_CLASS
......@@ -84,6 +103,15 @@ config SENSORS_IR35221
This driver can also be built as a module. If so, the module will
be called ir35221.
config SENSORS_IR36021
tristate "Infineon IR36021"
help
If you say yes here you get hardware monitoring support for Infineon
IR36021.
This driver can also be built as a module. If so, the module will
be called ir36021.
config SENSORS_IR38064
tristate "Infineon IR38064"
help
......@@ -148,6 +176,15 @@ config SENSORS_LTC3815
This driver can also be built as a module. If so, the module will
be called ltc3815.
config SENSORS_MAX15301
tristate "Maxim MAX15301"
help
If you say yes here you get hardware monitoring support for Maxim
MAX15301, as well as for Flex BMR461.
This driver can also be built as a module. If so, the module will
be called max15301.
config SENSORS_MAX16064
tristate "Maxim MAX16064"
help
......@@ -247,6 +284,16 @@ config SENSORS_Q54SJ108A2
This driver can also be built as a module. If so, the module will
be called q54sj108a2.
config SENSORS_STPDDC60
tristate "ST STPDDC60"
help
If you say yes here you get hardware monitoring support for ST
STPDDC60 Universal Digital Multicell Controller, as well as for
Flex BMR481.
This driver can also be built as a module. If so, the module will
be called stpddc60.
config SENSORS_TPS40422
tristate "TI TPS40422"
help
......@@ -257,10 +304,10 @@ config SENSORS_TPS40422
be called tps40422.
config SENSORS_TPS53679
tristate "TI TPS53647, TPS53667, TPS53679, TPS53681, TPS53688"
tristate "TI TPS53647, TPS53667, TPS53676, TPS53679, TPS53681, TPS53688"
help
If you say yes here you get hardware monitoring support for TI
TPS53647, TPS53667, TPS53679, TPS53681, and TPS53688.
TPS53647, TPS53667, TPS53676, TPS53679, TPS53681, and TPS53688.
This driver can also be built as a module. If so, the module will
be called tps53679.
......
......@@ -8,15 +8,19 @@ obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
obj-$(CONFIG_SENSORS_BPA_RS600) += bpa-rs600.o
obj-$(CONFIG_SENSORS_FSP_3Y) += fsp-3y.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
obj-$(CONFIG_SENSORS_IR36021) += ir36021.o
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_LTC2978) += ltc2978.o
obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
obj-$(CONFIG_SENSORS_MAX15301) += max15301.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX16601) += max16601.o
obj-$(CONFIG_SENSORS_MAX20730) += max20730.o
......@@ -28,6 +32,7 @@ obj-$(CONFIG_SENSORS_MP2975) += mp2975.o
obj-$(CONFIG_SENSORS_PM6764TR) += pm6764tr.o
obj-$(CONFIG_SENSORS_PXE1610) += pxe1610.o
obj-$(CONFIG_SENSORS_Q54SJ108A2) += q54sj108a2.o
obj-$(CONFIG_SENSORS_STPDDC60) += stpddc60.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
......
......@@ -510,3 +510,4 @@ module_i2c_driver(adm1266_driver);
MODULE_AUTHOR("Alexandru Tachici <alexandru.tachici@analog.com>");
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1266");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(PMBUS);
......@@ -805,3 +805,4 @@ module_i2c_driver(adm1275_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -129,3 +129,4 @@ module_i2c_driver(pfe_pmbus_driver);
MODULE_AUTHOR("Tao Ren <rentao.bupt@gmail.com>");
MODULE_DESCRIPTION("PMBus driver for BEL PFE Family Power Supplies");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hardware monitoring driver for BluTek BPA-RS600 Power Supplies
*
* Copyright 2021 Allied Telesis Labs
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pmbus.h>
#include "pmbus.h"
#define BPARS600_MFR_VIN_MIN 0xa0
#define BPARS600_MFR_VIN_MAX 0xa1
#define BPARS600_MFR_IIN_MAX 0xa2
#define BPARS600_MFR_PIN_MAX 0xa3
#define BPARS600_MFR_VOUT_MIN 0xa4
#define BPARS600_MFR_VOUT_MAX 0xa5
#define BPARS600_MFR_IOUT_MAX 0xa6
#define BPARS600_MFR_POUT_MAX 0xa7
static int bpa_rs600_read_byte_data(struct i2c_client *client, int page, int reg)
{
int ret;
if (page > 0)
return -ENXIO;
switch (reg) {
case PMBUS_FAN_CONFIG_12:
/*
* Two fans are reported in PMBUS_FAN_CONFIG_12 but there is
* only one fan in the module. Mask out the FAN2 bits.
*/
ret = pmbus_read_byte_data(client, 0, PMBUS_FAN_CONFIG_12);
if (ret >= 0)
ret &= ~(PB_FAN_2_INSTALLED | PB_FAN_2_PULSE_MASK);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static int bpa_rs600_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{
int ret;
if (page > 0)
return -ENXIO;
switch (reg) {
case PMBUS_VIN_UV_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VIN_MIN);
break;
case PMBUS_VIN_OV_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VIN_MAX);
break;
case PMBUS_VOUT_UV_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VOUT_MIN);
break;
case PMBUS_VOUT_OV_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_VOUT_MAX);
break;
case PMBUS_IIN_OC_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_IIN_MAX);
break;
case PMBUS_IOUT_OC_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_IOUT_MAX);
break;
case PMBUS_PIN_OP_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_PIN_MAX);
break;
case PMBUS_POUT_OP_WARN_LIMIT:
ret = pmbus_read_word_data(client, 0, 0xff, BPARS600_MFR_POUT_MAX);
break;
case PMBUS_VIN_UV_FAULT_LIMIT:
case PMBUS_VIN_OV_FAULT_LIMIT:
case PMBUS_VOUT_UV_FAULT_LIMIT:
case PMBUS_VOUT_OV_FAULT_LIMIT:
/* These commands return data but it is invalid/un-documented */
ret = -ENXIO;
break;
default:
if (reg >= PMBUS_VIRT_BASE)
ret = -ENXIO;
else
ret = -ENODATA;
break;
}
return ret;
}
static struct pmbus_driver_info bpa_rs600_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
.format[PSC_TEMPERATURE] = linear,
.format[PSC_FAN] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT |
PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT |
PMBUS_HAVE_PIN | PMBUS_HAVE_POUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
PMBUS_HAVE_FAN12 |
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
PMBUS_HAVE_STATUS_FAN12,
.read_byte_data = bpa_rs600_read_byte_data,
.read_word_data = bpa_rs600_read_word_data,
};
static int bpa_rs600_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
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_MODEL, buf);
if (ret < 0) {
dev_err(dev, "Failed to read Manufacturer Model\n");
return ret;
}
if (strncmp(buf, "BPA-RS600", 8)) {
buf[ret] = '\0';
dev_err(dev, "Unsupported Manufacturer Model '%s'\n", buf);
return -ENODEV;
}
return pmbus_do_probe(client, &bpa_rs600_info);
}
static const struct i2c_device_id bpa_rs600_id[] = {
{ "bpars600", 0 },
{},
};
MODULE_DEVICE_TABLE(i2c, bpa_rs600_id);
static const struct of_device_id __maybe_unused bpa_rs600_of_match[] = {
{ .compatible = "blutek,bpa-rs600" },
{},
};
MODULE_DEVICE_TABLE(of, bpa_rs600_of_match);
static struct i2c_driver bpa_rs600_driver = {
.driver = {
.name = "bpa-rs600",
.of_match_table = of_match_ptr(bpa_rs600_of_match),
},
.probe_new = bpa_rs600_probe,
.id_table = bpa_rs600_id,
};
module_i2c_driver(bpa_rs600_driver);
MODULE_AUTHOR("Chris Packham");
MODULE_DESCRIPTION("PMBus driver for BluTek BPA-RS600");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hardware monitoring driver for FSP 3Y-Power PSUs
*
* Copyright (c) 2021 Václav Kubernát, CESNET
*
* This driver is mostly reverse engineered with the help of a tool called pmbus_peek written by
* David Brownell (and later adopted by Jan Kundrát). The device has some sort of a timing issue
* when switching pages, details are explained in the code. The driver support is limited. It
* exposes only the values, that have been tested to work correctly. Unsupported values either
* aren't supported by the devices or their encondings are unknown.
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"
#define YM2151_PAGE_12V_LOG 0x00
#define YM2151_PAGE_12V_REAL 0x00
#define YM2151_PAGE_5VSB_LOG 0x01
#define YM2151_PAGE_5VSB_REAL 0x20
#define YH5151E_PAGE_12V_LOG 0x00
#define YH5151E_PAGE_12V_REAL 0x00
#define YH5151E_PAGE_5V_LOG 0x01
#define YH5151E_PAGE_5V_REAL 0x10
#define YH5151E_PAGE_3V3_LOG 0x02
#define YH5151E_PAGE_3V3_REAL 0x11
enum chips {
ym2151e,
yh5151e
};
struct fsp3y_data {
struct pmbus_driver_info info;
int chip;
int page;
};
#define to_fsp3y_data(x) container_of(x, struct fsp3y_data, info)
static int page_log_to_page_real(int page_log, enum chips chip)
{
switch (chip) {
case ym2151e:
switch (page_log) {
case YM2151_PAGE_12V_LOG:
return YM2151_PAGE_12V_REAL;
case YM2151_PAGE_5VSB_LOG:
return YM2151_PAGE_5VSB_REAL;
}
return -EINVAL;
case yh5151e:
switch (page_log) {
case YH5151E_PAGE_12V_LOG:
return YH5151E_PAGE_12V_REAL;
case YH5151E_PAGE_5V_LOG:
return YH5151E_PAGE_5V_LOG;
case YH5151E_PAGE_3V3_LOG:
return YH5151E_PAGE_3V3_REAL;
}
return -EINVAL;
}
return -EINVAL;
}
static int set_page(struct i2c_client *client, int page_log)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct fsp3y_data *data = to_fsp3y_data(info);
int rv;
int page_real;
if (page_log < 0)
return 0;
page_real = page_log_to_page_real(page_log, data->chip);
if (page_real < 0)
return page_real;
if (data->page != page_real) {
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page_real);
if (rv < 0)
return rv;
data->page = page_real;
/*
* Testing showed that the device has a timing issue. After
* setting a page, it takes a while, before the device actually
* gives the correct values from the correct page. 20 ms was
* tested to be enough to not give wrong values (15 ms wasn't
* enough).
*/
usleep_range(20000, 30000);
}
return 0;
}
static int fsp3y_read_byte_data(struct i2c_client *client, int page, int reg)
{
int rv;
rv = set_page(client, page);
if (rv < 0)
return rv;
return i2c_smbus_read_byte_data(client, reg);
}
static int fsp3y_read_word_data(struct i2c_client *client, int page, int phase, int reg)
{
int rv;
/*
* This masks commands which weren't tested to work correctly. Some of
* the masked commands return 0xFFFF. These would probably get tagged as
* invalid by pmbus_core. Other ones do return values which might be
* useful (that is, they are not 0xFFFF), but their encoding is unknown,
* and so they are unsupported.
*/
switch (reg) {
case PMBUS_READ_FAN_SPEED_1:
case PMBUS_READ_IIN:
case PMBUS_READ_IOUT:
case PMBUS_READ_PIN:
case PMBUS_READ_POUT:
case PMBUS_READ_TEMPERATURE_1:
case PMBUS_READ_TEMPERATURE_2:
case PMBUS_READ_TEMPERATURE_3:
case PMBUS_READ_VIN:
case PMBUS_READ_VOUT:
case PMBUS_STATUS_WORD:
break;
default:
return -ENXIO;
}
rv = set_page(client, page);
if (rv < 0)
return rv;
return i2c_smbus_read_word_data(client, reg);
}
static struct pmbus_driver_info fsp3y_info[] = {
[ym2151e] = {
.pages = 2,
.func[YM2151_PAGE_12V_LOG] =
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
PMBUS_HAVE_PIN | PMBUS_HAVE_POUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
PMBUS_HAVE_VIN | PMBUS_HAVE_IIN |
PMBUS_HAVE_FAN12,
.func[YM2151_PAGE_5VSB_LOG] =
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT,
PMBUS_HAVE_IIN,
.read_word_data = fsp3y_read_word_data,
.read_byte_data = fsp3y_read_byte_data,
},
[yh5151e] = {
.pages = 3,
.func[YH5151E_PAGE_12V_LOG] =
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
PMBUS_HAVE_POUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3,
.func[YH5151E_PAGE_5V_LOG] =
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
PMBUS_HAVE_POUT,
.func[YH5151E_PAGE_3V3_LOG] =
PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
PMBUS_HAVE_POUT,
.read_word_data = fsp3y_read_word_data,
.read_byte_data = fsp3y_read_byte_data,
}
};
static int fsp3y_detect(struct i2c_client *client)
{
int rv;
u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
rv = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
if (rv < 0)
return rv;
buf[rv] = '\0';
if (rv == 8) {
if (!strcmp(buf, "YM-2151E"))
return ym2151e;
else if (!strcmp(buf, "YH-5151E"))
return yh5151e;
}
dev_err(&client->dev, "Unsupported model %.*s\n", rv, buf);
return -ENODEV;
}
static const struct i2c_device_id fsp3y_id[] = {
{"ym2151e", ym2151e},
{"yh5151e", yh5151e},
{ }
};
static int fsp3y_probe(struct i2c_client *client)
{
struct fsp3y_data *data;
const struct i2c_device_id *id;
int rv;
data = devm_kzalloc(&client->dev, sizeof(struct fsp3y_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->chip = fsp3y_detect(client);
if (data->chip < 0)
return data->chip;
id = i2c_match_id(fsp3y_id, client);
if (data->chip != id->driver_data)
dev_warn(&client->dev, "Device mismatch: Configured %s (%d), detected %d\n",
id->name, (int)id->driver_data, data->chip);
rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
if (rv < 0)
return rv;
data->page = rv;
data->info = fsp3y_info[data->chip];
return pmbus_do_probe(client, &data->info);
}
MODULE_DEVICE_TABLE(i2c, fsp3y_id);
static struct i2c_driver fsp3y_driver = {
.driver = {
.name = "fsp3y",
},
.probe_new = fsp3y_probe,
.id_table = fsp3y_id
};
module_i2c_driver(fsp3y_driver);
MODULE_AUTHOR("Václav Kubernát");
MODULE_DESCRIPTION("PMBus driver for FSP/3Y-Power power supplies");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -625,3 +625,4 @@ module_i2c_driver(ibm_cffps_driver);
MODULE_AUTHOR("Eddie James");
MODULE_DESCRIPTION("PMBus driver for IBM Common Form Factor power supplies");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -70,7 +70,7 @@ static ssize_t ipsps_string_show(struct device *dev,
p = memscan(data, '#', rc);
*p = '\0';
return snprintf(buf, PAGE_SIZE, "%s\n", data);
return sysfs_emit(buf, "%s\n", data);
}
static ssize_t ipsps_fw_version_show(struct device *dev,
......@@ -91,9 +91,9 @@ static ssize_t ipsps_fw_version_show(struct device *dev,
if (rc != 6)
return -EPROTO;
return snprintf(buf, PAGE_SIZE, "%u.%02u%u-%u.%02u\n",
data[1], data[2]/* < 100 */, data[3]/*< 10*/,
data[4], data[5]/* < 100 */);
return sysfs_emit(buf, "%u.%02u%u-%u.%02u\n",
data[1], data[2]/* < 100 */, data[3]/*< 10*/,
data[4], data[5]/* < 100 */);
}
static ssize_t ipsps_mode_show(struct device *dev,
......@@ -111,19 +111,19 @@ static ssize_t ipsps_mode_show(struct device *dev,
switch (rc) {
case MODE_ACTIVE:
return snprintf(buf, PAGE_SIZE, "[%s] %s %s\n",
MODE_ACTIVE_STRING,
MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
return sysfs_emit(buf, "[%s] %s %s\n",
MODE_ACTIVE_STRING,
MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
case MODE_STANDBY:
return snprintf(buf, PAGE_SIZE, "%s [%s] %s\n",
MODE_ACTIVE_STRING,
MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
return sysfs_emit(buf, "%s [%s] %s\n",
MODE_ACTIVE_STRING,
MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
case MODE_REDUNDANCY:
return snprintf(buf, PAGE_SIZE, "%s %s [%s]\n",
MODE_ACTIVE_STRING,
MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
return sysfs_emit(buf, "%s %s [%s]\n",
MODE_ACTIVE_STRING,
MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
default:
return snprintf(buf, PAGE_SIZE, "unspecified\n");
return sysfs_emit(buf, "unspecified\n");
}
}
......@@ -224,3 +224,4 @@ module_i2c_driver(ipsps_driver);
MODULE_AUTHOR("John Wang");
MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -145,3 +145,4 @@ module_i2c_driver(ir35221_driver);
MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
MODULE_DESCRIPTION("PMBus driver for IR35221");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
// SPDX-License-Identifier: GPL-2.0+
/*
* Hardware monitoring driver for Infineon IR36021
*
* Copyright (c) 2021 Allied Telesis
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"
static struct pmbus_driver_info ir36021_info = {
.pages = 1,
.format[PSC_VOLTAGE_IN] = linear,
.format[PSC_VOLTAGE_OUT] = linear,
.format[PSC_CURRENT_IN] = linear,
.format[PSC_CURRENT_OUT] = linear,
.format[PSC_POWER] = linear,
.format[PSC_TEMPERATURE] = linear,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT
| PMBUS_HAVE_IIN | PMBUS_HAVE_IOUT
| PMBUS_HAVE_PIN | PMBUS_HAVE_POUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
| PMBUS_HAVE_STATUS_TEMP,
};
static int ir36021_probe(struct i2c_client *client)
{
u8 buf[I2C_SMBUS_BLOCK_MAX];
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_i2c_block_data(client, PMBUS_MFR_MODEL, 2, buf);
if (ret < 0) {
dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
return ret;
}
if (ret != 2 || buf[0] != 0x01 || buf[1] != 0x2d) {
dev_err(&client->dev, "MFR_MODEL unrecognised\n");
return -ENODEV;
}
return pmbus_do_probe(client, &ir36021_info);
}
static const struct i2c_device_id ir36021_id[] = {
{ "ir36021", 0 },
{},
};
MODULE_DEVICE_TABLE(i2c, ir36021_id);
static const struct of_device_id __maybe_unused ir36021_of_id[] = {
{ .compatible = "infineon,ir36021" },
{},
};
MODULE_DEVICE_TABLE(of, ir36021_of_id);
static struct i2c_driver ir36021_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "ir36021",
.of_match_table = of_match_ptr(ir36021_of_id),
},
.probe_new = ir36021_probe,
.id_table = ir36021_id,
};
module_i2c_driver(ir36021_driver);
MODULE_AUTHOR("Chris Packham <chris.packham@alliedtelesis.co.nz>");
MODULE_DESCRIPTION("PMBus driver for Infineon IR36021");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -61,3 +61,4 @@ module_i2c_driver(ir38064_driver);
MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon IR38064");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -63,3 +63,4 @@ module_i2c_driver(irps5401_driver);
MODULE_AUTHOR("Robert Hancock");
MODULE_DESCRIPTION("PMBus driver for Infineon IRPS5401");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -332,3 +332,4 @@ module_i2c_driver(isl68137_driver);
MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");
MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -511,3 +511,4 @@ module_i2c_driver(lm25066_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for LM25066 and compatible chips");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -883,3 +883,4 @@ module_i2c_driver(ltc2978_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for LTC2978 and compatible chips");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -208,3 +208,4 @@ module_i2c_driver(ltc3815_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for LTC3815");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Hardware monitoring driver for Maxim MAX15301
*
* Copyright (c) 2021 Flextronics International Sweden AB
*
* Even though the specification does not specifically mention it,
* extensive empirical testing has revealed that auto-detection of
* limit-registers will fail in a random fashion unless the delay
* parameter is set to above about 80us. The default delay is set
* to 100us to include some safety margin.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/ktime.h>
#include <linux/delay.h>
#include <linux/pmbus.h>
#include "pmbus.h"
static const struct i2c_device_id max15301_id[] = {
{"bmr461", 0},
{"max15301", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, max15301_id);
struct max15301_data {
int id;
ktime_t access; /* Chip access time */
int delay; /* Delay between chip accesses in us */
struct pmbus_driver_info info;
};
#define to_max15301_data(x) container_of(x, struct max15301_data, info)
#define MAX15301_WAIT_TIME 100 /* us */
static ushort delay = MAX15301_WAIT_TIME;
module_param(delay, ushort, 0644);
MODULE_PARM_DESC(delay, "Delay between chip accesses in us");
static struct max15301_data max15301_data = {
.info = {
.pages = 1,
.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
| PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT,
}
};
/* This chip needs a delay between accesses */
static inline void max15301_wait(const struct max15301_data *data)
{
if (data->delay) {
s64 delta = ktime_us_delta(ktime_get(), data->access);
if (delta < data->delay)
udelay(data->delay - delta);
}
}
static int max15301_read_word_data(struct i2c_client *client, int page,
int phase, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct max15301_data *data = to_max15301_data(info);
int ret;
if (page > 0)
return -ENXIO;
if (reg >= PMBUS_VIRT_BASE)
return -ENXIO;
max15301_wait(data);
ret = pmbus_read_word_data(client, page, phase, reg);
data->access = ktime_get();
return ret;
}
static int max15301_read_byte_data(struct i2c_client *client, int page, int reg)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct max15301_data *data = to_max15301_data(info);
int ret;
if (page > 0)
return -ENXIO;
max15301_wait(data);
ret = pmbus_read_byte_data(client, page, reg);
data->access = ktime_get();
return ret;
}
static int max15301_write_word_data(struct i2c_client *client, int page, int reg,
u16 word)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct max15301_data *data = to_max15301_data(info);
int ret;
if (page > 0)
return -ENXIO;
if (reg >= PMBUS_VIRT_BASE)
return -ENXIO;
max15301_wait(data);
ret = pmbus_write_word_data(client, page, reg, word);
data->access = ktime_get();
return ret;
}
static int max15301_write_byte(struct i2c_client *client, int page, u8 value)
{
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct max15301_data *data = to_max15301_data(info);
int ret;
if (page > 0)
return -ENXIO;
max15301_wait(data);
ret = pmbus_write_byte(client, page, value);
data->access = ktime_get();
return ret;
}
static int max15301_probe(struct i2c_client *client)
{
int status;
u8 device_id[I2C_SMBUS_BLOCK_MAX + 1];
const struct i2c_device_id *mid;
struct pmbus_driver_info *info = &max15301_data.info;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA
| I2C_FUNC_SMBUS_BLOCK_DATA))
return -ENODEV;
status = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, device_id);
if (status < 0) {
dev_err(&client->dev, "Failed to read Device Id\n");
return status;
}
for (mid = max15301_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, device_id, strlen(mid->name)))
break;
}
if (!mid->name[0]) {
dev_err(&client->dev, "Unsupported device\n");
return -ENODEV;
}
max15301_data.delay = delay;
info->read_byte_data = max15301_read_byte_data;
info->read_word_data = max15301_read_word_data;
info->write_byte = max15301_write_byte;
info->write_word_data = max15301_write_word_data;
return pmbus_do_probe(client, info);
}
static struct i2c_driver max15301_driver = {
.driver = {
.name = "max15301",
},
.probe_new = max15301_probe,
.id_table = max15301_id,
};
module_i2c_driver(max15301_driver);
MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX15301");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -111,3 +111,4 @@ module_i2c_driver(max16064_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -359,3 +359,4 @@ module_i2c_driver(max16601_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX16601");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(PMBUS);
......@@ -785,3 +785,4 @@ module_i2c_driver(max20730_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX20710 / MAX20730 / MAX20734 / MAX20743");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -51,3 +51,4 @@ module_i2c_driver(max20751_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX20751");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -403,3 +403,4 @@ module_i2c_driver(max31785_driver);
MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -529,3 +529,4 @@ module_i2c_driver(max34440_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -191,3 +191,4 @@ module_i2c_driver(max8688_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -766,3 +766,4 @@ module_i2c_driver(mp2975_driver);
MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>");
MODULE_DESCRIPTION("PMBus driver for MPS MP2975 device");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -73,3 +73,4 @@ module_i2c_driver(pm6764tr_driver);
MODULE_AUTHOR("Charles Hsu");
MODULE_DESCRIPTION("PMBus driver for ST PM6764TR");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -246,3 +246,4 @@ module_i2c_driver(pmbus_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("Generic PMBus driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -475,6 +475,7 @@ extern const struct regulator_ops pmbus_regulator_ops;
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
void pmbus_set_update(struct i2c_client *client, u8 reg, bool update);
int pmbus_set_page(struct i2c_client *client, int page, int phase);
int pmbus_read_word_data(struct i2c_client *client, int page, int phase,
u8 reg);
......
This diff is collapsed.
......@@ -41,6 +41,15 @@ static int pxe1610_identify(struct i2c_client *client,
info->vrm_version[i] = vr13;
break;
default:
/*
* If prior pages are available limit operation
* to them
*/
if (i != 0) {
info->pages = i;
return 0;
}
return -ENODEV;
}
}
......@@ -139,3 +148,4 @@ module_i2c_driver(pxe1610_driver);
MODULE_AUTHOR("Vijay Khemka <vijaykhemka@fb.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon PXE1610, PXE1110 and PXM1310");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -420,3 +420,4 @@ module_i2c_driver(q54sj108a2_driver);
MODULE_AUTHOR("Xiao.Ma <xiao.mx.ma@deltaww.com>");
MODULE_DESCRIPTION("PMBus driver for Delta Q54SJ108A2 series modules");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
This diff is collapsed.
......@@ -51,3 +51,4 @@ module_i2c_driver(tps40422_driver);
MODULE_AUTHOR("Zhu Laiwen <richard.zhu@nsn.com>");
MODULE_DESCRIPTION("PMBus driver for TI TPS40422");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
This diff is collapsed.
......@@ -629,3 +629,4 @@ module_i2c_driver(ucd9000_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -209,3 +209,4 @@ module_i2c_driver(ucd9200_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -168,3 +168,4 @@ module_i2c_driver(xdpe122_driver);
MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
MODULE_DESCRIPTION("PMBus driver for Infineon XDPE122 family");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
......@@ -404,3 +404,4 @@ module_i2c_driver(zl6100_driver);
MODULE_AUTHOR("Guenter Roeck");
MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS(PMBUS);
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