Merge tag 'hwmon-for-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 20:44:16 +0000 (13:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 20:44:16 +0000 (13:44 -0700)
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
  ...

45 files changed:
Documentation/devicetree/bindings/hwmon/as370.txt [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/ibm,cffps1.txt
Documentation/devicetree/bindings/hwmon/lm75.txt
Documentation/devicetree/bindings/iio/adc/ads1015.txt [moved from Documentation/devicetree/bindings/hwmon/ads1015.txt with 100% similarity]
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/hwmon/ads1015.rst [deleted file]
Documentation/hwmon/index.rst
Documentation/hwmon/inspur-ipsps1.rst [new file with mode: 0644]
Documentation/hwmon/lm75.rst
Documentation/hwmon/pxe1610.rst [moved from Documentation/hwmon/pxe1610 with 82% similarity]
Documentation/hwmon/shtc1.rst
Documentation/hwmon/submitting-patches.rst
MAINTAINERS
arch/x86/kernel/amd_nb.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/acpi_power_meter.c
drivers/hwmon/ads1015.c [deleted file]
drivers/hwmon/adt7475.c
drivers/hwmon/as370-hwmon.c [new file with mode: 0644]
drivers/hwmon/asb100.c
drivers/hwmon/coretemp.c
drivers/hwmon/iio_hwmon.c
drivers/hwmon/k10temp.c
drivers/hwmon/k8temp.c
drivers/hwmon/lm75.c
drivers/hwmon/ltc2990.c
drivers/hwmon/nct6775.c
drivers/hwmon/nct7904.c
drivers/hwmon/npcm750-pwm-fan.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/Makefile
drivers/hwmon/pmbus/ibm-cffps.c
drivers/hwmon/pmbus/inspur-ipsps.c [new file with mode: 0644]
drivers/hwmon/pmbus/max31785.c
drivers/hwmon/pmbus/ucd9000.c
drivers/hwmon/raspberrypi-hwmon.c
drivers/hwmon/shtc1.c
drivers/hwmon/smm665.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83791d.c
drivers/hwmon/w83792d.c
drivers/hwmon/w83793.c
drivers/iio/adc/Kconfig
include/linux/pci_ids.h

diff --git a/Documentation/devicetree/bindings/hwmon/as370.txt b/Documentation/devicetree/bindings/hwmon/as370.txt
new file mode 100644 (file)
index 0000000..d102fe7
--- /dev/null
@@ -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>;
+       };
index f68a0a68fc524cdc1ee547313892a34e78248800..1036f65fb778eeb54d6e600d0722c5c6a1746680 100644 (file)
@@ -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.
 
index 586b5ed70be7a0f2ff21e49c60ba2ae072645083..273616702c51b5f089c521dd49d734b42879aa29 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
                "maxim,max31725",
                "maxim,max31726",
                "maxim,mcp980x",
+               "nxp,pct2075",
                "st,stds75",
                "st,stlm75",
                "microchip,tcn75",
index 2e742d399e87b039cc77f04c53ff33634e94c177..870ac52d2225923961712ced3a51c030cba0a386 100644 (file)
@@ -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
diff --git a/Documentation/hwmon/ads1015.rst b/Documentation/hwmon/ads1015.rst
deleted file mode 100644 (file)
index e0951c4..0000000
+++ /dev/null
@@ -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
index ee090e51653a65d6302cf979baaf51ff660e62f0..8147c3f218bfb11167ca160ebc69c3d33b5b07f4 100644 (file)
@@ -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
diff --git a/Documentation/hwmon/inspur-ipsps1.rst b/Documentation/hwmon/inspur-ipsps1.rst
new file mode 100644 (file)
index 0000000..2b871ae
--- /dev/null
@@ -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.
+======================= ======================================================
index ba8acbd2a6cb3f0c1945e3f9fa4d5b2699fcc27e..e749f827c00236ba7d5ada47d4ec34b1d1c86db6 100644 (file)
@@ -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
similarity index 82%
rename from Documentation/hwmon/pxe1610
rename to Documentation/hwmon/pxe1610.rst
index 211cedeefb444e8e90ec083e032e4239eea9ec5e..4f2388840d06ca27f0a65c71b388842a0d5aaa24 100644 (file)
@@ -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
+======================  ====================================
index aa116332ba26087a35f72b1541ee388ac21b7d1f..9b0f1eee5bf2adad564efba59a791da5039400d4 100644 (file)
@@ -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
index 452fc28d8e0bb3f7efefc6f20c5a0786ae72b22e..9a218ea996d8633e8705d4f9e8f41f0e90f3b2ad 100644 (file)
@@ -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().
 
index 9398837c276bd31351c968c0e454938314fb559e..97be6abb05eab3f7e2c0c7d5063ac0294ebb2546 100644 (file)
@@ -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
index d63e63b7d1d9581d8036a98e439185e460eaffe8..251c795b4eb3cd75991aabd6b1cffa6b3fedb8fe 100644 (file)
@@ -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) },
        {}
 };
index 650dd71f9724ae605761066b75ff191dc8bd7229..2ca5668bdb626a866b9b581caa0e76af23378f28 100644 (file)
@@ -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.
index 8db472ea04f00880b8aee3a303847d95fb733261..c86ce4d3d36b9e67f2173cceed38466c36051657 100644 (file)
@@ -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
index 6ba1a08253f0a3cc12a7657e4c31a0853c13b963..4cf25458f0b9515e419a6f0b88047bf35809a2e5 100644 (file)
@@ -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;
                }
 
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
deleted file mode 100644 (file)
index 3727a37..0000000
+++ /dev/null
@@ -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");
index c3c6031a728520d9e0035de8ff2e5e02d693d41f..6c64d50c9aae8ec175d9477fa98af6c851849d2f 100644 (file)
@@ -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);
diff --git a/drivers/hwmon/as370-hwmon.c b/drivers/hwmon/as370-hwmon.c
new file mode 100644 (file)
index 0000000..464244b
--- /dev/null
@@ -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");
index c9fa84b256783df45824abe066bdbe1cb5896422..4c609e23a4efb93d683bcefbd6e78b4ab53ea0ea 100644 (file)
@@ -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;
        }
 
