Commit 6729fb66 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 8e97be2a 4e19e72f
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>;
};
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: 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 - reg = < I2C bus address >; : Address of the power supply on the
I2C bus. I2C bus.
......
...@@ -15,6 +15,7 @@ Required properties: ...@@ -15,6 +15,7 @@ Required properties:
"maxim,max31725", "maxim,max31725",
"maxim,max31726", "maxim,max31726",
"maxim,mcp980x", "maxim,mcp980x",
"nxp,pct2075",
"st,stds75", "st,stds75",
"st,stlm75", "st,stlm75",
"microchip,tcn75", "microchip,tcn75",
......
...@@ -104,6 +104,8 @@ properties: ...@@ -104,6 +104,8 @@ properties:
- infineon,slb9645tt - infineon,slb9645tt
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor # Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
- infineon,tlv493d-a1b6 - infineon,tlv493d-a1b6
# Inspur Power System power supply unit version 1
- inspur,ipsps1
# Intersil ISL29028 Ambient Light and Proximity Sensor # Intersil ISL29028 Ambient Light and Proximity Sensor
- isil,isl29028 - isil,isl29028
# Intersil ISL29030 Ambient Light and Proximity Sensor # Intersil ISL29030 Ambient Light and Proximity Sensor
......
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 ...@@ -30,7 +30,6 @@ Hardware Monitoring Kernel Drivers
adm1031 adm1031
adm1275 adm1275
adm9240 adm9240
ads1015
ads7828 ads7828
adt7410 adt7410
adt7411 adt7411
...@@ -130,6 +129,7 @@ Hardware Monitoring Kernel Drivers ...@@ -130,6 +129,7 @@ Hardware Monitoring Kernel Drivers
pcf8591 pcf8591
pmbus pmbus
powr1220 powr1220
pxe1610
pwm-fan pwm-fan
raspberrypi-hwmon raspberrypi-hwmon
sch5627 sch5627
......
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: ...@@ -119,9 +119,9 @@ Supported chips:
http://www.ti.com/product/tmp275 http://www.ti.com/product/tmp275
* NXP LM75B * NXP LM75B, PCT2075
Prefix: 'lm75b' Prefix: 'lm75b', 'pct2075'
Addresses scanned: none Addresses scanned: none
...@@ -129,6 +129,8 @@ Supported chips: ...@@ -129,6 +129,8 @@ Supported chips:
http://www.nxp.com/documents/data_sheet/LM75B.pdf 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> Author: Frodo Looijaard <frodol@dds.nl>
Description Description
......
...@@ -2,19 +2,29 @@ Kernel driver pxe1610 ...@@ -2,19 +2,29 @@ Kernel driver pxe1610
===================== =====================
Supported chips: Supported chips:
* Infineon PXE1610 * Infineon PXE1610
Prefix: 'pxe1610' Prefix: 'pxe1610'
Addresses scanned: - Addresses scanned: -
Datasheet: Datasheet is not publicly available. Datasheet: Datasheet is not publicly available.
* Infineon PXE1110 * Infineon PXE1110
Prefix: 'pxe1110' Prefix: 'pxe1110'
Addresses scanned: - Addresses scanned: -
Datasheet: Datasheet is not publicly available. Datasheet: Datasheet is not publicly available.
* Infineon PXM1310 * Infineon PXM1310
Prefix: 'pxm1310' Prefix: 'pxm1310'
Addresses scanned: - Addresses scanned: -
Datasheet: Datasheet is not publicly available. Datasheet: Datasheet is not publicly available.
Author: Vijay Khemka <vijaykhemka@fb.com> Author: Vijay Khemka <vijaykhemka@fb.com>
...@@ -25,14 +35,19 @@ Description ...@@ -25,14 +35,19 @@ Description
PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers PXE1610/PXE1110 are Multi-rail/Multiphase Digital Controllers
and compliant to 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 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 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 Used for DDR3/DDR4 Memory power regulation for Intel VR13 and
IMVP8 based systems IMVP8 based systems
...@@ -44,10 +59,10 @@ This driver does not probe for PMBus devices. You will have ...@@ -44,10 +59,10 @@ This driver does not probe for PMBus devices. You will have
to instantiate devices explicitly. to instantiate devices explicitly.
Example: the following commands will load the driver for an PXE1610 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 # modprobe pxe1610
# echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device # echo pxe1610 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
It can also be instantiated by declaring in device tree It can also be instantiated by declaring in device tree
...@@ -55,6 +70,7 @@ 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 Sysfs attributes
---------------- ----------------
====================== ====================================
curr1_label "iin" curr1_label "iin"
curr1_input Measured input current curr1_input Measured input current
curr1_alarm Current high alarm curr1_alarm Current high alarm
...@@ -88,3 +104,4 @@ temp[1-3]_crit Critical high temperature ...@@ -88,3 +104,4 @@ temp[1-3]_crit Critical high temperature
temp[1-3]_crit_alarm Chip temperature critical high alarm temp[1-3]_crit_alarm Chip temperature critical high alarm
temp[1-3]_max Maximum temperature temp[1-3]_max Maximum temperature
temp[1-3]_max_alarm Chip temperature high alarm temp[1-3]_max_alarm Chip temperature high alarm
====================== ====================================
...@@ -19,7 +19,17 @@ Supported chips: ...@@ -19,7 +19,17 @@ Supported chips:
Addresses scanned: none 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: ...@@ -30,10 +40,9 @@ Author:
Description Description
----------- -----------
This driver implements support for the Sensirion SHTC1 chip, a humidity and This driver implements support for the Sensirion SHTC1, SHTW1, and SHTC3
temperature sensor. Temperature is measured in degrees celsius, relative chips, a humidity and temperature sensor. Temperature is measured in degrees
humidity is expressed as a percentage. Driver can be used as well for SHTW1 celsius, relative humidity is expressed as a percentage.
chip, which has the same electrical interface.
The device communicates with the I2C protocol. All sensors are set to I2C The device communicates with the I2C protocol. All sensors are set to I2C
address 0x70. See Documentation/i2c/instantiating-devices for methods to address 0x70. See Documentation/i2c/instantiating-devices for methods to
......
...@@ -20,6 +20,10 @@ increase the chances of your change being accepted. ...@@ -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 errors, no warnings, and few if any check messages. If there are any
messages, please be prepared to explain. 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, * If your patch generates checkpatch errors, warnings, or check messages,
please refrain from explanations such as "I prefer that coding style". please refrain from explanations such as "I prefer that coding style".
Keep in mind that each unnecessary message helps hiding a real problem, Keep in mind that each unnecessary message helps hiding a real problem,
...@@ -120,8 +124,8 @@ increase the chances of your change being accepted. ...@@ -120,8 +124,8 @@ increase the chances of your change being accepted.
completely initialize your chip and your driver first, then register with completely initialize your chip and your driver first, then register with
the hwmon subsystem. the hwmon subsystem.
* Use devm_hwmon_device_register_with_groups() or, if your driver needs a remove * Use devm_hwmon_device_register_with_info() or, if your driver needs a remove
function, hwmon_device_register_with_groups() to register your driver with the 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 hwmon subsystem. Try using devm_add_action() instead of a remove function if
possible. Do not use hwmon_device_register(). possible. Do not use hwmon_device_register().
......
...@@ -517,14 +517,6 @@ W: http://ez.analog.com/community/linux-device-drivers ...@@ -517,14 +517,6 @@ W: http://ez.analog.com/community/linux-device-drivers
S: Supported S: Supported
F: drivers/video/backlight/adp8860_bl.c 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 ADT746X FAN DRIVER
M: Colin Leroy <colin@colino.net> M: Colin Leroy <colin@colino.net>
S: Maintained S: Maintained
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define PCI_DEVICE_ID_AMD_17H_DF_F4 0x1464 #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_M10H_DF_F4 0x15ec
#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F4 0x1494 #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. */ /* Protect the PCI config register pairs used for SMN and DF indirect access. */
static DEFINE_MUTEX(smn_mutex); static DEFINE_MUTEX(smn_mutex);
...@@ -50,6 +51,7 @@ const struct pci_device_id amd_nb_misc_ids[] = { ...@@ -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_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_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_CNB17H_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
{} {}
}; };
EXPORT_SYMBOL_GPL(amd_nb_misc_ids); EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
...@@ -63,6 +65,7 @@ static const struct pci_device_id amd_nb_link_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_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_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_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) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CNB17H_F4) },
{} {}
}; };
......
...@@ -246,6 +246,16 @@ config SENSORS_ADT7475 ...@@ -246,6 +246,16 @@ config SENSORS_ADT7475
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called adt7475. 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 config SENSORS_ASC7621
tristate "Andigilog aSC7621" tristate "Andigilog aSC7621"
depends on I2C depends on I2C
...@@ -1382,8 +1392,8 @@ config SENSORS_SHTC1 ...@@ -1382,8 +1392,8 @@ config SENSORS_SHTC1
tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
depends on I2C depends on I2C
help help
If you say yes here you get support for the Sensiron SHTC1 and SHTW1 If you say yes here you get support for the Sensiron SHTC1, SHTW1,
humidity and temperature sensors. and SHTC3 humidity and temperature sensors.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called shtc1. will be called shtc1.
...@@ -1570,16 +1580,6 @@ config SENSORS_ADC128D818 ...@@ -1570,16 +1580,6 @@ config SENSORS_ADC128D818
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called adc128d818. 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 config SENSORS_ADS7828
tristate "Texas Instruments ADS7828 and compatibles" tristate "Texas Instruments ADS7828 and compatibles"
depends on I2C depends on I2C
...@@ -1834,17 +1834,12 @@ config SENSORS_W83795 ...@@ -1834,17 +1834,12 @@ config SENSORS_W83795
will be called w83795. will be called w83795.
config SENSORS_W83795_FANCTRL config SENSORS_W83795_FANCTRL
bool "Include automatic fan control support (DANGEROUS)" bool "Include automatic fan control support"
depends on SENSORS_W83795 depends on SENSORS_W83795
help help
If you say yes here, support for automatic fan speed control If you say yes here, support for automatic fan speed control
will be included in the driver. 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 Please also note that this option will create sysfs attribute
files which may change in the future, so you shouldn't rely files which may change in the future, so you shouldn't rely
on them being stable. on them being stable.
......
...@@ -35,7 +35,6 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o ...@@ -35,7 +35,6 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
obj-$(CONFIG_SENSORS_ADT7X10) += adt7x10.o obj-$(CONFIG_SENSORS_ADT7X10) += adt7x10.o
...@@ -48,6 +47,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o ...@@ -48,6 +47,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o obj-$(CONFIG_SENSORS_ARM_SCMI) += scmi-hwmon.o
obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-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_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
......
...@@ -681,7 +681,7 @@ static int setup_attrs(struct acpi_power_meter_resource *resource) ...@@ -681,7 +681,7 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
if (resource->caps.flags & POWER_METER_CAN_CAP) { if (resource->caps.flags & POWER_METER_CAN_CAP) {
if (!can_cap_in_hardware()) { if (!can_cap_in_hardware()) {
dev_err(&resource->acpi_dev->dev, dev_warn(&resource->acpi_dev->dev,
"Ignoring unsafe software power cap!\n"); "Ignoring unsafe software power cap!\n");
goto skip_unsafe_cap; goto skip_unsafe_cap;
} }
......
// 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");
This diff is collapsed.
// 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) ...@@ -706,21 +706,21 @@ static int asb100_detect_subclients(struct i2c_client *client)
goto ERROR_SC_2; goto ERROR_SC_2;
} }
data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]); data->lm75[0] = i2c_new_dummy_device(adapter, sc_addr[0]);
if (!data->lm75[0]) { if (IS_ERR(data->lm75[0])) {
dev_err(&client->dev, dev_err(&client->dev,
"subclient %d registration at address 0x%x failed.\n", "subclient %d registration at address 0x%x failed.\n",
1, sc_addr[0]); 1, sc_addr[0]);
err = -ENOMEM; err = PTR_ERR(data->lm75[0]);
goto ERROR_SC_2; goto ERROR_SC_2;
} }
data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]); data->lm75[1] = i2c_new_dummy_device(adapter, sc_addr[1]);
if (!data->lm75[1]) { if (IS_ERR(data->lm75[1])) {
dev_err(&client->dev, dev_err(&client->dev,
"subclient %d registration at address 0x%x failed.\n", "subclient %d registration at address 0x%x failed.\n",
2, sc_addr[1]); 2, sc_addr[1]);
err = -ENOMEM; err = PTR_ERR(data->lm75[1]);
goto ERROR_SC_3; goto ERROR_SC_3;
} }
......
...@@ -736,7 +736,7 @@ static int __init coretemp_init(void) ...@@ -736,7 +736,7 @@ static int __init coretemp_init(void)
err = platform_driver_register(&coretemp_driver); err = platform_driver_register(&coretemp_driver);
if (err) if (err)
return err; goto outzone;
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online", err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hwmon/coretemp:online",
coretemp_cpu_online, coretemp_cpu_offline); coretemp_cpu_online, coretemp_cpu_offline);
...@@ -747,6 +747,7 @@ static int __init coretemp_init(void) ...@@ -747,6 +747,7 @@ static int __init coretemp_init(void)
outdrv: outdrv:
platform_driver_unregister(&coretemp_driver); platform_driver_unregister(&coretemp_driver);
outzone:
kfree(zone_devices); kfree(zone_devices);
return err; return err;
} }
......
...@@ -44,12 +44,20 @@ static ssize_t iio_hwmon_read_val(struct device *dev, ...@@ -44,12 +44,20 @@ static ssize_t iio_hwmon_read_val(struct device *dev,
int ret; int ret;
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
struct iio_hwmon_state *state = dev_get_drvdata(dev); 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(chan, &result);
if (ret < 0)
return ret;
ret = iio_read_channel_processed(&state->channels[sattr->index], ret = iio_get_channel_type(chan, &type);
&result);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (type == IIO_POWER)
result *= 1000; /* mili-Watts to micro-Watts conversion */
return sprintf(buf, "%d\n", result); return sprintf(buf, "%d\n", result);
} }
...@@ -59,7 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev) ...@@ -59,7 +67,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
struct iio_hwmon_state *st; struct iio_hwmon_state *st;
struct sensor_device_attribute *a; struct sensor_device_attribute *a;
int ret, i; 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; enum iio_chan_type type;
struct iio_channel *channels; struct iio_channel *channels;
struct device *hwmon_dev; struct device *hwmon_dev;
...@@ -114,6 +122,10 @@ static int iio_hwmon_probe(struct platform_device *pdev) ...@@ -114,6 +122,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
n = curr_i++; n = curr_i++;
prefix = "curr"; prefix = "curr";
break; break;
case IIO_POWER:
n = power_i++;
prefix = "power";
break;
case IIO_HUMIDITYRELATIVE: case IIO_HUMIDITYRELATIVE:
n = humidity_i++; n = humidity_i++;
prefix = "humidity"; prefix = "humidity";
......
...@@ -349,6 +349,7 @@ static const struct pci_device_id k10temp_id_table[] = { ...@@ -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_DF_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_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_M30H_DF_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
{ PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) }, { PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
{} {}
}; };
......
...@@ -10,10 +10,8 @@ ...@@ -10,10 +10,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -24,108 +22,18 @@ ...@@ -24,108 +22,18 @@
#define SEL_CORE 0x04 #define SEL_CORE 0x04
struct k8temp_data { struct k8temp_data {
struct device *hwmon_dev;
struct mutex update_lock; struct mutex update_lock;
const char *name;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* registers values */ /* registers values */
u8 sensorsp; /* sensor presence bits - SEL_CORE, SEL_PLACE */ 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 */ u8 swap_core_select; /* meaning of SEL_CORE is inverted */
u32 temp_offset; 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[] = { static const struct pci_device_id k8temp_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
{ 0 }, { 0 },
}; };
MODULE_DEVICE_TABLE(pci, k8temp_ids); MODULE_DEVICE_TABLE(pci, k8temp_ids);
static int is_rev_g_desktop(u8 model) static int is_rev_g_desktop(u8 model)
...@@ -159,14 +67,76 @@ static int is_rev_g_desktop(u8 model) ...@@ -159,14 +67,76 @@ static int is_rev_g_desktop(u8 model)
return 1; 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, static int k8temp_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
int err;
u8 scfg; u8 scfg;
u32 temp; u32 temp;
u8 model, stepping; u8 model, stepping;
struct k8temp_data *data; struct k8temp_data *data;
struct device *hwmon_dev;
data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL); data = devm_kzalloc(&pdev->dev, sizeof(struct k8temp_data), GFP_KERNEL);
if (!data) if (!data)
...@@ -231,86 +201,21 @@ static int k8temp_probe(struct pci_dev *pdev, ...@@ -231,86 +201,21 @@ static int k8temp_probe(struct pci_dev *pdev,
data->sensorsp &= ~SEL_CORE; data->sensorsp &= ~SEL_CORE;
} }
data->name = "k8temp";
mutex_init(&data->update_lock); 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;
/* 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)) { hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
err = PTR_ERR(data->hwmon_dev); "k8temp",
goto exit_remove; data,
} &k8temp_chip_info,
NULL);
return 0;
exit_remove: return PTR_ERR_OR_ZERO(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 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);
} }
static struct pci_driver k8temp_driver = { static struct pci_driver k8temp_driver = {
.name = "k8temp", .name = "k8temp",
.id_table = k8temp_ids, .id_table = k8temp_ids,
.probe = k8temp_probe, .probe = k8temp_probe,
.remove = k8temp_remove,
}; };
module_pci_driver(k8temp_driver); module_pci_driver(k8temp_driver);
......
This diff is collapsed.
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/property.h>
#define LTC2990_STATUS 0x00 #define LTC2990_STATUS 0x00
#define LTC2990_CONTROL 0x01 #define LTC2990_CONTROL 0x01
...@@ -206,7 +206,6 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c, ...@@ -206,7 +206,6 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
int ret; int ret;
struct device *hwmon_dev; struct device *hwmon_dev;
struct ltc2990_data *data; struct ltc2990_data *data;
struct device_node *of_node = i2c->dev.of_node;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA)) I2C_FUNC_SMBUS_WORD_DATA))
...@@ -218,8 +217,9 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c, ...@@ -218,8 +217,9 @@ static int ltc2990_i2c_probe(struct i2c_client *i2c,
data->i2c = i2c; data->i2c = i2c;
if (of_node) { if (dev_fwnode(&i2c->dev)) {
ret = of_property_read_u32_array(of_node, "lltc,meas-mode", ret = device_property_read_u32_array(&i2c->dev,
"lltc,meas-mode",
data->mode, 2); data->mode, 2);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
This diff is collapsed.
This diff is collapsed.
...@@ -967,10 +967,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev) ...@@ -967,10 +967,8 @@ static int npcm7xx_pwm_fan_probe(struct platform_device *pdev)
spin_lock_init(&data->fan_lock[i]); spin_lock_init(&data->fan_lock[i]);
data->fan_irq[i] = platform_get_irq(pdev, i); data->fan_irq[i] = platform_get_irq(pdev, i);
if (data->fan_irq[i] < 0) { if (data->fan_irq[i] < 0)
dev_err(dev, "get IRQ fan%d failed\n", i);
return data->fan_irq[i]; return data->fan_irq[i];
}
sprintf(name, "NPCM7XX-FAN-MD%d", i); sprintf(name, "NPCM7XX-FAN-MD%d", i);
ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr, ret = devm_request_irq(dev, data->fan_irq[i], npcm7xx_fan_isr,
......
...@@ -46,6 +46,15 @@ config SENSORS_IBM_CFFPS ...@@ -46,6 +46,15 @@ config SENSORS_IBM_CFFPS
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called ibm-cffps. 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 config SENSORS_IR35221
tristate "Infineon IR35221" tristate "Infineon IR35221"
help help
......
...@@ -7,6 +7,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o ...@@ -7,6 +7,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.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_IR35221) += ir35221.o
obj-$(CONFIG_SENSORS_IR38064) += ir38064.o obj-$(CONFIG_SENSORS_IR38064) += ir38064.o
obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o obj-$(CONFIG_SENSORS_IRPS5401) += irps5401.o
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/pmbus.h> #include <linux/pmbus.h>
#include "pmbus.h" #include "pmbus.h"
...@@ -20,8 +21,9 @@ ...@@ -20,8 +21,9 @@
#define CFFPS_PN_CMD 0x9B #define CFFPS_PN_CMD 0x9B
#define CFFPS_SN_CMD 0x9E #define CFFPS_SN_CMD 0x9E
#define CFFPS_CCIN_CMD 0xBD #define CFFPS_CCIN_CMD 0xBD
#define CFFPS_FW_CMD_START 0xFA #define CFFPS_FW_CMD 0xFA
#define CFFPS_FW_NUM_BYTES 4 #define CFFPS1_FW_NUM_BYTES 4
#define CFFPS2_FW_NUM_WORDS 3
#define CFFPS_SYS_CONFIG_CMD 0xDA #define CFFPS_SYS_CONFIG_CMD 0xDA
#define CFFPS_INPUT_HISTORY_CMD 0xD6 #define CFFPS_INPUT_HISTORY_CMD 0xD6
...@@ -52,6 +54,8 @@ enum { ...@@ -52,6 +54,8 @@ enum {
CFFPS_DEBUGFS_NUM_ENTRIES CFFPS_DEBUGFS_NUM_ENTRIES
}; };
enum versions { cffps1, cffps2 };
struct ibm_cffps_input_history { struct ibm_cffps_input_history {
struct mutex update_lock; struct mutex update_lock;
unsigned long last_update; unsigned long last_update;
...@@ -61,6 +65,7 @@ struct ibm_cffps_input_history { ...@@ -61,6 +65,7 @@ struct ibm_cffps_input_history {
}; };
struct ibm_cffps { struct ibm_cffps {
enum versions version;
struct i2c_client *client; struct i2c_client *client;
struct ibm_cffps_input_history input_history; struct ibm_cffps_input_history input_history;
...@@ -132,6 +137,8 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf, ...@@ -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); struct ibm_cffps *psu = to_psu(idxp, idx);
char data[I2C_SMBUS_BLOCK_MAX] = { 0 }; char data[I2C_SMBUS_BLOCK_MAX] = { 0 };
pmbus_set_page(psu->client, 0);
switch (idx) { switch (idx) {
case CFFPS_DEBUGFS_INPUT_HISTORY: case CFFPS_DEBUGFS_INPUT_HISTORY:
return ibm_cffps_read_input_history(psu, buf, count, ppos); return ibm_cffps_read_input_history(psu, buf, count, ppos);
...@@ -152,9 +159,12 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf, ...@@ -152,9 +159,12 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
rc = snprintf(data, 5, "%04X", rc); rc = snprintf(data, 5, "%04X", rc);
goto done; goto done;
case CFFPS_DEBUGFS_FW: case CFFPS_DEBUGFS_FW:
for (i = 0; i < CFFPS_FW_NUM_BYTES; ++i) { switch (psu->version) {
case cffps1:
for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) {
rc = i2c_smbus_read_byte_data(psu->client, rc = i2c_smbus_read_byte_data(psu->client,
CFFPS_FW_CMD_START + i); CFFPS_FW_CMD +
i);
if (rc < 0) if (rc < 0)
return rc; return rc;
...@@ -162,6 +172,23 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf, ...@@ -162,6 +172,23 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
} }
rc = i * 2; 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;
}
goto done; goto done;
default: default:
return -EINVAL; return -EINVAL;
...@@ -279,6 +306,8 @@ static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev, ...@@ -279,6 +306,8 @@ static void ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
psu->led_state = CFFPS_LED_ON; psu->led_state = CFFPS_LED_ON;
} }
pmbus_set_page(psu->client, 0);
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
psu->led_state); psu->led_state);
if (rc < 0) if (rc < 0)
...@@ -299,6 +328,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev, ...@@ -299,6 +328,8 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
if (led_cdev->brightness == LED_OFF) if (led_cdev->brightness == LED_OFF)
return 0; return 0;
pmbus_set_page(psu->client, 0);
rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD, rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
CFFPS_LED_BLINK); CFFPS_LED_BLINK);
if (rc < 0) if (rc < 0)
...@@ -328,15 +359,32 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu) ...@@ -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); dev_warn(dev, "failed to register led class: %d\n", rc);
} }
static struct pmbus_driver_info ibm_cffps_info = { static struct pmbus_driver_info ibm_cffps_info[] = {
[cffps1] = {
.pages = 1, .pages = 1,
.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP | PMBUS_HAVE_PIN | PMBUS_HAVE_FAN12 | PMBUS_HAVE_TEMP |
PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_STATUS_TEMP | PMBUS_HAVE_STATUS_FAN12, 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_byte_data = ibm_cffps_read_byte_data,
.read_word_data = ibm_cffps_read_word_data, .read_word_data = ibm_cffps_read_word_data,
},
}; };
static struct pmbus_platform_data ibm_cffps_pdata = { static struct pmbus_platform_data ibm_cffps_pdata = {
...@@ -347,12 +395,21 @@ static int ibm_cffps_probe(struct i2c_client *client, ...@@ -347,12 +395,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
int i, rc; int i, rc;
enum versions vs;
struct dentry *debugfs; struct dentry *debugfs;
struct dentry *ibm_cffps_dir; struct dentry *ibm_cffps_dir;
struct ibm_cffps *psu; 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; 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) if (rc)
return rc; return rc;
...@@ -364,6 +421,7 @@ static int ibm_cffps_probe(struct i2c_client *client, ...@@ -364,6 +421,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
if (!psu) if (!psu)
return 0; return 0;
psu->version = vs;
psu->client = client; psu->client = client;
mutex_init(&psu->input_history.update_lock); mutex_init(&psu->input_history.update_lock);
psu->input_history.last_update = jiffies - HZ; psu->input_history.last_update = jiffies - HZ;
...@@ -405,13 +463,21 @@ static int ibm_cffps_probe(struct i2c_client *client, ...@@ -405,13 +463,21 @@ static int ibm_cffps_probe(struct i2c_client *client,
} }
static const struct i2c_device_id ibm_cffps_id[] = { 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); MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
static const struct of_device_id ibm_cffps_of_match[] = { 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); MODULE_DEVICE_TABLE(of, ibm_cffps_of_match);
......
// 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, ...@@ -244,8 +244,6 @@ static int max31785_write_word_data(struct i2c_client *client, int page,
#define MAX31785_VOUT_FUNCS \ #define MAX31785_VOUT_FUNCS \
(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT) (PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
#define MAX37185_NUM_FAN_PAGES 6
static const struct pmbus_driver_info max31785_info = { static const struct pmbus_driver_info max31785_info = {
.pages = MAX31785_NR_PAGES, .pages = MAX31785_NR_PAGES,
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/pmbus.h> #include <linux/pmbus.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include "pmbus.h" #include "pmbus.h"
......
...@@ -146,7 +146,7 @@ static struct platform_driver rpi_hwmon_driver = { ...@@ -146,7 +146,7 @@ static struct platform_driver rpi_hwmon_driver = {
}; };
module_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_DESCRIPTION("Raspberry Pi voltage sensor driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:raspberrypi-hwmon"); MODULE_ALIAS("platform:raspberrypi-hwmon");
...@@ -26,17 +26,31 @@ static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c }; ...@@ -26,17 +26,31 @@ static const unsigned char shtc1_cmd_measure_nonblocking_lpm[] = { 0x60, 0x9c };
/* command for reading the ID register */ /* 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 * constants for reading the ID register
#define SHTC1_ID_REG_MASK 0x1f * 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 */ /* delays for non-blocking i2c commands, both in us */
#define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400 #define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400
#define SHTC1_NONBLOCKING_WAIT_TIME_LPM 1000 #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_CMD_LENGTH 2
#define SHTC1_RESPONSE_LENGTH 6 #define SHTC1_RESPONSE_LENGTH 6
enum shtcx_chips {
shtc1,
shtc3,
};
struct shtc1_data { struct shtc1_data {
struct i2c_client *client; struct i2c_client *client;
struct mutex update_lock; struct mutex update_lock;
...@@ -47,6 +61,7 @@ struct shtc1_data { ...@@ -47,6 +61,7 @@ struct shtc1_data {
unsigned int nonblocking_wait_time; /* in us */ unsigned int nonblocking_wait_time; /* in us */
struct shtc1_platform_data setup; struct shtc1_platform_data setup;
enum shtcx_chips chip;
int temperature; /* 1000 * temperature in dgr C */ int temperature; /* 1000 * temperature in dgr C */
int humidity; /* 1000 * relative humidity in %RH */ int humidity; /* 1000 * relative humidity in %RH */
...@@ -157,13 +172,16 @@ static void shtc1_select_command(struct shtc1_data *data) ...@@ -157,13 +172,16 @@ static void shtc1_select_command(struct shtc1_data *data)
data->command = data->setup.blocking_io ? data->command = data->setup.blocking_io ?
shtc1_cmd_measure_blocking_hpm : shtc1_cmd_measure_blocking_hpm :
shtc1_cmd_measure_nonblocking_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 { } else {
data->command = data->setup.blocking_io ? data->command = data->setup.blocking_io ?
shtc1_cmd_measure_blocking_lpm : shtc1_cmd_measure_blocking_lpm :
shtc1_cmd_measure_nonblocking_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, ...@@ -171,9 +189,11 @@ static int shtc1_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
int ret; int ret;
char id_reg[2]; u16 id_reg;
char id_reg_buf[2];
struct shtc1_data *data; struct shtc1_data *data;
struct device *hwmon_dev; struct device *hwmon_dev;
enum shtcx_chips chip = id->driver_data;
struct i2c_adapter *adap = client->adapter; struct i2c_adapter *adap = client->adapter;
struct device *dev = &client->dev; struct device *dev = &client->dev;
...@@ -187,13 +207,20 @@ static int shtc1_probe(struct i2c_client *client, ...@@ -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); dev_err(dev, "could not send read_id_reg command: %d\n", ret);
return ret < 0 ? ret : -ENODEV; return ret < 0 ? ret : -ENODEV;
} }
ret = i2c_master_recv(client, id_reg, sizeof(id_reg)); ret = i2c_master_recv(client, id_reg_buf, sizeof(id_reg_buf));
if (ret != sizeof(id_reg)) { if (ret != sizeof(id_reg_buf)) {
dev_err(dev, "could not read ID register: %d\n", ret); dev_err(dev, "could not read ID register: %d\n", ret);
return -ENODEV; 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; return -ENODEV;
} }
...@@ -204,6 +231,7 @@ static int shtc1_probe(struct i2c_client *client, ...@@ -204,6 +231,7 @@ static int shtc1_probe(struct i2c_client *client,
data->setup.blocking_io = false; data->setup.blocking_io = false;
data->setup.high_precision = true; data->setup.high_precision = true;
data->client = client; data->client = client;
data->chip = chip;
if (client->dev.platform_data) if (client->dev.platform_data)
data->setup = *(struct shtc1_platform_data *)dev->platform_data; data->setup = *(struct shtc1_platform_data *)dev->platform_data;
...@@ -222,8 +250,9 @@ static int shtc1_probe(struct i2c_client *client, ...@@ -222,8 +250,9 @@ static int shtc1_probe(struct i2c_client *client,
/* device ID table */ /* device ID table */
static const struct i2c_device_id shtc1_id[] = { static const struct i2c_device_id shtc1_id[] = {
{ "shtc1", 0 }, { "shtc1", shtc1 },
{ "shtw1", 0 }, { "shtw1", shtc1 },
{ "shtc3", shtc3 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, shtc1_id); MODULE_DEVICE_TABLE(i2c, shtc1_id);
......
...@@ -586,10 +586,10 @@ static int smm665_probe(struct i2c_client *client, ...@@ -586,10 +586,10 @@ static int smm665_probe(struct i2c_client *client,
data->client = client; data->client = client;
data->type = id->driver_data; 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); | SMM665_CMDREG_BASE);
if (!data->cmdreg) if (IS_ERR(data->cmdreg))
return -ENOMEM; return PTR_ERR(data->cmdreg);
switch (data->type) { switch (data->type) {
case smm465: case smm465:
......
...@@ -894,12 +894,12 @@ w83781d_detect_subclients(struct i2c_client *new_client) ...@@ -894,12 +894,12 @@ w83781d_detect_subclients(struct i2c_client *new_client)
} }
for (i = 0; i < num_sc; i++) { for (i = 0; i < num_sc; i++) {
data->lm75[i] = i2c_new_dummy(adapter, sc_addr[i]); data->lm75[i] = i2c_new_dummy_device(adapter, sc_addr[i]);
if (!data->lm75[i]) { if (IS_ERR(data->lm75[i])) {
dev_err(&new_client->dev, dev_err(&new_client->dev,
"Subclient %d registration at address 0x%x failed.\n", "Subclient %d registration at address 0x%x failed.\n",
i, sc_addr[i]); i, sc_addr[i]);
err = -ENOMEM; err = PTR_ERR(data->lm75[i]);
if (i == 1) if (i == 1)
goto ERROR_SC_3; goto ERROR_SC_3;
goto ERROR_SC_2; goto ERROR_SC_2;
......
...@@ -1260,7 +1260,7 @@ static int w83791d_detect_subclients(struct i2c_client *client) ...@@ -1260,7 +1260,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
struct i2c_adapter *adapter = client->adapter; struct i2c_adapter *adapter = client->adapter;
struct w83791d_data *data = i2c_get_clientdata(client); struct w83791d_data *data = i2c_get_clientdata(client);
int address = client->addr; int address = client->addr;
int i, id, err; int i, id;
u8 val; u8 val;
id = i2c_adapter_id(adapter); id = i2c_adapter_id(adapter);
...@@ -1272,8 +1272,7 @@ static int w83791d_detect_subclients(struct i2c_client *client) ...@@ -1272,8 +1272,7 @@ static int w83791d_detect_subclients(struct i2c_client *client)
"invalid subclient " "invalid subclient "
"address %d; must be 0x48-0x4f\n", "address %d; must be 0x48-0x4f\n",
force_subclients[i]); force_subclients[i]);
err = -ENODEV; return -ENODEV;
goto error_sc_0;
} }
} }
w83791d_write(client, W83791D_REG_I2C_SUBADDR, w83791d_write(client, W83791D_REG_I2C_SUBADDR,
...@@ -1283,29 +1282,22 @@ static int w83791d_detect_subclients(struct i2c_client *client) ...@@ -1283,29 +1282,22 @@ static int w83791d_detect_subclients(struct i2c_client *client)
val = w83791d_read(client, W83791D_REG_I2C_SUBADDR); val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
if (!(val & 0x08)) 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 (!(val & 0x80)) {
if ((data->lm75[0] != NULL) && if (!IS_ERR(data->lm75[0]) &&
((val & 0x7) == ((val >> 4) & 0x7))) { ((val & 0x7) == ((val >> 4) & 0x7))) {
dev_err(&client->dev, dev_err(&client->dev,
"duplicate addresses 0x%x, " "duplicate addresses 0x%x, "
"use force_subclient\n", "use force_subclient\n",
data->lm75[0]->addr); data->lm75[0]->addr);
err = -ENODEV; return -ENODEV;
goto error_sc_1;
} }
data->lm75[1] = i2c_new_dummy(adapter, data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
0x48 + ((val >> 4) & 0x7)); 0x48 + ((val >> 4) & 0x7));
} }
return 0; 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, ...@@ -1394,7 +1386,7 @@ static int w83791d_probe(struct i2c_client *client,
/* Register sysfs hooks */ /* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &w83791d_group); err = sysfs_create_group(&client->dev.kobj, &w83791d_group);
if (err) if (err)
goto error3; return err;
/* Check if pins of fan/pwm 4-5 are in use as GPIO */ /* Check if pins of fan/pwm 4-5 are in use as GPIO */
has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10; has_fanpwm45 = w83791d_read(client, W83791D_REG_GPIO) & 0x10;
...@@ -1419,9 +1411,6 @@ static int w83791d_probe(struct i2c_client *client, ...@@ -1419,9 +1411,6 @@ static int w83791d_probe(struct i2c_client *client,
sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45); sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45);
error4: error4:
sysfs_remove_group(&client->dev.kobj, &w83791d_group); sysfs_remove_group(&client->dev.kobj, &w83791d_group);
error3:
i2c_unregister_device(data->lm75[0]);
i2c_unregister_device(data->lm75[1]);
return err; return err;
} }
...@@ -1432,9 +1421,6 @@ static int w83791d_remove(struct i2c_client *client) ...@@ -1432,9 +1421,6 @@ static int w83791d_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev); hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &w83791d_group); sysfs_remove_group(&client->dev.kobj, &w83791d_group);
i2c_unregister_device(data->lm75[0]);
i2c_unregister_device(data->lm75[1]);
return 0; return 0;
} }
......
...@@ -924,7 +924,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr, ...@@ -924,7 +924,7 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
static int static int
w83792d_detect_subclients(struct i2c_client *new_client) w83792d_detect_subclients(struct i2c_client *new_client)
{ {
int i, id, err; int i, id;
int address = new_client->addr; int address = new_client->addr;
u8 val; u8 val;
struct i2c_adapter *adapter = new_client->adapter; struct i2c_adapter *adapter = new_client->adapter;
...@@ -938,8 +938,7 @@ w83792d_detect_subclients(struct i2c_client *new_client) ...@@ -938,8 +938,7 @@ w83792d_detect_subclients(struct i2c_client *new_client)
dev_err(&new_client->dev, dev_err(&new_client->dev,
"invalid subclient address %d; must be 0x48-0x4f\n", "invalid subclient address %d; must be 0x48-0x4f\n",
force_subclients[i]); force_subclients[i]);
err = -ENODEV; return -ENODEV;
goto ERROR_SC_0;
} }
} }
w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR, w83792d_write_value(new_client, W83792D_REG_I2C_SUBADDR,
...@@ -949,28 +948,21 @@ w83792d_detect_subclients(struct i2c_client *new_client) ...@@ -949,28 +948,21 @@ w83792d_detect_subclients(struct i2c_client *new_client)
val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR); val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
if (!(val & 0x08)) 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 (!(val & 0x80)) {
if ((data->lm75[0] != NULL) && if (!IS_ERR(data->lm75[0]) &&
((val & 0x7) == ((val >> 4) & 0x7))) { ((val & 0x7) == ((val >> 4) & 0x7))) {
dev_err(&new_client->dev, dev_err(&new_client->dev,
"duplicate addresses 0x%x, use force_subclient\n", "duplicate addresses 0x%x, use force_subclient\n",
data->lm75[0]->addr); data->lm75[0]->addr);
err = -ENODEV; return -ENODEV;
goto ERROR_SC_1;
} }
data->lm75[1] = i2c_new_dummy(adapter, data->lm75[1] = devm_i2c_new_dummy_device(&new_client->dev, adapter,
0x48 + ((val >> 4) & 0x7)); 0x48 + ((val >> 4) & 0x7));
} }
return 0; 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); 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) ...@@ -1396,7 +1388,7 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* Register sysfs hooks */ /* Register sysfs hooks */
err = sysfs_create_group(&dev->kobj, &w83792d_group); err = sysfs_create_group(&dev->kobj, &w83792d_group);
if (err) if (err)
goto exit_i2c_unregister; return err;
/* /*
* Read GPIO enable register to check if pins for fan 4,5 are used as * Read GPIO enable register to check if pins for fan 4,5 are used as
...@@ -1441,9 +1433,6 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1441,9 +1433,6 @@ w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
sysfs_remove_group(&dev->kobj, &w83792d_group); sysfs_remove_group(&dev->kobj, &w83792d_group);
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++) for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
sysfs_remove_group(&dev->kobj, &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; return err;
} }
...@@ -1459,9 +1448,6 @@ w83792d_remove(struct i2c_client *client) ...@@ -1459,9 +1448,6 @@ w83792d_remove(struct i2c_client *client)
sysfs_remove_group(&client->dev.kobj, sysfs_remove_group(&client->dev.kobj,
&w83792d_group_fan[i]); &w83792d_group_fan[i]);
i2c_unregister_device(data->lm75[0]);
i2c_unregister_device(data->lm75[1]);
return 0; return 0;
} }
......
...@@ -1551,9 +1551,6 @@ static int w83793_remove(struct i2c_client *client) ...@@ -1551,9 +1551,6 @@ static int w83793_remove(struct i2c_client *client)
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
device_remove_file(dev, &w83793_temp[i].dev_attr); 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 */ /* Decrease data reference counter */
mutex_lock(&watchdog_data_mutex); mutex_lock(&watchdog_data_mutex);
kref_put(&data->kref, w83793_release_resources); kref_put(&data->kref, w83793_release_resources);
...@@ -1565,7 +1562,7 @@ static int w83793_remove(struct i2c_client *client) ...@@ -1565,7 +1562,7 @@ static int w83793_remove(struct i2c_client *client)
static int static int
w83793_detect_subclients(struct i2c_client *client) w83793_detect_subclients(struct i2c_client *client)
{ {
int i, id, err; int i, id;
int address = client->addr; int address = client->addr;
u8 tmp; u8 tmp;
struct i2c_adapter *adapter = client->adapter; struct i2c_adapter *adapter = client->adapter;
...@@ -1580,8 +1577,7 @@ w83793_detect_subclients(struct i2c_client *client) ...@@ -1580,8 +1577,7 @@ w83793_detect_subclients(struct i2c_client *client)
"invalid subclient " "invalid subclient "
"address %d; must be 0x48-0x4f\n", "address %d; must be 0x48-0x4f\n",
force_subclients[i]); force_subclients[i]);
err = -EINVAL; return -EINVAL;
goto ERROR_SC_0;
} }
} }
w83793_write_value(client, W83793_REG_I2C_SUBADDR, w83793_write_value(client, W83793_REG_I2C_SUBADDR,
...@@ -1591,28 +1587,21 @@ w83793_detect_subclients(struct i2c_client *client) ...@@ -1591,28 +1587,21 @@ w83793_detect_subclients(struct i2c_client *client)
tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR); tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
if (!(tmp & 0x08)) 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 (!(tmp & 0x80)) {
if ((data->lm75[0] != NULL) if (!IS_ERR(data->lm75[0])
&& ((tmp & 0x7) == ((tmp >> 4) & 0x7))) { && ((tmp & 0x7) == ((tmp >> 4) & 0x7))) {
dev_err(&client->dev, dev_err(&client->dev,
"duplicate addresses 0x%x, " "duplicate addresses 0x%x, "
"use force_subclients\n", data->lm75[0]->addr); "use force_subclients\n", data->lm75[0]->addr);
err = -ENODEV; return -ENODEV;
goto ERROR_SC_1;
} }
data->lm75[1] = i2c_new_dummy(adapter, data->lm75[1] = devm_i2c_new_dummy_device(&client->dev, adapter,
0x48 + ((tmp >> 4) & 0x7)); 0x48 + ((tmp >> 4) & 0x7));
} }
return 0; 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 */ /* Return 0 if detection is successful, -ENODEV otherwise */
...@@ -1945,9 +1934,6 @@ static int w83793_probe(struct i2c_client *client, ...@@ -1945,9 +1934,6 @@ static int w83793_probe(struct i2c_client *client,
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
device_remove_file(dev, &w83793_temp[i].dev_attr); device_remove_file(dev, &w83793_temp[i].dev_attr);
i2c_unregister_device(data->lm75[0]);
i2c_unregister_device(data->lm75[1]);
free_mem: free_mem:
kfree(data); kfree(data);
exit: exit:
......
...@@ -958,7 +958,7 @@ config TI_ADC161S626 ...@@ -958,7 +958,7 @@ config TI_ADC161S626
config TI_ADS1015 config TI_ADS1015
tristate "Texas Instruments ADS1015 ADC" tristate "Texas Instruments ADS1015 ADC"
depends on I2C && !SENSORS_ADS1015 depends on I2C
select REGMAP_I2C select REGMAP_I2C
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
......
...@@ -548,6 +548,7 @@ ...@@ -548,6 +548,7 @@
#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463 #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_M10H_DF_F3 0x15eb
#define PCI_DEVICE_ID_AMD_17H_M30H_DF_F3 0x1493 #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_CNB17H_F3 0x1703
#define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment