hwmon updates for v5.4
New drivers and chip support - Add Inspur Power System power supply driver - Add Synaptics AS370 PVT sensor driver - Add support for SHTC3 to shtc1 driver - Add support for NCT6116 to nct6775 driver - Add support for AMD family 17h, model 70h CPUs to k10temp driver - Add support for PCT2075 to lm75 driver Removed drivers - Remove ads1015 driver (now supported in iio) Other changes - Convert drivers to use devm_i2c_new_dummy_device - Substantial structural improvements in lm75 driver Add support for writing sample interval for supported chips - Add support for PSU version 2 to ibm-cffps driver - Add support for power attribute to iio_hwmon bridge - Add support for additional fan, voltage and temperature attributes to nct7904 driver - Convert adt7475 driver to use hwmon_device_register_with_groups() - Convert k8temp driver to use hwmon_device_register_with_info() - Various other improvements and minor fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAl1+t+UACgkQyx8mb86f mYF3VA/9EMM6XOOTAyDgxmiE3UltgIWsKzVyWvU/uJpaxmTNG9aPF2cQXBslJyqH 6vqHYCh6ilPqNR7ExFf1Y85rvpA+8oOzn9jkWxVr4ywJYsiJfIC9Amxf55hfKk3V ej+MZ2WjWXmwyHfV0vw8LPB8LEnDBH5f9bwM4Q5vCwwrgByfV7z3F7zpGjv5kZmm XbqCkfPgge+lZOV3/hDJKh9ylajpxJDhdrP4hhsFDVq9Tys17WZVSRGyKAvJLPMm Ya4TcJzQlIlr7OaxRQjONvPn34Wh3L299Hg6L5rqIxS8+WnIkLPse4YAOXbpO4Nf J01mS1H7XNHHWf76fedbK6+jnhLhyl67QaGoTttiNyjQyW/PYEz7PkmRNz8xsLbd TbUjqd3izPCrx2OEJYBoQDhQS6K3HijtRo8mBO7Svh61Y749+v0DegnEzpz6J+l4 fIegne/LvNcyB0nQUtNQl+UpeqSlGeujAR2MVT6RYIiMlVCMueLfVk/zlGIO+tzO TPQoYyhosYdBG9uLgG796pQ4LPmx9L3aqd8oXqAWDx55+sOjLMWiNolJJgkH3Vfz 8eUV8CrdNgs7NQadv+Dp5NoS3pXle8SZAbSqy40GYDlX6BORPujIJgXOcazRIreG IhyMoxGt6WfgSob38Od+jRE6d9rkke36gFfDUJTUzJROOCRMLLw= =sRtz -----END PGP SIGNATURE----- Merge tag 'hwmon-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon updates from Guenter Roeck: "New drivers: - Inspur Power System power supply driver - Synaptics AS370 PVT sensor driver Chip support: - support SHTC3 in shtc1 driver - support NCT6116 in nct6775 driver - support AMD family 17h, model 70h CPUs in k10temp driver - support PCT2075 in lm75 driver Removed drivers: - ads1015 driver (now supported in iio) Other changes: - Convert drivers to use devm_i2c_new_dummy_device - Substantial structural improvements in lm75 driver adding support for writing sample interval for supported chips - Add support for PSU version 2 to ibm-cffps driver - Add support for power attribute to iio_hwmon bridge - Add support for additional fan, voltage and temperature attributes to nct7904 driver - Convert adt7475 driver to use hwmon_device_register_with_groups() - Convert k8temp driver to use hwmon_device_register_with_info() - Various other improvements and minor fixes" * tag 'hwmon-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (48 commits) hwmon: submitting-patches: Add note on comment style hwmon: submitting-patches: Point to with_info API hwmon: (nct7904) Fix incorrect SMI status register setting of LTD temperature and fan. hwmon: (shtc1) add support for the SHTC3 sensor hwmon: (shtc1) fix shtc1 and shtw1 id mask hwmon: (lm75) Aproximate sample times to data-sheet values hwmon: (w83793d) convert to use devm_i2c_new_dummy_device hwmon: (w83792d) convert to use devm_i2c_new_dummy_device hwmon: (w83791d) convert to use devm_i2c_new_dummy_device hwmon: (as370-hwmon) fix devm_platform_ioremap_resource.cocci warnings hwmon: (lm75) Add support for writing sampling period on PCT2075 hwmon: (lm75) Add support for writing conversion time for TMP112 hwmon: (lm75) Move updating the sample interval to its own function hwmon: (lm75) Support configuring the sample time for various chips hwmon: (nct7904) Fix incorrect temperature limitation register setting of LTD. hwmon: (as370-hwmon) Add DT bindings for Synaptics AS370 PVT hwmon: Add Synaptics AS370 PVT sensor driver pmbus: (ibm-cffps) Add support for version 2 of the PSU dt-bindings: hwmon: Document ibm,cffps2 compatible string hwmon: (iio_hwmon) Enable power exporting from IIO ...
This commit is contained in:
Коммит
6729fb666a
|
@ -0,0 +1,11 @@
|
|||
Bindings for Synaptics AS370 PVT sensors
|
||||
|
||||
Required properties:
|
||||
- compatible : "syna,as370-hwmon"
|
||||
- reg : address and length of the register set.
|
||||
|
||||
Example:
|
||||
hwmon@ea0810 {
|
||||
compatible = "syna,as370-hwmon";
|
||||
reg = <0xea0810 0xc>;
|
||||
};
|
|
@ -1,8 +1,10 @@
|
|||
Device-tree bindings for IBM Common Form Factor Power Supply Version 1
|
||||
----------------------------------------------------------------------
|
||||
Device-tree bindings for IBM Common Form Factor Power Supply Versions 1 and 2
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible = "ibm,cffps1";
|
||||
- compatible : Must be one of the following:
|
||||
"ibm,cffps1"
|
||||
"ibm,cffps2"
|
||||
- reg = < I2C bus address >; : Address of the power supply on the
|
||||
I2C bus.
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ Required properties:
|
|||
"maxim,max31725",
|
||||
"maxim,max31726",
|
||||
"maxim,mcp980x",
|
||||
"nxp,pct2075",
|
||||
"st,stds75",
|
||||
"st,stlm75",
|
||||
"microchip,tcn75",
|
||||
|
|
|
@ -104,6 +104,8 @@ properties:
|
|||
- infineon,slb9645tt
|
||||
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
|
||||
- infineon,tlv493d-a1b6
|
||||
# Inspur Power System power supply unit version 1
|
||||
- inspur,ipsps1
|
||||
# Intersil ISL29028 Ambient Light and Proximity Sensor
|
||||
- isil,isl29028
|
||||
# Intersil ISL29030 Ambient Light and Proximity Sensor
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
Kernel driver ads1015
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Texas Instruments ADS1015
|
||||
|
||||
Prefix: 'ads1015'
|
||||
|
||||
Datasheet: Publicly available at the Texas Instruments website:
|
||||
|
||||
http://focus.ti.com/lit/ds/symlink/ads1015.pdf
|
||||
|
||||
* Texas Instruments ADS1115
|
||||
|
||||
Prefix: 'ads1115'
|
||||
|
||||
Datasheet: Publicly available at the Texas Instruments website:
|
||||
|
||||
http://focus.ti.com/lit/ds/symlink/ads1115.pdf
|
||||
|
||||
Authors:
|
||||
Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Texas Instruments ADS1015/ADS1115.
|
||||
|
||||
This device is a 12/16-bit A-D converter with 4 inputs.
|
||||
|
||||
The inputs can be used single ended or in certain differential combinations.
|
||||
|
||||
The inputs can be made available by 8 sysfs input files in0_input - in7_input:
|
||||
|
||||
- in0: Voltage over AIN0 and AIN1.
|
||||
- in1: Voltage over AIN0 and AIN3.
|
||||
- in2: Voltage over AIN1 and AIN3.
|
||||
- in3: Voltage over AIN2 and AIN3.
|
||||
- in4: Voltage over AIN0 and GND.
|
||||
- in5: Voltage over AIN1 and GND.
|
||||
- in6: Voltage over AIN2 and GND.
|
||||
- in7: Voltage over AIN3 and GND.
|
||||
|
||||
Which inputs are available can be configured using platform data or devicetree.
|
||||
|
||||
By default all inputs are exported.
|
||||
|
||||
Platform Data
|
||||
-------------
|
||||
|
||||
In linux/platform_data/ads1015.h platform data is defined, channel_data contains
|
||||
configuration data for the used input combinations:
|
||||
|
||||
- pga is the programmable gain amplifier (values are full scale)
|
||||
|
||||
- 0: +/- 6.144 V
|
||||
- 1: +/- 4.096 V
|
||||
- 2: +/- 2.048 V
|
||||
- 3: +/- 1.024 V
|
||||
- 4: +/- 0.512 V
|
||||
- 5: +/- 0.256 V
|
||||
|
||||
- data_rate in samples per second
|
||||
|
||||
- 0: 128
|
||||
- 1: 250
|
||||
- 2: 490
|
||||
- 3: 920
|
||||
- 4: 1600
|
||||
- 5: 2400
|
||||
- 6: 3300
|
||||
|
||||
Example::
|
||||
|
||||
struct ads1015_platform_data data = {
|
||||
.channel_data = {
|
||||
[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
|
||||
[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
|
||||
}
|
||||
};
|
||||
|
||||
In this case only in2_input (FS +/- 4.096 V, 128 SPS) and in4_input
|
||||
(FS +/- 0.512 V, 2400 SPS) would be created.
|
||||
|
||||
Devicetree
|
||||
----------
|
||||
|
||||
Configuration is also possible via devicetree:
|
||||
Documentation/devicetree/bindings/hwmon/ads1015.txt
|
|
@ -30,7 +30,6 @@ Hardware Monitoring Kernel Drivers
|
|||
adm1031
|
||||
adm1275
|
||||
adm9240
|
||||
ads1015
|
||||
ads7828
|
||||
adt7410
|
||||
adt7411
|
||||
|
@ -130,6 +129,7 @@ Hardware Monitoring Kernel Drivers
|
|||
pcf8591
|
||||
pmbus
|
||||
powr1220
|
||||
pxe1610
|
||||
pwm-fan
|
||||
raspberrypi-hwmon
|
||||
sch5627
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
Kernel driver inspur-ipsps1
|
||||
=======================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Inspur Power System power supply unit
|
||||
|
||||
Author: John Wang <wangzqbj@inspur.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver supports Inspur Power System power supplies. This driver
|
||||
is a client to the core PMBus driver.
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
||||
This driver does not auto-detect devices. You will have to instantiate the
|
||||
devices explicitly. Please see Documentation/i2c/instantiating-devices for
|
||||
details.
|
||||
|
||||
Sysfs entries
|
||||
-------------
|
||||
|
||||
The following attributes are supported:
|
||||
|
||||
======================= ======================================================
|
||||
curr1_input Measured input current
|
||||
curr1_label "iin"
|
||||
curr1_max Maximum current
|
||||
curr1_max_alarm Current high alarm
|
||||
curr2_input Measured output current in mA.
|
||||
curr2_label "iout1"
|
||||
curr2_crit Critical maximum current
|
||||
curr2_crit_alarm Current critical high alarm
|
||||
curr2_max Maximum current
|
||||
curr2_max_alarm Current high alarm
|
||||
|
||||
fan1_alarm Fan 1 warning.
|
||||
fan1_fault Fan 1 fault.
|
||||
fan1_input Fan 1 speed in RPM.
|
||||
|
||||
in1_alarm Input voltage under-voltage alarm.
|
||||
in1_input Measured input voltage in mV.
|
||||
in1_label "vin"
|
||||
in2_input Measured output voltage in mV.
|
||||
in2_label "vout1"
|
||||
in2_lcrit Critical minimum output voltage
|
||||
in2_lcrit_alarm Output voltage critical low alarm
|
||||
in2_max Maximum output voltage
|
||||
in2_max_alarm Output voltage high alarm
|
||||
in2_min Minimum output voltage
|
||||
in2_min_alarm Output voltage low alarm
|
||||
|
||||
power1_alarm Input fault or alarm.
|
||||
power1_input Measured input power in uW.
|
||||
power1_label "pin"
|
||||
power1_max Input power limit
|
||||
power2_max_alarm Output power high alarm
|
||||
power2_max Output power limit
|
||||
power2_input Measured output power in uW.
|
||||
power2_label "pout"
|
||||
|
||||
temp[1-3]_input Measured temperature
|
||||
temp[1-2]_max Maximum temperature
|
||||
temp[1-3]_max_alarm Temperature high alarm
|
||||
|
||||
vendor Manufacturer name
|
||||
model Product model
|
||||
part_number Product part number
|
||||
serial_number Product serial number
|
||||
fw_version Firmware version
|
||||
hw_version Hardware version
|
||||
mode Work mode. Can be set to active or
|
||||
standby, when set to standby, PSU will
|
||||
automatically switch between standby
|
||||
and redundancy mode.
|
||||
======================= ======================================================
|
|
@ -119,9 +119,9 @@ Supported chips:
|
|||
|
||||
http://www.ti.com/product/tmp275
|
||||
|
||||
* NXP LM75B
|
||||
* NXP LM75B, PCT2075
|
||||
|
||||
Prefix: 'lm75b'
|
||||
Prefix: 'lm75b', 'pct2075'
|
||||
|
||||
Addresses scanned: none
|
||||
|
||||
|
@ -129,6 +129,8 @@ Supported chips:
|
|||
|
||||
http://www.nxp.com/documents/data_sheet/LM75B.pdf
|
||||
|
||||
http://www.nxp.com/docs/en/data-sheet/PCT2075.pdf
|
||||
|
||||
Author: Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
Description
|
||||
|
|
|
@ -2,19 +2,29 @@ Kernel driver pxe1610
|
|||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Infineon PXE1610
|
||||
|
||||
Prefix: 'pxe1610'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: Datasheet is not publicly available.
|
||||
|
||||
* Infineon PXE1110
|
||||
|
||||
Prefix: 'pxe1110'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: Datasheet is not publicly available.
|
||||
|
||||
* Infineon PXM1310
|
||||
|
||||
Prefix: 'pxm1310'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Datasheet: Datasheet is not publicly available.
|
||||
|
||||
Author: Vijay Khemka <vijaykhemka@fb.com>
|
||||
|
@ -25,14 +35,19 @@ Description
|
|||
|
||||
PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
|
||||
and compliant to
|
||||
-- Intel VR13 DC-DC converter specifications.
|
||||
-- Intel SVID protocol.
|
||||
|
||||
- Intel VR13 DC-DC converter specifications.
|
||||
- Intel SVID protocol.
|
||||
|
||||
Used for Vcore power regulation for Intel VR13 based microprocessors
|
||||
-- Servers, Workstations, and High-end desktops
|
||||
|
||||
- Servers, Workstations, and High-end desktops
|
||||
|
||||
PXM1310 is a Multi-rail Controller and it is compliant to
|
||||
-- Intel VR13 DC-DC converter specifications.
|
||||
-- Intel SVID protocol.
|
||||
|
||||
- Intel VR13 DC-DC converter specifications.
|
||||
- Intel SVID protocol.
|
||||
|
||||
Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
|
||||
IMVP8 based systems
|
||||
|
||||
|
@ -44,10 +59,10 @@ This driver does not probe for PMBus devices. You will have
|
|||
to instantiate devices explicitly.
|
||||
|
||||
Example: the following commands will load the driver for an PXE1610
|
||||
at address 0x70 on I2C bus #4:
|
||||
at address 0x70 on I2C bus #4::
|
||||
|
||||
# modprobe pxe1610
|
||||
# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
|
||||
# modprobe pxe1610
|
||||
# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
|
||||
|
||||
It can also be instantiated by declaring in device tree
|
||||
|
||||
|
@ -55,6 +70,7 @@ It can also be instantiated by declaring in device tree
|
|||
Sysfs attributes
|
||||
----------------
|
||||
|
||||
====================== ====================================
|
||||
curr1_label "iin"
|
||||
curr1_input Measured input current
|
||||
curr1_alarm Current high alarm
|
||||
|
@ -88,3 +104,4 @@ temp[1-3]_crit Critical high temperature
|
|||
temp[1-3]_crit_alarm Chip temperature critical high alarm
|
||||
temp[1-3]_max Maximum temperature
|
||||
temp[1-3]_max_alarm Chip temperature high alarm
|
||||
====================== ====================================
|
|
@ -19,7 +19,17 @@ Supported chips:
|
|||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Not publicly available
|
||||
Datasheet: http://www.sensirion.com/file/datasheet_shtw1
|
||||
|
||||
|
||||
|
||||
* Sensirion SHTC3
|
||||
|
||||
Prefix: 'shtc3'
|
||||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: http://www.sensirion.com/file/datasheet_shtc3
|
||||
|
||||
|
||||
|
||||
|
@ -30,10 +40,9 @@ Author:
|
|||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Sensirion SHTC1 chip, a humidity and
|
||||
temperature sensor. Temperature is measured in degrees celsius, relative
|
||||
humidity is expressed as a percentage. Driver can be used as well for SHTW1
|
||||
chip, which has the same electrical interface.
|
||||
This driver implements support for the Sensirion SHTC1, SHTW1, and SHTC3
|
||||
chips, a humidity and temperature sensor. Temperature is measured in degrees
|
||||
celsius, relative humidity is expressed as a percentage.
|
||||
|
||||
The device communicates with the I2C protocol. All sensors are set to I2C
|
||||
address 0x70. See Documentation/i2c/instantiating-devices for methods to
|
||||
|
|
|
@ -20,6 +20,10 @@ increase the chances of your change being accepted.
|
|||
errors, no warnings, and few if any check messages. If there are any
|
||||
messages, please be prepared to explain.
|
||||
|
||||
* Please use the standard multi-line comment style. Do not mix C and C++
|
||||
style comments in a single driver (with the exception of the SPDX license
|
||||
identifier).
|
||||
|
||||
* If your patch generates checkpatch errors, warnings, or check messages,
|
||||
please refrain from explanations such as "I prefer that coding style".
|
||||
Keep in mind that each unnecessary message helps hiding a real problem,
|
||||
|
@ -120,8 +124,8 @@ increase the chances of your change being accepted.
|
|||
completely initialize your chip and your driver first, then register with
|
||||
the hwmon subsystem.
|
||||
|
||||
* Use devm_hwmon_device_register_with_groups() or, if your driver needs a remove
|
||||
function, hwmon_device_register_with_groups() to register your driver with the
|
||||
* Use devm_hwmon_device_register_with_info() or, if your driver needs a remove
|
||||
function, hwmon_device_register_with_info() to register your driver with the
|
||||
hwmon subsystem. Try using devm_add_action() instead of a remove function if
|
||||
possible. Do not use hwmon_device_register().
|
||||
|
||||
|
|
|
@ -517,14 +517,6 @@ W: http://ez.analog.com/community/linux-device-drivers
|
|||
S: Supported
|
||||
F: drivers/video/backlight/adp8860_bl.c
|
||||
|
||||
ADS1015 HARDWARE MONITOR DRIVER
|
||||
M: Dirk Eibach <eibach@gdsys.de>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/ads1015.rst
|
||||
F: drivers/hwmon/ads1015.c
|
||||
F: include/linux/platform_data/ads1015.h
|
||||
|
||||
ADT746X FAN DRIVER
|
||||
M: Colin Leroy <colin@colino.net>
|
||||
S: Maintained
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464
|
||||
#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F4 0x15ec
|
||||
#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494
|
||||
#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F4 0x1444
|
||||
|
||||
/* Protect the PCI config register pairs used for SMN and DF indirect access. */
|
||||
static DEFINE_MUTEX(smn_mutex);
|
||||
|
@ -50,6 +51,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
|
||||
{}
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
|
||||
|
@ -63,6 +65,7 @@ static const struct pci_device_id amd_nb_link_ids[] = {
|
|||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_DF_F4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -246,6 +246,16 @@ config SENSORS_ADT7475
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called adt7475.
|
||||
|
||||
config SENSORS_AS370
|
||||
tristate "Synaptics AS370 SoC hardware monitoring driver"
|
||||
help
|
||||
If you say yes here you get support for the PVT sensors of
|
||||
the Synaptics AS370 SoC
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called as370-hwmon.
|
||||
|
||||
|
||||
config SENSORS_ASC7621
|
||||
tristate "Andigilog aSC7621"
|
||||
depends on I2C
|
||||
|
@ -1382,8 +1392,8 @@ config SENSORS_SHTC1
|
|||
tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Sensiron SHTC1 and SHTW1
|
||||
humidity and temperature sensors.
|
||||
If you say yes here you get support for the Sensiron SHTC1, SHTW1,
|
||||
and SHTC3 humidity and temperature sensors.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called shtc1.
|
||||
|
@ -1570,16 +1580,6 @@ config SENSORS_ADC128D818
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called adc128d818.
|
||||
|
||||
config SENSORS_ADS1015
|
||||
tristate "Texas Instruments ADS1015"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments
|
||||
ADS1015/ADS1115 12/16-bit 4-input ADC device.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ads1015.
|
||||
|
||||
config SENSORS_ADS7828
|
||||
tristate "Texas Instruments ADS7828 and compatibles"
|
||||
depends on I2C
|
||||
|
@ -1834,17 +1834,12 @@ config SENSORS_W83795
|
|||
will be called w83795.
|
||||
|
||||
config SENSORS_W83795_FANCTRL
|
||||
bool "Include automatic fan control support (DANGEROUS)"
|
||||
bool "Include automatic fan control support"
|
||||
depends on SENSORS_W83795
|
||||
help
|
||||
If you say yes here, support for automatic fan speed control
|
||||
will be included in the driver.
|
||||
|
||||
This part of the code wasn't carefully reviewed and tested yet,
|
||||
so enabling this option is strongly discouraged on production
|
||||
servers. Only developers and testers should enable it for the
|
||||
time being.
|
||||
|
||||
Please also note that this option will create sysfs attribute
|
||||
files which may change in the future, so you shouldn't rely
|
||||
on them being stable.
|
||||
|
|
|
@ -35,7 +35,6 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
|
|||
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
|
||||
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
|
||||
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
|
||||
obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o
|
||||
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
|
||||
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
|
||||
obj-$(CONFIG_SENSORS_ADT7X10) += adt7x10.o
|
||||
|
@ -48,6 +47,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
|
|||
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
|
||||
obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_AS370) += as370-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
|
||||
obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o
|
||||
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
|
||||
|
|
|
@ -681,8 +681,8 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
|
|||
|
||||
if (resource->caps.flags & POWER_METER_CAN_CAP) {
|
||||
if (!can_cap_in_hardware()) {
|
||||
dev_err(&resource->acpi_dev->dev,
|
||||
"Ignoring unsafe software power cap!\n");
|
||||
dev_warn(&resource->acpi_dev->dev,
|
||||
"Ignoring unsafe software power cap!\n");
|
||||
goto skip_unsafe_cap;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,324 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC
|
||||
* (C) Copyright 2010
|
||||
* Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
|
||||
*
|
||||
* Based on the ads7828 driver by Steve Hardy.
|
||||
*
|
||||
* Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/platform_data/ads1015.h>
|
||||
|
||||
/* ADS1015 registers */
|
||||
enum {
|
||||
ADS1015_CONVERSION = 0,
|
||||
ADS1015_CONFIG = 1,
|
||||
};
|
||||
|
||||
/* PGA fullscale voltages in mV */
|
||||
static const unsigned int fullscale_table[8] = {
|
||||
6144, 4096, 2048, 1024, 512, 256, 256, 256 };
|
||||
|
||||
/* Data rates in samples per second */
|
||||
static const unsigned int data_rate_table_1015[8] = {
|
||||
128, 250, 490, 920, 1600, 2400, 3300, 3300
|
||||
};
|
||||
|
||||
static const unsigned int data_rate_table_1115[8] = {
|
||||
8, 16, 32, 64, 128, 250, 475, 860
|
||||
};
|
||||
|
||||
#define ADS1015_DEFAULT_CHANNELS 0xff
|
||||
#define ADS1015_DEFAULT_PGA 2
|
||||
#define ADS1015_DEFAULT_DATA_RATE 4
|
||||
|
||||
enum ads1015_chips {
|
||||
ads1015,
|
||||
ads1115,
|
||||
};
|
||||
|
||||
struct ads1015_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock; /* mutex protect updates */
|
||||
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
|
||||
enum ads1015_chips id;
|
||||
};
|
||||
|
||||
static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
|
||||
{
|
||||
u16 config;
|
||||
struct ads1015_data *data = i2c_get_clientdata(client);
|
||||
unsigned int pga = data->channel_data[channel].pga;
|
||||
unsigned int data_rate = data->channel_data[channel].data_rate;
|
||||
unsigned int conversion_time_ms;
|
||||
const unsigned int * const rate_table = data->id == ads1115 ?
|
||||
data_rate_table_1115 : data_rate_table_1015;
|
||||
int res;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
/* get channel parameters */
|
||||
res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
|
||||
if (res < 0)
|
||||
goto err_unlock;
|
||||
config = res;
|
||||
conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]);
|
||||
|
||||
/* setup and start single conversion */
|
||||
config &= 0x001f;
|
||||
config |= (1 << 15) | (1 << 8);
|
||||
config |= (channel & 0x0007) << 12;
|
||||
config |= (pga & 0x0007) << 9;
|
||||
config |= (data_rate & 0x0007) << 5;
|
||||
|
||||
res = i2c_smbus_write_word_swapped(client, ADS1015_CONFIG, config);
|
||||
if (res < 0)
|
||||
goto err_unlock;
|
||||
|
||||
/* wait until conversion finished */
|
||||
msleep(conversion_time_ms);
|
||||
res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG);
|
||||
if (res < 0)
|
||||
goto err_unlock;
|
||||
config = res;
|
||||
if (!(config & (1 << 15))) {
|
||||
/* conversion not finished in time */
|
||||
res = -EIO;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION);
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
|
||||
s16 reg)
|
||||
{
|
||||
struct ads1015_data *data = i2c_get_clientdata(client);
|
||||
unsigned int pga = data->channel_data[channel].pga;
|
||||
int fullscale = fullscale_table[pga];
|
||||
const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0;
|
||||
|
||||
return DIV_ROUND_CLOSEST(reg * fullscale, mask);
|
||||
}
|
||||
|
||||
/* sysfs callback function */
|
||||
static ssize_t in_show(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int res;
|
||||
int index = attr->index;
|
||||
|
||||
res = ads1015_read_adc(client, index);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return sprintf(buf, "%d\n", ads1015_reg_to_mv(client, index, res));
|
||||
}
|
||||
|
||||
static const struct sensor_device_attribute ads1015_in[] = {
|
||||
SENSOR_ATTR_RO(in0_input, in, 0),
|
||||
SENSOR_ATTR_RO(in1_input, in, 1),
|
||||
SENSOR_ATTR_RO(in2_input, in, 2),
|
||||
SENSOR_ATTR_RO(in3_input, in, 3),
|
||||
SENSOR_ATTR_RO(in4_input, in, 4),
|
||||
SENSOR_ATTR_RO(in5_input, in, 5),
|
||||
SENSOR_ATTR_RO(in6_input, in, 6),
|
||||
SENSOR_ATTR_RO(in7_input, in, 7),
|
||||
};
|
||||
|
||||
/*
|
||||
* Driver interface
|
||||
*/
|
||||
|
||||
static int ads1015_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ads1015_data *data = i2c_get_clientdata(client);
|
||||
int k;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
for (k = 0; k < ADS1015_CHANNELS; ++k)
|
||||
device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int ads1015_get_channels_config_of(struct i2c_client *client)
|
||||
{
|
||||
struct ads1015_data *data = i2c_get_clientdata(client);
|
||||
struct device_node *node;
|
||||
|
||||
if (!client->dev.of_node
|
||||
|| !of_get_next_child(client->dev.of_node, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
for_each_child_of_node(client->dev.of_node, node) {
|
||||
u32 pval;
|
||||
unsigned int channel;
|
||||
unsigned int pga = ADS1015_DEFAULT_PGA;
|
||||
unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
|
||||
|
||||
if (of_property_read_u32(node, "reg", &pval)) {
|
||||
dev_err(&client->dev, "invalid reg on %pOF\n", node);
|
||||
continue;
|
||||
}
|
||||
|
||||
channel = pval;
|
||||
if (channel >= ADS1015_CHANNELS) {
|
||||
dev_err(&client->dev,
|
||||
"invalid channel index %d on %pOF\n",
|
||||
channel, node);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(node, "ti,gain", &pval)) {
|
||||
pga = pval;
|
||||
if (pga > 6) {
|
||||
dev_err(&client->dev, "invalid gain on %pOF\n",
|
||||
node);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(node, "ti,datarate", &pval)) {
|
||||
data_rate = pval;
|
||||
if (data_rate > 7) {
|
||||
dev_err(&client->dev,
|
||||
"invalid data_rate on %pOF\n", node);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
data->channel_data[channel].enabled = true;
|
||||
data->channel_data[channel].pga = pga;
|
||||
data->channel_data[channel].data_rate = data_rate;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ads1015_get_channels_config(struct i2c_client *client)
|
||||
{
|
||||
unsigned int k;
|
||||
struct ads1015_data *data = i2c_get_clientdata(client);
|
||||
struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
|
||||
/* prefer platform data */
|
||||
if (pdata) {
|
||||
memcpy(data->channel_data, pdata->channel_data,
|
||||
sizeof(data->channel_data));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (!ads1015_get_channels_config_of(client))
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* fallback on default configuration */
|
||||
for (k = 0; k < ADS1015_CHANNELS; ++k) {
|
||||
data->channel_data[k].enabled = true;
|
||||
data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
|
||||
data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
|
||||
}
|
||||
}
|
||||
|
||||
static int ads1015_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ads1015_data *data;
|
||||
int err;
|
||||
unsigned int k;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (client->dev.of_node)
|
||||
data->id = (enum ads1015_chips)
|
||||
of_device_get_match_data(&client->dev);
|
||||
else
|
||||
data->id = id->driver_data;
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* build sysfs attribute group */
|
||||
ads1015_get_channels_config(client);
|
||||
for (k = 0; k < ADS1015_CHANNELS; ++k) {
|
||||
if (!data->channel_data[k].enabled)
|
||||
continue;
|
||||
err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
for (k = 0; k < ADS1015_CHANNELS; ++k)
|
||||
device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ads1015_id[] = {
|
||||
{ "ads1015", ads1015},
|
||||
{ "ads1115", ads1115},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ads1015_id);
|
||||
|
||||
static const struct of_device_id __maybe_unused ads1015_of_match[] = {
|
||||
{
|
||||
.compatible = "ti,ads1015",
|
||||
.data = (void *)ads1015
|
||||
},
|
||||
{
|
||||
.compatible = "ti,ads1115",
|
||||
.data = (void *)ads1115
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads1015_of_match);
|
||||
|
||||
static struct i2c_driver ads1015_driver = {
|
||||
.driver = {
|
||||
.name = "ads1015",
|
||||
.of_match_table = of_match_ptr(ads1015_of_match),
|
||||
},
|
||||
.probe = ads1015_probe,
|
||||
.remove = ads1015_remove,
|
||||
.id_table = ads1015_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ads1015_driver);
|
||||
|
||||
MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>");
|
||||
MODULE_DESCRIPTION("ADS1015 driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -187,7 +187,7 @@ static const struct of_device_id __maybe_unused adt7475_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, adt7475_of_match);
|
||||
|
||||
struct adt7475_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
|
||||
unsigned long measure_updated;
|
||||
|
@ -212,6 +212,7 @@ struct adt7475_data {
|
|||
|
||||
u8 vid;
|
||||
u8 vrm;
|
||||
const struct attribute_group *groups[9];
|
||||
};
|
||||
|
||||
static struct i2c_driver adt7475_driver;
|
||||
|
@ -346,8 +347,8 @@ static ssize_t voltage_store(struct device *dev,
|
|||
{
|
||||
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned char reg;
|
||||
long val;
|
||||
|
||||
|
@ -440,8 +441,8 @@ static ssize_t temp_store(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned char reg = 0;
|
||||
u8 out;
|
||||
int temp;
|
||||
|
@ -542,8 +543,7 @@ static ssize_t temp_st_show(struct device *dev, struct device_attribute *attr,
|
|||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
|
||||
switch (sattr->index) {
|
||||
|
@ -570,8 +570,8 @@ static ssize_t temp_st_store(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned char reg;
|
||||
int shift, idx;
|
||||
ulong val;
|
||||
|
@ -647,8 +647,8 @@ static ssize_t point2_show(struct device *dev, struct device_attribute *attr,
|
|||
static ssize_t point2_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
int temp;
|
||||
long val;
|
||||
|
@ -710,8 +710,8 @@ static ssize_t tach_store(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned long val;
|
||||
|
||||
if (kstrtoul(buf, 10, &val))
|
||||
|
@ -769,8 +769,8 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
unsigned char reg = 0;
|
||||
long val;
|
||||
|
||||
|
@ -818,8 +818,8 @@ static ssize_t stall_disable_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
|
||||
u8 mask = BIT(5 + sattr->index);
|
||||
|
||||
return sprintf(buf, "%d\n", !!(data->enh_acoustics[0] & mask));
|
||||
|
@ -830,8 +830,8 @@ static ssize_t stall_disable_store(struct device *dev,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
u8 mask = BIT(5 + sattr->index);
|
||||
|
||||
|
@ -914,8 +914,8 @@ static ssize_t pwmchan_store(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int r;
|
||||
long val;
|
||||
|
||||
|
@ -938,8 +938,8 @@ static ssize_t pwmctrl_store(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int r;
|
||||
long val;
|
||||
|
||||
|
@ -982,8 +982,8 @@ static ssize_t pwmfreq_store(struct device *dev,
|
|||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int out;
|
||||
long val;
|
||||
|
||||
|
@ -1022,8 +1022,8 @@ static ssize_t pwm_use_point2_pwm_at_crit_store(struct device *dev,
|
|||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long val;
|
||||
|
||||
if (kstrtol(buf, 10, &val))
|
||||
|
@ -1342,26 +1342,6 @@ static int adt7475_detect(struct i2c_client *client,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void adt7475_remove_files(struct i2c_client *client,
|
||||
struct adt7475_data *data)
|
||||
{
|
||||
sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group);
|
||||
if (data->has_fan4)
|
||||
sysfs_remove_group(&client->dev.kobj, &fan4_attr_group);
|
||||
if (data->has_pwm2)
|
||||
sysfs_remove_group(&client->dev.kobj, &pwm2_attr_group);
|
||||
if (data->has_voltage & (1 << 0))
|
||||
sysfs_remove_group(&client->dev.kobj, &in0_attr_group);
|
||||
if (data->has_voltage & (1 << 3))
|
||||
sysfs_remove_group(&client->dev.kobj, &in3_attr_group);
|
||||
if (data->has_voltage & (1 << 4))
|
||||
sysfs_remove_group(&client->dev.kobj, &in4_attr_group);
|
||||
if (data->has_voltage & (1 << 5))
|
||||
sysfs_remove_group(&client->dev.kobj, &in5_attr_group);
|
||||
if (data->has_vid)
|
||||
sysfs_remove_group(&client->dev.kobj, &vid_attr_group);
|
||||
}
|
||||
|
||||
static int adt7475_update_limits(struct i2c_client *client)
|
||||
{
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
|
@ -1489,7 +1469,8 @@ static int adt7475_probe(struct i2c_client *client,
|
|||
};
|
||||
|
||||
struct adt7475_data *data;
|
||||
int i, ret = 0, revision;
|
||||
struct device *hwmon_dev;
|
||||
int i, ret = 0, revision, group_num = 0;
|
||||
u8 config2, config3;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
|
@ -1497,6 +1478,7 @@ static int adt7475_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
mutex_init(&data->lock);
|
||||
data->client = client;
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
if (client->dev.of_node)
|
||||
|
@ -1590,52 +1572,40 @@ static int adt7475_probe(struct i2c_client *client,
|
|||
break;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->groups[group_num++] = &adt7475_attr_group;
|
||||
|
||||
/* Features that can be disabled individually */
|
||||
if (data->has_fan4) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, &fan4_attr_group);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
data->groups[group_num++] = &fan4_attr_group;
|
||||
}
|
||||
if (data->has_pwm2) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, &pwm2_attr_group);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
data->groups[group_num++] = &pwm2_attr_group;
|
||||
}
|
||||
if (data->has_voltage & (1 << 0)) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, &in0_attr_group);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
data->groups[group_num++] = &in0_attr_group;
|
||||
}
|
||||
if (data->has_voltage & (1 << 3)) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, &in3_attr_group);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
data->groups[group_num++] = &in3_attr_group;
|
||||
}
|
||||
if (data->has_voltage & (1 << 4)) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, &in4_attr_group);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
data->groups[group_num++] = &in4_attr_group;
|
||||
}
|
||||
if (data->has_voltage & (1 << 5)) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, &in5_attr_group);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
data->groups[group_num++] = &in5_attr_group;
|
||||
}
|
||||
if (data->has_vid) {
|
||||
data->vrm = vid_which_vrm();
|
||||
ret = sysfs_create_group(&client->dev.kobj, &vid_attr_group);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
data->groups[group_num] = &vid_attr_group;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
ret = PTR_ERR(data->hwmon_dev);
|
||||
goto eremove;
|
||||
/* register device with all the acquired attributes */
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
|
||||
client->name, data,
|
||||
data->groups);
|
||||
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
ret = PTR_ERR(hwmon_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "%s device, revision %d\n",
|
||||
|
@ -1657,21 +1627,7 @@ static int adt7475_probe(struct i2c_client *client,
|
|||
/* Limits and settings, should never change update more than once */
|
||||
ret = adt7475_update_limits(client);
|
||||
if (ret)
|
||||
goto eremove;
|
||||
|
||||
return 0;
|
||||
|
||||
eremove:
|
||||
adt7475_remove_files(client, data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adt7475_remove(struct i2c_client *client)
|
||||
{
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
adt7475_remove_files(client, data);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1683,7 +1639,6 @@ static struct i2c_driver adt7475_driver = {
|
|||
.of_match_table = of_match_ptr(adt7475_of_match),
|
||||
},
|
||||
.probe = adt7475_probe,
|
||||
.remove = adt7475_remove,
|
||||
.id_table = adt7475_id,
|
||||
.detect = adt7475_detect,
|
||||
.address_list = normal_i2c,
|
||||
|
@ -1757,8 +1712,8 @@ static void adt7475_read_pwm(struct i2c_client *client, int index)
|
|||
|
||||
static int adt7475_update_measure(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
u16 ext;
|
||||
int i;
|
||||
int ret;
|
||||
|
@ -1854,8 +1809,7 @@ static int adt7475_update_measure(struct device *dev)
|
|||
|
||||
static struct adt7475_data *adt7475_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct adt7475_data *data = i2c_get_clientdata(client);
|
||||
struct adt7475_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Synaptics AS370 SoC Hardware Monitoring Driver
|
||||
*
|
||||
* Copyright (C) 2018 Synaptics Incorporated
|
||||
* Author: Jisheng Zhang <jszhang@kernel.org>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define CTRL 0x0
|
||||
#define PD BIT(0)
|
||||
#define EN BIT(1)
|
||||
#define T_SEL BIT(2)
|
||||
#define V_SEL BIT(3)
|
||||
#define NMOS_SEL BIT(8)
|
||||
#define PMOS_SEL BIT(9)
|
||||
#define STS 0x4
|
||||
#define BN_MASK GENMASK(11, 0)
|
||||
#define EOC BIT(12)
|
||||
|
||||
struct as370_hwmon {
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static void init_pvt(struct as370_hwmon *hwmon)
|
||||
{
|
||||
u32 val;
|
||||
void __iomem *addr = hwmon->base + CTRL;
|
||||
|
||||
val = PD;
|
||||
writel_relaxed(val, addr);
|
||||
val |= T_SEL;
|
||||
writel_relaxed(val, addr);
|
||||
val |= EN;
|
||||
writel_relaxed(val, addr);
|
||||
val &= ~PD;
|
||||
writel_relaxed(val, addr);
|
||||
}
|
||||
|
||||
static int as370_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *temp)
|
||||
{
|
||||
int val;
|
||||
struct as370_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
val = readl_relaxed(hwmon->base + STS) & BN_MASK;
|
||||
*temp = DIV_ROUND_CLOSEST(val * 251802, 4096) - 85525;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t
|
||||
as370_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
if (type != hwmon_temp)
|
||||
return 0;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const u32 as370_hwmon_temp_config[] = {
|
||||
HWMON_T_INPUT,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info as370_hwmon_temp = {
|
||||
.type = hwmon_temp,
|
||||
.config = as370_hwmon_temp_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *as370_hwmon_info[] = {
|
||||
&as370_hwmon_temp,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops as370_hwmon_ops = {
|
||||
.is_visible = as370_hwmon_is_visible,
|
||||
.read = as370_hwmon_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info as370_chip_info = {
|
||||
.ops = &as370_hwmon_ops,
|
||||
.info = as370_hwmon_info,
|
||||
};
|
||||
|
||||
static int as370_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *hwmon_dev;
|
||||
struct as370_hwmon *hwmon;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
|
||||
if (!hwmon)
|
||||
return -ENOMEM;
|
||||
|
||||
hwmon->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(hwmon->base))
|
||||
return PTR_ERR(hwmon->base);
|
||||
|
||||
init_pvt(hwmon);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev,
|
||||
"as370",
|
||||
hwmon,
|
||||
&as370_chip_info,
|
||||
NULL);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id as370_hwmon_match[] = {
|
||||
{ .compatible = "syna,as370-hwmon" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, as370_hwmon_match);
|
||||
|
||||
static struct platform_driver as370_hwmon_driver = {
|
||||
.probe = as370_hwmon_probe,
|
||||
.driver = {
|
||||
.name = "as370-hwmon",
|
||||
.of_match_table = as370_hwmon_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(as370_hwmon_driver);
|
||||
|
||||
MODULE_AUTHOR("Jisheng Zhang<jszhang@kernel.org>");
|
||||
MODULE_DESCRIPTION("Synaptics AS370 SoC hardware monitor");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -706,21 +706,21 @@ static int asb100_detect_subclients(struct i2c_client *client)
|
|||
goto ERROR_SC_2;
|
||||
}
|
||||
|
||||
data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
|
||||
if (!data->lm75[0]) {
|
||||
data->lm75[0] = i2c_new_dummy_device(adapter, sc_addr[0]);
|
||||
if (IS_ERR(data->lm75[0])) {
|
||||
dev_err(&client->dev,
|
||||
"subclient %d registration at address 0x%x failed.\n",
|
||||
1, sc_addr[0]);
|
||||
err = -ENOMEM;
|
||||
err = PTR_ERR(data->lm75[0]);
|
||||
goto ERROR_SC_2;
|
||||
}
|
||||
|
||||
data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
|
||||
if (!data->lm75[1]) {
|
||||
data->lm75[1] = i2c_new_dummy_device(adapter, sc_addr[1]);
|
||||
if (IS_ERR(data->lm75[1])) {
|
||||
dev_err(&client->dev,
|
||||
"subclient %d registration at address 0x%x failed.\n",
|
||||
2, sc_addr[1]);
|
||||
err = -ENOMEM;
|
||||
err = PTR_ERR(data->lm75[1]);
|
||||
goto ERROR_SC_3;
|
||||
}
|
||||
|
||||
|
|
|
@ -736,7 +736,7 @@ static int __init coretemp_init(void)
|
|||
|
||||
err = platform_driver_register(&coretemp_driver);
|
||||
if (err)
|
||||
return err;
|
||||
goto outzone;
|
||||
|
||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
|
||||
coretemp_cpu_online, coretemp_cpu_offline);
|
||||
|
@ -747,6 +747,7 @@ static int __init coretemp_init(void)
|
|||
|
||||
outdrv:
|
||||
platform_driver_unregister(&coretemp_driver);
|
||||
outzone:
|
||||
kfree(zone_devices);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -44,12 +44,20 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
|
|||
int ret;
|
||||
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
|
||||
struct iio_hwmon_state *state = dev_get_drvdata(dev);
|
||||
struct iio_channel *chan = &state->channels[sattr->index];
|
||||
enum iio_chan_type type;
|
||||
|
||||
ret = iio_read_channel_processed(&state->channels[sattr->index],
|
||||
&result);
|
||||
ret = iio_read_channel_processed(chan, &result);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_get_channel_type(chan, &type);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (type == IIO_POWER)
|
||||
result *= 1000; /* mili-Watts to micro-Watts conversion */
|
||||
|
||||
return sprintf(buf, "%d\n", result);
|
||||
}
|
||||
|
||||
|
@ -59,7 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
|||
struct iio_hwmon_state *st;
|
||||
struct sensor_device_attribute *a;
|
||||
int ret, i;
|
||||
int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
|
||||
int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1, power_i = 1;
|
||||
enum iio_chan_type type;
|
||||
struct iio_channel *channels;
|
||||
struct device *hwmon_dev;
|
||||
|
@ -114,6 +122,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
|||
n = curr_i++;
|
||||
prefix = "curr";
|
||||
break;
|
||||
case IIO_POWER:
|
||||
n = power_i++;
|
||||
prefix = "power";
|
||||
break;
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
n = humidity_i++;
|
||||
prefix = "humidity";
|
||||
|
|
|
@ -349,6 +349,7 @@ static const struct pci_device_id k10temp_id_table[] = {
|
|||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
|
||||
{ PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/processor.h>
|
||||
|
@ -24,108 +22,18 @@
|
|||
#define SEL_CORE 0x04
|
||||
|
||||
struct k8temp_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
const char *name;
|
||||
char valid; /* zero until following fields are valid */
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
|
||||
/* registers values */
|
||||
u8 sensorsp; /* sensor presence bits - SEL_CORE, SEL_PLACE */
|
||||
u32 temp[2][2]; /* core, place */
|
||||
u8 swap_core_select; /* meaning of SEL_CORE is inverted */
|
||||
u32 temp_offset;
|
||||
};
|
||||
|
||||
static struct k8temp_data *k8temp_update_device(struct device *dev)
|
||||
{
|
||||
struct k8temp_data *data = dev_get_drvdata(dev);
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
u8 tmp;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (!data->valid
|
||||
|| time_after(jiffies, data->last_updated + HZ)) {
|
||||
pci_read_config_byte(pdev, REG_TEMP, &tmp);
|
||||
tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
|
||||
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
tmp |= SEL_PLACE; /* Select sensor 1, core0 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP,
|
||||
&data->temp[0][1]);
|
||||
}
|
||||
|
||||
if (data->sensorsp & SEL_CORE) {
|
||||
tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */
|
||||
tmp |= SEL_CORE;
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP,
|
||||
&data->temp[1][0]);
|
||||
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
tmp |= SEL_PLACE; /* Select sensor 1, core1 */
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP,
|
||||
&data->temp[1][1]);
|
||||
}
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sysfs stuff
|
||||
*/
|
||||
|
||||
static ssize_t name_show(struct device *dev, struct device_attribute
|
||||
*devattr, char *buf)
|
||||
{
|
||||
struct k8temp_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", data->name);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t temp_show(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr =
|
||||
to_sensor_dev_attr_2(devattr);
|
||||
int core = attr->nr;
|
||||
int place = attr->index;
|
||||
int temp;
|
||||
struct k8temp_data *data = k8temp_update_device(dev);
|
||||
|
||||
if (data->swap_core_select && (data->sensorsp & SEL_CORE))
|
||||
core = core ? 0 : 1;
|
||||
|
||||
temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset;
|
||||
|
||||
return sprintf(buf, "%d\n", temp);
|
||||
}
|
||||
|
||||
/* core, place */
|
||||
|
||||
static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, 0, 0);
|
||||
static SENSOR_DEVICE_ATTR_2_RO(temp2_input, temp, 0, 1);
|
||||
static SENSOR_DEVICE_ATTR_2_RO(temp3_input, temp, 1, 0);
|
||||
static SENSOR_DEVICE_ATTR_2_RO(temp4_input, temp, 1, 1);
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
static const struct pci_device_id k8temp_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, k8temp_ids);
|
||||
|
||||
static int is_rev_g_desktop(u8 model)
|
||||
|
@ -159,14 +67,76 @@ static int is_rev_g_desktop(u8 model)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static umode_t
|
||||
k8temp_is_visible(const void *drvdata, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
const struct k8temp_data *data = drvdata;
|
||||
|
||||
if ((channel & 1) && !(data->sensorsp & SEL_PLACE))
|
||||
return 0;
|
||||
|
||||
if ((channel & 2) && !(data->sensorsp & SEL_CORE))
|
||||
return 0;
|
||||
|
||||
return 0444;
|
||||
}
|
||||
|
||||
static int
|
||||
k8temp_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct k8temp_data *data = dev_get_drvdata(dev);
|
||||
struct pci_dev *pdev = to_pci_dev(dev->parent);
|
||||
int core, place;
|
||||
u32 temp;
|
||||
u8 tmp;
|
||||
|
||||
core = (channel >> 1) & 1;
|
||||
place = channel & 1;
|
||||
|
||||
core ^= data->swap_core_select;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
pci_read_config_byte(pdev, REG_TEMP, &tmp);
|
||||
tmp &= ~(SEL_PLACE | SEL_CORE);
|
||||
if (core)
|
||||
tmp |= SEL_CORE;
|
||||
if (place)
|
||||
tmp |= SEL_PLACE;
|
||||
pci_write_config_byte(pdev, REG_TEMP, tmp);
|
||||
pci_read_config_dword(pdev, REG_TEMP, &temp);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
*val = TEMP_FROM_REG(temp) + data->temp_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_ops k8temp_ops = {
|
||||
.is_visible = k8temp_is_visible,
|
||||
.read = k8temp_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *k8temp_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT, HWMON_T_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info k8temp_chip_info = {
|
||||
.ops = &k8temp_ops,
|
||||
.info = k8temp_info,
|
||||
};
|
||||
|
||||
static int k8temp_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int err;
|
||||
u8 scfg;
|
||||
u32 temp;
|
||||
u8 model, stepping;
|
||||
struct k8temp_data *data;
|
||||
struct device *hwmon_dev;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
|
@ -231,86 +201,21 @@ static int k8temp_probe(struct pci_dev *pdev,
|
|||
data->sensorsp &= ~SEL_CORE;
|
||||
}
|
||||
|
||||
data->name = "k8temp";
|
||||
mutex_init(&data->update_lock);
|
||||
pci_set_drvdata(pdev, data);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
|
||||
"k8temp",
|
||||
data,
|
||||
&k8temp_chip_info,
|
||||
NULL);
|
||||
|
||||
/* sensor can be changed and reports something */
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
/* core can be changed and reports something */
|
||||
if (data->sensorsp & SEL_CORE) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
if (data->sensorsp & SEL_PLACE) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp4_input.
|
||||
dev_attr);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
}
|
||||
}
|
||||
|
||||
err = device_create_file(&pdev->dev, &dev_attr_name);
|
||||
if (err)
|
||||
goto exit_remove;
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp4_input.dev_attr);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void k8temp_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct k8temp_data *data = pci_get_drvdata(pdev);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp1_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp2_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp3_input.dev_attr);
|
||||
device_remove_file(&pdev->dev,
|
||||
&sensor_dev_attr_temp4_input.dev_attr);
|
||||
device_remove_file(&pdev->dev, &dev_attr_name);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static struct pci_driver k8temp_driver = {
|
||||
.name = "k8temp",
|
||||
.id_table = k8temp_ids,
|
||||
.probe = k8temp_probe,
|
||||
.remove = k8temp_remove,
|
||||
};
|
||||
|
||||
module_pci_driver(k8temp_driver);
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/util_macros.h>
|
||||
#include "lm75.h"
|
||||
|
||||
|
||||
/*
|
||||
* This driver handles the LM75 and compatible digital temperature sensors.
|
||||
*/
|
||||
|
@ -36,6 +36,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
|||
max6626,
|
||||
max31725,
|
||||
mcp980x,
|
||||
pct2075,
|
||||
stds75,
|
||||
stlm75,
|
||||
tcn75,
|
||||
|
@ -50,6 +51,41 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
|||
tmp75c,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct lm75_params - lm75 configuration parameters.
|
||||
* @set_mask: Bits to set in configuration register when configuring
|
||||
* the chip.
|
||||
* @clr_mask: Bits to clear in configuration register when configuring
|
||||
* the chip.
|
||||
* @default_resolution: Default number of bits to represent the temperature
|
||||
* value.
|
||||
* @resolution_limits: Limit register resolution. Optional. Should be set if
|
||||
* the resolution of limit registers does not match the
|
||||
* resolution of the temperature register.
|
||||
* @resolutions: List of resolutions associated with sample times.
|
||||
* Optional. Should be set if num_sample_times is larger
|
||||
* than 1, and if the resolution changes with sample times.
|
||||
* If set, number of entries must match num_sample_times.
|
||||
* @default_sample_time:Sample time to be set by default.
|
||||
* @num_sample_times: Number of possible sample times to be set. Optional.
|
||||
* Should be set if the number of sample times is larger
|
||||
* than one.
|
||||
* @sample_times: All the possible sample times to be set. Mandatory if
|
||||
* num_sample_times is larger than 1. If set, number of
|
||||
* entries must match num_sample_times.
|
||||
*/
|
||||
|
||||
struct lm75_params {
|
||||
u8 set_mask;
|
||||
u8 clr_mask;
|
||||
u8 default_resolution;
|
||||
u8 resolution_limits;
|
||||
const u8 *resolutions;
|
||||
unsigned int default_sample_time;
|
||||
u8 num_sample_times;
|
||||
const unsigned int *sample_times;
|
||||
};
|
||||
|
||||
/* Addresses scanned */
|
||||
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
|
||||
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
|
||||
|
@ -59,24 +95,231 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
|
|||
#define LM75_REG_CONF 0x01
|
||||
#define LM75_REG_HYST 0x02
|
||||
#define LM75_REG_MAX 0x03
|
||||
#define PCT2075_REG_IDLE 0x04
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct lm75_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
u8 orig_conf;
|
||||
u8 resolution; /* In bits, between 9 and 16 */
|
||||
u8 resolution_limits;
|
||||
unsigned int sample_time; /* In ms */
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
u8 orig_conf;
|
||||
u8 current_conf;
|
||||
u8 resolution; /* In bits, 9 to 16 */
|
||||
unsigned int sample_time; /* In ms */
|
||||
enum lm75_type kind;
|
||||
const struct lm75_params *params;
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static const u8 lm75_sample_set_masks[] = { 0 << 5, 1 << 5, 2 << 5, 3 << 5 };
|
||||
|
||||
#define LM75_SAMPLE_CLEAR_MASK (3 << 5)
|
||||
|
||||
/* The structure below stores the configuration values of the supported devices.
|
||||
* In case of being supported multiple configurations, the default one must
|
||||
* always be the first element of the array
|
||||
*/
|
||||
static const struct lm75_params device_params[] = {
|
||||
[adt75] = {
|
||||
.clr_mask = 1 << 5, /* not one-shot mode */
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = MSEC_PER_SEC / 10,
|
||||
},
|
||||
[ds1775] = {
|
||||
.clr_mask = 3 << 5,
|
||||
.set_mask = 2 << 5, /* 11-bit mode */
|
||||
.default_resolution = 11,
|
||||
.default_sample_time = 500,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 125, 250, 500, 1000 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[ds75] = {
|
||||
.clr_mask = 3 << 5,
|
||||
.set_mask = 2 << 5, /* 11-bit mode */
|
||||
.default_resolution = 11,
|
||||
.default_sample_time = 600,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 150, 300, 600, 1200 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[stds75] = {
|
||||
.clr_mask = 3 << 5,
|
||||
.set_mask = 2 << 5, /* 11-bit mode */
|
||||
.default_resolution = 11,
|
||||
.default_sample_time = 600,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 150, 300, 600, 1200 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[stlm75] = {
|
||||
.default_resolution = 9,
|
||||
.default_sample_time = MSEC_PER_SEC / 6,
|
||||
},
|
||||
[ds7505] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode*/
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 200,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 25, 50, 100, 200 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[g751] = {
|
||||
.default_resolution = 9,
|
||||
.default_sample_time = MSEC_PER_SEC / 10,
|
||||
},
|
||||
[lm75] = {
|
||||
.default_resolution = 9,
|
||||
.default_sample_time = MSEC_PER_SEC / 10,
|
||||
},
|
||||
[lm75a] = {
|
||||
.default_resolution = 9,
|
||||
.default_sample_time = MSEC_PER_SEC / 10,
|
||||
},
|
||||
[lm75b] = {
|
||||
.default_resolution = 11,
|
||||
.default_sample_time = MSEC_PER_SEC / 10,
|
||||
},
|
||||
[max6625] = {
|
||||
.default_resolution = 9,
|
||||
.default_sample_time = MSEC_PER_SEC / 7,
|
||||
},
|
||||
[max6626] = {
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = MSEC_PER_SEC / 7,
|
||||
.resolution_limits = 9,
|
||||
},
|
||||
[max31725] = {
|
||||
.default_resolution = 16,
|
||||
.default_sample_time = MSEC_PER_SEC / 20,
|
||||
},
|
||||
[tcn75] = {
|
||||
.default_resolution = 9,
|
||||
.default_sample_time = MSEC_PER_SEC / 18,
|
||||
},
|
||||
[pct2075] = {
|
||||
.default_resolution = 11,
|
||||
.default_sample_time = MSEC_PER_SEC / 10,
|
||||
.num_sample_times = 31,
|
||||
.sample_times = (unsigned int []){ 100, 200, 300, 400, 500, 600,
|
||||
700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700,
|
||||
1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
|
||||
2800, 2900, 3000, 3100 },
|
||||
},
|
||||
[mcp980x] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode */
|
||||
.clr_mask = 1 << 7, /* not one-shot mode */
|
||||
.default_resolution = 12,
|
||||
.resolution_limits = 9,
|
||||
.default_sample_time = 240,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 30, 60, 120, 240 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[tmp100] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode */
|
||||
.clr_mask = 1 << 7, /* not one-shot mode */
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 320,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 40, 80, 160, 320 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[tmp101] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode */
|
||||
.clr_mask = 1 << 7, /* not one-shot mode */
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 320,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 40, 80, 160, 320 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[tmp105] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode */
|
||||
.clr_mask = 1 << 7, /* not one-shot mode*/
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 220,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 28, 55, 110, 220 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[tmp112] = {
|
||||
.set_mask = 3 << 5, /* 8 samples / second */
|
||||
.clr_mask = 1 << 7, /* no one-shot mode*/
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 125,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 125, 250, 1000, 4000 },
|
||||
},
|
||||
[tmp175] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode */
|
||||
.clr_mask = 1 << 7, /* not one-shot mode*/
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 220,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 28, 55, 110, 220 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[tmp275] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode */
|
||||
.clr_mask = 1 << 7, /* not one-shot mode*/
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 220,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 28, 55, 110, 220 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[tmp75] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode */
|
||||
.clr_mask = 1 << 7, /* not one-shot mode*/
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 220,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 28, 55, 110, 220 },
|
||||
.resolutions = (u8 []) {9, 10, 11, 12 },
|
||||
},
|
||||
[tmp75b] = { /* not one-shot mode, Conversion rate 37Hz */
|
||||
.clr_mask = 1 << 7 | 3 << 5,
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = MSEC_PER_SEC / 37,
|
||||
.sample_times = (unsigned int []){ MSEC_PER_SEC / 37,
|
||||
MSEC_PER_SEC / 18,
|
||||
MSEC_PER_SEC / 9, MSEC_PER_SEC / 4 },
|
||||
.num_sample_times = 4,
|
||||
},
|
||||
[tmp75c] = {
|
||||
.clr_mask = 1 << 5, /*not one-shot mode*/
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = MSEC_PER_SEC / 12,
|
||||
}
|
||||
};
|
||||
|
||||
static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
|
||||
{
|
||||
return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
|
||||
}
|
||||
|
||||
static int lm75_write_config(struct lm75_data *data, u8 set_mask,
|
||||
u8 clr_mask)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
clr_mask |= LM75_SHUTDOWN;
|
||||
value = data->current_conf & ~clr_mask;
|
||||
value |= set_mask;
|
||||
|
||||
if (data->current_conf != value) {
|
||||
s32 err;
|
||||
|
||||
err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF,
|
||||
value);
|
||||
if (err)
|
||||
return err;
|
||||
data->current_conf = value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
|
@ -120,16 +363,12 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long temp)
|
||||
static int lm75_write_temp(struct device *dev, u32 attr, long temp)
|
||||
{
|
||||
struct lm75_data *data = dev_get_drvdata(dev);
|
||||
u8 resolution;
|
||||
int reg;
|
||||
|
||||
if (type != hwmon_temp)
|
||||
return -EINVAL;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_max:
|
||||
reg = LM75_REG_MAX;
|
||||
|
@ -145,8 +384,8 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
* Resolution of limit registers is assumed to be the same as the
|
||||
* temperature input register resolution unless given explicitly.
|
||||
*/
|
||||
if (data->resolution_limits)
|
||||
resolution = data->resolution_limits;
|
||||
if (data->params->resolution_limits)
|
||||
resolution = data->params->resolution_limits;
|
||||
else
|
||||
resolution = data->resolution;
|
||||
|
||||
|
@ -154,16 +393,88 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
temp = DIV_ROUND_CLOSEST(temp << (resolution - 8),
|
||||
1000) << (16 - resolution);
|
||||
|
||||
return regmap_write(data->regmap, reg, temp);
|
||||
return regmap_write(data->regmap, reg, (u16)temp);
|
||||
}
|
||||
|
||||
static int lm75_update_interval(struct device *dev, long val)
|
||||
{
|
||||
struct lm75_data *data = dev_get_drvdata(dev);
|
||||
unsigned int reg;
|
||||
u8 index;
|
||||
s32 err;
|
||||
|
||||
index = find_closest(val, data->params->sample_times,
|
||||
(int)data->params->num_sample_times);
|
||||
|
||||
switch (data->kind) {
|
||||
default:
|
||||
err = lm75_write_config(data, lm75_sample_set_masks[index],
|
||||
LM75_SAMPLE_CLEAR_MASK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
data->sample_time = data->params->sample_times[index];
|
||||
if (data->params->resolutions)
|
||||
data->resolution = data->params->resolutions[index];
|
||||
break;
|
||||
case tmp112:
|
||||
err = regmap_read(data->regmap, LM75_REG_CONF, ®);
|
||||
if (err < 0)
|
||||
return err;
|
||||
reg &= ~0x00c0;
|
||||
reg |= (3 - index) << 6;
|
||||
err = regmap_write(data->regmap, LM75_REG_CONF, reg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
data->sample_time = data->params->sample_times[index];
|
||||
break;
|
||||
case pct2075:
|
||||
err = i2c_smbus_write_byte_data(data->client, PCT2075_REG_IDLE,
|
||||
index + 1);
|
||||
if (err)
|
||||
return err;
|
||||
data->sample_time = data->params->sample_times[index];
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm75_write_chip(struct device *dev, u32 attr, long val)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_chip_update_interval:
|
||||
return lm75_update_interval(dev, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_chip:
|
||||
return lm75_write_chip(dev, attr, val);
|
||||
case hwmon_temp:
|
||||
return lm75_write_temp(dev, attr, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
const struct lm75_data *config_data = data;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_chip:
|
||||
switch (attr) {
|
||||
case hwmon_chip_update_interval:
|
||||
if (config_data->params->num_sample_times > 1)
|
||||
return 0644;
|
||||
return 0444;
|
||||
}
|
||||
break;
|
||||
|
@ -208,13 +519,13 @@ static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg)
|
|||
|
||||
static bool lm75_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg == LM75_REG_TEMP;
|
||||
return reg == LM75_REG_TEMP || reg == LM75_REG_CONF;
|
||||
}
|
||||
|
||||
static const struct regmap_config lm75_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.max_register = LM75_REG_MAX,
|
||||
.max_register = PCT2075_REG_IDLE,
|
||||
.writeable_reg = lm75_is_writeable_reg,
|
||||
.volatile_reg = lm75_is_volatile_reg,
|
||||
.val_format_endian = REGMAP_ENDIAN_BIG,
|
||||
|
@ -238,8 +549,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
struct device *hwmon_dev;
|
||||
struct lm75_data *data;
|
||||
int status, err;
|
||||
u8 set_mask, clr_mask;
|
||||
int new;
|
||||
enum lm75_type kind;
|
||||
|
||||
if (client->dev.of_node)
|
||||
|
@ -256,6 +565,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
return -ENOMEM;
|
||||
|
||||
data->client = client;
|
||||
data->kind = kind;
|
||||
|
||||
data->regmap = devm_regmap_init_i2c(client, &lm75_regmap_config);
|
||||
if (IS_ERR(data->regmap))
|
||||
|
@ -264,114 +574,31 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
/* Set to LM75 resolution (9 bits, 1/2 degree C) and range.
|
||||
* Then tweak to be more precise when appropriate.
|
||||
*/
|
||||
set_mask = 0;
|
||||
clr_mask = LM75_SHUTDOWN; /* continuous conversions */
|
||||
|
||||
switch (kind) {
|
||||
case adt75:
|
||||
clr_mask |= 1 << 5; /* not one-shot mode */
|
||||
data->resolution = 12;
|
||||
data->sample_time = MSEC_PER_SEC / 8;
|
||||
break;
|
||||
case ds1775:
|
||||
case ds75:
|
||||
case stds75:
|
||||
clr_mask |= 3 << 5;
|
||||
set_mask |= 2 << 5; /* 11-bit mode */
|
||||
data->resolution = 11;
|
||||
data->sample_time = MSEC_PER_SEC;
|
||||
break;
|
||||
case stlm75:
|
||||
data->resolution = 9;
|
||||
data->sample_time = MSEC_PER_SEC / 5;
|
||||
break;
|
||||
case ds7505:
|
||||
set_mask |= 3 << 5; /* 12-bit mode */
|
||||
data->resolution = 12;
|
||||
data->sample_time = MSEC_PER_SEC / 4;
|
||||
break;
|
||||
case g751:
|
||||
case lm75:
|
||||
case lm75a:
|
||||
data->resolution = 9;
|
||||
data->sample_time = MSEC_PER_SEC / 2;
|
||||
break;
|
||||
case lm75b:
|
||||
data->resolution = 11;
|
||||
data->sample_time = MSEC_PER_SEC / 4;
|
||||
break;
|
||||
case max6625:
|
||||
data->resolution = 9;
|
||||
data->sample_time = MSEC_PER_SEC / 4;
|
||||
break;
|
||||
case max6626:
|
||||
data->resolution = 12;
|
||||
data->resolution_limits = 9;
|
||||
data->sample_time = MSEC_PER_SEC / 4;
|
||||
break;
|
||||
case max31725:
|
||||
data->resolution = 16;
|
||||
data->sample_time = MSEC_PER_SEC / 8;
|
||||
break;
|
||||
case tcn75:
|
||||
data->resolution = 9;
|
||||
data->sample_time = MSEC_PER_SEC / 8;
|
||||
break;
|
||||
case mcp980x:
|
||||
data->resolution_limits = 9;
|
||||
/* fall through */
|
||||
case tmp100:
|
||||
case tmp101:
|
||||
set_mask |= 3 << 5; /* 12-bit mode */
|
||||
data->resolution = 12;
|
||||
data->sample_time = MSEC_PER_SEC;
|
||||
clr_mask |= 1 << 7; /* not one-shot mode */
|
||||
break;
|
||||
case tmp112:
|
||||
set_mask |= 3 << 5; /* 12-bit mode */
|
||||
clr_mask |= 1 << 7; /* not one-shot mode */
|
||||
data->resolution = 12;
|
||||
data->sample_time = MSEC_PER_SEC / 4;
|
||||
break;
|
||||
case tmp105:
|
||||
case tmp175:
|
||||
case tmp275:
|
||||
case tmp75:
|
||||
set_mask |= 3 << 5; /* 12-bit mode */
|
||||
clr_mask |= 1 << 7; /* not one-shot mode */
|
||||
data->resolution = 12;
|
||||
data->sample_time = MSEC_PER_SEC / 2;
|
||||
break;
|
||||
case tmp75b: /* not one-shot mode, Conversion rate 37Hz */
|
||||
clr_mask |= 1 << 7 | 0x3 << 5;
|
||||
data->resolution = 12;
|
||||
data->sample_time = MSEC_PER_SEC / 37;
|
||||
break;
|
||||
case tmp75c:
|
||||
clr_mask |= 1 << 5; /* not one-shot mode */
|
||||
data->resolution = 12;
|
||||
data->sample_time = MSEC_PER_SEC / 4;
|
||||
break;
|
||||
}
|
||||
data->params = &device_params[data->kind];
|
||||
|
||||
/* configure as specified */
|
||||
/* Save default sample time and resolution*/
|
||||
data->sample_time = data->params->default_sample_time;
|
||||
data->resolution = data->params->default_resolution;
|
||||
|
||||
/* Cache original configuration */
|
||||
status = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
|
||||
if (status < 0) {
|
||||
dev_dbg(dev, "Can't read config? %d\n", status);
|
||||
return status;
|
||||
}
|
||||
data->orig_conf = status;
|
||||
new = status & ~clr_mask;
|
||||
new |= set_mask;
|
||||
if (status != new)
|
||||
i2c_smbus_write_byte_data(client, LM75_REG_CONF, new);
|
||||
data->current_conf = status;
|
||||
|
||||
err = lm75_write_config(data, data->params->set_mask,
|
||||
data->params->clr_mask);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_add_action_or_reset(dev, lm75_remove, data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_dbg(dev, "Config %02x\n", new);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
|
||||
data, &lm75_chip_info,
|
||||
NULL);
|
||||
|
@ -397,6 +624,7 @@ static const struct i2c_device_id lm75_ids[] = {
|
|||
{ "max31725", max31725, },
|
||||
{ "max31726", max31725, },
|
||||
{ "mcp980x", mcp980x, },
|
||||
{ "pct2075", pct2075, },
|
||||
{ "stds75", stds75, },
|
||||
{ "stlm75", stlm75, },
|
||||
{ "tcn75", tcn75, },
|
||||
|
@ -466,6 +694,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
|
|||
.compatible = "maxim,mcp980x",
|
||||
.data = (void *)mcp980x
|
||||
},
|
||||
{
|
||||
.compatible = "nxp,pct2075",
|
||||
.data = (void *)pct2075
|
||||
},
|
||||
{
|
||||
.compatible = "st,stds75",
|
||||
.data = (void *)stds75
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#define LTC2990_STATUS 0x00
|
||||
#define LTC2990_CONTROL 0x01
|
||||
|
@ -206,7 +206,6 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
|
|||
int ret;
|
||||
struct device *hwmon_dev;
|
||||
struct ltc2990_data *data;
|
||||
struct device_node *of_node = i2c->dev.of_node;
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA))
|
||||
|
@ -218,9 +217,10 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
data->i2c = i2c;
|
||||
|
||||
if (of_node) {
|
||||
ret = of_property_read_u32_array(of_node, "lltc,meas-mode",
|
||||
data->mode, 2);
|
||||
if (dev_fwnode(&i2c->dev)) {
|
||||
ret = device_property_read_u32_array(&i2c->dev,
|
||||
"lltc,meas-mode",
|
||||
data->mode, 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
* Chip #vin #fan #pwm #temp chip IDs man ID
|
||||
* nct6106d 9 3 3 6+3 0xc450 0xc1 0x5ca3
|
||||
* nct6116d 9 5 5 3+3 0xd280 0xc1 0x5ca3
|
||||
* nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3
|
||||
* nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
|
||||
* nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
|
||||
|
@ -58,12 +59,13 @@
|
|||
|
||||
#define USE_ALTERNATE
|
||||
|
||||
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
|
||||
nct6795, nct6796, nct6797, nct6798 };
|
||||
enum kinds { nct6106, nct6116, nct6775, nct6776, nct6779, nct6791, nct6792,
|
||||
nct6793, nct6795, nct6796, nct6797, nct6798 };
|
||||
|
||||
/* used to set data->name = nct6775_device_names[data->sio_kind] */
|
||||
static const char * const nct6775_device_names[] = {
|
||||
"nct6106",
|
||||
"nct6116",
|
||||
"nct6775",
|
||||
"nct6776",
|
||||
"nct6779",
|
||||
|
@ -78,6 +80,7 @@ static const char * const nct6775_device_names[] = {
|
|||
|
||||
static const char * const nct6775_sio_names[] __initconst = {
|
||||
"NCT6106D",
|
||||
"NCT6116D",
|
||||
"NCT6775F",
|
||||
"NCT6776D/F",
|
||||
"NCT6779D",
|
||||
|
@ -115,6 +118,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
|
|||
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
|
||||
|
||||
#define SIO_NCT6106_ID 0xc450
|
||||
#define SIO_NCT6116_ID 0xd280
|
||||
#define SIO_NCT6775_ID 0xb470
|
||||
#define SIO_NCT6776_ID 0xc330
|
||||
#define SIO_NCT6779_ID 0xc560
|
||||
|
@ -825,10 +829,8 @@ static const u16 NCT6106_FAN_PULSE_SHIFT[] = { 0, 2, 4 };
|
|||
|
||||
static const u8 NCT6106_REG_PWM_MODE[] = { 0xf3, 0xf3, 0xf3 };
|
||||
static const u8 NCT6106_PWM_MODE_MASK[] = { 0x01, 0x02, 0x04 };
|
||||
static const u16 NCT6106_REG_PWM[] = { 0x119, 0x129, 0x139 };
|
||||
static const u16 NCT6106_REG_PWM_READ[] = { 0x4a, 0x4b, 0x4c };
|
||||
static const u16 NCT6106_REG_FAN_MODE[] = { 0x113, 0x123, 0x133 };
|
||||
static const u16 NCT6106_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130 };
|
||||
static const u16 NCT6106_REG_TEMP_SOURCE[] = {
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5 };
|
||||
|
||||
|
@ -896,6 +898,70 @@ static const u16 NCT6106_REG_TEMP_CRIT[32] = {
|
|||
[12] = 0x205,
|
||||
};
|
||||
|
||||
/* NCT6112D/NCT6114D/NCT6116D specific data */
|
||||
|
||||
static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 };
|
||||
static const u16 NCT6116_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe4, 0xe6, 0xe8 };
|
||||
static const u16 NCT6116_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf6, 0xf6, 0xf5 };
|
||||
static const u16 NCT6116_FAN_PULSE_SHIFT[] = { 0, 2, 4, 6, 6 };
|
||||
|
||||
static const u16 NCT6116_REG_PWM[] = { 0x119, 0x129, 0x139, 0x199, 0x1a9 };
|
||||
static const u16 NCT6116_REG_FAN_MODE[] = { 0x113, 0x123, 0x133, 0x193, 0x1a3 };
|
||||
static const u16 NCT6116_REG_TEMP_SEL[] = { 0x110, 0x120, 0x130, 0x190, 0x1a0 };
|
||||
static const u16 NCT6116_REG_TEMP_SOURCE[] = {
|
||||
0xb0, 0xb1, 0xb2 };
|
||||
|
||||
static const u16 NCT6116_REG_CRITICAL_TEMP[] = {
|
||||
0x11a, 0x12a, 0x13a, 0x19a, 0x1aa };
|
||||
static const u16 NCT6116_REG_CRITICAL_TEMP_TOLERANCE[] = {
|
||||
0x11b, 0x12b, 0x13b, 0x19b, 0x1ab };
|
||||
|
||||
static const u16 NCT6116_REG_CRITICAL_PWM_ENABLE[] = {
|
||||
0x11c, 0x12c, 0x13c, 0x19c, 0x1ac };
|
||||
static const u16 NCT6116_REG_CRITICAL_PWM[] = {
|
||||
0x11d, 0x12d, 0x13d, 0x19d, 0x1ad };
|
||||
|
||||
static const u16 NCT6116_REG_FAN_STEP_UP_TIME[] = {
|
||||
0x114, 0x124, 0x134, 0x194, 0x1a4 };
|
||||
static const u16 NCT6116_REG_FAN_STEP_DOWN_TIME[] = {
|
||||
0x115, 0x125, 0x135, 0x195, 0x1a5 };
|
||||
static const u16 NCT6116_REG_FAN_STOP_OUTPUT[] = {
|
||||
0x116, 0x126, 0x136, 0x196, 0x1a6 };
|
||||
static const u16 NCT6116_REG_FAN_START_OUTPUT[] = {
|
||||
0x117, 0x127, 0x137, 0x197, 0x1a7 };
|
||||
static const u16 NCT6116_REG_FAN_STOP_TIME[] = {
|
||||
0x118, 0x128, 0x138, 0x198, 0x1a8 };
|
||||
static const u16 NCT6116_REG_TOLERANCE_H[] = {
|
||||
0x112, 0x122, 0x132, 0x192, 0x1a2 };
|
||||
|
||||
static const u16 NCT6116_REG_TARGET[] = {
|
||||
0x111, 0x121, 0x131, 0x191, 0x1a1 };
|
||||
|
||||
static const u16 NCT6116_REG_AUTO_TEMP[] = {
|
||||
0x160, 0x170, 0x180, 0x1d0, 0x1e0 };
|
||||
static const u16 NCT6116_REG_AUTO_PWM[] = {
|
||||
0x164, 0x174, 0x184, 0x1d4, 0x1e4 };
|
||||
|
||||
static const s8 NCT6116_ALARM_BITS[] = {
|
||||
0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
|
||||
9, -1, -1, -1, -1, -1, -1, /* in8..in9 */
|
||||
-1, /* unused */
|
||||
32, 33, 34, 35, 36, /* fan1..fan5 */
|
||||
-1, -1, -1, /* unused */
|
||||
16, 17, 18, -1, -1, -1, /* temp1..temp6 */
|
||||
48, -1 /* intrusion0, intrusion1 */
|
||||
};
|
||||
|
||||
static const s8 NCT6116_BEEP_BITS[] = {
|
||||
0, 1, 2, 3, 4, 5, 7, 8, /* in0.. in7 */
|
||||
9, 10, 11, 12, -1, -1, -1, /* in8..in14 */
|
||||
32, /* global beep enable */
|
||||
24, 25, 26, 27, 28, /* fan1..fan5 */
|
||||
-1, -1, -1, /* unused */
|
||||
16, 17, 18, -1, -1, -1, /* temp1..temp6 */
|
||||
34, -1 /* intrusion0, intrusion1 */
|
||||
};
|
||||
|
||||
static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
|
||||
{
|
||||
if (mode == 0 && pwm == 255)
|
||||
|
@ -1294,6 +1360,11 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
|
|||
return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
|
||||
reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
|
||||
reg == 0x111 || reg == 0x121 || reg == 0x131;
|
||||
case nct6116:
|
||||
return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
|
||||
reg == 0x26 || reg == 0x28 || reg == 0xe0 || reg == 0xe2 ||
|
||||
reg == 0xe4 || reg == 0xe6 || reg == 0xe8 || reg == 0x111 ||
|
||||
reg == 0x121 || reg == 0x131 || reg == 0x191 || reg == 0x1a1;
|
||||
case nct6775:
|
||||
return (((reg & 0xff00) == 0x100 ||
|
||||
(reg & 0xff00) == 0x200) &&
|
||||
|
@ -1673,6 +1744,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
|
|||
data->auto_pwm[i][data->auto_pwm_num] = 0xff;
|
||||
break;
|
||||
case nct6106:
|
||||
case nct6116:
|
||||
case nct6779:
|
||||
case nct6791:
|
||||
case nct6792:
|
||||
|
@ -3109,6 +3181,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
|
|||
case nct6776:
|
||||
break; /* always enabled, nothing to do */
|
||||
case nct6106:
|
||||
case nct6116:
|
||||
case nct6779:
|
||||
case nct6791:
|
||||
case nct6792:
|
||||
|
@ -3535,6 +3608,23 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
|||
|
||||
fan3pin = !(cr24 & 0x80);
|
||||
pwm3pin = cr24 & 0x08;
|
||||
} else if (data->kind == nct6116) {
|
||||
int cr1a = superio_inb(sioreg, 0x1a);
|
||||
int cr1b = superio_inb(sioreg, 0x1b);
|
||||
int cr24 = superio_inb(sioreg, 0x24);
|
||||
int cr2a = superio_inb(sioreg, 0x2a);
|
||||
int cr2b = superio_inb(sioreg, 0x2b);
|
||||
int cr2f = superio_inb(sioreg, 0x2f);
|
||||
|
||||
fan3pin = !(cr2b & 0x10);
|
||||
fan4pin = (cr2b & 0x80) || // pin 1(2)
|
||||
(!(cr2f & 0x10) && (cr1a & 0x04)); // pin 65(66)
|
||||
fan5pin = (cr2b & 0x80) || // pin 126(127)
|
||||
(!(cr1b & 0x03) && (cr2a & 0x02)); // pin 94(96)
|
||||
|
||||
pwm3pin = fan3pin && (cr24 & 0x08);
|
||||
pwm4pin = fan4pin;
|
||||
pwm5pin = fan5pin;
|
||||
} else {
|
||||
/*
|
||||
* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D,
|
||||
|
@ -3765,7 +3855,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
|
||||
data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
|
||||
data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
|
||||
data->REG_PWM[0] = NCT6106_REG_PWM;
|
||||
data->REG_PWM[0] = NCT6116_REG_PWM;
|
||||
data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
|
||||
data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
|
||||
data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
|
||||
|
@ -3784,7 +3874,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
|
||||
data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
|
||||
data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
|
||||
data->REG_TEMP_SEL = NCT6106_REG_TEMP_SEL;
|
||||
data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
|
||||
data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
|
||||
data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
|
||||
data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
|
||||
|
@ -3806,6 +3896,79 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
|
||||
reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
|
||||
|
||||
break;
|
||||
case nct6116:
|
||||
data->in_num = 9;
|
||||
data->pwm_num = 3;
|
||||
data->auto_pwm_num = 4;
|
||||
data->temp_fixed_num = 3;
|
||||
data->num_temp_alarms = 3;
|
||||
data->num_temp_beeps = 3;
|
||||
|
||||
data->fan_from_reg = fan_from_reg13;
|
||||
data->fan_from_reg_min = fan_from_reg13;
|
||||
|
||||
data->temp_label = nct6776_temp_label;
|
||||
data->temp_mask = NCT6776_TEMP_MASK;
|
||||
data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
|
||||
|
||||
data->REG_VBAT = NCT6106_REG_VBAT;
|
||||
data->REG_DIODE = NCT6106_REG_DIODE;
|
||||
data->DIODE_MASK = NCT6106_DIODE_MASK;
|
||||
data->REG_VIN = NCT6106_REG_IN;
|
||||
data->REG_IN_MINMAX[0] = NCT6106_REG_IN_MIN;
|
||||
data->REG_IN_MINMAX[1] = NCT6106_REG_IN_MAX;
|
||||
data->REG_TARGET = NCT6116_REG_TARGET;
|
||||
data->REG_FAN = NCT6116_REG_FAN;
|
||||
data->REG_FAN_MODE = NCT6116_REG_FAN_MODE;
|
||||
data->REG_FAN_MIN = NCT6116_REG_FAN_MIN;
|
||||
data->REG_FAN_PULSES = NCT6116_REG_FAN_PULSES;
|
||||
data->FAN_PULSE_SHIFT = NCT6116_FAN_PULSE_SHIFT;
|
||||
data->REG_FAN_TIME[0] = NCT6116_REG_FAN_STOP_TIME;
|
||||
data->REG_FAN_TIME[1] = NCT6116_REG_FAN_STEP_UP_TIME;
|
||||
data->REG_FAN_TIME[2] = NCT6116_REG_FAN_STEP_DOWN_TIME;
|
||||
data->REG_TOLERANCE_H = NCT6116_REG_TOLERANCE_H;
|
||||
data->REG_PWM[0] = NCT6116_REG_PWM;
|
||||
data->REG_PWM[1] = NCT6116_REG_FAN_START_OUTPUT;
|
||||
data->REG_PWM[2] = NCT6116_REG_FAN_STOP_OUTPUT;
|
||||
data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
|
||||
data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
|
||||
data->REG_PWM_READ = NCT6106_REG_PWM_READ;
|
||||
data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
|
||||
data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
|
||||
data->REG_AUTO_TEMP = NCT6116_REG_AUTO_TEMP;
|
||||
data->REG_AUTO_PWM = NCT6116_REG_AUTO_PWM;
|
||||
data->REG_CRITICAL_TEMP = NCT6116_REG_CRITICAL_TEMP;
|
||||
data->REG_CRITICAL_TEMP_TOLERANCE
|
||||
= NCT6116_REG_CRITICAL_TEMP_TOLERANCE;
|
||||
data->REG_CRITICAL_PWM_ENABLE = NCT6116_REG_CRITICAL_PWM_ENABLE;
|
||||
data->CRITICAL_PWM_ENABLE_MASK
|
||||
= NCT6106_CRITICAL_PWM_ENABLE_MASK;
|
||||
data->REG_CRITICAL_PWM = NCT6116_REG_CRITICAL_PWM;
|
||||
data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
|
||||
data->REG_TEMP_SOURCE = NCT6116_REG_TEMP_SOURCE;
|
||||
data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
|
||||
data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
|
||||
data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
|
||||
data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
|
||||
data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
|
||||
data->REG_ALARM = NCT6106_REG_ALARM;
|
||||
data->ALARM_BITS = NCT6116_ALARM_BITS;
|
||||
data->REG_BEEP = NCT6106_REG_BEEP;
|
||||
data->BEEP_BITS = NCT6116_BEEP_BITS;
|
||||
|
||||
reg_temp = NCT6106_REG_TEMP;
|
||||
reg_temp_mon = NCT6106_REG_TEMP_MON;
|
||||
num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP);
|
||||
num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON);
|
||||
reg_temp_over = NCT6106_REG_TEMP_OVER;
|
||||
reg_temp_hyst = NCT6106_REG_TEMP_HYST;
|
||||
reg_temp_config = NCT6106_REG_TEMP_CONFIG;
|
||||
reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
|
||||
reg_temp_crit = NCT6106_REG_TEMP_CRIT;
|
||||
reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
|
||||
reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
|
||||
|
||||
break;
|
||||
case nct6775:
|
||||
data->in_num = 9;
|
||||
|
@ -4352,6 +4515,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
data->have_vid = (cr2a & 0x60) == 0x40;
|
||||
break;
|
||||
case nct6106:
|
||||
case nct6116:
|
||||
case nct6779:
|
||||
case nct6791:
|
||||
case nct6792:
|
||||
|
@ -4381,6 +4545,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
NCT6775_REG_CR_FAN_DEBOUNCE);
|
||||
switch (data->kind) {
|
||||
case nct6106:
|
||||
case nct6116:
|
||||
tmp |= 0xe0;
|
||||
break;
|
||||
case nct6775:
|
||||
|
@ -4576,6 +4741,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
|
|||
case SIO_NCT6106_ID:
|
||||
sio_data->kind = nct6106;
|
||||
break;
|
||||
case SIO_NCT6116_ID:
|
||||
sio_data->kind = nct6116;
|
||||
break;
|
||||
case SIO_NCT6775_ID:
|
||||
sio_data->kind = nct6775;
|
||||
break;
|
||||
|
|
|
@ -46,10 +46,34 @@
|
|||
#define DTS_T_CTRL1_REG 0x27
|
||||
#define VT_ADC_MD_REG 0x2E
|
||||
|
||||
#define VSEN1_HV_LL_REG 0x02 /* Bank 1; 2 regs (HV/LV) per sensor */
|
||||
#define VSEN1_LV_LL_REG 0x03 /* Bank 1; 2 regs (HV/LV) per sensor */
|
||||
#define VSEN1_HV_HL_REG 0x00 /* Bank 1; 2 regs (HV/LV) per sensor */
|
||||
#define VSEN1_LV_HL_REG 0x01 /* Bank 1; 2 regs (HV/LV) per sensor */
|
||||
#define SMI_STS1_REG 0xC1 /* Bank 0; SMI Status Register */
|
||||
#define SMI_STS3_REG 0xC3 /* Bank 0; SMI Status Register */
|
||||
#define SMI_STS5_REG 0xC5 /* Bank 0; SMI Status Register */
|
||||
#define SMI_STS7_REG 0xC7 /* Bank 0; SMI Status Register */
|
||||
#define SMI_STS8_REG 0xC8 /* Bank 0; SMI Status Register */
|
||||
|
||||
#define VSEN1_HV_REG 0x40 /* Bank 0; 2 regs (HV/LV) per sensor */
|
||||
#define TEMP_CH1_HV_REG 0x42 /* Bank 0; same as VSEN2_HV */
|
||||
#define LTD_HV_REG 0x62 /* Bank 0; 2 regs in VSEN range */
|
||||
#define LTD_HV_HL_REG 0x44 /* Bank 1; 1 reg for LTD */
|
||||
#define LTD_LV_HL_REG 0x45 /* Bank 1; 1 reg for LTD */
|
||||
#define LTD_HV_LL_REG 0x46 /* Bank 1; 1 reg for LTD */
|
||||
#define LTD_LV_LL_REG 0x47 /* Bank 1; 1 reg for LTD */
|
||||
#define TEMP_CH1_CH_REG 0x05 /* Bank 1; 1 reg for LTD */
|
||||
#define TEMP_CH1_W_REG 0x06 /* Bank 1; 1 reg for LTD */
|
||||
#define TEMP_CH1_WH_REG 0x07 /* Bank 1; 1 reg for LTD */
|
||||
#define TEMP_CH1_C_REG 0x04 /* Bank 1; 1 reg per sensor */
|
||||
#define DTS_T_CPU1_C_REG 0x90 /* Bank 1; 1 reg per sensor */
|
||||
#define DTS_T_CPU1_CH_REG 0x91 /* Bank 1; 1 reg per sensor */
|
||||
#define DTS_T_CPU1_W_REG 0x92 /* Bank 1; 1 reg per sensor */
|
||||
#define DTS_T_CPU1_WH_REG 0x93 /* Bank 1; 1 reg per sensor */
|
||||
#define FANIN1_HV_REG 0x80 /* Bank 0; 2 regs (HV/LV) per sensor */
|
||||
#define FANIN1_HV_HL_REG 0x60 /* Bank 1; 2 regs (HV/LV) per sensor */
|
||||
#define FANIN1_LV_HL_REG 0x61 /* Bank 1; 2 regs (HV/LV) per sensor */
|
||||
#define T_CPU1_HV_REG 0xA0 /* Bank 0; 2 regs (HV/LV) per sensor */
|
||||
|
||||
#define PRTS_REG 0x03 /* Bank 2 */
|
||||
|
@ -58,6 +82,8 @@
|
|||
#define FANCTL1_FMR_REG 0x00 /* Bank 3; 1 reg per channel */
|
||||
#define FANCTL1_OUT_REG 0x10 /* Bank 3; 1 reg per channel */
|
||||
|
||||
#define ENABLE_TSI BIT(1)
|
||||
|
||||
static const unsigned short normal_i2c[] = {
|
||||
0x2d, 0x2e, I2C_CLIENT_END
|
||||
};
|
||||
|
@ -72,6 +98,7 @@ struct nct7904_data {
|
|||
u8 fan_mode[FANCTL_MAX];
|
||||
u8 enable_dts;
|
||||
u8 has_dts;
|
||||
u8 temp_mode; /* 0: TR mode, 1: TD mode */
|
||||
};
|
||||
|
||||
/* Access functions */
|
||||
|
@ -170,6 +197,25 @@ static int nct7904_read_fan(struct device *dev, u32 attr, int channel,
|
|||
rpm = 1350000 / cnt;
|
||||
*val = rpm;
|
||||
return 0;
|
||||
case hwmon_fan_min:
|
||||
ret = nct7904_read_reg16(data, BANK_1,
|
||||
FANIN1_HV_HL_REG + channel * 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f);
|
||||
if (cnt == 0x1fff)
|
||||
rpm = 0;
|
||||
else
|
||||
rpm = 1350000 / cnt;
|
||||
*val = rpm;
|
||||
return 0;
|
||||
case hwmon_fan_alarm:
|
||||
ret = nct7904_read_reg(data, BANK_0,
|
||||
SMI_STS5_REG + (channel >> 3));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> (channel & 0x07)) & 1;
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -179,8 +225,20 @@ static umode_t nct7904_fan_is_visible(const void *_data, u32 attr, int channel)
|
|||
{
|
||||
const struct nct7904_data *data = _data;
|
||||
|
||||
if (attr == hwmon_fan_input && data->fanin_mask & (1 << channel))
|
||||
return 0444;
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
case hwmon_fan_alarm:
|
||||
if (data->fanin_mask & (1 << channel))
|
||||
return 0444;
|
||||
break;
|
||||
case hwmon_fan_min:
|
||||
if (data->fanin_mask & (1 << channel))
|
||||
return 0644;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -211,6 +269,37 @@ static int nct7904_read_in(struct device *dev, u32 attr, int channel,
|
|||
volt *= 6; /* 0.006V scale */
|
||||
*val = volt;
|
||||
return 0;
|
||||
case hwmon_in_min:
|
||||
ret = nct7904_read_reg16(data, BANK_1,
|
||||
VSEN1_HV_LL_REG + index * 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
|
||||
if (index < 14)
|
||||
volt *= 2; /* 0.002V scale */
|
||||
else
|
||||
volt *= 6; /* 0.006V scale */
|
||||
*val = volt;
|
||||
return 0;
|
||||
case hwmon_in_max:
|
||||
ret = nct7904_read_reg16(data, BANK_1,
|
||||
VSEN1_HV_HL_REG + index * 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
volt = ((ret & 0xff00) >> 5) | (ret & 0x7);
|
||||
if (index < 14)
|
||||
volt *= 2; /* 0.002V scale */
|
||||
else
|
||||
volt *= 6; /* 0.006V scale */
|
||||
*val = volt;
|
||||
return 0;
|
||||
case hwmon_in_alarm:
|
||||
ret = nct7904_read_reg(data, BANK_0,
|
||||
SMI_STS1_REG + (index >> 3));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> (index & 0x07)) & 1;
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -221,9 +310,20 @@ static umode_t nct7904_in_is_visible(const void *_data, u32 attr, int channel)
|
|||
const struct nct7904_data *data = _data;
|
||||
int index = nct7904_chan_to_index[channel];
|
||||
|
||||
if (channel > 0 && attr == hwmon_in_input &&
|
||||
(data->vsen_mask & BIT(index)))
|
||||
return 0444;
|
||||
switch (attr) {
|
||||
case hwmon_in_input:
|
||||
case hwmon_in_alarm:
|
||||
if (channel > 0 && (data->vsen_mask & BIT(index)))
|
||||
return 0444;
|
||||
break;
|
||||
case hwmon_in_min:
|
||||
case hwmon_in_max:
|
||||
if (channel > 0 && (data->vsen_mask & BIT(index)))
|
||||
return 0644;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -233,6 +333,7 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
|
|||
{
|
||||
struct nct7904_data *data = dev_get_drvdata(dev);
|
||||
int ret, temp;
|
||||
unsigned int reg1, reg2, reg3;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
|
@ -250,16 +351,106 @@ static int nct7904_read_temp(struct device *dev, u32 attr, int channel,
|
|||
temp = ((ret & 0xff00) >> 5) | (ret & 0x7);
|
||||
*val = sign_extend32(temp, 10) * 125;
|
||||
return 0;
|
||||
case hwmon_temp_alarm:
|
||||
if (channel == 4) {
|
||||
ret = nct7904_read_reg(data, BANK_0,
|
||||
SMI_STS3_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> 1) & 1;
|
||||
} else if (channel < 4) {
|
||||
ret = nct7904_read_reg(data, BANK_0,
|
||||
SMI_STS1_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> (((channel * 2) + 1) & 0x07)) & 1;
|
||||
} else {
|
||||
if ((channel - 5) < 4) {
|
||||
ret = nct7904_read_reg(data, BANK_0,
|
||||
SMI_STS7_REG +
|
||||
((channel - 5) >> 3));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> ((channel - 5) & 0x07)) & 1;
|
||||
} else {
|
||||
ret = nct7904_read_reg(data, BANK_0,
|
||||
SMI_STS8_REG +
|
||||
((channel - 5) >> 3));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = (ret >> (((channel - 5) & 0x07) - 4))
|
||||
& 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case hwmon_temp_type:
|
||||
if (channel < 5) {
|
||||
if ((data->tcpu_mask >> channel) & 0x01) {
|
||||
if ((data->temp_mode >> channel) & 0x01)
|
||||
*val = 3; /* TD */
|
||||
else
|
||||
*val = 4; /* TR */
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
} else {
|
||||
if ((data->has_dts >> (channel - 5)) & 0x01) {
|
||||
if (data->enable_dts & ENABLE_TSI)
|
||||
*val = 5; /* TSI */
|
||||
else
|
||||
*val = 6; /* PECI */
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
case hwmon_temp_max:
|
||||
reg1 = LTD_HV_LL_REG;
|
||||
reg2 = TEMP_CH1_W_REG;
|
||||
reg3 = DTS_T_CPU1_W_REG;
|
||||
break;
|
||||
case hwmon_temp_max_hyst:
|
||||
reg1 = LTD_LV_LL_REG;
|
||||
reg2 = TEMP_CH1_WH_REG;
|
||||
reg3 = DTS_T_CPU1_WH_REG;
|
||||
break;
|
||||
case hwmon_temp_crit:
|
||||
reg1 = LTD_HV_HL_REG;
|
||||
reg2 = TEMP_CH1_C_REG;
|
||||
reg3 = DTS_T_CPU1_C_REG;
|
||||
break;
|
||||
case hwmon_temp_crit_hyst:
|
||||
reg1 = LTD_LV_HL_REG;
|
||||
reg2 = TEMP_CH1_CH_REG;
|
||||
reg3 = DTS_T_CPU1_CH_REG;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (channel == 4)
|
||||
ret = nct7904_read_reg(data, BANK_1, reg1);
|
||||
else if (channel < 5)
|
||||
ret = nct7904_read_reg(data, BANK_1,
|
||||
reg2 + channel * 8);
|
||||
else
|
||||
ret = nct7904_read_reg(data, BANK_1,
|
||||
reg3 + (channel - 5) * 4);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
|
||||
{
|
||||
const struct nct7904_data *data = _data;
|
||||
|
||||
if (attr == hwmon_temp_input) {
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
case hwmon_temp_alarm:
|
||||
case hwmon_temp_type:
|
||||
if (channel < 5) {
|
||||
if (data->tcpu_mask & BIT(channel))
|
||||
return 0444;
|
||||
|
@ -267,6 +458,21 @@ static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel)
|
|||
if (data->has_dts & BIT(channel - 5))
|
||||
return 0444;
|
||||
}
|
||||
break;
|
||||
case hwmon_temp_max:
|
||||
case hwmon_temp_max_hyst:
|
||||
case hwmon_temp_crit:
|
||||
case hwmon_temp_crit_hyst:
|
||||
if (channel < 5) {
|
||||
if (data->tcpu_mask & BIT(channel))
|
||||
return 0644;
|
||||
} else {
|
||||
if (data->has_dts & BIT(channel - 5))
|
||||
return 0644;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -297,6 +503,137 @@ static int nct7904_read_pwm(struct device *dev, u32 attr, int channel,
|
|||
}
|
||||
}
|
||||
|
||||
static int nct7904_write_temp(struct device *dev, u32 attr, int channel,
|
||||
long val)
|
||||
{
|
||||
struct nct7904_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
unsigned int reg1, reg2, reg3;
|
||||
|
||||
val = clamp_val(val / 1000, -128, 127);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_max:
|
||||
reg1 = LTD_HV_LL_REG;
|
||||
reg2 = TEMP_CH1_W_REG;
|
||||
reg3 = DTS_T_CPU1_W_REG;
|
||||
break;
|
||||
case hwmon_temp_max_hyst:
|
||||
reg1 = LTD_LV_LL_REG;
|
||||
reg2 = TEMP_CH1_WH_REG;
|
||||
reg3 = DTS_T_CPU1_WH_REG;
|
||||
break;
|
||||
case hwmon_temp_crit:
|
||||
reg1 = LTD_HV_HL_REG;
|
||||
reg2 = TEMP_CH1_C_REG;
|
||||
reg3 = DTS_T_CPU1_C_REG;
|
||||
break;
|
||||
case hwmon_temp_crit_hyst:
|
||||
reg1 = LTD_LV_HL_REG;
|
||||
reg2 = TEMP_CH1_CH_REG;
|
||||
reg3 = DTS_T_CPU1_CH_REG;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
if (channel == 4)
|
||||
ret = nct7904_write_reg(data, BANK_1, reg1, val);
|
||||
else if (channel < 5)
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
reg2 + channel * 8, val);
|
||||
else
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
reg3 + (channel - 5) * 4, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nct7904_write_fan(struct device *dev, u32 attr, int channel,
|
||||
long val)
|
||||
{
|
||||
struct nct7904_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
u8 tmp;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_fan_min:
|
||||
if (val <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), 1, 0x1fff);
|
||||
tmp = (val >> 5) & 0xff;
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
FANIN1_HV_HL_REG + channel * 2, tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
tmp = val & 0x1f;
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
FANIN1_LV_HL_REG + channel * 2, tmp);
|
||||
return ret;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int nct7904_write_in(struct device *dev, u32 attr, int channel,
|
||||
long val)
|
||||
{
|
||||
struct nct7904_data *data = dev_get_drvdata(dev);
|
||||
int ret, index, tmp;
|
||||
|
||||
index = nct7904_chan_to_index[channel];
|
||||
|
||||
if (index < 14)
|
||||
val = val / 2; /* 0.002V scale */
|
||||
else
|
||||
val = val / 6; /* 0.006V scale */
|
||||
|
||||
val = clamp_val(val, 0, 0x7ff);
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_in_min:
|
||||
tmp = nct7904_read_reg(data, BANK_1,
|
||||
VSEN1_LV_LL_REG + index * 4);
|
||||
if (tmp < 0)
|
||||
return tmp;
|
||||
tmp &= ~0x7;
|
||||
tmp |= val & 0x7;
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
VSEN1_LV_LL_REG + index * 4, tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
tmp = nct7904_read_reg(data, BANK_1,
|
||||
VSEN1_HV_LL_REG + index * 4);
|
||||
if (tmp < 0)
|
||||
return tmp;
|
||||
tmp = (val >> 3) & 0xff;
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
VSEN1_HV_LL_REG + index * 4, tmp);
|
||||
return ret;
|
||||
case hwmon_in_max:
|
||||
tmp = nct7904_read_reg(data, BANK_1,
|
||||
VSEN1_LV_HL_REG + index * 4);
|
||||
if (tmp < 0)
|
||||
return tmp;
|
||||
tmp &= ~0x7;
|
||||
tmp |= val & 0x7;
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
VSEN1_LV_HL_REG + index * 4, tmp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
tmp = nct7904_read_reg(data, BANK_1,
|
||||
VSEN1_HV_HL_REG + index * 4);
|
||||
if (tmp < 0)
|
||||
return tmp;
|
||||
tmp = (val >> 3) & 0xff;
|
||||
ret = nct7904_write_reg(data, BANK_1,
|
||||
VSEN1_HV_HL_REG + index * 4, tmp);
|
||||
return ret;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int nct7904_write_pwm(struct device *dev, u32 attr, int channel,
|
||||
long val)
|
||||
{
|
||||
|
@ -354,8 +691,14 @@ static int nct7904_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
u32 attr, int channel, long val)
|
||||
{
|
||||
switch (type) {
|
||||
case hwmon_in:
|
||||
return nct7904_write_in(dev, attr, channel, val);
|
||||
case hwmon_fan:
|
||||
return nct7904_write_fan(dev, attr, channel, val);
|
||||
case hwmon_pwm:
|
||||
return nct7904_write_pwm(dev, attr, channel, val);
|
||||
case hwmon_temp:
|
||||
return nct7904_write_temp(dev, attr, channel, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -404,51 +747,91 @@ static int nct7904_detect(struct i2c_client *client,
|
|||
|
||||
static const struct hwmon_channel_info *nct7904_info[] = {
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_INPUT, /* dummy, skipped in is_visible */
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT),
|
||||
/* dummy, skipped in is_visible */
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
|
||||
HWMON_I_ALARM),
|
||||
HWMON_CHANNEL_INFO(fan,
|
||||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT,
|
||||
HWMON_F_INPUT),
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
|
||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM),
|
||||
HWMON_CHANNEL_INFO(pwm,
|
||||
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
|
||||
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
|
||||
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
|
||||
HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT,
|
||||
HWMON_T_INPUT),
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST,
|
||||
HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
|
||||
HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
|
||||
HWMON_T_CRIT_HYST),
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -530,11 +913,14 @@ static int nct7904_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->temp_mode = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
val = (ret & (0x03 << i)) >> (i * 2);
|
||||
bit = (1 << i);
|
||||
if (val == 0)
|
||||
data->tcpu_mask &= ~bit;
|
||||
else if (val == 0x1 || val == 0x2)
|
||||
data->temp_mode |= bit;
|
||||
}
|
||||
|
||||
/* PECI */
|
||||
|
@ -557,7 +943,7 @@ static int nct7904_probe(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
data->has_dts = ret & 0xF;
|
||||
if (data->enable_dts & 0x2) {
|
||||
if (data->enable_dts & ENABLE_TSI) {
|
||||
ret = nct7904_read_reg(data, BANK_0, DTS_T_CTRL1_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
@ -967,10 +967,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&data->fan_lock[i]);
|
||||
|
||||
data->fan_irq[i] = platform_get_irq(pdev, i);
|
||||
if (data->fan_irq[i] < 0) {
|
||||
dev_err(dev, "get IRQ fan%d failed\n", i);
|
||||
if (data->fan_irq[i] < 0)
|
||||
return data->fan_irq[i];
|
||||
}
|
||||
|
||||
sprintf(name, "NPCM7XX-FAN-MD%d", i);
|
||||
ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr,
|
||||
|
|
|
@ -46,6 +46,15 @@ config SENSORS_IBM_CFFPS
|
|||
This driver can also be built as a module. If so, the module will
|
||||
be called ibm-cffps.
|
||||
|
||||
config SENSORS_INSPUR_IPSPS
|
||||
tristate "INSPUR Power System Power Supply"
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for the INSPUR
|
||||
Power System power supply.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called inspur-ipsps.
|
||||
|
||||
config SENSORS_IR35221
|
||||
tristate "Infineon IR35221"
|
||||
help
|
||||
|
|
|
@ -7,6 +7,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o
|
|||
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
|
||||
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.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_IR38064) += ir38064.o
|
||||
obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pmbus.h>
|
||||
|
||||
#include "pmbus.h"
|
||||
|
@ -20,8 +21,9 @@
|
|||
#define CFFPS_PN_CMD 0x9B
|
||||
#define CFFPS_SN_CMD 0x9E
|
||||
#define CFFPS_CCIN_CMD 0xBD
|
||||
#define CFFPS_FW_CMD_START 0xFA
|
||||
#define CFFPS_FW_NUM_BYTES 4
|
||||
#define CFFPS_FW_CMD 0xFA
|
||||
#define CFFPS1_FW_NUM_BYTES 4
|
||||
#define CFFPS2_FW_NUM_WORDS 3
|
||||
#define CFFPS_SYS_CONFIG_CMD 0xDA
|
||||
|
||||
#define CFFPS_INPUT_HISTORY_CMD 0xD6
|
||||
|
@ -52,6 +54,8 @@ enum {
|
|||
CFFPS_DEBUGFS_NUM_ENTRIES
|
||||
};
|
||||
|
||||
enum versions { cffps1, cffps2 };
|
||||
|
||||
struct ibm_cffps_input_history {
|
||||
struct mutex update_lock;
|
||||
unsigned long last_update;
|
||||
|
@ -61,6 +65,7 @@ struct ibm_cffps_input_history {
|
|||
};
|
||||
|
||||
struct ibm_cffps {
|
||||
enum versions version;
|
||||
struct i2c_client *client;
|
||||
|
||||
struct ibm_cffps_input_history input_history;
|
||||
|
@ -132,6 +137,8 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
|
|||
struct ibm_cffps *psu = to_psu(idxp, idx);
|
||||
char data[I2C_SMBUS_BLOCK_MAX] = { 0 };
|
||||
|
||||
pmbus_set_page(psu->client, 0);
|
||||
|
||||
switch (idx) {
|
||||
case CFFPS_DEBUGFS_INPUT_HISTORY:
|
||||
return ibm_cffps_read_input_history(psu, buf, count, ppos);
|
||||
|
@ -152,16 +159,36 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
|
|||
rc = snprintf(data, 5, "%04X", rc);
|
||||
goto done;
|
||||
case CFFPS_DEBUGFS_FW:
|
||||
for (i = 0; i < CFFPS_FW_NUM_BYTES; ++i) {
|
||||
rc = i2c_smbus_read_byte_data(psu->client,
|
||||
CFFPS_FW_CMD_START + i);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
switch (psu->version) {
|
||||
case cffps1:
|
||||
for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) {
|
||||
rc = i2c_smbus_read_byte_data(psu->client,
|
||||
CFFPS_FW_CMD +
|
||||
i);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
snprintf(&data[i * 2], 3, "%02X", rc);
|
||||
snprintf(&data[i * 2], 3, "%02X", rc);
|
||||
}
|
||||
|
||||
rc = i * 2;
|
||||
break;
|
||||
case cffps2:
|
||||
for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) {
|
||||
rc = i2c_smbus_read_word_data(psu->client,
|
||||
CFFPS_FW_CMD +
|
||||
i);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
snprintf(&data[i * 4], 5, "%04X", rc);
|
||||
}
|
||||
|
||||
rc = i * 4;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
rc = i * 2;
|
||||
goto done;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -279,6 +306,8 @@ static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
|
|||
psu->led_state = CFFPS_LED_ON;
|
||||
}
|
||||
|
||||
pmbus_set_page(psu->client, 0);
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
|
||||
psu->led_state);
|
||||
if (rc < 0)
|
||||
|
@ -299,6 +328,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
|
|||
if (led_cdev->brightness == LED_OFF)
|
||||
return 0;
|
||||
|
||||
pmbus_set_page(psu->client, 0);
|
||||
|
||||
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
|
||||
CFFPS_LED_BLINK);
|
||||
if (rc < 0)
|
||||
|
@ -328,15 +359,32 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu)
|
|||
dev_warn(dev, "failed to register led class: %d\n", rc);
|
||||
}
|
||||
|
||||
static struct pmbus_driver_info ibm_cffps_info = {
|
||||
.pages = 1,
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
|
||||
PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
|
||||
PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
|
||||
PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
|
||||
PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
|
||||
.read_byte_data = ibm_cffps_read_byte_data,
|
||||
.read_word_data = ibm_cffps_read_word_data,
|
||||
static struct pmbus_driver_info ibm_cffps_info[] = {
|
||||
[cffps1] = {
|
||||
.pages = 1,
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
|
||||
PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
|
||||
PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
|
||||
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
|
||||
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
|
||||
PMBUS_HAVE_STATUS_FAN12,
|
||||
.read_byte_data = ibm_cffps_read_byte_data,
|
||||
.read_word_data = ibm_cffps_read_word_data,
|
||||
},
|
||||
[cffps2] = {
|
||||
.pages = 2,
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
|
||||
PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
|
||||
PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
|
||||
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
|
||||
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
|
||||
PMBUS_HAVE_STATUS_FAN12,
|
||||
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
|
||||
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
|
||||
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT,
|
||||
.read_byte_data = ibm_cffps_read_byte_data,
|
||||
.read_word_data = ibm_cffps_read_word_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct pmbus_platform_data ibm_cffps_pdata = {
|
||||
|
@ -347,12 +395,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i, rc;
|
||||
enum versions vs;
|
||||
struct dentry *debugfs;
|
||||
struct dentry *ibm_cffps_dir;
|
||||
struct ibm_cffps *psu;
|
||||
const void *md = of_device_get_match_data(&client->dev);
|
||||
|
||||
if (md)
|
||||
vs = (enum versions)md;
|
||||
else if (id)
|
||||
vs = (enum versions)id->driver_data;
|
||||
else
|
||||
vs = cffps1;
|
||||
|
||||
client->dev.platform_data = &ibm_cffps_pdata;
|
||||
rc = pmbus_do_probe(client, id, &ibm_cffps_info);
|
||||
rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -364,6 +421,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
|
|||
if (!psu)
|
||||
return 0;
|
||||
|
||||
psu->version = vs;
|
||||
psu->client = client;
|
||||
mutex_init(&psu->input_history.update_lock);
|
||||
psu->input_history.last_update = jiffies - HZ;
|
||||
|
@ -405,13 +463,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
static const struct i2c_device_id ibm_cffps_id[] = {
|
||||
{ "ibm_cffps1", 1 },
|
||||
{ "ibm_cffps1", cffps1 },
|
||||
{ "ibm_cffps2", cffps2 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
|
||||
|
||||
static const struct of_device_id ibm_cffps_of_match[] = {
|
||||
{ .compatible = "ibm,cffps1" },
|
||||
{
|
||||
.compatible = "ibm,cffps1",
|
||||
.data = (void *)cffps1
|
||||
},
|
||||
{
|
||||
.compatible = "ibm,cffps2",
|
||||
.data = (void *)cffps2
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ibm_cffps_of_match);
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright 2019 Inspur Corp.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pmbus.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
#include "pmbus.h"
|
||||
|
||||
#define IPSPS_REG_VENDOR_ID 0x99
|
||||
#define IPSPS_REG_MODEL 0x9A
|
||||
#define IPSPS_REG_FW_VERSION 0x9B
|
||||
#define IPSPS_REG_PN 0x9C
|
||||
#define IPSPS_REG_SN 0x9E
|
||||
#define IPSPS_REG_HW_VERSION 0xB0
|
||||
#define IPSPS_REG_MODE 0xFC
|
||||
|
||||
#define MODE_ACTIVE 0x55
|
||||
#define MODE_STANDBY 0x0E
|
||||
#define MODE_REDUNDANCY 0x00
|
||||
|
||||
#define MODE_ACTIVE_STRING "active"
|
||||
#define MODE_STANDBY_STRING "standby"
|
||||
#define MODE_REDUNDANCY_STRING "redundancy"
|
||||
|
||||
enum ipsps_index {
|
||||
vendor,
|
||||
model,
|
||||
fw_version,
|
||||
part_number,
|
||||
serial_number,
|
||||
hw_version,
|
||||
mode,
|
||||
num_regs,
|
||||
};
|
||||
|
||||
static const u8 ipsps_regs[num_regs] = {
|
||||
[vendor] = IPSPS_REG_VENDOR_ID,
|
||||
[model] = IPSPS_REG_MODEL,
|
||||
[fw_version] = IPSPS_REG_FW_VERSION,
|
||||
[part_number] = IPSPS_REG_PN,
|
||||
[serial_number] = IPSPS_REG_SN,
|
||||
[hw_version] = IPSPS_REG_HW_VERSION,
|
||||
[mode] = IPSPS_REG_MODE,
|
||||
};
|
||||
|
||||
static ssize_t ipsps_string_show(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
u8 reg;
|
||||
int rc;
|
||||
char *p;
|
||||
char data[I2C_SMBUS_BLOCK_MAX + 1];
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
|
||||
reg = ipsps_regs[attr->index];
|
||||
rc = i2c_smbus_read_block_data(client, reg, data);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* filled with printable characters, ending with # */
|
||||
p = memscan(data, '#', rc);
|
||||
*p = '\0';
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", data);
|
||||
}
|
||||
|
||||
static ssize_t ipsps_fw_version_show(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
u8 reg;
|
||||
int rc;
|
||||
u8 data[I2C_SMBUS_BLOCK_MAX] = { 0 };
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
|
||||
reg = ipsps_regs[attr->index];
|
||||
rc = i2c_smbus_read_block_data(client, reg, data);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
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 */);
|
||||
}
|
||||
|
||||
static ssize_t ipsps_mode_show(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
u8 reg;
|
||||
int rc;
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
|
||||
reg = ipsps_regs[attr->index];
|
||||
rc = i2c_smbus_read_byte_data(client, reg);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
switch (rc) {
|
||||
case MODE_ACTIVE:
|
||||
return snprintf(buf, PAGE_SIZE, "[%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);
|
||||
case MODE_REDUNDANCY:
|
||||
return snprintf(buf, PAGE_SIZE, "%s %s [%s]\n",
|
||||
MODE_ACTIVE_STRING,
|
||||
MODE_STANDBY_STRING, MODE_REDUNDANCY_STRING);
|
||||
default:
|
||||
return snprintf(buf, PAGE_SIZE, "unspecified\n");
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ipsps_mode_store(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
u8 reg;
|
||||
int rc;
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
|
||||
reg = ipsps_regs[attr->index];
|
||||
if (sysfs_streq(MODE_STANDBY_STRING, buf)) {
|
||||
rc = i2c_smbus_write_byte_data(client, reg,
|
||||
MODE_STANDBY);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return count;
|
||||
} else if (sysfs_streq(MODE_ACTIVE_STRING, buf)) {
|
||||
rc = i2c_smbus_write_byte_data(client, reg,
|
||||
MODE_ACTIVE);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return count;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR_RO(vendor, ipsps_string, vendor);
|
||||
static SENSOR_DEVICE_ATTR_RO(model, ipsps_string, model);
|
||||
static SENSOR_DEVICE_ATTR_RO(part_number, ipsps_string, part_number);
|
||||
static SENSOR_DEVICE_ATTR_RO(serial_number, ipsps_string, serial_number);
|
||||
static SENSOR_DEVICE_ATTR_RO(hw_version, ipsps_string, hw_version);
|
||||
static SENSOR_DEVICE_ATTR_RO(fw_version, ipsps_fw_version, fw_version);
|
||||
static SENSOR_DEVICE_ATTR_RW(mode, ipsps_mode, mode);
|
||||
|
||||
static struct attribute *ipsps_attrs[] = {
|
||||
&sensor_dev_attr_vendor.dev_attr.attr,
|
||||
&sensor_dev_attr_model.dev_attr.attr,
|
||||
&sensor_dev_attr_part_number.dev_attr.attr,
|
||||
&sensor_dev_attr_serial_number.dev_attr.attr,
|
||||
&sensor_dev_attr_hw_version.dev_attr.attr,
|
||||
&sensor_dev_attr_fw_version.dev_attr.attr,
|
||||
&sensor_dev_attr_mode.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(ipsps);
|
||||
|
||||
static struct pmbus_driver_info ipsps_info = {
|
||||
.pages = 1,
|
||||
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
|
||||
PMBUS_HAVE_IIN | PMBUS_HAVE_POUT | PMBUS_HAVE_PIN |
|
||||
PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
|
||||
PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT |
|
||||
PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT |
|
||||
PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12,
|
||||
.groups = ipsps_groups,
|
||||
};
|
||||
|
||||
static struct pmbus_platform_data ipsps_pdata = {
|
||||
.flags = PMBUS_SKIP_STATUS_CHECK,
|
||||
};
|
||||
|
||||
static int ipsps_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
client->dev.platform_data = &ipsps_pdata;
|
||||
return pmbus_do_probe(client, id, &ipsps_info);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ipsps_id[] = {
|
||||
{ "ipsps1", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ipsps_id);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ipsps_of_match[] = {
|
||||
{ .compatible = "inspur,ipsps1" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ipsps_of_match);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver ipsps_driver = {
|
||||
.driver = {
|
||||
.name = "inspur-ipsps",
|
||||
.of_match_table = of_match_ptr(ipsps_of_match),
|
||||
},
|
||||
.probe = ipsps_probe,
|
||||
.remove = pmbus_do_remove,
|
||||
.id_table = ipsps_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ipsps_driver);
|
||||
|
||||
MODULE_AUTHOR("John Wang");
|
||||
MODULE_DESCRIPTION("PMBus driver for Inspur Power System power supplies");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -244,8 +244,6 @@ static int max31785_write_word_data(struct i2c_client *client, int page,
|
|||
#define MAX31785_VOUT_FUNCS \
|
||||
(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
|
||||
|
||||
#define MAX37185_NUM_FAN_PAGES 6
|
||||
|
||||
static const struct pmbus_driver_info max31785_info = {
|
||||
.pages = MAX31785_NR_PAGES,
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pmbus.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ static struct platform_driver rpi_hwmon_driver = {
|
|||
};
|
||||
module_platform_driver(rpi_hwmon_driver);
|
||||
|
||||
MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>");
|
||||
MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net>");
|
||||
MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:raspberrypi-hwmon");
|
||||
|
|
|
@ -24,19 +24,33 @@ static const unsigned char shtc1_cmd_measure_blocking_lpm[] = { 0x64, 0x58 };
|
|||
static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };
|
||||
|
||||
/* command for reading the ID register */
|
||||
static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 };
|
||||
static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 };
|
||||
|
||||
/* constants for reading the ID register */
|
||||
#define SHTC1_ID 0x07
|
||||
#define SHTC1_ID_REG_MASK 0x1f
|
||||
/*
|
||||
* constants for reading the ID register
|
||||
* SHTC1: 0x0007 with mask 0x003f
|
||||
* SHTW1: 0x0007 with mask 0x003f
|
||||
* SHTC3: 0x0807 with mask 0x083f
|
||||
*/
|
||||
#define SHTC3_ID 0x0807
|
||||
#define SHTC3_ID_MASK 0x083f
|
||||
#define SHTC1_ID 0x0007
|
||||
#define SHTC1_ID_MASK 0x003f
|
||||
|
||||
/* delays for non-blocking i2c commands, both in us */
|
||||
#define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400
|
||||
#define SHTC1_NONBLOCKING_WAIT_TIME_LPM 1000
|
||||
#define SHTC3_NONBLOCKING_WAIT_TIME_HPM 12100
|
||||
#define SHTC3_NONBLOCKING_WAIT_TIME_LPM 800
|
||||
|
||||
#define SHTC1_CMD_LENGTH 2
|
||||
#define SHTC1_RESPONSE_LENGTH 6
|
||||
|
||||
enum shtcx_chips {
|
||||
shtc1,
|
||||
shtc3,
|
||||
};
|
||||
|
||||
struct shtc1_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex update_lock;
|
||||
|
@ -47,6 +61,7 @@ struct shtc1_data {
|
|||
unsigned int nonblocking_wait_time; /* in us */
|
||||
|
||||
struct shtc1_platform_data setup;
|
||||
enum shtcx_chips chip;
|
||||
|
||||
int temperature; /* 1000 * temperature in dgr C */
|
||||
int humidity; /* 1000 * relative humidity in %RH */
|
||||
|
@ -157,13 +172,16 @@ static void shtc1_select_command(struct shtc1_data *data)
|
|||
data->command = data->setup.blocking_io ?
|
||||
shtc1_cmd_measure_blocking_hpm :
|
||||
shtc1_cmd_measure_nonblocking_hpm;
|
||||
data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_HPM;
|
||||
|
||||
data->nonblocking_wait_time = (data->chip == shtc1) ?
|
||||
SHTC1_NONBLOCKING_WAIT_TIME_HPM :
|
||||
SHTC3_NONBLOCKING_WAIT_TIME_HPM;
|
||||
} else {
|
||||
data->command = data->setup.blocking_io ?
|
||||
shtc1_cmd_measure_blocking_lpm :
|
||||
shtc1_cmd_measure_nonblocking_lpm;
|
||||
data->nonblocking_wait_time = SHTC1_NONBLOCKING_WAIT_TIME_LPM;
|
||||
data->nonblocking_wait_time = (data->chip == shtc1) ?
|
||||
SHTC1_NONBLOCKING_WAIT_TIME_LPM :
|
||||
SHTC3_NONBLOCKING_WAIT_TIME_LPM;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,9 +189,11 @@ static int shtc1_probe(struct i2c_client *client,
|
|||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
char id_reg[2];
|
||||
u16 id_reg;
|
||||
char id_reg_buf[2];
|
||||
struct shtc1_data *data;
|
||||
struct device *hwmon_dev;
|
||||
enum shtcx_chips chip = id->driver_data;
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct device *dev = &client->dev;
|
||||
|
||||
|
@ -187,13 +207,20 @@ static int shtc1_probe(struct i2c_client *client,
|
|||
dev_err(dev, "could not send read_id_reg command: %d\n", ret);
|
||||
return ret < 0 ? ret : -ENODEV;
|
||||
}
|
||||
ret = i2c_master_recv(client, id_reg, sizeof(id_reg));
|
||||
if (ret != sizeof(id_reg)) {
|
||||
ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf));
|
||||
if (ret != sizeof(id_reg_buf)) {
|
||||
dev_err(dev, "could not read ID register: %d\n", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((id_reg[1] & SHTC1_ID_REG_MASK) != SHTC1_ID) {
|
||||
dev_err(dev, "ID register doesn't match\n");
|
||||
|
||||
id_reg = be16_to_cpup((__be16 *)id_reg_buf);
|
||||
if (chip == shtc3) {
|
||||
if ((id_reg & SHTC3_ID_MASK) != SHTC3_ID) {
|
||||
dev_err(dev, "SHTC3 ID register does not match\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if ((id_reg & SHTC1_ID_MASK) != SHTC1_ID) {
|
||||
dev_err(dev, "SHTC1 ID register does not match\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -204,6 +231,7 @@ static int shtc1_probe(struct i2c_client *client,
|
|||
data->setup.blocking_io = false;
|
||||
data->setup.high_precision = true;
|
||||
data->client = client;
|
||||
data->chip = chip;
|
||||
|
||||
if (client->dev.platform_data)
|
||||
data->setup = *(struct shtc1_platform_data *)dev->platform_data;
|
||||
|
@ -222,8 +250,9 @@ static int shtc1_probe(struct i2c_client *client,
|
|||
|
||||
/* device ID table */
|
||||
static const struct i2c_device_id shtc1_id[] = {
|
||||
{ "shtc1", 0 },
|
||||
{ "shtw1", 0 },
|
||||
{ "shtc1", shtc1 },
|
||||
{ "shtw1", shtc1 },
|
||||
{ "shtc3", shtc3 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, shtc1_id);
|
||||
|
|
|
@ -586,10 +586,10 @@ static int smm665_probe(struct i2c_client *client,
|
|||
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
data->cmdreg = i2c_new_dummy(adapter, (client->addr & ~SMM665_REGMASK)
|
||||
data->cmdreg = i2c_new_dummy_device(adapter, (client->addr & ~SMM665_REGMASK)
|
||||
| SMM665_CMDREG_BASE);
|
||||
if (!data->cmdreg)
|
||||
return -ENOMEM;
|
||||
if (IS_ERR(data->cmdreg))
|
||||
return PTR_ERR(data->cmdreg);
|
||||
|
||||
switch (data->type) {
|
||||
case smm465:
|
||||
|
|
|
@ -894,12 +894,12 @@ w83781d_detect_subclients(struct i2c_client *new_client)
|
|||
}
|
||||
|
||||
for (i = 0; i < num_sc; i++) {
|
||||
data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]);
|
||||
if (!data->lm75[i]) {
|
||||
data->lm75[i] = i2c_new_dummy_device(adapter, sc_addr[i]);
|
||||
if (IS_ERR(data->lm75[i])) {
|
||||
dev_err(&new_client->dev,
|
||||
"Subclient %d registration at address 0x%x failed.\n",
|
||||
i, sc_addr[i]);
|
||||
err = -ENOMEM;
|
||||
err = PTR_ERR(data->lm75[i]);
|
||||
if (i == 1)
|
||||
goto ERROR_SC_3;
|
||||
goto ERROR_SC_2;
|
||||
|
|
|
@ -1260,7 +1260,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
|
|||
struct i2c_adapter *adapter = client->adapter;
|
||||
struct w83791d_data *data = i2c_get_clientdata(client);
|
||||
int address = client->addr;
|
||||
int i, id, err;
|
||||
int i, id;
|
||||
u8 val;
|
||||
|
||||
id = i2c_adapter_id(adapter);
|
||||
|
@ -1272,8 +1272,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
|
|||
"invalid subclient "
|
||||
"address %d; must be 0x48-0x4f\n",
|
||||
force_subclients[i]);
|
||||
err = -ENODEV;
|
||||
goto error_sc_0;
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
w83791d_write(client, W83791D_REG_I2C_SUBADDR,
|
||||
|
@ -1283,29 +1282,22 @@ static int w83791d_detect_subclients(struct i2c_client *client)
|
|||
|
||||
val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
|
||||
if (!(val & 0x08))
|
||||
data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
|
||||
data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
|
||||
0x48 + (val & 0x7));
|
||||
if (!(val & 0x80)) {
|
||||
if ((data->lm75[0] != NULL) &&
|
||||
if (!IS_ERR(data->lm75[0]) &&
|
||||
((val & 0x7) == ((val >> 4) & 0x7))) {
|
||||
dev_err(&client->dev,
|
||||
"duplicate addresses 0x%x, "
|
||||
"use force_subclient\n",
|
||||
data->lm75[0]->addr);
|
||||
err = -ENODEV;
|
||||
goto error_sc_1;
|
||||
return -ENODEV;
|
||||
}
|
||||
data->lm75[1] = i2c_new_dummy(adapter,
|
||||
0x48 + ((val >> 4) & 0x7));
|
||||
data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
|
||||
0x48 + ((val >> 4) & 0x7));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* Undo inits in case of errors */
|
||||
|
||||
error_sc_1:
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
error_sc_0:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1394,7 +1386,7 @@ static int w83791d_probe(struct i2c_client *client,
|
|||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &w83791d_group);
|
||||
if (err)
|
||||
goto error3;
|
||||
return err;
|
||||
|
||||
/* Check if pins of fan/pwm 4-5 are in use as GPIO */
|
||||
has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10;
|
||||
|
@ -1419,9 +1411,6 @@ error5:
|
|||
sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45);
|
||||
error4:
|
||||
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
|
||||
error3:
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
i2c_unregister_device(data->lm75[1]);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1432,9 +1421,6 @@ static int w83791d_remove(struct i2c_client *client)
|
|||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
|
||||
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
i2c_unregister_device(data->lm75[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -924,7 +924,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
|
|||
static int
|
||||
w83792d_detect_subclients(struct i2c_client *new_client)
|
||||
{
|
||||
int i, id, err;
|
||||
int i, id;
|
||||
int address = new_client->addr;
|
||||
u8 val;
|
||||
struct i2c_adapter *adapter = new_client->adapter;
|
||||
|
@ -938,8 +938,7 @@ w83792d_detect_subclients(struct i2c_client *new_client)
|
|||
dev_err(&new_client->dev,
|
||||
"invalid subclient address %d; must be 0x48-0x4f\n",
|
||||
force_subclients[i]);
|
||||
err = -ENODEV;
|
||||
goto ERROR_SC_0;
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
|
||||
|
@ -949,28 +948,21 @@ w83792d_detect_subclients(struct i2c_client *new_client)
|
|||
|
||||
val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
|
||||
if (!(val & 0x08))
|
||||
data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
|
||||
data->lm75[0] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
|
||||
0x48 + (val & 0x7));
|
||||
if (!(val & 0x80)) {
|
||||
if ((data->lm75[0] != NULL) &&
|
||||
if (!IS_ERR(data->lm75[0]) &&
|
||||
((val & 0x7) == ((val >> 4) & 0x7))) {
|
||||
dev_err(&new_client->dev,
|
||||
"duplicate addresses 0x%x, use force_subclient\n",
|
||||
data->lm75[0]->addr);
|
||||
err = -ENODEV;
|
||||
goto ERROR_SC_1;
|
||||
return -ENODEV;
|
||||
}
|
||||
data->lm75[1] = i2c_new_dummy(adapter,
|
||||
0x48 + ((val >> 4) & 0x7));
|
||||
data->lm75[1] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
|
||||
0x48 + ((val >> 4) & 0x7));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* Undo inits in case of errors */
|
||||
|
||||
ERROR_SC_1:
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
ERROR_SC_0:
|
||||
return err;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
|
||||
|
@ -1396,7 +1388,7 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&dev->kobj, &w83792d_group);
|
||||
if (err)
|
||||
goto exit_i2c_unregister;
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Read GPIO enable register to check if pins for fan 4,5 are used as
|
||||
|
@ -1441,9 +1433,6 @@ exit_remove_files:
|
|||
sysfs_remove_group(&dev->kobj, &w83792d_group);
|
||||
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
|
||||
sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
|
||||
exit_i2c_unregister:
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
i2c_unregister_device(data->lm75[1]);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1459,9 +1448,6 @@ w83792d_remove(struct i2c_client *client)
|
|||
sysfs_remove_group(&client->dev.kobj,
|
||||
&w83792d_group_fan[i]);
|
||||
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
i2c_unregister_device(data->lm75[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1551,9 +1551,6 @@ static int w83793_remove(struct i2c_client *client)
|
|||
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
|
||||
device_remove_file(dev, &w83793_temp[i].dev_attr);
|
||||
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
i2c_unregister_device(data->lm75[1]);
|
||||
|
||||
/* Decrease data reference counter */
|
||||
mutex_lock(&watchdog_data_mutex);
|
||||
kref_put(&data->kref, w83793_release_resources);
|
||||
|
@ -1565,7 +1562,7 @@ static int w83793_remove(struct i2c_client *client)
|
|||
static int
|
||||
w83793_detect_subclients(struct i2c_client *client)
|
||||
{
|
||||
int i, id, err;
|
||||
int i, id;
|
||||
int address = client->addr;
|
||||
u8 tmp;
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
|
@ -1580,8 +1577,7 @@ w83793_detect_subclients(struct i2c_client *client)
|
|||
"invalid subclient "
|
||||
"address %d; must be 0x48-0x4f\n",
|
||||
force_subclients[i]);
|
||||
err = -EINVAL;
|
||||
goto ERROR_SC_0;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
w83793_write_value(client, W83793_REG_I2C_SUBADDR,
|
||||
|
@ -1591,28 +1587,21 @@ w83793_detect_subclients(struct i2c_client *client)
|
|||
|
||||
tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
|
||||
if (!(tmp & 0x08))
|
||||
data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7));
|
||||
data->lm75[0] = devm_i2c_new_dummy_device(&client->dev, adapter,
|
||||
0x48 + (tmp & 0x7));
|
||||
if (!(tmp & 0x80)) {
|
||||
if ((data->lm75[0] != NULL)
|
||||
if (!IS_ERR(data->lm75[0])
|
||||
&& ((tmp & 0x7) == ((tmp >> 4) & 0x7))) {
|
||||
dev_err(&client->dev,
|
||||
"duplicate addresses 0x%x, "
|
||||
"use force_subclients\n", data->lm75[0]->addr);
|
||||
err = -ENODEV;
|
||||
goto ERROR_SC_1;
|
||||
return -ENODEV;
|
||||
}
|
||||
data->lm75[1] = i2c_new_dummy(adapter,
|
||||
0x48 + ((tmp >> 4) & 0x7));
|
||||
data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
|
||||
0x48 + ((tmp >> 4) & 0x7));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
/* Undo inits in case of errors */
|
||||
|
||||
ERROR_SC_1:
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
ERROR_SC_0:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
|
@ -1945,9 +1934,6 @@ exit_remove:
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
|
||||
device_remove_file(dev, &w83793_temp[i].dev_attr);
|
||||
|
||||
i2c_unregister_device(data->lm75[0]);
|
||||
i2c_unregister_device(data->lm75[1]);
|
||||
free_mem:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
|
|
@ -958,7 +958,7 @@ config TI_ADC161S626
|
|||
|
||||
config TI_ADS1015
|
||||
tristate "Texas Instruments ADS1015 ADC"
|
||||
depends on I2C && !SENSORS_ADS1015
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
|
|
|
@ -548,6 +548,7 @@
|
|||
#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
|
||||
#define PCI_DEVICE_ID_AMD_17H_M10H_DF_F3 0x15eb
|
||||
#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F3 0x1493
|
||||
#define PCI_DEVICE_ID_AMD_17H_M70H_DF_F3 0x1443
|
||||
#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703
|
||||
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
|
||||
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
|
||||
|
|
Загрузка…
Ссылка в новой задаче