index fe6618e49dc436cafda1e5ad12f6a8cbd89ef7c6..d855c78fb8bea77d87df0fe2a16289a039bc63ed 100644 (file)
@@ -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;
 }
index f1c2d5faedf0d76d2074b305065cf2261e6ceb72..b85a125dd86f46a26ac817bd42a718c4ad97310c 100644 (file)
@@ -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(chan, &result);
+       if (ret < 0)
+               return ret;
 
-       ret = iio_read_channel_processed(&state->channels[sattr->index],
-                                       &result);
+       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";
index c77e89239dcd9a32c143203030362264d86f83b7..5c1dddde193c3e1ce50c539ba91e00b885a73190 100644 (file)
@@ -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) },
        {}
 };
index 4994c90c892986d9546765607eb7726b41adfee9..f73bd4eceb28f0e46c628b1902b3b2d6d90c0195 100644 (file)
 #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>
 #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;
-
-       /* 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);
+       hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
+                                                        "k8temp",
+                                                        data,
+                                                        &k8temp_chip_info,
+                                                        NULL);
 
-       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);
index ce5ec403ec739c819ee8f896e5958d63380246ee..5e6392294c0351e529754bef61426dbdcd35876d 100644 (file)
@@ -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, &reg);
+               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,113 +574,30 @@ 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;
-       }
 
-       /* configure as specified */
+       data->params = &device_params[data->kind];
+
+       /* 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 = devm_add_action_or_reset(dev, lm75_remove, data);
+       err = lm75_write_config(data, data->params->set_mask,
+                               data->params->clr_mask);
        if (err)
                return err;
 
-       dev_dbg(dev, "Config %02x\n", new);
+       err = devm_add_action_or_reset(dev, lm75_remove, data);
+       if (err)
+               return err;
 
        hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
                                                         data, &lm75_chip_info,
@@ -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
index f9431ad43ad3b02a0b83e3e4990d56aa2f0fcdba..53ff5051774ccc5e1a3254105da6499b1b69fed4 100644 (file)
@@ -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;
 
index d42bc0883a32b4ba115f113d84e6503ecd43e081..7efa6bfef06097e5d20878566a84bc9666b3f2d6 100644 (file)
@@ -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
 
 #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;
index 710c30562fc1fe62ff14bee4122c539c3cd7ad71..95b447cfa24cb82a118fa62f3bc4c99caec33153 100644 (file)
 #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;
index 09aaefa6fdb8c192e561d720dab6cc7d65a40138..11a28609da3c769343fd83c976a6ffdc13050bc5 100644 (file)
@@ -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,
index b6588483fae125a28562df82e90b2fb1446f29ea..d62d69bb7e490412b72ec7e6eb4e2ad612add115 100644 (file)
@@ -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
index c950ea9a5d003e0645be173a871303875cc6a47b..03bacfcfd6607dbb2365b6d1e912489f3838f92b 100644 (file)
@@ -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
index ee2ee9e3ffd739ab06116b6d6ef9db1867980665..d44745e498e76b0d847caaff878118e711a571d0 100644 (file)
@@ -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 * 2;
+                       rc = i * 4;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
                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);
diff --git a/drivers/hwmon/pmbus/inspur-ipsps.c b/drivers/hwmon/pmbus/inspur-ipsps.c
new file mode 100644 (file)
index 0000000..42e0154
--- /dev/null
@@ -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");
index 69d9029ea410d03581515b954a74a5264f2a6f20..254b0f98c7552024dad65835e3805342b9147ba4 100644 (file)
@@ -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,
 
index c846759bc1c0866d3954f5fd9b895e315275a800..a9229c6b0e84dcc7435d18bd9e19bef9a60227ae 100644 (file)
@@ -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"
 
index efe4bb1ff221c871d99c1c6697690cf870cdeea7..d3a64a35f7a9af2d11fe31de0d37b5abb7c2301a 100644 (file)
@@ -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");
index 83fe08185ac7d9a9a1a92338277b742fa0547919..a0078ccede03f9302db615deab5e0d65df75fdcc 100644 (file)
@@ -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);
index d8c91c2cb8cf5eab77498c81cd465033597bc2dd..6eff14fe395d3466ba944b1b81a37fffc0c87b19 100644 (file)
@@ -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:
index d2c04b6a3f2b7cfd7974b8cf19ae1f21ad80ed69..015f1ea319669eff7932daf49456a6638b9a7add 100644 (file)
@@ -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;
index 050ad42016914803181eb5e6f306185039f4eac8..aad8d4da5802be02cf981778ea68642075706f4a 100644 (file)
@@ -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;
 }
 
index da8a6d62aa2347c9c7fd8dac5aae66193082b3f5..7fc8a1160c8f95269a8c29e07db0ff3e92c962d9 100644 (file)
@@ -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;
 }
 
index 46f5dfec8d0a29ef6ff40b151d19f4e3024320fd..9df48b70c70c7381fbcba60119182a39edb2a2cd 100644 (file)
@@ -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:
index 7e3286265a3845346d11b82d7d8c2b3fe72042fe..f0af3a42f53cf6d605b3c1ad413468bcdd9138dd 100644 (file)
@@ -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
index c842735a4f45a41d4ce305d236d08a8b2d0ef3b6..4b97f427cc929972de59bcd4b1de5531ea56e16a 100644 (file)
 #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